synergy-1.8.8-stable/000077500000000000000000000000001305627404700145105ustar00rootroot00000000000000synergy-1.8.8-stable/.github/000077500000000000000000000000001305627404700160505ustar00rootroot00000000000000synergy-1.8.8-stable/.github/ISSUE_TEMPLATE.md000066400000000000000000000024141305627404700205560ustar00rootroot00000000000000### Operating Systems ### Server: microOS Tiara Client: Applesoft Windy OS 10 **READ ME, DELETE ME**: On Windows, hold the Windows key and press 'r', type 'winver' and hit return to get your OS version. On Mac, hit the Apple menu (top left of the screen) and check 'About this Mac'. Linux users... you know what you're using ;) ### Synergy Version ### 1.8.π **READ ME, DELETE ME**: Go to the 'Help' (on Windows) or 'Synergy' (on macOS) menu and then 'About Synergy' to check your version. Verify that you are using the same version across all of your machines, and that your issue still occurs with the latest release available at https://symless.com/account/login ### Steps to reproduce bug ### **READ ME, DELETE ME**: Try to be succinct. If your bug is intermittent, try and describe what you're doing when it happens most. 1. Click things. 2. Type things. 3. Bug occurs. 4. ... 5. Profit? ### Other info ### * When did the problem start to occur? When I... * Is there a way to work around it? No/Yes, you can... * Does this bug prevent you from using Synergy entirely? Yes/No Please follow the link below to send us logs from both your server and client sides if it's appropriate. https://github.com/symless/synergy/wiki/Sending-logs Put anything else you can think of here. synergy-1.8.8-stable/.gitignore000066400000000000000000000004661305627404700165060ustar00rootroot00000000000000config.h .DS_Store *.pyc *.o *~ \.*.swp *build-gui-Desktop_Qt* /bin /lib /build /CMakeFiles /ext/cryptopp562 /ext/gmock-1.6.0 /ext/gtest-1.6.0 /ext/openssl /src/gui/Makefile* /src/gui/object_script* /src/gui/tmp /src/gui/ui_* src/gui/gui.pro.user* src/gui/.qmake.stash src/gui/.rnd src/setup/win32/synergy.suo synergy-1.8.8-stable/.lvimrc000066400000000000000000000005071305627404700160070ustar00rootroot00000000000000"Instructions "Download vim script 411 "http://www.vim.org/scripts/script.php?script_id=441 "Install localvimrc.vim to .vim/plugin " " Hint: You can disable it asking before sourcing a file by adding this to " your .vimrc: let g:localvimrc_ask=0 set nosmarttab set noexpandtab set shiftwidth=8 set softtabstop=0 set tabstop=4 synergy-1.8.8-stable/CMakeLists.txt000066400000000000000000000255471305627404700172650ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Version number for Synergy set(VERSION_MAJOR 1) set(VERSION_MINOR 8) set(VERSION_REV 8) set(VERSION_STAGE stable) set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REV}") cmake_minimum_required(VERSION 2.6) # CMake complains if we don't have this. if (COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif() # We're escaping quotes in the Windows version number, because # for some reason CMake won't do it at config version 2.4.7 # It seems that this restores the newer behaviour where define # args are not auto-escaped. if (COMMAND cmake_policy) cmake_policy(SET CMP0005 NEW) endif() # First, declare project (important for prerequisite checks). project(synergy C CXX) # put binaries in a different dir to make them easier to find. set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) # for unix, put debug files in a separate bin "debug" dir. # release bin files should stay in the root of the bin dir. if (CMAKE_GENERATOR STREQUAL "Unix Makefiles") if (CMAKE_BUILD_TYPE STREQUAL Debug) set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin/debug) set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib/debug) endif() endif() # Set some easy to type variables. set(root_dir ${CMAKE_SOURCE_DIR}) set(cmake_dir ${root_dir}/res) set(bin_dir ${root_dir}/bin) set(doc_dir ${root_dir}/doc) set(doc_dir ${root_dir}/doc) # Declare libs, so we can use list in linker later. There's probably # a more elegant way of doing this; with SCons, when you check for the # lib, it is automatically passed to the linker. set(libs) # only include headers as "source" if not unix makefiles, # which is useful when using an IDE. if (${CMAKE_GENERATOR} STREQUAL "Unix Makefiles") set(SYNERGY_ADD_HEADERS FALSE) else() set(SYNERGY_ADD_HEADERS TRUE) endif() # Depending on the platform, pass in the required defines. if (UNIX) if (NOT APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") endif() # For config.h, detect the libraries, functions, etc. include(CheckIncludeFiles) include(CheckLibraryExists) include(CheckFunctionExists) include(CheckTypeSize) include(CheckIncludeFileCXX) include(CheckSymbolExists) include(CheckCSourceCompiles) check_include_file_cxx(istream HAVE_ISTREAM) check_include_file_cxx(ostream HAVE_OSTREAM) check_include_file_cxx(sstream HAVE_SSTREAM) check_include_files(inttypes.h HAVE_INTTYPES_H) check_include_files(locale.h HAVE_LOCALE_H) check_include_files(memory.h HAVE_MEMORY_H) check_include_files(stdlib.h HAVE_STDLIB_H) check_include_files(strings.h HAVE_STRINGS_H) check_include_files(string.h HAVE_STRING_H) check_include_files(sys/select.h HAVE_SYS_SELECT_H) check_include_files(sys/socket.h HAVE_SYS_SOCKET_H) check_include_files(sys/stat.h HAVE_SYS_STAT_H) check_include_files(sys/time.h HAVE_SYS_TIME_H) check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H) check_include_files(unistd.h HAVE_UNISTD_H) check_include_files(wchar.h HAVE_WCHAR_H) check_function_exists(getpwuid_r HAVE_GETPWUID_R) check_function_exists(gmtime_r HAVE_GMTIME_R) check_function_exists(nanosleep HAVE_NANOSLEEP) check_function_exists(poll HAVE_POLL) check_function_exists(sigwait HAVE_POSIX_SIGWAIT) check_function_exists(strftime HAVE_STRFTIME) check_function_exists(vsnprintf HAVE_VSNPRINTF) check_function_exists(inet_aton HAVE_INET_ATON) # For some reason, the check_function_exists macro doesn't detect # the inet_aton on some pure Unix platforms (e.g. sunos5). So we # need to do a more detailed check and also include some extra libs. if (NOT HAVE_INET_ATON) set(CMAKE_REQUIRED_LIBRARIES nsl) check_c_source_compiles( "#include \n int main() { inet_aton(0, 0); }" HAVE_INET_ATON_ADV) set(CMAKE_REQUIRED_LIBRARIES) if (HAVE_INET_ATON_ADV) # Override the previous fail. set(HAVE_INET_ATON 1) # Assume that both nsl and socket will be needed, # it seems safe to add socket on the back of nsl, # since socket only ever needed when nsl is needed. list(APPEND libs nsl socket) endif() endif() check_type_size(char SIZEOF_CHAR) check_type_size(int SIZEOF_INT) check_type_size(long SIZEOF_LONG) check_type_size(short SIZEOF_SHORT) # pthread is used on both Linux and Mac check_library_exists("pthread" pthread_create "" HAVE_PTHREAD) if (HAVE_PTHREAD) list(APPEND libs pthread) else() message(FATAL_ERROR "Missing library: pthread") endif() # curl is used on both Linux and Mac find_package(CURL) if (CURL_FOUND) list(APPEND libs curl) else() message(FATAL_ERROR "Missing library: curl") endif() if (APPLE) message(STATUS "OSX_TARGET_MAJOR=${OSX_TARGET_MAJOR}") message(STATUS "OSX_TARGET_MINOR=${OSX_TARGET_MINOR}") if (NOT (OSX_TARGET_MAJOR EQUAL 10)) message(FATAL_ERROR "Mac OS X target must be 10.x") endif () if (OSX_TARGET_MINOR LESS 6) # <= 10.5: 32-bit Intel and PowerPC set(CMAKE_OSX_ARCHITECTURES "ppc;i386" CACHE STRING "" FORCE) else() # >= 10.6: Intel only set(CMAKE_OSX_ARCHITECTURES "i386" CACHE STRING "" FORCE) endif() set(CMAKE_CXX_FLAGS "--sysroot ${CMAKE_OSX_SYSROOT} ${CMAKE_CXX_FLAGS} -DGTEST_USE_OWN_TR1_TUPLE=1") find_library(lib_ScreenSaver ScreenSaver) find_library(lib_IOKit IOKit) find_library(lib_ApplicationServices ApplicationServices) find_library(lib_Foundation Foundation) find_library(lib_Carbon Carbon) list(APPEND libs ${lib_ScreenSaver} ${lib_IOKit} ${lib_ApplicationServices} ${lib_Foundation} ${lib_Carbon} ) else() # not-apple # add include dir for bsd (posix uses /usr/include/) set(CMAKE_INCLUDE_PATH "${CMAKE_INCLUDE_PATH}:/usr/local/include") set(XKBlib "X11/Xlib.h;X11/XKBlib.h") set(CMAKE_EXTRA_INCLUDE_FILES "${XKBlib};X11/extensions/Xrandr.h") check_type_size("XRRNotifyEvent" X11_EXTENSIONS_XRANDR_H) set(HAVE_X11_EXTENSIONS_XRANDR_H "${X11_EXTENSIONS_XRANDR_H}") set(CMAKE_EXTRA_INCLUDE_FILES) check_include_files("${XKBlib};X11/extensions/dpms.h" HAVE_X11_EXTENSIONS_DPMS_H) check_include_files("X11/extensions/Xinerama.h" HAVE_X11_EXTENSIONS_XINERAMA_H) check_include_files("${XKBlib};X11/extensions/XKBstr.h" HAVE_X11_EXTENSIONS_XKBSTR_H) check_include_files("X11/extensions/XKB.h" HAVE_XKB_EXTENSION) check_include_files("X11/extensions/XTest.h" HAVE_X11_EXTENSIONS_XTEST_H) check_include_files("${XKBlib}" HAVE_X11_XKBLIB_H) check_include_files("X11/extensions/XInput2.h" HAVE_XI2) if (HAVE_X11_EXTENSIONS_DPMS_H) # Assume that function prototypes declared, when include exists. set(HAVE_DPMS_PROTOTYPES 1) endif() if (NOT HAVE_X11_XKBLIB_H) message(FATAL_ERROR "Missing header: " ${XKBlib}) endif() check_library_exists("SM;ICE" IceConnectionNumber "" HAVE_ICE) check_library_exists("Xext;X11" DPMSQueryExtension "" HAVE_Xext) check_library_exists("Xtst;Xext;X11" XTestQueryExtension "" HAVE_Xtst) check_library_exists("Xinerama" XineramaQueryExtension "" HAVE_Xinerama) check_library_exists("Xi" XISelectEvents "" HAVE_Xi) check_library_exists("Xrandr" XRRQueryExtension "" HAVE_Xrandr) if (HAVE_ICE) # Assume we have SM if we have ICE. set(HAVE_SM 1) list(APPEND libs SM ICE) endif() if (HAVE_Xtst) # Xtxt depends on X11. set(HAVE_X11) list(APPEND libs Xtst X11) else() message(FATAL_ERROR "Missing library: Xtst") endif() if (HAVE_Xext) list(APPEND libs Xext) endif() if (HAVE_Xinerama) list(APPEND libs Xinerama) else (HAVE_Xinerama) if (HAVE_X11_EXTENSIONS_XINERAMA_H) set(HAVE_X11_EXTENSIONS_XINERAMA_H 0) message(WARNING "Old Xinerama implementation detected, disabled") endif() endif() if (HAVE_Xrandr) list(APPEND libs Xrandr) endif() # this was outside of the linux scope, # not sure why, moving it back inside. if(HAVE_Xi) list(APPEND libs Xi) endif() endif() # For config.h, set some static values; it may be a good idea to make # these values dynamic for non-standard UNIX compilers. set(ACCEPT_TYPE_ARG3 socklen_t) set(HAVE_CXX_BOOL 1) set(HAVE_CXX_CASTS 1) set(HAVE_CXX_EXCEPTIONS 1) set(HAVE_CXX_MUTABLE 1) set(HAVE_CXX_STDLIB 1) set(HAVE_PTHREAD_SIGNAL 1) set(SELECT_TYPE_ARG1 int) set(SELECT_TYPE_ARG234 "(fd_set *)") set(SELECT_TYPE_ARG5 "(struct timeval *)") set(STDC_HEADERS 1) set(TIME_WITH_SYS_TIME 1) set(HAVE_SOCKLEN_T 1) # For config.h, save the results based on a template (config.h.in). configure_file(res/config.h.in ${root_dir}/config.h) add_definitions(-DSYSAPI_UNIX=1 -DHAVE_CONFIG_H) if (APPLE) add_definitions(-DWINAPI_CARBON=1 -D_THREAD_SAFE) else (APPLE) add_definitions(-DWINAPI_XWINDOWS=1) endif() else() # not-unix list(APPEND libs Wtsapi32 Userenv Wininet comsuppw Shlwapi) add_definitions( /DWIN32 /D_WINDOWS /D_CRT_SECURE_NO_WARNINGS /DVERSION=\"${VERSION}\" ) if (MSVC_VERSION EQUAL 1600) set(SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/synergy.sln") if (EXISTS "${SLN_FILENAME}" ) file(APPEND "${SLN_FILENAME}" "\n# This should be regenerated!\n") endif() endif() endif() add_subdirectory(src) if (WIN32) # TODO: consider using /analyze to uncover potential bugs in the source code. # /WX - warnings as errors (we have a problem with people checking in code with warnings). # /FR - generate browse information (ncb files) useful for using IDE. # /MP - use multi cores to compile. # /D _BIND_TO_CURRENT_VCLIBS_VERSION - TODO: explain why. # /D _SECURE_SCL=1 - find bugs with iterators. set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX /FR /MP /D _BIND_TO_CURRENT_VCLIBS_VERSION=1 /D _SECURE_SCL=1") # /MD - use multi-core libraries. # /O2 - get the fastest code. # /Ob2 - expand inline functions (auto-inlining). set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD /O2 /Ob2") endif() if (${CMAKE_SYSTEM_NAME} MATCHES "IRIX") set_target_properties(synergys PROPERTIES LINK_FLAGS "-all -woff 33 -woff 84 -woff 15") set_target_properties(synergyc PROPERTIES LINK_FLAGS "-all -woff 33 -woff 84 -woff 15") set_target_properties(synergyd PROPERTIES LINK_FLAGS "-all -woff 33 -woff 84 -woff 15") endif() if (CONF_CPACK) message(FATAL_ERROR "CPack support has been removed.") endif() if (CONF_DOXYGEN) set(VERSION, "${VERSION}") # For doxygen.cfg, save the results based on a template (doxygen.cfg.in). configure_file(${cmake_dir}/doxygen.cfg.in ${doc_dir}/doxygen.cfg) endif() synergy-1.8.8-stable/COMPILE000066400000000000000000000000751305627404700155250ustar00rootroot00000000000000Compiling: https://github.com/symless/synergy/wiki/Compiling synergy-1.8.8-stable/ChangeLog000066400000000000000000000452461305627404700162750ustar00rootroot00000000000000v1.8.8-rc1 ========== Bug #5196 - Some keys on Korean and Japanese keyboards have the same keycode Bug #5578 - Pressing Hangul key results in alt+'a' Bug #5785 - Can't switch screens when cursor is in a corner Bug #3992 - macOS: Dragging is broken in Unity 3D Bug #5075 - macOS: Build fails on macOS 10.9 due to unknown compiler flag Bug #5809 - macOS: No version number is shown in the App Info dialog Bug #3197 - Linux: switchDoubleTap option is not working Bug #4477 - Linux: Mouse buttons higher than id 10 result in crash Bug #5832 - Linux: Screen size misdetected on multi-monitor display Enhancement #4504 - Improved Korean language description Enhancement #5525 - Added support for precise screen positioning in config file Enhancement #4290 - Windows: Removed annoying alt+print screen functionality v1.8.7-stable ============= Bug #5784 - Edition changes when reopening GUI v1.8.6-stable ============= Bug #5592 - Some keys don't work for macOS Sierra clients Bug #5186 - Cursor stuck on client when using multi-DPI server Bug #5722 - Malformed serial key in registry will crash GUI on startup Bug #5752 - Tab order is incorrect on Settings dialog Enhancement #5699 - Unified installers on macOS Feature #4836 - macOS Sierra build v1.8.5-stable ============= Bug #5680 - Server crashes when disconnecting SSL clients Bug #5626 - Build fails using Xcode 8 and macOS SDK 10.12 Feature #5657 - Trial version support Feature #5707 - User upgrade statistics v1.8.4-stable ============= Bug #5183 - Slowly moving the cursor has no effect on high DPI clients Bug #4041 - UHD/4K DPI scaling broken on Windows servers Bug #4420 - When XRandR adds a screen, it is inaccessible Bug #5603 - Activation notification depends on existence of /etc/os-release Bug #5624 - Update notification sometimes requests a downgrade Bug #5329 - Current date is shown for build date in the about dialog Enhancement #5617 - Remove redundant plugin infrastructure Enhancement #5627 - Move SSL certificate generation to main window Enhancement #5628 - Move SSL implementation into core binary Enhancement #5629 - Move activation from wizard into new dialog window v1.8.3-stable ============= Bug #2765 - A letter appears on macOS clients when the spacebar is pressed Bug #3241 - Windows UAC disconnects clients when elevated Bug #4740 - Linux client crashes with "Assertion '!m_open' failed" Bug #4879 - Memory leak caused by IpcReader Bug #5373 - Tab behaves like shift tab on client Bug #5502 - Copy and paste from server to client doesn't work Enhancement #123 - Option to disable clipboard sharing Enhancement #3305 - Media key support on macOS Enhancement #4323 - Make automatic elevation on Windows optional v1.8.2-stable ============= Bug #3044 - Unable to drag-select in MS Office Bug #4768 - Copy paste causes 'server is dead' error on switching Bug #4792 - Server logging crashes when switching with clipboard data Bug #2975 - Middle click does not close Chrome tab on Mac client Bug #5087 - Linux client fails to start due to invalid cursor size Bug #5471 - Serial key textbox on activation screen overflows on Mac Bug #4836 - Stop button resets to Start when settings dialog canceled Enhancement #5277 - Auto restart service when synwinhk.dll fails on Windows Enhancement #4913 - Future-proof GUI login by using newer auth URL Enhancement #4922 - Add --enable-crypto argument to help text Enhancement #5299 - High resolution App icon on Mac Enhancement #4894 - Improve grammar in connection notification dialog v1.8.1-stable ============= Bug #5461 - GUI crash during activation on Mac v1.8.0-beta ============= Enhancement #4696 - Include 'ns' plugin in installers (instead of wizard download) Enhancement #4715 - Activation dialog which also accepts a serial key Enhancement #5020 - Recommend using serial key when online activation fails Enhancement #4893 - Show detailed version info on GUI about screen Enhancement #4327 - GUI setting to disable drag and drop feature Enhancement #4793 - Additional logging to output OpenSSL version Enhancement #4932 - Notify activation system when wizard finishes Enhancement #4716 - Allow software to be time limited with serial key v1.7.6-stable ============= Bug #451 - Fast cursor on any client with Mac server Bug #5041 - Copying from the Chrome web browser doesn't work Bug #4735 - Clipboard doesn't work from client to server Bug #2909 - Clipboard copies only plaintext between Mac and Windows Bug #4353 - Large clipboard causes crash Bug #3774 - Missing MinGW dependencies after install on Windows Bug #4723 - Waiting for active desktop result freezes Windows service v1.7.5-stable ============= Bug #5030 - Display scaling breaks edge detection on Windows Bug #5064 - Compile fails on Mac OS X 10.11 (unused typedef) v1.7.4-stable ============= Bug #4721 - High CPU usage for Windows service Bug #4750 - SSL connect error 'passive ssl error limit' Bug #4584 - Drag and drop with SSL causes crash Bug #4749 - Clipboard thread race condition causes assertion failure Bug #4720 - Plugin download shows 'Could not get Linux package type' error Bug #4712 - Unable to send clipboard with size above 1KB when using SSL Bug #4642 - Connecting causes SSL23_GET_SERVER_HELLO error Bug #4690 - Log line 'activeDesktop' does not use logging system Bug #4866 - Wrong ns plugin version can be loaded Enhancement #4901 - Auto restart when running from GUI in desktop mode Enhancement #4845 - Add timestamp to log output Enhancement #4898 - Move version stage name to build config v1.7.3-stable ============= Bug #4565 - Incorrect plugin downloads on Debian and Mint Bug #4677 - Windows service log file grows to very large size Bug #4651 - High logging rate causes Windows service to crash Bug #4650 - SSL error log message repeats excessively and freezes cursor Bug #4624 - Runaway logging causes GUI to freeze Bug #4617 - Windows service randomly stops after 'ssl handshake failure' error Bug #4601 - Large clipboard data with SSL causes 'protocol is shutdown' error Bug #4593 - Locking Windows server causes SSL_ERROR_SSL to repeat Bug #4577 - Memory leak in GUI on Windows caused by logging Bug #4538 - Windows service crashes intermittently with no error Bug #4341 - GUI freezes on first load when reading log Bug #4566 - Client or server crashes with 'ssl handshake failure' error Bug #4706 - Installer is not output to build config dir on Windows Bug #4704 - Plugin 'ns' release build is overwritten with debug version on Linux Bug #4703 - Plugins are not built to config directory on Mac Bug #4697 - Timing can allow an SSL socket to be used after cleanup call Enhancement #4661 - Log error but do not crash when failing to load plugins Enhancement #4708 - Download ns plugin for specific Mac versions Enhancement #4587 - Include OpenSSL binaries in source for easier building Enhancement #4695 - Automatically upload plugins as Buildbot step v1.7.2-stable ============= Bug #4564 - Modifier keys often stuck down on Mac client Bug #4581 - Starting GUI on Mac crashes instantly on syntool segfault Bug #4520 - Laggy or sluggish cursor (ping spikes) on Mac when using WiFi Bug #4607 - GUI doesn't start after install on Windows Enhancement #4412 - Automate extract and compile for OpenSSL Enhancement #4567 - SSL plugin should use TLSv1_method() minimum Enhancement #4591 - Revert to legacy Mac deployment and signing Enhancement #4569 - Reintroduce GUI auto-hide setting (disabled by default) Enhancement #4570 - Make `--crypto-pass` show deprecated message Enhancement #4596 - Typo 'occurred' in WebClient.cpp v1.7.1-stable ============= Bug #3784 - Double click & drag doesn't select words on client Bug #3052 - Triple-click (select line) does not work Bug #4367 - Duplicate Alt-S Keyboard Shortcuts on Gui Bug #4554 - Server unable to accept new SSL connection Bug #4553 - SSL handshake failure error causes GUI to crash Bug #4551 - Plugin wizard doesn't create SSL directory Bug #4548 - Severe code duplication in fingerprint logic Bug #4547 - Windows server crashes when client fingerprint dialog open Bug #4539 - Mac client dies when server has SSL_ERROR_SSL Bug #4537 - Plugin wizard doesn't complete but finish button enabled Bug #4535 - Server crashes on shut down after multiple connections failed Bug #4528 - Error SSL_ERROR_SSL is logged on unknown error Bug #4527 - Server fingerprint dialog on client GUI keeps showing Bug #4469 - GUI crashes on Windows when generating certificate Bug #4410 - SSL_ERROR_SSL (unknown protocol) on Mac client Bug #4409 - SSL_ERROR_SSL (unknown alert type) on Windows 8.1 client Bug #4557 - GUI doesn't show local fingerprint on fresh install Enhancement #4522 - SSL server fingerprint verification from client Enhancement #4526 - Display local fingerprint on server GUI Enhancement #4549 - Extract SSL certificate and fingerprint generate function Enhancement #4546 - Redistribute OpenSSL on Windows with installer Enhancement #4540 - Enable Network Security checkbox only when ns plugin exists Enhancement #4525 - Reorganize app data directory Enhancement #4390 - Disable GUI auto-hide by default v1.7.0-beta =========== Enhancement #4313 - SSL encrypted secure connection Enhancement #4168 - Plugin manager for GUI Enhancement #4307 - Always show client auto-detect dialog Enhancement #4397 - Modernize Mac build script (deployment and signing) Enhancement #4398 - Remove obsolete Mac database cleaner Enhancement #4337 - Remove IStreamFilterFactory dead code 1.6.3 ===== Bug #4349 - Mouse click does not always bring window to front Bug #4463 - Unidentified developer error on Mac OS X Bug #4464 - Code signing verify failure not reported on Mac build Bug #4465 - Binary (syntool) is not code signed on Windows Enhancement #4455 - Replace version with branch name in package filename 1.6.2 ===== Bug #4227 - Helper tool crashes when service checks elevation state Bug #4091 - Zeroconf on server advertises bogus IP address Bug #4249 - Drag file causes client crash on Mac (10.10) Enhancement #4196 - Optional Bonjour requirement for Windows Enhancement #4235 - Automatic Bonjour download and install Enhancement #4218 - Auto-config available servers combo box Enhancement #4230 - More user friendly dialog when client is detected Enhancement #4240 - Minimize auto config message box usage Enhancement #4247 - Firewall exception for GUI (needed for Bonjour) Enhancement #4242 - Consistent naming for auto config feature 1.6.1 ===== Bug #4002 - Carbon loop not ready within 5 sec Bug #4191 - Accessibility helper tool crashes Bug #4149 - Mac 10.9.5 or 10.10 gatekeeper blocks Synergy Bug #4139 - Exception thrown when ProcessIdToSessionId() fails Bug #4055 - Shift keys are not sent to clients (Win 8.1 server) Bug #4021 - Copy & paste not working for EFL applications Bug #3749 - Linux Chrome hover doesn't work Bug #4128 - Daemon logging not written with "log to file" Enhancement #4122 - Enable drag and drop by default Enhancement #4158 - Build for Mac OS X 10.10 Enhancement #4130 - Auto elevate for Windows UAC and screen lock Enhancement #4126 - 64-bit support for OS X Enhancement #4141 - DMRM message support for μSynergy Enhancement #4124 - More robust argument parsing 1.6.0 ===== Feature #65 - Auto config feature using Zeroconf/Bonjour 1.5.1 ===== Bug #3307 - Configuration file paths containing spaces don't work Bug #3404 - Log path needs to be in quotes on windows Bug #3996 - Installer fails when Windows Firewall is disabled 1.5.0 ===== Bug #4060 - Key stuck down on Windows server Bug #4061 - Windows server repeats modifier keys 1.4.18 ====== Bug #3980 - Shell extension DLL causes explorer.exe to crash Task #4049 - Correct code style in OSXKeyState compilation unit Task #4050 - Fix subversion issue tracker URL Task #4053 - Improve deb package quality Task #4054 - Improve rpm package quality 1.4.17 ====== Bug #2836 - Unable to begin screen name or alias with numbers Bug #3796 - Some files being unintentionally dragged (including explorer.exe) Bug #3886 - Alias is allowed to match screen name Bug #3919 - RPM install fails on Fedora 20, failed dependencies: libcurl Bug #3921 - Error: synwinxt.dll outdated (upgrading from 1.4.15 to 1.4.16) Bug #3927 - Mavericks accessibility exception not working (when upgrading from 1.4.15 to 1.4.16) Bug #3933 - Plus signs in the email address cause premium login to fail Bug #3939 - Compile fails on ARM (Raspberry Pi) because of cryptopp/Crypto++ lib Bug #3947 - Conflicts when using yum localinstall on Fedora 20 Bug #3959 - Premium title doesn't always show on first login Bug #3968 - GUI auto-hides on initial first install (with no config) Task #3936 - Change installer to WiX for improved file upgrade process Task #3950 - Poll modifier after key down on Mac OS X and log results Task #3951 - Clear filename stored in synwinxt on mouse up Task #3952 - Make Premium wizard page cleaner Task #3953 - Inherit XArch and XBase from std::exception Task #3954 - Make "lock to screen" log message go to NOTE level instead of DEBUG Task #3960 - Split CMSWindowsHookLibraryLoader into hook and shellex loaders Task #3961 - Remove Windows 95 support Task #3963 - Disable failing Linux unit/integ tests on Fedora 20 32-bit (valgrind SIGILL) Task #3964 - Make Premium login error more verbose Task #3969 - Merge String.cpp and StringUtil.cpp 1.4.16 ====== Bug #3338 - Alt tab not working with Windows 8 Bug #3642 - Failed to start server on Mac OS X 10.9 Mavericks, assistive devices problem Bug #3785 - Synwinxt.dll error opening file for writing during install of 1.4.15 Bug #3787 - Wont automatically load after login on OS X Bug #3788 - Configuration wizard: Premium login fails when behind a proxy Bug #3796 - Some files being unintentionally dragged (including explorer.exe) Bug #3799 - Synergy Client on Fedora crashes on drag/drop operations Bug #3818 - Client freezes on Mac OS 10.6.8 Bug #3874 - Premium GUI login is case sensitive for email Bug #3911 - Drag and drop error on OS X 10.9 Mavericks 1.4.15 ====== Bug #3765 - Synergy Service - Error 87: The parameter is incorrect. Bug #3781 - Option not supported on Linux: --enable-drag-drop (server not starting) 1.4.14 ====== Bug #3287 - Mac does not wake up Bug #3758 - Unstable service (synergyd) Bug #3759 - Exploit: C:\Program.exe (if it exists) is run by service (elevated) Bug #3760 - Encryption broken (GCM, CTR and OFB) Bug #3761 - Start button is visible when Synergy is running Bug #3762 - Apply button is disabled for Mac and Linux Feature #46 - Drag and drop between computers (Windows and Mac) 1.4.13 ====== Version not released, unstable. 1.4.12 ====== Bug #3565 - Encryption fails when typing fast (Invalid message from client) Bug #3606 - GUI is elevated after setup Bug #3572 - Mac caps lock causes disconnect 1.4.11 ====== Feature #12 - Encryption Feature #421 - Portable version Bug #2855 - Mouse cursor remains hidden on Mac client (intermittently/randomly) Bug #3281 - server start on OS X defaults to 'interactive' Bug #3310 - P&ort in settings screen 1.4.10 ====== Bug #2799 - Right shift broken (Windows server, Mac OS X client) Bug #3302 - GUI does not show/hide when tray icon is double clicked (Windows) Bug #3303 - Mac OS X IPC integ test fails intermittently Feature #2974 - Gesture Support for Magic Mouse/Trackpad Feature #3172 - Button to stop Synergy when in service mode Feature #3241 - Option to elevate synergyc/s when in service mode Feature #3242 - Show a list of available IP addresses and screen name on the main screen Feature #3296 - 64-bit Windows installer should display helpful message on 32-bit Windows Feature #3300 - Make service mode default mode (now that we have elevate option) Feature #3301 - Add process mode option to settings (remove startup wizard page) Feature #3306 - Gatekeeper compatibility on Mac OS X 10.8 1.4.9 ===== Bug #3159 - In service mode, server doesn't start unless GUI is running Bug #3214 - Client sometimes can't connect if GUI is closed Bug #56 - Mac OS X server not sending keystrokes to client Bug #3161 - First time GUI appears, service doesn't send logging Bug #3164 - In service mode, you need to add a firewall exception Bug #3166 - Service shutdown stalls when GUI is closed Bug #3216 - Fatal error if plugins folder doesn't exist Bug #3221 - ERROR: could not connect to service, error: 2 Feature #3192 - Add support for JOYINFOEX structure to poll game device info Feature #3202 - Plugin support (sending for primary screen events on Windows only) Feature #3155 - Cross-platform TCP IPC between GUI and service Task #3177 - Fix Mac buildslave to build multiple versions Task #3193 - Add Micro Synergy to repository Task #3275 - Change hostname label to "IP address or hostname" Task #3276 - Installation recovery mechanism for synrgyhk.dll 1.4.8 ===== Bug #143: Cursor on Mac OS X goes to center when inactive Bug #146: Screen Resize causes problems with moving off right-hand side of screen Bug #3058: Modifier keys not working on Mac OS X server Bug #3139: Double click too strict (click, move, click should not count) Bug #3195: Service install can fail first time Bug #3196: Wizard buttons not visible Bug #3197: GUI doesn't take focus after install Bug #3202: Hook DLL (synrgyhk.dll) is not released Feature #3143: Setup wizard for first time users Feature #3145: Check for updates Feature #3174: Startup mode wizard page Feature #3184: New service for process management 1.4.7 ===== Bug #3132: GUI hides before successful connection Bug #3133: Can't un-hide GUI on Mac Feature #3054: Hide synergy[cs] dock icon (Mac OS X) Feature #3135: Integrate log into main window Task #3134: Move hotkey warnings to DEBUG 1.4.6 ===== Bug #155: Build error on FreeBSD (missing sentinel in function call) Bug #571: Synergy SegFaults with "Unknown Quartz Event type: 0x1d" Bug #617: xrandr rotation on client confines cursor in wrong area Bug #642: `synergyc --help` segfaults on sparc64 architecture Bug #652: Stack overflow in getIDForKey Bug #1071: Can't copy from the Firefox address bar on Linux Bug #1662: Copying text from remote computer crashes java programs. Bug #1731: YouTube can cause server to freeze randomly Bug #2752: Use SAS for ctrl+alt+del on win7 Bug #2763: Double-click broken on Mac OS Bug #2817: Keypad Subtract has wrong keycode on OS X Bug #2958: GNOME 3 mouse problem (gnome-shell) Bug #2962: Clipboard not working on mac client Bug #3063: Segfault in copy buffer Bug #3066: Server segfault on clipboard paste Bug #3089: Comma and Period translated wrong when using the NEO2-layout Bug #3092: Wrong screen rotation detected Bug #3105: There doesn't seem to be a system tray available. Quitting Bug #3116: Memory Leak due to the XInput2 patches Bug #3117: Dual monitors not detected properly anymore Feature #3073: Re-introduce auto-start GUI (Windows) Feature #3076: Re-introduce auto-start backend Feature #3077: Re-introduce hidden on start Feature #3091: Add option to remap altgr modifier Feature #3119: Mac OS X secondary screen Task #2905: Unit tests: Clipboard classes Task #3072: Downgrade Linux build machines Task #3090: CXWindowsKeyState integ test args wrong synergy-1.8.8-stable/INSTALL000066400000000000000000000001161305627404700155370ustar00rootroot00000000000000Help: http://symless.com/help/ Wiki: https://github.com/symless/synergy/wiki/ synergy-1.8.8-stable/LICENSE000066400000000000000000000362261305627404700155260ustar00rootroot00000000000000synergy -- mouse and keyboard sharing utility Copyright (C) 2012-2016 Symless Ltd. Copyright (C) 2008-2014 Nick Bolton Copyright (C) 2002-2014 Chris Schoeneman This program is released under the GPL with the additional exemption that compiling, linking, and/or using OpenSSL is allowed. GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS synergy-1.8.8-stable/README000066400000000000000000000006011305627404700153650ustar00rootroot00000000000000Synergy ======= Share one mouse and keyboard between multiple computers. Synergy is free and open source (free as in free speech), meaning you are free to run it and redistribute it with or without changes. Just use "hm conf" and "hm build" to compile (./hm.sh on Linux and Mac). For detailed compile instructions: https://github.com/symless/synergy/wiki/Compiling Happy hacking! synergy-1.8.8-stable/configure000077500000000000000000000000701305627404700164140ustar00rootroot00000000000000cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release . synergy-1.8.8-stable/doc/000077500000000000000000000000001305627404700152555ustar00rootroot00000000000000synergy-1.8.8-stable/doc/MacReadme.txt000077500000000000000000000015531305627404700176430ustar00rootroot00000000000000Mac OS X Readme =============== To install on Mac OS X with the .zip distribution (first seen in 1.3.6) you must follow these steps: 1. Extract the zip file to any location (usually double click will do this) 2. Open Terminal, and cd to the extracted directory (e.g. /Users/my-name/Downloads/extracted-dir/) 3. Copy the binaries to /usr/bin using: sudo cp synergy* /usr/bin 4. Correct the permissions and ownership: sudo chown root:wheel /usr/bin/synergy*; sudo chmod 555 /usr/bin/synergy* Alternatively, you can copy the binaries as root. How to enable the root user in Mac OS X: http://support.apple.com/en-us/ht1528 Once the binaries have been copied to /usr/bin, you should follow the configuration guide: http://synergy2.sourceforge.net/configuration.html If you have any problems, see the [[Support]] page: http://symless.com/help/ synergy-1.8.8-stable/doc/QtCodeStyle.xml000066400000000000000000000265321305627404700202070ustar00rootroot00000000000000 CodeStyleData false false true false false false true false true false false false true true false true false false false 4 true false 2 false 4 DisplayName Synergy CodeStyleData false false true false false false true false true false false false true true false true false false false 4 true false 2 false 4 DisplayName Synergy CodeStyleData false false true false false false true false true false false false true true false true false false false 4 true false 2 false 4 DisplayName Synergy CodeStyleData false false true false false false true false true false false false true true false true false false false 4 true false 2 false 4 DisplayName Synergy CodeStyleData false false true false false false true false true false false false true true false true false false false 4 true false 2 false 4 DisplayName Synergy CodeStyleData false false true false false false true false true false false false true true false true false false false 4 true false 2 false 4 DisplayName Synergy synergy-1.8.8-stable/doc/org.synergy-foss.org.synergyc.plist000066400000000000000000000013071305627404700242210ustar00rootroot00000000000000 Label org.symless.com.synergyc.plist OnDemand ProgramArguments /usr/bin/synergyc 192.168.0.2 RunAtLoad synergy-1.8.8-stable/doc/org.synergy-foss.org.synergys.plist000066400000000000000000000014771305627404700242510ustar00rootroot00000000000000 Label org.symless.com.synergys.plist OnDemand ProgramArguments /usr/bin/synergys --no-daemon --config /Users/snorp/.synergy.conf RunAtLoad synergy-1.8.8-stable/doc/synergy.conf.example000066400000000000000000000014311305627404700212550ustar00rootroot00000000000000# sample synergy configuration file # # comments begin with the # character and continue to the end of # line. comments may appear anywhere the syntax permits. section: screens # three hosts named: moe, larry, and curly moe: larry: curly: end section: links # larry is to the right of moe and curly is above moe moe: right = larry up = curly # moe is to the left of larry and curly is above larry. # note that curly is above both moe and larry and moe # and larry have a symmetric connection (they're in # opposite directions of each other). larry: left = moe up = curly # larry is below curly. if you move up from moe and then # down, you'll end up on larry. curly: down = larry end section: aliases # curly is also known as shemp curly: shemp end synergy-1.8.8-stable/doc/synergy.conf.example-advanced000066400000000000000000000033151305627404700230230ustar00rootroot00000000000000# sample synergy configuration file # # comments begin with the # character and continue to the end of # line. comments may appear anywhere the syntax permits. # This example uses 3 computers. A laptop and two desktops (one a mac) # They are arranged in the following configuration with Desktop1 acting as the server # Desktop 2 has 3 screens arranged around desktop1 # # +--------+ +---------+ # |Desktop2| |Desktop2 | # | | | | # +--------+ +---------+ # +-------+ +--------+ +---------+ # |Laptop | |Desktop1| |Desktop2 | # | | | | | | # +-------+ +--------+ +---------+ # # The laptop comes and goes but that doesn't really affect this configuration # The screens section is for the logical or short name of the computers section: screens # three computers that are logically named: desktop1, desktop2, and laptop desktop1: desktop2: laptop: end section: links # larry is to the right of moe and curly is above moe moe: right = larry up = curly # moe is to the left of larry and curly is above larry. # note that curly is above both moe and larry and moe # and larry have a symmetric connection (they're in # opposite directions of each other). larry: left = moe up = curly # larry is below curly. if you move up from moe and then # down, you'll end up on larry. curly: down = larry end # The aliases section is to map the full names of the computers to their logical names used in the screens section # One way to find the actual name of a comptuer is to run hostname from a command window section: aliases # Laptop is actually known as John-Smiths-MacBook-3.local desktop2: John-Smiths-MacBook-3.local end synergy-1.8.8-stable/doc/synergy.conf.example-basic000066400000000000000000000021401305627404700223320ustar00rootroot00000000000000# sample synergy configuration file # # comments begin with the # character and continue to the end of # line. comments may appear anywhere the syntax permits. # +-------+ +--------+ +---------+ # |Laptop | |Desktop1| |iMac | # | | | | | | # +-------+ +--------+ +---------+ section: screens # three hosts named: Laptop, Desktop1, and iMac # These are the nice names of the hosts to make it easy to write the config file # The aliases section below contain the "actual" names of the hosts (their hostnames) Laptop: Desktop1: iMac: end section: links # iMac is to the right of Desktop1 # Laptop is to the left of Desktop1 Desktop1: right = iMac left = Laptop # Desktop1 is to the right of Laptop Laptop: right = Desktop1 # Desktop1 is to the left of iMac iMac: left = Desktop1 end section: aliases # The "real" name of iMac is John-Smiths-iMac-3.local. If we wanted we could remove this alias and instead use John-Smiths-iMac-3.local everywhere iMac is above. Hopefully it should be easy to see why using an alias is nicer iMac: John-Smiths-iMac-3.local end synergy-1.8.8-stable/doc/synergyc.man000066400000000000000000000030411305627404700176130ustar00rootroot00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. .TH SYNERGYC "1" "June 2010" "synergyc 1.5.0, protocol version 1.3" "User Commands" .SH NAME synergyc \- manual page for synergyc 1.5.0, protocol version 1.3 .SH SYNOPSIS .B synergyc [\fI--yscroll \fR] [\fI--daemon|--no-daemon\fR] [\fI--name \fR] [\fI--restart|--no-restart\fR] [\fI--debug \fR] \fI\fR .SH DESCRIPTION Connect to a synergy mouse/keyboard sharing server. .TP \fB\-d\fR, \fB\-\-debug\fR filter out log messages with priority below level. level may be: FATAL, ERROR, WARNING, NOTE, INFO, DEBUG, DEBUGn (1\-5). .TP \fB\-n\fR, \fB\-\-name\fR use screen\-name instead the hostname to identify this screen in the configuration. .TP \fB\-1\fR, \fB\-\-no\-restart\fR do not try to restart on failure. .PP * \fB\-\-restart\fR restart the server automatically if it fails. .TP \fB\-l\fR \fB\-\-log\fR write log messages to file. .TP \fB\-f\fR, \fB\-\-no\-daemon\fR run in the foreground. .PP * \fB\-\-daemon\fR run as a daemon. .TP \fB\-\-yscroll\fR defines the vertical scrolling delta, which is .TP \fB\-h\fR, \fB\-\-help\fR display this help and exit. .TP \fB\-\-version\fR display version information and exit. .PP * marks defaults. .PP The server address is of the form: [][:]. The hostname must be the address or hostname of the server. The port overrides the default port, 24800. .SH COPYRIGHT Copyright \(co 2010 Chris Schoeneman, Nick Bolton, Sorin Sbarnea synergy-1.8.8-stable/doc/synergys.man000066400000000000000000000035661305627404700176470ustar00rootroot00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.38.2. .TH SYNERGYS "1" "June 2010" "synergys 1.5.0, protocol version 1.3" "User Commands" .SH NAME synergys \- manual page for synergys 1.5.0, protocol version 1.3 .SH SYNOPSIS .B synergys [\fI--address
\fR] [\fI--config \fR] [\fI--daemon|--no-daemon\fR] [\fI--name \fR] [\fI--restart|--no-restart\fR] [\fI--debug \fR] .SH DESCRIPTION Start the synergy mouse/keyboard sharing server. .TP \fB\-a\fR, \fB\-\-address\fR
listen for clients on the given address. .TP \fB\-c\fR, \fB\-\-config\fR use the named configuration file instead. .TP \fB\-d\fR, \fB\-\-debug\fR filter out log messages with priority below level. level may be: FATAL, ERROR, WARNING, NOTE, INFO, DEBUG, DEBUGn (1\-5). .TP \fB\-n\fR, \fB\-\-name\fR use screen\-name instead the hostname to identify this screen in the configuration. .TP \fB\-1\fR, \fB\-\-no\-restart\fR do not try to restart on failure. .PP * \fB\-\-restart\fR restart the server automatically if it fails. .TP \fB\-l\fR \fB\-\-log\fR write log messages to file. .TP \fB\-f\fR, \fB\-\-no\-daemon\fR run in the foreground. .PP * \fB\-\-daemon\fR run as a daemon. .TP \fB\-h\fR, \fB\-\-help\fR display this help and exit. .TP \fB\-\-version\fR display version information and exit. .PP * marks defaults. .PP The argument for \fB\-\-address\fR is of the form: [][:]. The hostname must be the address or hostname of an interface on the system. The default is to listen on all interfaces. The port overrides the default port, 24800. .PP If no configuration file pathname is provided then the first of the following to load successfully sets the configuration: .IP $HOME/.synergy.conf /etc/synergy.conf .SH COPYRIGHT Copyright \(co 2010 Chris Schoeneman, Nick Bolton, Sorin Sbarnea synergy-1.8.8-stable/ext/000077500000000000000000000000001305627404700153105ustar00rootroot00000000000000synergy-1.8.8-stable/ext/LICENSE (OpenSSL)000066400000000000000000000142071305627404700177060ustar00rootroot00000000000000 LICENSE ISSUES ============== The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the OpenSSL License and the original SSLeay license apply to the toolkit. See below for the actual license texts. Actually both licenses are BSD-style Open Source licenses. In case of any license issues related to OpenSSL please contact openssl-core@openssl.org. OpenSSL License --------------- /* ==================================================================== * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" * * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to * endorse or promote products derived from this software without * prior written permission. For written permission, please contact * openssl-core@openssl.org. * * 5. Products derived from this software may not be called "OpenSSL" * nor may "OpenSSL" appear in their names without prior written * permission of the OpenSSL Project. * * 6. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the OpenSSL Project * for use in the OpenSSL Toolkit (http://www.openssl.org/)" * * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This product includes cryptographic software written by Eric Young * (eay@cryptsoft.com). This product includes software written by Tim * Hudson (tjh@cryptsoft.com). * */ Original SSLeay License ----------------------- /* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) * All rights reserved. * * This package is an SSL implementation written * by Eric Young (eay@cryptsoft.com). * The implementation was written so as to conform with Netscapes SSL. * * This library is free for commercial and non-commercial use as long as * the following conditions are aheared to. The following conditions * apply to all code found in this distribution, be it the RC4, RSA, * lhash, DES, etc., code; not just the SSL code. The SSL documentation * included with this distribution is covered by the same copyright terms * except that the holder is Tim Hudson (tjh@cryptsoft.com). * * Copyright remains Eric Young's, and as such any Copyright notices in * the code are not to be removed. * If this package is used in a product, Eric Young should be given attribution * as the author of the parts of the library used. * This can be in the form of a textual message at program startup or * in documentation (online or textual) provided with the package. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * "This product includes cryptographic software written by * Eric Young (eay@cryptsoft.com)" * The word 'cryptographic' can be left out if the rouines from the library * being used are not cryptographic related :-). * 4. If you include any Windows specific code (or a derivative thereof) from * the apps directory (application code) you must include an acknowledgement: * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" * * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * The licence and distribution terms for any publically available version or * derivative of this code cannot be changed. i.e. this code cannot simply be * copied and put under another distribution licence * [including the GNU Public Licence.] */ synergy-1.8.8-stable/ext/toolchain/000077500000000000000000000000001305627404700172705ustar00rootroot00000000000000synergy-1.8.8-stable/ext/toolchain/README.txt000066400000000000000000000000731305627404700207660ustar00rootroot00000000000000Source code for the build system belongs in this directory.synergy-1.8.8-stable/ext/toolchain/__init__.py000066400000000000000000000013001305627404700213730ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . synergy-1.8.8-stable/ext/toolchain/commands1.py000066400000000000000000001545431305627404700215400ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # TODO: split this file up, it's too long! import sys, os, ConfigParser, shutil, re, ftputil, zipfile, glob, commands from generators import VisualStudioGenerator, EclipseGenerator, XcodeGenerator, MakefilesGenerator from getopt import gnu_getopt if sys.version_info >= (2, 4): import subprocess class Toolchain: # minimum required version. # 2.6 needed for ZipFile.extractall. # do not change to 2.7, as the build machines are still at 2.6 # and are a massive pain in the ass to upgrade. requiredMajor = 2 requiredMinor = 6 # options used by all commands globalOptions = 'v' globalOptionsLong = ['no-prompts', 'verbose', 'skip-gui', 'skip-core'] # list of valid commands as keys. the values are optarg strings, but most # are None for now (this is mainly for extensibility) cmd_opt_dict = { 'about' : ['', []], 'setup' : ['g:', ['generator=']], 'configure' : ['g:dr', ['generator=', 'debug', 'release', 'mac-sdk=', 'mac-deploy=', 'mac-identity=']], 'build' : ['dr', ['debug', 'release']], 'clean' : ['dr', ['debug', 'release']], 'update' : ['', []], 'install' : ['', []], 'doxygen' : ['', []], 'dist' : ['', ['vcredist-dir=', 'qt-dir=']], 'distftp' : ['', ['host=', 'user=', 'pass=', 'dir=']], 'kill' : ['', []], 'usage' : ['', []], 'revision' : ['', []], 'reformat' : ['', []], 'open' : ['', []], 'genlist' : ['', []], 'reset' : ['', []], 'signwin' : ['', ['pfx=', 'pwd=', 'dist']], 'signmac' : ['', []] } # aliases to valid commands cmd_alias_dict = { 'info' : 'about', 'help' : 'usage', 'package' : 'dist', 'docs' : 'doxygen', 'make' : 'build', 'cmake' : 'configure', } def complete_command(self, arg): completions = [] for cmd, optarg in self.cmd_opt_dict.iteritems(): # if command was matched fully, return only this, so that # if `dist` is typed, it will return only `dist` and not # `dist` and `distftp` for example. if cmd == arg: return [cmd,] if cmd.startswith(arg): completions.append(cmd) for alias, cmd in self.cmd_alias_dict.iteritems(): # don't know if this will work just like above, but it's # probably worth adding. if alias == arg: return [alias,] if alias.startswith(arg): completions.append(alias) return completions def start_cmd(self, argv): cmd_arg = '' if len(argv) > 1: cmd_arg = argv[1] # change common help args to help command if cmd_arg in ('--help', '-h', '--usage', '-u', '/?'): cmd_arg = 'usage' completions = self.complete_command(cmd_arg) if cmd_arg and len(completions) > 0: if len(completions) == 1: # get the only completion (since in this case we have 1) cmd = completions[0] # build up the first part of the map (for illustrative purposes) cmd_map = list() if cmd_arg != cmd: cmd_map.append(cmd_arg) cmd_map.append(cmd) # map an alias to the command, and build up the map if cmd in self.cmd_alias_dict.keys(): alias = cmd if cmd_arg == cmd: cmd_map.append(alias) cmd = self.cmd_alias_dict[cmd] cmd_map.append(cmd) # show command map to avoid confusion if len(cmd_map) != 0: print 'Mapping command: %s' % ' -> '.join(cmd_map) self.run_cmd(cmd, argv[2:]) return 0 else: print ( 'Command `%s` too ambiguous, ' 'could mean any of: %s' ) % (cmd_arg, ', '.join(completions)) else: if len(argv) == 1: print 'No command specified, showing usage.\n' else: print 'Command not recognised: %s\n' % cmd_arg self.run_cmd('usage') # generic error code if not returned sooner return 1 def run_cmd(self, cmd, argv = []): verbose = False try: options_pair = self.cmd_opt_dict[cmd] options = self.globalOptions + options_pair[0] options_long = [] options_long.extend(self.globalOptionsLong) options_long.extend(options_pair[1]) opts, args = gnu_getopt(argv, options, options_long) for o, a in opts: if o in ('-v', '--verbose'): verbose = True # pass args and optarg data to command handler, which figures out # how to handle the arguments handler = CommandHandler(argv, opts, args, verbose) # use reflection to get the function pointer cmd_func = getattr(handler, cmd) cmd_func() except: if not verbose: # print friendly error for users sys.stderr.write('Error: ' + sys.exc_info()[1].__str__() + '\n') sys.exit(1) else: # if user wants to be verbose let python do it's thing raise def run(self, argv): if sys.version_info < (self.requiredMajor, self.requiredMinor): print ('Python version must be at least ' + str(self.requiredMajor) + '.' + str(self.requiredMinor) + ', but is ' + str(sys.version_info[0]) + '.' + str(sys.version_info[1])) sys.exit(1) try: self.start_cmd(argv) except KeyboardInterrupt: print '\n\nUser aborted, exiting.' class InternalCommands: project = 'synergy' setup_version = 5 # increment to force setup/config website_url = 'http://symless.com/' this_cmd = 'hm' cmake_cmd = 'cmake' qmake_cmd = 'qmake' make_cmd = 'make' xcodebuild_cmd = 'xcodebuild' w32_make_cmd = 'mingw32-make' w32_qt_version = '4.6.2' defaultTarget = 'release' cmake_dir = 'res' gui_dir = 'src/gui' doc_dir = 'doc' extDir = 'ext' sln_filename = '%s.sln' % project xcodeproj_filename = '%s.xcodeproj' % project configDir = 'build' configFilename = '%s/%s.cfg' % (configDir, this_cmd) qtpro_filename = 'gui.pro' doxygen_filename = 'doxygen.cfg' cmake_url = 'http://www.cmake.org/cmake/resources/software.html' # try_chdir(...) and restore_chdir() will use this prevdir = '' # by default, no index specified as arg generator_id = None # by default, prompt user for input no_prompts = False # by default, compile the core enableMakeCore = True # by default, compile the gui enableMakeGui = True # by default, unknown macSdk = None # by default, unknown macDeploy = None # by default, unknown macIdentity = None # gtest dir with version number gtestDir = 'gtest-1.6.0' # gmock dir with version number gmockDir = 'gmock-1.6.0' win32_generators = { 1 : VisualStudioGenerator('10'), 2 : VisualStudioGenerator('10 Win64'), 3 : VisualStudioGenerator('9 2008'), 4 : VisualStudioGenerator('9 2008 Win64'), 5 : VisualStudioGenerator('8 2005'), 6 : VisualStudioGenerator('8 2005 Win64') } unix_generators = { 1 : MakefilesGenerator(), 2 : EclipseGenerator(), } darwin_generators = { 1 : MakefilesGenerator(), 2 : XcodeGenerator(), 3 : EclipseGenerator(), } def getBuildDir(self, target=''): return self.getGenerator().getBuildDir(target) def getBinDir(self, target=''): return self.getGenerator().getBinDir(target) def sln_filepath(self): return '%s\%s' % (self.getBuildDir(), self.sln_filename) def xcodeproj_filepath(self, target=''): return '%s/%s' % (self.getBuildDir(target), self.xcodeproj_filename) def usage(self): app = sys.argv[0] print ('Usage: %s [-g |-v|--no-prompts|]\n' '\n' 'Replace [command] with one of:\n' ' about Show information about this script\n' ' setup Runs the initial setup for this script\n' ' conf Runs cmake (generates project files)\n' ' open Attempts to open the generated project file\n' ' build Builds using the platform build chain\n' ' clean Cleans using the platform build chain\n' ' kill Kills all synergy processes (run as admin)\n' ' update Updates the source code from repository\n' ' revision Display the current source code revision\n' ' package Create a distribution package (e.g. tar.gz)\n' ' install Installs the program\n' ' doxygen Builds doxygen documentation\n' ' reformat Reformat .cpp and .h files using AStyle\n' ' genlist Shows the list of available platform generators\n' ' usage Shows the help screen\n' '\n' 'Example: %s conf -g 3' ) % (app, app) def configureAll(self, targets, extraArgs=''): # if no mode specified, use default if len(targets) == 0: targets += [self.defaultTarget,] for target in targets: self.configure(target) def checkGTest(self): dir = self.extDir + '/' + self.gtestDir if (os.path.isdir(dir)): return zipFilename = dir + '.zip' if (not os.path.exists(zipFilename)): raise Exception('GTest zip not found at: ' + zipFilename) if not os.path.exists(dir): os.mkdir(dir) zip = zipfile.ZipFile(zipFilename) self.zipExtractAll(zip, dir) def checkGMock(self): dir = self.extDir + '/' + self.gmockDir if (os.path.isdir(dir)): return zipFilename = dir + '.zip' if (not os.path.exists(zipFilename)): raise Exception('GMock zip not found at: ' + zipFilename) if not os.path.exists(dir): os.mkdir(dir) zip = zipfile.ZipFile(zipFilename) self.zipExtractAll(zip, dir) # ZipFile.extractall() is buggy in 2.6.1 # http://bugs.python.org/issue4710 def zipExtractAll(self, z, dir): if not dir.endswith("/"): dir += "/" for f in z.namelist(): if f.endswith("/"): os.makedirs(dir + f) else: z.extract(f, dir) def configure(self, target='', extraArgs=''): # ensure latest setup and do not ask config for generator (only fall # back to prompt if not specified as arg) self.ensure_setup_latest() if sys.platform == "darwin": config = self.getConfig() if self.macSdk: config.set('hm', 'macSdk', self.macSdk) elif config.has_option("hm", "macSdk"): self.macSdk = config.get('hm', 'macSdk') if self.macDeploy: config.set('hm', 'macDeploy', self.macDeploy) elif config.has_option("hm", "macDeploy"): self.macSdk = config.get('hm', 'macDeploy') if self.macIdentity: config.set('hm', 'macIdentity', self.macIdentity) elif config.has_option("hm", "macIdentity"): self.macIdentity = config.get('hm', 'macIdentity') self.write_config(config) if not self.macSdk: raise Exception("Arg missing: --mac-sdk "); if not self.macDeploy: self.macDeploy = self.macSdk if not self.macIdentity: raise Exception("Arg missing: --mac-identity "); sdkDir = self.getMacSdkDir() if not os.path.exists(sdkDir): raise Exception("Mac SDK not found at: " + sdkDir) os.environ["MACOSX_DEPLOYMENT_TARGET"] = self.macSdk # default is release if target == '': print 'Defaulting target to: ' + self.defaultTarget target = self.defaultTarget # allow user to skip core compile if self.enableMakeCore: self.configureCore(target, extraArgs) # allow user to skip gui compile if self.enableMakeGui: self.configureGui(target, extraArgs) self.setConfRun(target) def configureCore(self, target="", extraArgs=""): # ensure that we have access to cmake _cmake_cmd = self.persist_cmake() # now that we know we've got the latest setup, we can ask the config # file for the generator (but again, we only fall back to this if not # specified as arg). generator = self.getGenerator() if generator != self.findGeneratorFromConfig(): print('Generator changed, running setup.') self.setup(target) cmake_args = '' if generator.cmakeName != '': cmake_args += ' -G "' + generator.cmakeName + '"' # for makefiles always specify a build type (debug, release, etc) if generator.cmakeName.find('Unix Makefiles') != -1: cmake_args += ' -DCMAKE_BUILD_TYPE=' + target.capitalize() if sys.platform == "darwin": macSdkMatch = re.match("(\d+)\.(\d+)", self.macSdk) if not macSdkMatch: raise Exception("unknown osx version: " + self.macSdk) if generator.cmakeName.find('Unix Makefiles') == -1: sdkDir = self.getMacSdkDir() cmake_args += " -DCMAKE_OSX_SYSROOT=" + sdkDir cmake_args += " -DCMAKE_OSX_DEPLOYMENT_TARGET=" + self.macDeploy cmake_args += " -DOSX_TARGET_MAJOR=" + macSdkMatch.group(1) cmake_args += " -DOSX_TARGET_MINOR=" + macSdkMatch.group(2) # if not visual studio, use parent dir sourceDir = generator.getSourceDir() self.checkGTest() self.checkGMock() if extraArgs != '': cmake_args += ' ' + extraArgs cmake_cmd_string = _cmake_cmd + cmake_args + ' ' + sourceDir # Run from build dir so we have an out-of-source build. self.try_chdir(self.getBuildDir(target)) print "CMake command: " + cmake_cmd_string err = os.system(cmake_cmd_string) self.restore_chdir() if generator.cmakeName.find('Eclipse') != -1: self.fixCmakeEclipseBug() if err != 0: raise Exception('CMake encountered error: ' + str(err)) def configureGui(self, target="", extraArgs=""): # make sure we have qmake self.persist_qmake() qmake_cmd_string = self.qmake_cmd + " " + self.qtpro_filename + " -r" if sys.platform == "darwin": # create makefiles on mac (not xcode). qmake_cmd_string += " -spec macx-g++" (major, minor) = self.getMacVersion() if major == 10 and minor <= 4: # 10.4: universal (intel and power pc) qmake_cmd_string += ' CONFIG+="ppc i386"' libs = ( "-framework ApplicationServices " "-framework Security " "-framework cocoa") if major == 10 and minor >= 6: libs += " -framework ServiceManagement" qmake_cmd_string += " \"MACX_LIBS=%s\" " % libs sdkDir = self.getMacSdkDir() shortForm = "macosx" + self.macSdk version = str(major) + "." + str(minor) qmake_cmd_string += " QMAKE_MACOSX_DEPLOYMENT_TARGET=" + self.macDeploy (qMajor, qMinor, qRev) = self.getQmakeVersion() if qMajor <= 4: # 4.6: qmake takes full sdk dir. qmake_cmd_string += " QMAKE_MAC_SDK=" + sdkDir else: # 5.2: now we need to use the .path setting. qmake_cmd_string += " QMAKE_MAC_SDK=" + shortForm qmake_cmd_string += " QMAKE_MAC_SDK." + shortForm + ".path=" + sdkDir qmake_cmd_string += " QMAKE_VERSION_STAGE=" + self.getVersionStage() qmake_cmd_string += " QMAKE_VERSION_REVISION=" + self.getGitRevision() print "QMake command: " + qmake_cmd_string # run qmake from the gui dir self.try_chdir(self.gui_dir) err = os.system(qmake_cmd_string) self.restore_chdir() if err != 0: raise Exception('QMake encountered error: ' + str(err)) def getQmakeVersion(self): version = commands.getoutput("qmake --version") result = re.search('(\d+)\.(\d+)\.(\d)', version) if not result: raise Exception("Could not get qmake version.") major = int(result.group(1)) minor = int(result.group(2)) rev = int(result.group(3)) return (major, minor, rev) def getMacSdkDir(self): sdkName = "macosx" + self.macSdk # Ideally we'll use xcrun (which is influenced by $DEVELOPER_DIR), then try a couple # fallbacks to known paths if xcrun is not available status, sdkPath = commands.getstatusoutput("xcrun --show-sdk-path --sdk " + sdkName) if status == 0 and sdkPath: return sdkPath developerDir = os.getenv("DEVELOPER_DIR") if not developerDir: developerDir = "/Applications/Xcode.app/Contents/Developer" sdkDirName = sdkName.replace("macosx", "MacOSX") sdkPath = developerDir + "/Platforms/MacOSX.platform/Developer/SDKs/" + sdkDirName + ".sdk" if os.path.exists(sdkPath): return sdkPath # return os.popen('xcodebuild -version -sdk macosx' + self.macSdk + ' Path').read().strip() return "/Developer/SDKs/" + sdkDirName + ".sdk" # http://tinyurl.com/cs2rxxb def fixCmakeEclipseBug(self): print "Fixing CMake Eclipse bugs..." file = open('.project', 'r+') content = file.read() pattern = re.compile('\s+.+', re.S) content = pattern.sub('', content) file.seek(0) file.write(content) file.truncate() file.close() def persist_cmake(self): # even though we're running `cmake --version`, we're only doing this for the 0 return # code; we don't care about the version, since CMakeLists worrys about this for us. err = os.system('%s --version' % self.cmake_cmd) if err != 0: # if return code from cmake is not 0, then either something has # gone terribly wrong with --version, or it genuinely doesn't exist. print ('Could not find `%s` in system path.\n' 'Download the latest version from:\n %s') % ( self.cmake_cmd, self.cmake_url) raise Exception('Cannot continue without CMake.') else: return self.cmake_cmd def persist_qt(self): self.persist_qmake() def persist_qmake(self): # cannot use subprocess on < python 2.4 if sys.version_info < (2, 4): return try: p = subprocess.Popen( [self.qmake_cmd, '--version'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) except: print >> sys.stderr, 'Error: Could not find qmake.' if sys.platform == 'win32': # windows devs usually need hints ;) print ( 'Suggestions:\n' '1. Ensure that qmake.exe exists in your system path.\n' '2. Try to download Qt (check our dev FAQ for links):\n' ' qt-sdk-win-opensource-2010.02.exe') raise Exception('Cannot continue without qmake.') stdout, stderr = p.communicate() if p.returncode != 0: raise Exception('Could not test for cmake: %s' % stderr) else: m = re.search('.*Using Qt version (\d+\.\d+\.\d+).*', stdout) if m: if sys.platform == 'win32': ver = m.group(1) if ver != self.w32_qt_version: # TODO: test properly print >> sys.stderr, ( 'Warning: Not using supported Qt version %s' ' (your version is %s).' ) % (self.w32_qt_version, ver) else: pass # any version should be ok for other platforms else: raise Exception('Could not find qmake version.') def ensureConfHasRun(self, target, skipConfig): if self.hasConfRun(target): print 'Skipping config for target: ' + target skipConfig = True if not skipConfig: self.configure(target) def build(self, targets=[], skipConfig=False): # if no mode specified, use default if len(targets) == 0: targets += [self.defaultTarget,] self.ensure_setup_latest() self.loadConfig() # allow user to skip core compile if self.enableMakeCore: self.makeCore(targets) # allow user to skip gui compile if self.enableMakeGui: self.makeGui(targets) def loadConfig(self): config = self.getConfig() if config.has_option("hm", "macSdk"): self.macSdk = config.get("hm", "macSdk") if config.has_option("hm", "macDeploy"): self.macDeploy = config.get("hm", "macDeploy") if config.has_option("hm", "macIdentity"): self.macIdentity = config.get("hm", "macIdentity") def makeCore(self, targets): generator = self.getGeneratorFromConfig().cmakeName if self.macSdk: os.environ["MACOSX_DEPLOYMENT_TARGET"] = self.macSdk if generator.find('Unix Makefiles') != -1: for target in targets: self.runBuildCommand(self.make_cmd, target) else: for target in targets: if generator.startswith('Visual Studio'): self.run_vcbuild(generator, target, self.sln_filepath()) elif generator == 'Xcode': cmd = self.xcodebuild_cmd + ' -configuration ' + target.capitalize() self.runBuildCommand(cmd, target) else: raise Exception('Build command not supported with generator: ' + generator) def makeGui(self, targets, args=""): for target in targets: if sys.platform == 'win32': gui_make_cmd = self.w32_make_cmd + ' ' + target + args print 'Make GUI command: ' + gui_make_cmd self.try_chdir(self.gui_dir) err = os.system(gui_make_cmd) self.restore_chdir() if err != 0: raise Exception(gui_make_cmd + ' failed with error: ' + str(err)) elif sys.platform in ['linux2', 'sunos5', 'freebsd7', 'darwin']: gui_make_cmd = self.make_cmd + " -w" + args print 'Make GUI command: ' + gui_make_cmd # start with a clean app bundle targetDir = self.getGenerator().getBinDir(target) bundleTargetDir = targetDir + '/Synergy.app' if os.path.exists(bundleTargetDir): shutil.rmtree(bundleTargetDir) binDir = self.getGenerator().binDir bundleTempDir = binDir + '/Synergy.app' if os.path.exists(bundleTempDir): shutil.rmtree(bundleTempDir) self.try_chdir(self.gui_dir) err = os.system(gui_make_cmd) self.restore_chdir() if err != 0: raise Exception(gui_make_cmd + ' failed with error: ' + str(err)) if sys.platform == 'darwin' and not "clean" in args: self.macPostGuiMake(target) self.fixQtFrameworksLayout(target) else: raise Exception('Unsupported platform: ' + sys.platform) def macPostGuiMake(self, target): bundle = 'Synergy.app' binDir = self.getGenerator().binDir targetDir = self.getGenerator().getBinDir(target) bundleTempDir = binDir + '/' + bundle bundleTargetDir = targetDir + '/' + bundle if os.path.exists(bundleTempDir): shutil.move(bundleTempDir, bundleTargetDir) if self.enableMakeCore: # copy core binaries into the bundle, since the gui # now looks for the binaries in the current app dir. bundleBinDir = bundleTargetDir + "/Contents/MacOS/" shutil.copy(targetDir + "/synergyc", bundleBinDir) shutil.copy(targetDir + "/synergys", bundleBinDir) shutil.copy(targetDir + "/syntool", bundleBinDir) self.loadConfig() if not self.macIdentity: raise Exception("run config with --mac-identity") if self.enableMakeGui: # use qt to copy libs to bundle so no dependencies are needed. do not create a # dmg at this point, since we need to sign it first, and then create our own # after signing (so that qt does not affect the signed app bundle). bin = "macdeployqt Synergy.app -verbose=2" self.try_chdir(targetDir) err = os.system(bin) self.restore_chdir() print bundleTargetDir if err != 0: raise Exception(bin + " failed with error: " + str(err)) (qMajor, qMinor, qRev) = self.getQmakeVersion() if qMajor <= 4: frameworkRootDir = "/Library/Frameworks" else: # TODO: auto-detect, qt can now be installed anywhere. frameworkRootDir = "/Developer/Qt5.2.1/5.2.1/clang_64/lib" target = bundleTargetDir + "/Contents/Frameworks" # copy the missing Info.plist files for the frameworks. for root, dirs, files in os.walk(target): for dir in dirs: if dir.startswith("Qt"): shutil.copy( frameworkRootDir + "/" + dir + "/Contents/Info.plist", target + "/" + dir + "/Resources/") def symlink(self, source, target): if not os.path.exists(target): os.symlink(source, target) def move(self, source, target): if os.path.exists(source): shutil.move(source, target) def fixQtFrameworksLayout(self, target): # reorganize Qt frameworks layout on Mac 10.9.5 or later # http://goo.gl/BFnQ8l # QtCore example: # QtCore.framework/ # QtCore -> Versions/Current/QtCore # Resources -> Versions/Current/Resources # Versions/ # Current -> 5 # 5/ # QtCore # Resources/ # Info.plist targetDir = self.getGenerator().getBinDir(target) target = targetDir + "/Synergy.app/Contents/Frameworks" (major, minor) = self.getMacVersion() if major == 10: if minor >= 9: for root, dirs, files in os.walk(target): for dir in dirs: if dir.startswith("Qt"): self.try_chdir(target + "/" + dir +"/Versions") self.symlink("5", "Current") self.move("../Resources", "5") self.restore_chdir() self.try_chdir(target + "/" + dir) dot = dir.find('.') frameworkName = dir[:dot] self.symlink("Versions/Current/" + frameworkName, frameworkName) self.symlink("Versions/Current/Resources", "Resources") self.restore_chdir() def signmac(self): self.loadConfig() if not self.macIdentity: raise Exception("run config with --mac-identity") self.try_chdir("bin/Release/") err = os.system( 'codesign --deep -fs "' + self.macIdentity + '" Synergy.app') self.restore_chdir() if err != 0: raise Exception("codesign failed with error: " + str(err)) def signwin(self, pfx, pwdFile, dist): generator = self.getGeneratorFromConfig().cmakeName if not generator.startswith('Visual Studio'): raise Exception('only windows is supported') f = open(pwdFile) lines = f.readlines() f.close() pwd = lines[0] if (dist): self.signFile(pfx, pwd, 'bin/Release', self.getDistFilename('win')) else: self.signFile(pfx, pwd, 'bin/Release', 'synergy.exe') self.signFile(pfx, pwd, 'bin/Release', 'synergyc.exe') self.signFile(pfx, pwd, 'bin/Release', 'synergys.exe') self.signFile(pfx, pwd, 'bin/Release', 'synergyd.exe') self.signFile(pfx, pwd, 'bin/Release', 'syntool.exe') self.signFile(pfx, pwd, 'bin/Release', 'synwinhk.dll') def signFile(self, pfx, pwd, dir, file): self.try_chdir(dir) err = os.system( 'signtool sign' ' /f ' + pfx + ' /p ' + pwd + ' /t http://timestamp.verisign.com/scripts/timstamp.dll ' + file) self.restore_chdir() if err != 0: raise Exception("signtool failed with error: " + str(err)) def runBuildCommand(self, cmd, target): self.try_chdir(self.getBuildDir(target)) err = os.system(cmd) self.restore_chdir() if err != 0: raise Exception(cmd + ' failed: ' + str(err)) def clean(self, targets=[]): # if no mode specified, use default if len(targets) == 0: targets += [self.defaultTarget,] # allow user to skip core clean if self.enableMakeCore: self.cleanCore(targets) # allow user to skip qui clean if self.enableMakeGui: self.cleanGui(targets) def cleanCore(self, targets): generator = self.getGeneratorFromConfig().cmakeName if generator.startswith('Visual Studio'): # special case for version 10, use new /target:clean if generator.startswith('Visual Studio 10'): for target in targets: self.run_vcbuild(generator, target, self.sln_filepath(), '/target:clean') # any other version of visual studio, use /clean elif generator.startswith('Visual Studio'): for target in targets: self.run_vcbuild(generator, target, self.sln_filepath(), '/clean') else: cmd = '' if generator == "Unix Makefiles": print 'Cleaning with GNU Make...' cmd = self.make_cmd elif generator == 'Xcode': print 'Cleaning with Xcode...' cmd = self.xcodebuild_cmd else: raise Exception('Not supported with generator: ' + generator) for target in targets: self.try_chdir(self.getBuildDir(target)) err = os.system(cmd + ' clean') self.restore_chdir() if err != 0: raise Exception('Clean failed: ' + str(err)) def cleanGui(self, targets): self.makeGui(targets, " clean") def open(self): generator = self.getGeneratorFromConfig().cmakeName if generator.startswith('Visual Studio'): print 'Opening with %s...' % generator self.open_internal(self.sln_filepath()) elif generator.startswith('Xcode'): print 'Opening with %s...' % generator self.open_internal(self.xcodeproj_filepath(), 'open') else: raise Exception('Not supported with generator: ' + generator) def update(self): print "Running Subversion update..." err = os.system('svn update') if err != 0: raise Exception('Could not update from repository with error code code: ' + str(err)) def revision(self): print self.find_revision() def find_revision(self): return self.getGitRevision() def getGitRevision(self): if sys.version_info < (2, 4): raise Exception("Python 2.4 or greater required.") p = subprocess.Popen( ["git", "log", "--pretty=format:%h", "-n", "1"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: raise Exception('Could not get revision, git error: ' + str(p.returncode)) return stdout.strip() def getGitBranchName(self): if sys.version_info < (2, 4): raise Exception("Python 2.4 or greater required.") p = subprocess.Popen( ["git", "rev-parse", "--abbrev-ref", "HEAD"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: raise Exception('Could not get branch name, git error: ' + str(p.returncode)) result = stdout.strip() # sometimes, git will prepend "heads/" infront of the branch name, # remove this as it's not useful to us and causes ftp issues. result = re.sub("heads/", "", result) return result def find_revision_svn(self): if sys.version_info < (2, 4): stdout = commands.getoutput('svn info') else: p = subprocess.Popen(['svn', 'info'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: raise Exception('Could not get revision - svn info failed with code: ' + str(p.returncode)) m = re.search('.*Revision: (\d+).*', stdout) if not m: raise Exception('Could not find revision number in svn info output.') return m.group(1) def kill(self): if sys.platform == 'win32': return os.system('taskkill /F /FI "IMAGENAME eq synergy*"') else: raise Exception('Not implemented for platform: ' + sys.platform) def doxygen(self): self.enableMakeGui = False # The conf generates doc/doxygen.cfg from cmake/doxygen.cfg.in self.configure(self.defaultTarget, '-DCONF_DOXYGEN:BOOL=TRUE') err = os.system('doxygen %s/%s' % (self.doc_dir, self.doxygen_filename)) if err != 0: raise Exception('doxygen failed with error code: ' + str(err)) def dist(self, type, vcRedistDir, qtDir): # Package is supported by default. package_unsupported = False unixTarget = self.defaultTarget if type == '' or type == None: self.dist_usage() return moveExt = '' if type == 'src': self.distSrc() elif type == 'rpm': if sys.platform == 'linux2': self.distRpm() else: package_unsupported = True elif type == 'deb': if sys.platform == 'linux2': self.distDeb() else: package_unsupported = True elif type == 'win': if sys.platform == 'win32': #self.distNsis(vcRedistDir, qtDir) self.distWix() else: package_unsupported = True elif type == 'mac': if sys.platform == 'darwin': self.distMac() else: package_unsupported = True else: raise Exception('Package type not supported: ' + type) if moveExt != '': self.unixMove( self.getGenerator().buildDir + '/release/*.' + moveExt, self.getGenerator().binDir) if package_unsupported: raise Exception( ("Package type, '%s' is not supported for platform, '%s'") % (type, sys.platform)) def distRpm(self): rpmDir = self.getGenerator().buildDir + '/rpm' if os.path.exists(rpmDir): shutil.rmtree(rpmDir) os.makedirs(rpmDir) templateFile = open(self.cmake_dir + '/synergy.spec.in') template = templateFile.read() template = template.replace('${in:version}', self.getVersionNumber()) specPath = rpmDir + '/synergy.spec' specFile = open(specPath, 'w') specFile.write(template) specFile.close() target = '../../bin/synergy-%s-%s.rpm' % ( self.getVersionForFilename(), self.getLinuxPlatform()) try: self.try_chdir(rpmDir) cmd = 'rpmbuild -bb --define "_topdir `pwd`" synergy.spec' print "Command: " + cmd err = os.system(cmd) if err != 0: raise Exception('rpmbuild failed: ' + str(err)) self.unixMove('RPMS/*/*.rpm', target) cmd = 'rpmlint ' + target print "Command: " + cmd err = os.system(cmd) if err != 0: raise Exception('rpmlint failed: ' + str(err)) finally: self.restore_chdir() def distDeb(self): buildDir = self.getGenerator().buildDir binDir = self.getGenerator().binDir resDir = self.cmake_dir package = '%s-%s-%s' % ( self.project, self.getVersionForFilename(), self.getLinuxPlatform()) debDir = '%s/deb' % buildDir if os.path.exists(debDir): shutil.rmtree(debDir) metaDir = '%s/%s/DEBIAN' % (debDir, package) os.makedirs(metaDir) templateFile = open(resDir + '/deb/control.in') template = templateFile.read() template = template.replace('${in:version}', self.getVersionNumber()) template = template.replace('${in:arch}', self.getDebianArch()) controlPath = '%s/control' % metaDir controlFile = open(controlPath, 'w') controlFile.write(template) controlFile.close() targetBin = '%s/%s/usr/bin' % (debDir, package) targetShare = '%s/%s/usr/share' % (debDir, package) targetApplications = "%s/applications" % targetShare targetIcons = "%s/icons" % targetShare targetDocs = "%s/doc/%s" % (targetShare, self.project) os.makedirs(targetBin) os.makedirs(targetApplications) os.makedirs(targetIcons) os.makedirs(targetDocs) for root, dirs, files in os.walk(debDir): for d in dirs: os.chmod(os.path.join(root, d), 0o0755) binFiles = ['synergy', 'synergyc', 'synergys', 'synergyd', 'syntool'] for f in binFiles: shutil.copy("%s/%s" % (binDir, f), targetBin) target = "%s/%s" % (targetBin, f) os.chmod(target, 0o0755) err = os.system("strip " + target) if err != 0: raise Exception('strip failed: ' + str(err)) shutil.copy("%s/synergy.desktop" % resDir, targetApplications) shutil.copy("%s/synergy.ico" % resDir, targetIcons) docTarget = "%s/doc/%s" % (targetShare, self.project) copyrightPath = "%s/deb/copyright" % resDir shutil.copy(copyrightPath, docTarget) shutil.copy("%s/deb/changelog" % resDir, docTarget) os.system("gzip -9 %s/changelog" % docTarget) if err != 0: raise Exception('gzip failed: ' + str(err)) for root, dirs, files in os.walk(targetShare): for f in files: os.chmod(os.path.join(root, f), 0o0644) target = '../../bin/%s.deb' % package try: self.try_chdir(debDir) # TODO: consider dpkg-buildpackage (higher level tool) cmd = 'fakeroot dpkg-deb --build %s' % package print "Command: " + cmd err = os.system(cmd) if err != 0: raise Exception('dpkg-deb failed: ' + str(err)) cmd = 'lintian %s.deb' % package print "Command: " + cmd err = os.system(cmd) if err != 0: raise Exception('lintian failed: ' + str(err)) self.unixMove('*.deb', target) finally: self.restore_chdir() def distSrc(self): name = '%s-%s-%s' % ( self.project, self.getVersionForFilename(), 'Source') exportPath = self.getGenerator().buildDir + '/' + name if os.path.exists(exportPath): print "Removing existing export..." shutil.rmtree(exportPath) os.mkdir(exportPath) cmd = "git archive %s | tar -x -C %s" % ( self.getGitBranchName(), exportPath) print 'Exporting repository to: ' + exportPath err = os.system(cmd) if err != 0: raise Exception('Repository export failed: ' + str(err)) packagePath = '../' + self.getGenerator().binDir + '/' + name + '.tar.gz' try: self.try_chdir(self.getGenerator().buildDir) print 'Packaging to: ' + packagePath err = os.system('tar cfvz ' + packagePath + ' ' + name) if err != 0: raise Exception('Package failed: ' + str(err)) finally: self.restore_chdir() def unixMove(self, source, dest): print 'Moving ' + source + ' to ' + dest err = os.system('mv ' + source + ' ' + dest) if err != 0: raise Exception('Package failed: ' + str(err)) def distMac(self): self.loadConfig() binDir = self.getGenerator().getBinDir('Release') name = "Synergy" dist = binDir + "/" + name # ensure dist dir is clean if os.path.exists(dist): shutil.rmtree(dist) os.makedirs(dist) shutil.move(binDir + "/" + name + ".app", dist + "/" + name + ".app") self.try_chdir(dist) err = os.system("ln -s /Applications") self.restore_chdir() fileName = "%s-%s-%s.dmg" % ( self.project, self.getVersionForFilename(), self.getMacPackageName()) cmd = "hdiutil create " + fileName + " -srcfolder ./" + name + "/ -ov" self.try_chdir(binDir) err = os.system(cmd) self.restore_chdir() def distWix(self): generator = self.getGeneratorFromConfig().cmakeName arch = 'x86' if generator.endswith('Win64'): arch = 'x64' version = self.getVersionNumber() args = "/p:DefineConstants=\"Version=%s\"" % version self.run_vcbuild( generator, 'release', 'synergy.sln', args, 'src/setup/win32/', 'x86') filename = "%s-%s-Windows-%s.msi" % ( self.project, self.getVersionForFilename(), arch) old = "bin/Release/synergy.msi" new = "bin/Release/%s" % (filename) try: os.remove(new) except OSError: pass os.rename(old, new) def distNsis(self, vcRedistDir, qtDir): if vcRedistDir == '': raise Exception( 'VC++ redist dir path not specified (--vcredist-dir).') if qtDir == '': raise Exception( 'QT SDK dir path not specified (--qt-dir).') generator = self.getGeneratorFromConfig().cmakeName arch = 'x86' installDirVar = '$PROGRAMFILES32' if generator.endswith('Win64'): arch = 'x64' installDirVar = '$PROGRAMFILES64' templateFile = open(self.cmake_dir + '\Installer.nsi.in') template = templateFile.read() template = template.replace('${in:version}', self.getVersionNumber()) template = template.replace('${in:arch}', arch) template = template.replace('${in:vcRedistDir}', vcRedistDir) template = template.replace('${in:qtDir}', qtDir) template = template.replace('${in:installDirVar}', installDirVar) nsiPath = self.getGenerator().buildDir + '\Installer.nsi' nsiFile = open(nsiPath, 'w') nsiFile.write(template) nsiFile.close() command = 'makensis ' + nsiPath print 'NSIS command: ' + command err = os.system(command) if err != 0: raise Exception('Package failed: ' + str(err)) def getVersionNumber(self): cmakeFile = open('CMakeLists.txt') cmake = cmakeFile.read() majorRe = re.search('VERSION_MAJOR (\d+)', cmake) major = majorRe.group(1) minorRe = re.search('VERSION_MINOR (\d+)', cmake) minor = minorRe.group(1) revRe = re.search('VERSION_REV (\d+)', cmake) rev = revRe.group(1) return "%s.%s.%s" % (major, minor, rev) def getVersionStage(self): cmakeFile = open('CMakeLists.txt') cmake = cmakeFile.read() stageRe = re.search('VERSION_STAGE (\w+)', cmake) return stageRe.group(1) def getVersionForFilename(self): versionStage = self.getVersionStage() gitBranch = self.getGitBranchName() gitRevision = self.getGitRevision() return "%s-%s-%s" % (gitBranch, versionStage, gitRevision) def distftp(self, type, ftp): if not type: raise Exception('Platform type not specified.') self.loadConfig() binDir = self.getGenerator().getBinDir('Release') filename = self.getDistFilename(type) packageSource = binDir + '/' + filename packageTarget = filename ftp.upload(packageSource, packageTarget) def getLibraryDistFilename(self, type, dir, name): (platform, packageExt, libraryExt) = self.getDistributePlatformInfo(type) firstPart = '%s-%s-%s' % (name, self.getVersionForFilename(), platform) filename = '%s.%s' % (firstPart, libraryExt) if type == 'rpm' or type == 'deb': # linux is a bit special, include dist type (deb/rpm in filename) filename = '%s-%s.%s' % (firstPart, packageExt, libraryExt) return filename def findLibraryFile(self, type, dir, name): if not os.path.exists(dir): return None (platform, packageExt, libraryExt) = self.getDistributePlatformInfo(type) ext = libraryExt pattern = name + '\.' + ext for filename in os.listdir(dir): if re.search(pattern, filename): return dir + '/' + filename return None def getDistributePlatformInfo(self, type): ext = None libraryExt = None platform = None if type == 'src': ext = 'tar.gz' platform = 'Source' elif type == 'rpm' or type == 'deb': ext = type libraryExt = 'so' platform = self.getLinuxPlatform() elif type == 'win': # get platform based on last generator used ext = 'msi' libraryExt = 'dll' generator = self.getGeneratorFromConfig().cmakeName if generator.find('Win64') != -1: platform = 'Windows-x64' else: platform = 'Windows-x86' elif type == 'mac': ext = "dmg" libraryExt = 'dylib' platform = self.getMacPackageName() if not platform: raise Exception('Unable to detect distributable platform.') return (platform, ext, libraryExt) def getDistFilename(self, type): pattern = self.getVersionForFilename() for filename in os.listdir(self.getBinDir('Release')): if re.search(pattern, filename): return filename raise Exception('Could not find package name with pattern: ' + pattern) def getDebianArch(self): if os.uname()[4][:3] == 'arm': return 'armhf' # os_bits should be loaded with '32bit' or '64bit' import platform (os_bits, other) = platform.architecture() # get platform based on current platform if os_bits == '32bit': return 'i386' elif os_bits == '64bit': return 'amd64' else: raise Exception("unknown os bits: " + os_bits) def getLinuxPlatform(self): if os.uname()[4][:3] == 'arm': return 'Linux-armv6l' # os_bits should be loaded with '32bit' or '64bit' import platform (os_bits, other) = platform.architecture() # get platform based on current platform if os_bits == '32bit': return 'Linux-i686' elif os_bits == '64bit': return 'Linux-x86_64' else: raise Exception("unknown os bits: " + os_bits) def dist_usage(self): print ('Usage: %s package [package-type]\n' '\n' 'Replace [package-type] with one of:\n' ' src .tar.gz source (Posix only)\n' ' rpm .rpm package (Red Hat)\n' ' deb .deb package (Debian)\n' ' win .exe installer (Windows)\n' ' mac .dmg package (Mac OS X)\n' '\n' 'Example: %s package src-tgz') % (self.this_cmd, self.this_cmd) def about(self): print ('Help Me script, from the Synergy project.\n' '%s\n' '\n' 'For help, run: %s help') % (self.website_url, self.this_cmd) def try_chdir(self, dir): global prevdir if dir == '': prevdir = '' return # Ensure temp build dir exists. if not os.path.exists(dir): print 'Creating dir: ' + dir os.makedirs(dir) prevdir = os.path.abspath(os.curdir) # It will exist by this point, so it's safe to chdir. print 'Entering dir: ' + dir os.chdir(dir) def restore_chdir(self): global prevdir if prevdir == '': return print 'Going back to: ' + prevdir os.chdir(prevdir) def open_internal(self, project_filename, application = ''): if not os.path.exists(project_filename): raise Exception('Project file (%s) not found, run hm conf first.' % project_filename) else: path = project_filename if application != '': path = application + ' ' + path err = os.system(path) if err != 0: raise Exception('Could not open project with error code code: ' + str(err)) def setup(self, target=''): print "Running setup..." oldGenerator = self.findGeneratorFromConfig() if not oldGenerator == None: for target in ['debug', 'release']: buildDir = oldGenerator.getBuildDir(target) cmakeCacheFilename = 'CMakeCache.txt' if buildDir != '': cmakeCacheFilename = buildDir + '/' + cmakeCacheFilename if os.path.exists(cmakeCacheFilename): print "Removing %s, since generator changed." % cmakeCacheFilename os.remove(cmakeCacheFilename) # always either get generator from args, or prompt user when # running setup generator = self.get_generator_from_prompt() config = self.getConfig() config.set('hm', 'setup_version', self.setup_version) # store the generator so we don't need to ask again config.set('cmake', 'generator', generator) self.write_config(config) # for all targets, set conf not run self.setConfRun('all', False) self.setConfRun('debug', False) self.setConfRun('release', False) print "Setup complete." def getConfig(self): if os.path.exists(self.configFilename): config = ConfigParser.ConfigParser() config.read(self.configFilename) else: config = ConfigParser.ConfigParser() if not config.has_section('hm'): config.add_section('hm') if not config.has_section('cmake'): config.add_section('cmake') return config def write_config(self, config, target=''): if not os.path.isdir(self.configDir): os.mkdir(self.configDir) configfile = open(self.configFilename, 'wb') config.write(configfile) def getGeneratorFromConfig(self): generator = self.findGeneratorFromConfig() if generator: return generator raise Exception("Could not find generator: " + name) def findGeneratorFromConfig(self): config = ConfigParser.RawConfigParser() config.read(self.configFilename) if not config.has_section('cmake'): return None name = config.get('cmake', 'generator') generators = self.get_generators() keys = generators.keys() keys.sort() for k in keys: if generators[k].cmakeName == name: return generators[k] return None def min_setup_version(self, version): if os.path.exists(self.configFilename): config = ConfigParser.RawConfigParser() config.read(self.configFilename) try: return config.getint('hm', 'setup_version') >= version except: return False else: return False def hasConfRun(self, target): if self.min_setup_version(2): config = ConfigParser.RawConfigParser() config.read(self.configFilename) try: return config.getboolean('hm', 'conf_done_' + target) except: return False else: return False def setConfRun(self, target, hasRun=True): if self.min_setup_version(3): config = ConfigParser.RawConfigParser() config.read(self.configFilename) config.set('hm', 'conf_done_' + target, hasRun) self.write_config(config) else: raise Exception("User does not have correct setup version.") def get_generators(self): if sys.platform == 'win32': return self.win32_generators elif sys.platform in ['linux2', 'sunos5', 'freebsd7', 'aix5']: return self.unix_generators elif sys.platform == 'darwin': return self.darwin_generators else: raise Exception('Unsupported platform: ' + sys.platform) def get_generator_from_prompt(self): return self.getGenerator().cmakeName def getGenerator(self): generators = self.get_generators() if len(generators.keys()) == 1: return generators[generators.keys()[0]] # if user has specified a generator as an argument if self.generator_id: return generators[int(self.generator_id)] conf = self.findGeneratorFromConfig() if conf: return conf raise Exception( 'Generator not specified, use -g arg ' + '(use `hm genlist` for a list of generators).') def setup_generator_prompt(self, generators): if self.no_prompts: raise Exception('User prompting is disabled.') prompt = 'Enter a number:' print prompt, generator_id = raw_input() if generator_id in generators: print 'Selected generator:', generators[generator_id] else: print 'Invalid number, try again.' self.setup_generator_prompt(generators) return generators[generator_id] def get_vcvarsall(self, generator): import platform, _winreg # os_bits should be loaded with '32bit' or '64bit' (os_bits, other) = platform.architecture() # visual studio is a 32-bit app, so when we're on 64-bit, we need to check the WoW dungeon if os_bits == '64bit': key_name = r'SOFTWARE\Wow6432Node\Microsoft\VisualStudio\SxS\VS7' else: key_name = r'SOFTWARE\Microsoft\VisualStudio\SxS\VC7' try: key = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, key_name) except: raise Exception('Unable to open Visual Studio registry key. Application may not be installed.') if generator.startswith('Visual Studio 8'): value,type = _winreg.QueryValueEx(key, '8.0') elif generator.startswith('Visual Studio 9'): value,type = _winreg.QueryValueEx(key, '9.0') elif generator.startswith('Visual Studio 10'): value,type = _winreg.QueryValueEx(key, '10.0') else: raise Exception('Cannot determine vcvarsall.bat location for: ' + generator) # not sure why, but the value on 64-bit differs slightly to the original if os_bits == '64bit': path = value + r'vc\vcvarsall.bat' else: path = value + r'vcvarsall.bat' if not os.path.exists(path): raise Exception("'%s' not found." % path) return path def run_vcbuild(self, generator, mode, solution, args='', dir='', config32='Win32'): import platform # os_bits should be loaded with '32bit' or '64bit' (os_bits, other) = platform.architecture() # Now we choose the parameters bases on OS 32/64 and our target 32/64 # http://msdn.microsoft.com/en-us/library/x4d2c09s%28VS.80%29.aspx # valid options are only: ia64 amd64 x86_amd64 x86_ia64 # but calling vcvarsall.bat does not garantee that it will work # ret code from vcvarsall.bat is always 0 so the only way of knowing that I worked is by analysing the text output # ms bugg: install VS9, FeaturePack, VS9SP1 and you'll obtain a vcvarsall.bat that fails. if generator.find('Win64') != -1: # target = 64bit if os_bits == '32bit': vcvars_platform = 'x86_amd64' # 32bit OS building 64bit app else: vcvars_platform = 'amd64' # 64bit OS building 64bit app config_platform = 'x64' else: # target = 32bit vcvars_platform = 'x86' # 32/64bit OS building 32bit app config_platform = config32 if mode == 'release': config = 'Release' else: config = 'Debug' if generator.startswith('Visual Studio 10'): cmd = ('@echo off\n' 'call "%s" %s \n' 'cd "%s"\n' 'msbuild /nologo %s /p:Configuration="%s" /p:Platform="%s" "%s"' ) % (self.get_vcvarsall(generator), vcvars_platform, dir, args, config, config_platform, solution) else: config = config + '|' + config_platform cmd = ('@echo off\n' 'call "%s" %s \n' 'cd "%s"\n' 'vcbuild /nologo %s "%s" "%s"' ) % (self.get_vcvarsall(generator), vcvars_platform, dir, args, solution, config) # Generate a batch file, since we can't use environment variables directly. temp_bat = self.getBuildDir() + r'\vcbuild.bat' file = open(temp_bat, 'w') file.write(cmd) file.close() err = os.system(temp_bat) if err != 0: raise Exception('Microsoft compiler failed with error code: ' + str(err)) def ensure_setup_latest(self): if not self.min_setup_version(self.setup_version): self.setup() def reformat(self): err = os.system( r'tool\astyle\AStyle.exe ' '--quiet --suffix=none --style=java --indent=force-tab=4 --recursive ' 'lib/*.cpp lib/*.h cmd/*.cpp cmd/*.h') if err != 0: raise Exception('Reformat failed with error code: ' + str(err)) def printGeneratorList(self): generators = self.get_generators() keys = generators.keys() keys.sort() for k in keys: print str(k) + ': ' + generators[k].cmakeName def getMacVersion(self): if not self.macSdk: raise Exception("Mac OS X SDK not set.") result = re.search('(\d+)\.(\d+)', self.macSdk) if not result: print versions raise Exception("Could not find Mac OS X version.") major = int(result.group(1)) minor = int(result.group(2)) return (major, minor) def getMacPackageName(self): (major, minor) = self.getMacVersion() if major == 10: if minor <= 4: # 10.4: intel and power pc arch = "Universal" elif minor <= 6: # 10.5: 32-bit intel arch = "i386" else: # 10.7: 64-bit intel (gui only) arch = "x86_64" else: raise Exception("Mac OS major version unknown: " + str(major)) # version is major and minor with no dots (e.g. 106) version = str(major) + str(minor) if (self.macDeploy == self.macSdk): return "MacOSX%s-%s" % (version, arch) else: return "MacOSX-%s" % arch def reset(self): if os.path.exists('build'): shutil.rmtree('build') if os.path.exists('bin'): shutil.rmtree('bin') if os.path.exists('lib'): shutil.rmtree('lib') if os.path.exists('src/gui/tmp'): shutil.rmtree('src/gui/tmp') # qt 4.3 generates ui_ files. for filename in glob.glob("src/gui/ui_*"): os.remove(filename) # the command handler should be called only from hm.py (i.e. directly # from the command prompt). the purpose of this class is so that we # don't need to do argument handling all over the place in the internal # commands class. class CommandHandler: ic = InternalCommands() build_targets = [] vcRedistDir = '' qtDir = '' def __init__(self, argv, opts, args, verbose): self.ic.verbose = verbose self.opts = opts self.args = args for o, a in self.opts: if o == '--no-prompts': self.ic.no_prompts = True elif o in ('-g', '--generator'): self.ic.generator_id = a elif o == '--skip-gui': self.ic.enableMakeGui = False elif o == '--skip-core': self.ic.enableMakeCore = False elif o in ('-d', '--debug'): self.build_targets += ['debug',] elif o in ('-r', '--release'): self.build_targets += ['release',] elif o == '--vcredist-dir': self.vcRedistDir = a elif o == '--qt-dir': self.qtDir = a elif o == '--mac-sdk': self.ic.macSdk = a elif o == '--mac-deploy': self.ic.macDeploy = a elif o == '--mac-identity': self.ic.macIdentity = a def about(self): self.ic.about() def setup(self): self.ic.setup() def configure(self): self.ic.configureAll(self.build_targets) def build(self): self.ic.build(self.build_targets) def clean(self): self.ic.clean(self.build_targets) def update(self): self.ic.update() def install(self): print 'Not yet implemented: install' def doxygen(self): self.ic.doxygen() def dist(self): type = None if len(self.args) > 0: type = self.args[0] self.ic.dist(type, self.vcRedistDir, self.qtDir) def distftp(self): type = None host = None user = None password = None dir = None if len(self.args) > 0: type = self.args[0] for o, a in self.opts: if o == '--host': host = a elif o == '--user': user = a elif o == '--pass': password = a elif o == '--dir': dir = a if not host: raise Exception('FTP host was not specified.') ftp = ftputil.FtpUploader( host, user, password, dir) self.ic.distftp(type, ftp) def destroy(self): self.ic.destroy() def kill(self): self.ic.kill() def usage(self): self.ic.usage() def revision(self): self.ic.revision() def reformat(self): self.ic.reformat() def open(self): self.ic.open() def genlist(self): self.ic.printGeneratorList() def reset(self): self.ic.reset() def signwin(self): pfx = None pwd = None dist = False for o, a in self.opts: if o == '--pfx': pfx = a elif o == '--pwd': pwd = a elif o == '--dist': dist = True self.ic.signwin(pfx, pwd, dist) def signmac(self): self.ic.signmac() synergy-1.8.8-stable/ext/toolchain/ftputil.py000066400000000000000000000030121305627404700213250ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2010 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . from ftplib import FTP class FtpUploader: def __init__(self, host, user, password, dir): self.host = host self.user = user self.password = password self.dir = dir def upload(self, src, dest, subDir=None): print "Connecting to '%s'" % self.host ftp = FTP(self.host, self.user, self.password) self.changeDir(ftp, self.dir) if subDir: self.changeDir(ftp, subDir) print "Uploading '%s' as '%s'" % (src, dest) f = open(src, 'rb') ftp.storbinary('STOR ' + dest, f) f.close() ftp.close() print "Done" def changeDir(self, ftp, dir): if dir not in ftp.nlst(): print "Creating dir '%s'" % dir try: ftp.mkd(dir) except: # sometimes nlst may returns nothing, so mkd fails with 'File exists' print "Failed to create dir '%s'" % dir print "Changing to dir '%s'" % dir ftp.cwd(dir) synergy-1.8.8-stable/ext/toolchain/generators.py000066400000000000000000000050301305627404700220110ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . class Generator(object): def __init__(self, cmakeName, buildDir='build', sourceDir='..', binDir='bin'): self.cmakeName = cmakeName self.buildDir = buildDir self.sourceDir = sourceDir self.binDir = binDir def getBuildDir(self, target): return self.buildDir def getBinDir(self, target=''): return self.binDir def getSourceDir(self): return self.sourceDir class VisualStudioGenerator(Generator): def __init__(self, version): super(VisualStudioGenerator, self).__init__('Visual Studio ' + version) def getBinDir(self, target=''): return super(VisualStudioGenerator, self).getBinDir(target) + '/' + target class MakefilesGenerator(Generator): def __init__(self): super(MakefilesGenerator, self).__init__('Unix Makefiles') def getBuildDir(self, target): return super(MakefilesGenerator, self).getBuildDir(target) + '/' + target def getBinDir(self, target=''): workingDir = super(MakefilesGenerator, self).getBinDir(target) # only put debug files in separate bin dir if target == 'debug': workingDir += '/debug' return workingDir def getSourceDir(self): return super(MakefilesGenerator, self).getSourceDir() + '/..' class XcodeGenerator(Generator): def __init__(self): super(XcodeGenerator, self).__init__('Xcode') def getBinDir(self, target=''): if target == "": return super(XcodeGenerator, self).getBinDir(target) xcodeTarget = target[0].upper() + target[1:] return super(XcodeGenerator, self).getBinDir(target) + '/' + xcodeTarget class EclipseGenerator(Generator): def __init__(self): super(EclipseGenerator, self).__init__('Eclipse CDT4 - Unix Makefiles', '', '') def getBuildDir(self, target): # eclipse only works with in-source build. return '' def getBinDir(self, target=''): # eclipse only works with in-source build. return 'bin' def getSourceDir(self): return '' synergy-1.8.8-stable/hm.cmd000066400000000000000000000000561305627404700156020ustar00rootroot00000000000000@echo off python hm.py %* exit /b %errorlevel%synergy-1.8.8-stable/hm.py000066400000000000000000000015101305627404700154630ustar00rootroot00000000000000#! /usr/bin/env python # synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import sys sys.path.append('ext') from toolchain import commands1 tc = commands1.Toolchain() tc.run(sys.argv) synergy-1.8.8-stable/hm.sh000077500000000000000000000000401305627404700154450ustar00rootroot00000000000000#! /bin/bash python hm.py "$@" synergy-1.8.8-stable/res/000077500000000000000000000000001305627404700153015ustar00rootroot00000000000000synergy-1.8.8-stable/res/DefineIfExist.nsh000066400000000000000000000021671305627404700205070ustar00rootroot00000000000000; synergy -- mouse and keyboard sharing utility ; Copyright (C) 2012 Nick Bolton ; ; 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 LICENSE 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. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . !macro !defineifexist _VAR_NAME _FILE_NAME !tempfile _TEMPFILE !ifdef NSIS_WIN32_MAKENSIS ; Windows - cmd.exe !system 'if exist "${_FILE_NAME}" echo !define ${_VAR_NAME} > "${_TEMPFILE}"' !else ; Posix - sh !system 'if [ -e "${_FILE_NAME}" ]; then echo "!define ${_VAR_NAME}" > "${_TEMPFILE}"; fi' !endif !include '${_TEMPFILE}' !delfile '${_TEMPFILE}' !undef _TEMPFILE !macroend !define !defineifexist "!insertmacro !defineifexist" synergy-1.8.8-stable/res/Installer.nsi.in000066400000000000000000000016251305627404700203620ustar00rootroot00000000000000; synergy -- mouse and keyboard sharing utility ; Copyright (C) 2012 Nick Bolton ; ; 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 LICENSE 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. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . ; template variables !define version ${in:version} !define arch ${in:arch} !define vcRedistDir ${in:vcRedistDir} !define qtDir ${in:qtDir} !define installDirVar ${in:installDirVar} !addincludedir ..\res !include "synergy.nsh" synergy-1.8.8-stable/res/License.rtf000066400000000000000000000403011305627404700173760ustar00rootroot00000000000000{\rtf1\ansi\ansicpg1252\cocoartf949\cocoasubrtf460 {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\froman\fcharset0 Times-Roman;} {\colortbl;\red255\green255\blue255;} {\info {\title Original file was gpl-2.0.tex} {\doccomm Created using latex2rtf 1.9.19a on Sun Jul 12 19:21:22 2009}}\paperw12280\paperh15900\margl2680\margr2700\margb1760\margt2540\vieww12280\viewh15900\viewkind1 \deftab720 \pard\pardeftab720\ri0\qj \f0\fs24 \cf0 \ \pard\pardeftab720\ri0\qc \f1\fs30 \cf0 GNU GENERAL PUBLIC LICENSE \f0\fs24 \ \ \ \pard\pardeftab720\ri0\qc \f1 \cf0 Version 2, June 1991\ \ \ Copyright \'a9 1989, 1991 Free Software Foundation, Inc.\ \pard\pardeftab720\ri0\sb240\qc \cf0 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA\ \pard\pardeftab720\ri0\qc \cf0 Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. \ \pard\pardeftab720\ri0\qc \b\fs26 \cf0 Preamble \b0\fs24 \ \pard\pardeftab720\ri0\qj \cf0 The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software\'97to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation\'92s software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.\ When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.\ To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.\ For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.\ We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.\ Also, for each author\'92s protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors\'92 reputations.\ Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone\'92s free use or not licensed at all.\ The precise terms and conditions for copying, distribution and modification follow.\ \pard\pardeftab720\ri0\qc \fs31 \cf0 Terms and Conditions For Copying, Distribution and Modification \fs24 \ \pard\pardeftab720\li600\fi-300\ri0\sb50\qj \cf0 1. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The \'93Program\'94, below, refers to any such program or work, and a \'93work based on the Program\'94 means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term \'93modification\'94.) Each licensee is addressed as \'93you\'94.\ \pard\pardeftab720\li600\ri0\qj \cf0 Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.\ \pard\pardeftab720\li600\fi-300\ri0\sb50\qj \cf0 2. You may copy and distribute verbatim copies of the Program\'92s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.\ \pard\pardeftab720\li600\ri0\qj \cf0 You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.\ \pard\pardeftab720\li600\fi-300\ri0\sb50\qj \cf0 3. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:\ \pard\pardeftab720\li1200\fi-300\ri0\sb50\qj \cf0 (a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.\ (b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.\ (c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)\ \pard\pardeftab720\li600\ri0\sb100\qj \cf0 These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.\ \pard\pardeftab720\li600\fi-300\ri0\qj \cf0 Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.\ In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.\ \pard\pardeftab720\li600\fi-300\ri0\sb50\qj \cf0 4. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:\ \pard\pardeftab720\li1200\fi-300\ri0\sb50\qj \cf0 (a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\ (b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,\ (c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)\ \pard\pardeftab720\li600\ri0\sb100\qj \cf0 The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.\ \pard\pardeftab720\li600\fi-300\ri0\qj \cf0 If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.\ \pard\pardeftab720\li600\fi-300\ri0\sb50\qj \cf0 5. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.\ 6. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.\ 7. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients\'92 exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.\ 8. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.\ \pard\pardeftab720\li600\ri0\qj \cf0 If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.\ It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.\ This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.\ \pard\pardeftab720\li600\fi-300\ri0\sb50\qj \cf0 9. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.\ 10. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.\ \pard\pardeftab720\li600\ri0\qj \cf0 Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and \'93any later version\'94, you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.\ \pard\pardeftab720\li600\fi-300\ri0\sb50\qj \cf0 11. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.\ \pard\pardeftab720\li600\ri0\qc \fs31 \cf0 No Warranty \fs24 \ \pard\pardeftab720\li600\fi-300\ri0\sb50\qj \cf0 12. Because the program is licensed free of charge, there is no warranty for the program, to the extent permitted by applicable law. Except when otherwise stated in writing the copyright holders and/or other parties provide the program \'93as is\'94 without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair or correction. \f0 \ \f1 13. In no event unless required by applicable law or agreed to in writing will any copyright holder, or any other party who may modify and/or redistribute the program as permitted above, be liable to you for damages, including any general, special, incidental or consequential damages arising out of the use or inability to use the program (including but not limited to loss of data or data being rendered inaccurate or losses sustained by you or third parties or a failure of the program to operate with any other programs), even if such holder or other party has been advised of the possibility of such damages. \f0 \ \pard\pardeftab720\ri0\sb100\qc \f1\fs31 \cf0 End of Terms and Conditions \fs24 }synergy-1.8.8-stable/res/License.tex000066400000000000000000000440051305627404700174100ustar00rootroot00000000000000\documentclass[11pt]{article} \title{GNU GENERAL PUBLIC LICENSE} \date{Version 2, June 1991} \begin{document} \maketitle \begin{center} {\parindent 0in Copyright \copyright\ 1989, 1991 Free Software Foundation, Inc. \bigskip 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA \bigskip Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. } \end{center} \begin{center} {\bf\large Preamble} \end{center} The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software---to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. \begin{center} {\Large \sc Terms and Conditions For Copying, Distribution and Modification} \end{center} %\renewcommand{\theenumi}{\alpha{enumi}} \begin{enumerate} \addtocounter{enumi}{-1} \item This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The ``Program'', below, refers to any such program or work, and a ``work based on the Program'' means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term ``modification''.) Each licensee is addressed as ``you''. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. \item You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. \item You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: \begin{enumerate} \item You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. \item You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. \item If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) \end{enumerate} These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. \item You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: \begin{enumerate} \item Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, \item Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, \item Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) \end{enumerate} The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. \item You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. \item You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. \item Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. \item If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. \item If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. \item The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and ``any later version'', you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. \item If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. \begin{center} {\Large\sc No Warranty } \end{center} \item {\sc Because the program is licensed free of charge, there is no warranty for the program, to the extent permitted by applicable law. Except when otherwise stated in writing the copyright holders and/or other parties provide the program ``as is'' without warranty of any kind, either expressed or implied, including, but not limited to, the implied warranties of merchantability and fitness for a particular purpose. The entire risk as to the quality and performance of the program is with you. Should the program prove defective, you assume the cost of all necessary servicing, repair or correction.} \item {\sc In no event unless required by applicable law or agreed to in writing will any copyright holder, or any other party who may modify and/or redistribute the program as permitted above, be liable to you for damages, including any general, special, incidental or consequential damages arising out of the use or inability to use the program (including but not limited to loss of data or data being rendered inaccurate or losses sustained by you or third parties or a failure of the program to operate with any other programs), even if such holder or other party has been advised of the possibility of such damages.} \end{enumerate} \begin{center} {\Large\sc End of Terms and Conditions} \end{center} \pagebreak[2] \section*{Appendix: How to Apply These Terms to Your New Programs} If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the ``copyright'' line and a pointer to where the full notice is found. \begin{quote} one line to give the program's name and a brief idea of what it does. \\ Copyright (C) yyyy name of author \\ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. \end{quote} Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: \begin{quote} Gnomovision version 69, Copyright (C) yyyy name of author \\ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. \\ This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. \end{quote} The hypothetical commands {\tt show w} and {\tt show c} should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than {\tt show w} and {\tt show c}; they could even be mouse-clicks or menu items---whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a ``copyright disclaimer'' for the program, if necessary. Here is a sample; alter the names: \begin{quote} Yoyodyne, Inc., hereby disclaims all copyright interest in the program \\ `Gnomovision' (which makes passes at compilers) written by James Hacker. \\ signature of Ty Coon, 1 April 1989 \\ Ty Coon, President of Vice \end{quote} This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. \end{document} synergy-1.8.8-stable/res/Readme.txt000066400000000000000000000004531305627404700172410ustar00rootroot00000000000000Thank you for chosing Synergy! http://symless.com/ Synergy allows you to share your keyboard and mouse between computers over a network. For FAQ, setup, and usage instructions, please visit our online Readme: http://symless.com/pm/projects/synergy/wiki/Readme Have fun! Thanks, The Synergy Team synergy-1.8.8-stable/res/banner.bmp000066400000000000000000003375221305627404700172620ustar00rootroot00000000000000BMR|: Ⱦ  BGRs˞Ψ׷cϫ?Ø=×Aę̳u????Ũ`Ė`Ϊ=×=×=×=×=×=×=×~׺E??????å]ղZ̦=×=×=×=×=×=×=×=×=×=×Ͷy????????Tڽؼ=×=×=×=×=×=×=×=×=×=×=×=×Ŕ??????????̳uTʣ=×=×=×=×=×=×=×=×=×=×=×=×=×Ծ???????????NFś=×=×=×=×=×=×=×=×=×=×=×=×=×OȠ¤X????????????DܿCŚ=×=×=×=×=×=×=×=×=×=×=×=×=×GƜԱ??????????????BܿHǝ=×=×=×=×=×=×=×=×=×=×=×@ęoӱ׵˞˱rE???????????CXʥ=×=×=×=×=×=×=×=×=×=×Y˥ٺũb??????????Oھ=×=×=×=×=×=×=×=×=×HǝڽN?????????̳u=×=×=×=×=×=×=×=×=×eϬ˲r?????????ٺcΫ=×=×=×=×=×=×=×=×jѮͶy????????¢V=×=×=×=×=×=×=×=×bϪ˱p????????ղoӱ=×=×=×=×=×=×=×CŚO???????å]>×=×=×=×=×=×=×=×ܿ????????=×=×=×=×=×=×=×MȠŨa???????Ėsӳ=×=×=×=×=×=×=×ڻ???????ũbIƞ=×=×=×=×=×=×=×D??????@=×=×=×=×=×=×=×Z̦˳s???????=×=×=×=×=×=×=×ۿЧ??????T=×>×fϬؽֹRɢ=×Q?????ԯ_ΩǬg??FЩĨܺ`}]}]Ên˴Ӿsu5õ}]}]}]}]}]c`bdf ITpr1`b`b‰l}]}]}]}]}]}]ص`b`b`b`b`b`b`bʱ}]}]}]}]}]}]}]ōqL`b`b`b`b`b`b`bˆk}]}]}]}]}]}]}]ad`b`b`b`b`b`bceҧ}]}]}]}]}]}]}]ݾ`b`b`b`b`b`b`bMʽ}]}]}]}]}]}]}]gsu5`b`b`b`b`b`b`b_}]}]}]}]}]}]}]ܽ`b`b`b`b`b`b`b`bѥ}]}]}]}]}]}]}]`fh"`b`b`b`b`b`b`bK}]}]}]}]}]}]}]}]Ōp}~C`b`b`b`b`b`b`b`b˴Ξ}]}]}]}]}]}]}]}]ǐuI`b`b`b`b`b`b`b`b|}B~^}]}]}]}]}]}]}]}]Ōp|}B`b`b`b`b`b`b`b`b`bܺ}]}]}]}]}]}]}]}]}]~^ܹeg!`b`b`b`b`b`b`b`b`boɘ~}]}]}]}]}]}]}]}]}]}]g۸mo,`b`b`b`b`b`b`b`b`b`bwx:Ên}]}]}]}]}]}]}]}]}]}]}]}]Ênԩۺõwx:`b`b`b`b`b`b`b`b`b`b`b`bjl(‡j}]}]}]}]}]}]}]}]}]}]}]}]}]}]ڹkn+`b`b`b`b`b`b`b`b`b`b`b`b`bfi#ċn}]}]}]}]}]}]}]}]}]}]}]}]`P`b`b`b`b`b`b`b`b`b`b`b`b`bjl(ʚ}]}]}]}]}]}]}]}]}]}]}]Ȓx`b`b`b`b`b`b`b`b`b`b`b`b`bxz=ܼ_}]}]}]}]}]}]}]}]}]ɔz`b`b`b`b`b`b`b`b`b`b`b`bvϠ}]}]}]}]}]}]}]}]dwy;`b`b`b`b`b`b`b`b`bGѧ`}]}]}]}]}]}]˾ηac`b`b`b`b`bacXӾӨÉl}]}]}]gҾIeg!kn+`synergy-1.8.8-stable/res/config.h.in000066400000000000000000000143301305627404700173250ustar00rootroot00000000000000/* Define version here for Unix, but using /D for Windows. */ #cmakedefine VERSION "${VERSION}" /* Define to the base type of arg 3 for `accept`. */ #cmakedefine ACCEPT_TYPE_ARG3 ${ACCEPT_TYPE_ARG3} /* Define if your compiler has bool support. */ #cmakedefine HAVE_CXX_BOOL ${HAVE_CXX_BOOL} /* Define if your compiler has C++ cast support. */ #cmakedefine HAVE_CXX_CASTS ${HAVE_CXX_CASTS} /* Define if your compiler has exceptions support. */ #cmakedefine HAVE_CXX_EXCEPTIONS ${HAVE_CXX_EXCEPTIONS} /* Define if your compiler has mutable support. */ #cmakedefine HAVE_CXX_MUTABLE ${HAVE_CXX_MUTABLE} /* Define if your compiler has standard C++ library support. */ #cmakedefine HAVE_CXX_STDLIB ${HAVE_CXX_STDLIB} /* Define if the header file declares function prototypes. */ #cmakedefine HAVE_DPMS_PROTOTYPES ${HAVE_DPMS_PROTOTYPES} /* Define if you have a working `getpwuid_r` function. */ #cmakedefine HAVE_GETPWUID_R ${HAVE_GETPWUID_R} /* Define to 1 if you have the `gmtime_r` function. */ #cmakedefine HAVE_GMTIME_R ${HAVE_GMTIME_R} /* Define if you have the `inet_aton` function. */ #cmakedefine HAVE_INET_ATON ${HAVE_INET_ATON} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_ISTREAM ${HAVE_ISTREAM} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_LOCALE_H ${HAVE_LOCALE_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_MEMORY_H ${HAVE_MEMORY_H} /* Define if you have the `nanosleep` function. */ #cmakedefine HAVE_NANOSLEEP ${HAVE_NANOSLEEP} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_OSTREAM ${HAVE_OSTREAM} /* Define if you have the `poll` function. */ #cmakedefine HAVE_POLL ${HAVE_POLL} /* Define if you have a POSIX `sigwait` function. */ #cmakedefine HAVE_POSIX_SIGWAIT ${HAVE_POSIX_SIGWAIT} /* Define if you have POSIX threads libraries and header files. */ #cmakedefine HAVE_PTHREAD ${HAVE_PTHREAD} /* Define if you have `pthread_sigmask` and `pthread_kill` functions. */ #cmakedefine HAVE_PTHREAD_SIGNAL ${HAVE_PTHREAD_SIGNAL} /* Define if your compiler defines socklen_t. */ #cmakedefine HAVE_SOCKLEN_T ${HAVE_SOCKLEN_T} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SSTREAM ${HAVE_SSTREAM} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STDLIB_H ${HAVE_STDLIB_H} /* Define to 1 if you have the `strftime` function. */ #cmakedefine HAVE_STRFTIME ${HAVE_STRFTIME} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRINGS_H ${HAVE_STRINGS_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_STRING_H ${HAVE_STRING_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SELECT_H ${HAVE_SYS_SELECT_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_STAT_H ${HAVE_SYS_STAT_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TIME_H ${HAVE_SYS_TIME_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SYS_UTSNAME_H ${HAVE_SYS_UTSNAME_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H} /* Define to 1 if you have the `vsnprintf` function. */ #cmakedefine HAVE_VSNPRINTF ${HAVE_VSNPRINTF} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_WCHAR_H ${HAVE_WCHAR_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_X11_EXTENSIONS_XRANDR_H ${HAVE_X11_EXTENSIONS_XRANDR_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_X11_EXTENSIONS_DPMS_H ${HAVE_X11_EXTENSIONS_DPMS_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_X11_EXTENSIONS_XINERAMA_H ${HAVE_X11_EXTENSIONS_XINERAMA_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_X11_EXTENSIONS_XKBSTR_H ${HAVE_X11_EXTENSIONS_XKBSTR_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_X11_EXTENSIONS_XTEST_H ${HAVE_X11_EXTENSIONS_XTEST_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_X11_XKBLIB_H ${HAVE_X11_XKBLIB_H} /* Define to 1 if you have the header file. */ #cmakedefine HAVE_XI2 ${HAVE_XI2} /* Define this if the XKB extension is available. */ #cmakedefine HAVE_XKB_EXTENSION ${HAVE_XKB_EXTENSION} /* Define to necessary symbol if this constant uses a non-standard name on your system. */ #cmakedefine PTHREAD_CREATE_JOINABLE ${PTHREAD_CREATE_JOINABLE} /* Define to the type of arg 1 for `select`. */ #cmakedefine SELECT_TYPE_ARG1 ${SELECT_TYPE_ARG1} /* Define to the type of args 2, 3 and 4 for `select`. */ #cmakedefine SELECT_TYPE_ARG234 ${SELECT_TYPE_ARG234} /* Define to the type of arg 5 for `select`. */ #cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5} /* The size of `char`, as computed by sizeof. */ #cmakedefine SIZEOF_CHAR ${SIZEOF_CHAR} /* The size of `int`, as computed by sizeof. */ #cmakedefine SIZEOF_INT ${SIZEOF_INT} /* The size of `long`, as computed by sizeof. */ #cmakedefine SIZEOF_LONG ${SIZEOF_LONG} /* The size of `short`, as computed by sizeof. */ #cmakedefine SIZEOF_SHORT ${SIZEOF_SHORT} /* Define to 1 if you have the ANSI C header files. */ #cmakedefine STDC_HEADERS ${STDC_HEADERS} /* Define to 1 if you can safely include both and . */ #cmakedefine TIME_WITH_SYS_TIME ${TIME_WITH_SYS_TIME} /* Define to 1 if your declares `struct tm`. */ #cmakedefine TM_IN_SYS_TIME ${TM_IN_SYS_TIME} /* Define to 1 if the X Window System is missing or not being used. */ #cmakedefine X_DISPLAY_MISSING ${X_DISPLAY_MISSING} /* Define to `unsigned int` if does not define. */ #cmakedefine size_t ${size_t} synergy-1.8.8-stable/res/deb/000077500000000000000000000000001305627404700160335ustar00rootroot00000000000000synergy-1.8.8-stable/res/deb/changelog000066400000000000000000000001771305627404700177120ustar00rootroot00000000000000synergy (1.0) unstable; urgency=low * Initial release. -- Nick Bolton Wed, 09 Apr 2014 15:16:48 +0100 synergy-1.8.8-stable/res/deb/control.in000066400000000000000000000012151305627404700200420ustar00rootroot00000000000000Package: synergy Section: net Priority: optional Maintainer: Nick Bolton Version: ${in:version} Architecture: ${in:arch} Depends: libc6 (>= 2.11), libstdc++6 (>= 4.4.3), libx11-6 (>= 1.3.2), libxext6 (>= 1.1.1), libxi6 (>= 1.3), libxinerama1 (>= 1.1), libxtst6 (>= 1.1), libqtcore4 (>= 4.6.2), libqtgui4 (>= 4.6.2), libqt4-network (>= 4.6.2), libcurl3 (>= 7.19.7), libavahi-compat-libdnssd1 (>= 0.6.25), openssl (>= 1.0.1) Installed-Size: 30 Description: Keyboard and mouse sharing utility Synergy is free and open source software for sharing one mouse and keyboard between multiple computers. Works on Windows, Mac OS X and Linux. synergy-1.8.8-stable/res/deb/copyright000066400000000000000000000013121305627404700177630ustar00rootroot00000000000000/usr/share/common-licenses/GPL-2 synergy -- mouse and keyboard sharing utility Copyright (C) 2014-2016 Symless Ltd. Copyright (C) 2004 Chris Schoeneman This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License found in the file LICENSE 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. You should have received a copy of the GNU General Public License along with this program. If not, see . synergy-1.8.8-stable/res/dialog.bmp000066400000000000000000022617521305627404700172570ustar00rootroot00000000000000BMc |8 `c   BGRsŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽŽÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđđĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒĒēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēēŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŔŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕŕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƕƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƖƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗƗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǗǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǘǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙǙșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșșȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚȚɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɛɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜɜʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʝʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞʞ˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟˟ˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠˠ̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̡̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̢̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠̠ͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣͣ͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢͢ΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΤΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥΥϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϦϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧϧШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШШЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩЩѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѪѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫѫҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҬҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭҭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӭӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӮӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯӯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯԯ԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰԰ԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱԱձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձձղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղղճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճճֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳֳִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִִ״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״״׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׵׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶׶ضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضضططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططططظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظظٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٸٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹٹںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںںڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻڻۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼۼ۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽۽ܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܾܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿܿϧʯmʯmțțyԵIƝ=×=×=×IƝҼ?????ũb‘IƝ=×=×=×=×=×=×=×=×J???????ʯmIƝ=×=×=×=×=×=×=×=×=×=×ؼҼ?????????ʯmmѯ=×=×=×=×=×=×=×=×=×=×=×=×mѯȜ??????????JϧIƝ=×=×=×=×=×=×=×=×=×=×=×=×=×yԶɜ????????????ҼIƝ=×=×=×=×=×=×=×=×=×=×=×=×=×=×V?????????????ũbIƝ=×=×=×=×=×=×=×=×=×=×=×=×=×=×ؼϨ???????????????ũbIƝ=×=×=×=×=×=×=×=×=×=×=×=×aͪɝζzJ????????????Ҽaͩ=×=×=×=×=×=×=×=×=×=×IƝʯn???????????ϨsruWVYssuWWZssussuWWZ=×=×=×=×=×=×=×=×=×=×ٽV?????????JWWY # # # # #;;> # # # # # # #WWZWWZ # # # # #=×=×=×=×=×=×=×=×=×IƝζz?????????ʯnssu #;;>IIL # # #;;> # #--0WWZ # # # #--0ssu #;;>IIL # # #mѰ=×=×=×=×=×=×=×=×IƝҼ????????? # #eehIIL # #ssu # #WWZ=×=×=×=×=×=×=×=×=×ζz????????ʰnWWZ # #--0 # #WWZ # #ٽ=×=×=×=×=×=×=×=×V???????? # #ssu # # # #IƝ=×=×=×=×=×=×=×Uʤ????????ē--0 # # # # #IIL # #--0WWZ # #--0 # # #ssu # # # # # #WWZ # #ssu--0 # #eeh # # # #--0=×=×=×=×=×=×=×=×ʰo???????Ʃc;;> # # # # # # # #--0eeh # # #WWZ # # # # # #IIL # # # # # # # # # # # # # # # # # #IIL # #eeh # # #=×=×=×=×=×=×=×Uʤ????????WWZ # # #ssuIIL # #;;> # # # #WWZWWZ # # # #eehIIL # #--0--0--0 # # # # #;;>WWZ # # # # # # # #WWZmұ=×=×=×=×=×=×=×K???????--0IIL;;> # #ssu # #--0 # #WWZ # # # # # #--0 # #WWZ # #ssu # # # # #;;> # #IƝ=×=×=×=×=×=×=×ζ{??????? # #--0 #--0 # #WWZ # # # #eeh # # # # # #--0;;> # #--0 #--0 # #=×=×=×=×=×=×=×=×Ъ???????ssu # # # #--0 #--0WWZ # # # #--0 # # # # # #ssu # # # #--0 #--0=×=×Uʤyշ=×=×K?????ē # # #;;> # #ssu # #WWZ # # # # # # #WWZWWZWWZWWZWWZWWZWWZWWZWWZ # # # # # #;;> # #ssu # #=×ѥ͝ŷʰo???ēèRWWZ # # #WWZ # #WWZ # #WWZWWZ # # # # # # # # # # # # # # # #WWZ # # # # # # # #WWZ # #IILխ}]}]}]}]gik'o`bRWWZ # # # #;;>WWZ # #;;> # #WWZ # # # #WWZ # # # #ssu # #;;> # #ssussu # #WWZ # #;;> # #}]}]}]}]}]}]͝`b`b`b`b`b`b`boWWZ # # # # #ssu # #--0 # #ssuWWZ # #--0 # # # # # # # # #ssu # #--0--0 # # # #--0 # #ssu͝}]}]}]}]}]}]}]~`b`b`b`b`b`b`b--0 # # # #ssueeh # # # #--0IIL # # #--0--0 # #--0 # #--0 # # # # # #WWZWWZ # #IILWWZ # # #eeh # # # #--0͝}]}]}]}]}]}]}]}D`b`b`b`b`b`b`bè;;> # # #WWZ # # #IIL # # # # # # #IIL # # # # # # #--0 # # #IILeeh # # # # # # # # # # #--0 # # #WWZWWZ # # # # # # # # # #IIL # # #խ}]}]}]}]}]}]}]ѥ`b`b`b`b`b`b`b`b # #--0WWZ # #WWZ # # # # # #WWZWWZ # # # # #--0--0 # # # # # # # # # # # # #--0 # # # # #--0 # # # # # #WWZ # # #}]}]}]}]}]}]}]}]~`b`b`b`b`b`b`bik' # #ssuWWZWWZssuWWZWWZeehWWZeeh}]}]}]}]}]}]}]}]խik'`b`b`b`b`b`b`bo # #WWZ # #ɕ{}]}]}]}]}]}]}]}]a`b`b`b`b`b`b`b`bͶ # # #--0 # #}]}]}]}]}]}]}]}]ɕ{è`b`b`b`b`b`b`b`bsu5WWZ # # #IILWWZIIL # # #IILōq}]}]}]}]}]}]}]}]ѥik'`b`b`b`b`b`b`b`bWWZ # # # # # # #--0}]}]}]}]}]}]}]}]}]͝ik'`b`b`b`b`b`b`b`bik'eeh--0 #--0WWZɕ{}]}]}]}]}]}]}]}]}]ɕ{`b`b`b`b`b`b`b`b`b`bè}]}]}]}]}]}]}]}]}]}]}]խ}D`b`b`b`b`b`b`b`b`b`bRŷ}]}]}]}]}]}]}]}]}]}]}]}]ѥ~su5`b`b`b`b`b`b`b`b`b`b`bik'խ}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]ōqik'`b`b`b`b`b`b`b`b`b`b`b`b`bik'խ}]}]}]}]}]}]}]}]}]}]}]}]}]}]͝`b`b`b`b`b`b`b`b`b`b`b`b`b`bik'խ}]}]}]}]}]}]}]}]}]}]}]}]}]su5`b`b`b`b`b`b`b`b`b`b`b`b`bik'ŷ}]}]}]}]}]}]}]}]}]}]}]}]`b`b`b`b`b`b`b`b`b`b`b`b`b}Dɕ{}]}]}]}]}]}]}]}]}]}]`b`b`b`b`b`b`b`b`b`b`b`b~ōq}]}]}]}]}]}]}]}]ݽR`b`b`b`b`b`b`b`b`bR͝}]}]}]}]}]}]gik'`b`b`b`b`bik'oխɕ{}]}]}]ɕ{~RRͶsynergy-1.8.8-stable/res/doxygen.cfg.in000066400000000000000000002047471305627404700200620ustar00rootroot00000000000000# Doxyfile 1.7.1 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- # This tag specifies the encoding used for all characters in the config file # that follow. The default is UTF-8 which is also the encoding used for all # text before the first occurrence of this tag. Doxygen uses libiconv (or the # iconv built into libc) for the transcoding. See # http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "Synergy" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = "${VERSION}" # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = doc/doxygen # If the CREATE_SUBDIRS tag is set to YES, then doxygen will create # 4096 sub-directories (in 2 levels) under the output directory of each output # format and will distribute the generated files over these directories. # Enabling this option can be useful when feeding doxygen a huge amount of # source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, # Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, # Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English # messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, # Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, # Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # This tag implements a quasi-intelligent brief description abbreviator # that is used to form the text in various listings. Each string # in this list, if found as the leading text of the brief description, will be # stripped from the text and the result after processing the whole list, is # used as the annotated text. Otherwise, the brief description is used as-is. # If left blank, the following values are used ("$name" is automatically # replaced with the name of the entity): "The $name class" "The $name widget" # "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" ABBREVIATE_BRIEF = # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all # inherited members of a class in the documentation of that class as if those # members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user-defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. The tag can be used to show relative paths in the file list. # If left blank the directory from which doxygen is run is used as the # path to strip. STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells # the reader which header file to include in order to use a class. # If left blank only the name of the header file containing the class # definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter # (but less readable) file names. This can be useful is your file systems # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like regular Qt-style comments # (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = NO # If the QT_AUTOBRIEF tag is set to YES then Doxygen will # interpret the first line (until the first dot) of a Qt-style # comment as the brief description. If set to NO, the comments # will behave just like regular Qt-style comments (thus requiring # an explicit \brief command for a brief description.) QT_AUTOBRIEF = NO # The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen # treat a multi-line C++ special comment block (i.e. a block of //! or /// # comments) as a brief description. This used to be the default behaviour. # The new default is to treat a multi-line C++ comment block as a detailed # description. Set this tag to YES if you prefer the old behaviour instead. MULTILINE_CPP_IS_BRIEF = NO # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = YES # If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce # a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 4 # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C # sources only. Doxygen will then generate output that is more tailored for C. # For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = NO # Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java # sources only. Doxygen will then generate output that is more tailored for # Java. For instance, namespaces will be presented as packages, qualified # scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO # Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran # sources only. Doxygen will then generate output that is more tailored for # Fortran. OPTIMIZE_FOR_FORTRAN = NO # Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL # sources. Doxygen will then generate output that is tailored for # VHDL. OPTIMIZE_OUTPUT_VHDL = NO # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given extension. # Doxygen has a built-in mapping, but you can override or extend it using this # tag. The format is ext=language, where ext is a file extension, and language # is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, # C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make # doxygen treat .inc files as Fortran files (default is PHP), and .f files as C # (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions # you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. EXTENSION_MAPPING = # If you use STL classes (i.e. std::string, std::vector, etc.) but do not want # to include (a tag file for) the STL sources as input, then you should # set this tag to YES in order to let doxygen match functions declarations and # definitions whose arguments contain STL classes (e.g. func(std::string); v.s. # func(std::string) {}). This also make the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. # Doxygen will parse them like normal C++ but will assume all classes use public # instead of private inheritance when no explicit protection keyword is present. SIP_SUPPORT = NO # For Microsoft's IDL there are propget and propput attributes to indicate getter # and setter methods for a property. Setting this option to YES (the default) # will make doxygen to replace the get and set methods by a property in the # documentation. This will only work if the methods are indeed getting or # setting a simple type. If this is not the case, or you want to show the # methods anyway, you should set this option to NO. IDL_PROPERTY_SUPPORT = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # Set the SUBGROUPING tag to YES (the default) to allow class member groups of # the same type (for instance a group of public functions) to be put as a # subgroup of that type (e.g. under the Public Functions section). Set it to # NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES # When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum # is documented as struct, union, or enum with the name of the typedef. So # typedef struct TypeS {} TypeT, will appear in the documentation as a struct # with name TypeT. When disabled the typedef will appear as a member of a file, # namespace, or class. And the struct will be named TypeS. This can typically # be useful for C code in case the coding convention dictates that all compound # types are typedef'ed and only the typedef is referenced, never the tag name. TYPEDEF_HIDES_STRUCT = NO # The SYMBOL_CACHE_SIZE determines the size of the internal cache use to # determine which symbols to keep in memory and which to flush to disk. # When the cache is full, less often used symbols will be written to disk. # For small to medium size projects (<1000 input files) the default value is # probably good enough. For larger projects a too small cache size can cause # doxygen to be busy swapping symbols to and from disk most of the time # causing a significant performance penality. # If the system has enough physical memory increasing the cache will improve the # performance by keeping more symbols in memory. Note that the value works on # a logarithmic scale so increasing the size by one will rougly double the # memory usage. The cache size is given by this formula: # 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, # corresponding to a cache size of 2^16 = 65536 symbols #SYMBOL_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = NO # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO # If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) # defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES # This flag is only useful for Objective-C code. When set to YES local # methods, which are defined in the implementation section but not in # the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = NO # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called # 'anonymous_namespace{file}', where file will be replaced with the base # name of the file that contains the anonymous namespace. By default # anonymous namespace are hidden. EXTRACT_ANON_NSPACES = NO # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all # friend (class|struct|union) declarations. # If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO # If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any # documentation blocks found inside the body of a function. # If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower-case letters. If set to YES upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen # will list include files with double quotes in the documentation # rather than with sharp brackets. FORCE_LOCAL_INCLUDES = NO # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the # brief documentation of file, namespace and class members alphabetically # by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO # If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen # will sort the (brief and detailed) documentation of class members so that # constructors and destructors are listed first. If set to NO (the default) # the constructors will appear in the respective orders defined by # SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. # This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO # and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. SORT_MEMBERS_CTORS_1ST = NO # If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the # hierarchy of group names into alphabetical order. If set to NO (the default) # the group names will appear in their defined order. SORT_GROUP_NAMES = NO # If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be # sorted by fully-qualified names, including namespaces. If set to # NO (the default), the class list will be sorted only by class name, # not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. # Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # The GENERATE_BUGLIST tag can be used to enable (YES) or # disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. GENERATE_BUGLIST = YES # The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or # disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. GENERATE_DEPRECATEDLIST= YES # The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines # the initial value of a variable or define consists of for it to appear in # the documentation. If the initializer consists of more lines than specified # here it will be hidden. Use a value of 0 to hide initializers completely. # The appearance of the initializer of individual variables and defines in the # documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 # Set the SHOW_USED_FILES tag to NO to disable the list of files generated # at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = YES # If the sources in your project are distributed over multiple directories # then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy # in the documentation. The default is NO. #SHOW_DIRECTORIES = NO # Set the SHOW_FILES tag to NO to disable the generation of the Files page. # This will remove the Files entry from the Quick Index and from the # Folder Tree View (if specified). The default is YES. SHOW_FILES = YES # Set the SHOW_NAMESPACES tag to NO to disable the generation of the # Namespaces page. # This will remove the Namespaces entry from the Quick Index # and from the Folder Tree View (if specified). The default is YES. SHOW_NAMESPACES = YES # The FILE_VERSION_FILTER tag can be used to specify a program or script that # doxygen should invoke to get the current version for each file (typically from # the version control system). Doxygen will invoke the program by executing (via # popen()) the command , where is the value of # the FILE_VERSION_FILTER tag, and is the name of an input file # provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated # output files in an output format independent way. The create the layout file # that represents doxygen's defaults, run doxygen with the -l option. # You can optionally specify a file name after the option, if omitted # DoxygenLayout.xml will be used as the name of the layout file. LAYOUT_FILE = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO # If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for # potential errors in the documentation, such as not documenting some # parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be abled to get warnings for # functions that are documented, but have no documentation for their parameters # or return value. If set to NO (the default) doxygen will only warn about # wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. Optionally the format may contain # $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = . # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is # also the default input encoding. Doxygen uses libiconv (or the iconv built # into libc) for the transcoding. See http://www.gnu.org/software/libiconv for # the list of possible encodings. INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank the following patterns are tested: # *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx # *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 FILE_PATTERNS = *.cpp \ *.h # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used select whether or not files or # directories that are symbolic links (a Unix filesystem feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. Note that the wildcards are matched # against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* EXCLUDE_PATTERNS = */.svn/* \ */.git/* \ */ext/* \ */src/gui/* \ */src/test/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, # AClass::ANamespace, ANamespace::*Test EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude # commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. # If FILTER_PATTERNS is specified, this tag will be # ignored. INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. # Doxygen will compare the file name with each pattern and apply the # filter if there is a match. # The filters are a list of the form: # pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further # info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER # is applied to all files. FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. # Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES # then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES # then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will # link to the source code. # Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES # If the USE_HTAGS tag is set to YES then the references to source code # will point to the HTML generated by the htags(1) tool instead of doxygen # built-in source browser. The htags tool is part of GNU's global source # tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = YES # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 3 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet. Note that doxygen will try to copy # the style sheet file to the HTML output directory, so don't put your own # stylesheet in the HTML output directory as well, or it will be erased! HTML_STYLESHEET = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. # Doxygen will adjust the colors in the stylesheet and background images # according to this color. Hue is specified as an angle on a colorwheel, # see http://en.wikipedia.org/wiki/Hue for more information. # For instance the value 0 represents red, 60 is yellow, 120 is green, # 180 is cyan, 240 is blue, 300 purple, and 360 is red again. # The allowed range is 0 to 359. HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of # the colors in the HTML output. For a value of 0 the output will use # grayscales only. A value of 255 will produce the most vivid colors. HTML_COLORSTYLE_SAT = 100 # The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to # the luminance component of the colors in the HTML output. Values below # 100 gradually make the output lighter, whereas values above 100 make # the output darker. The value divided by 100 is the actual gamma applied, # so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, # and 100 does not change the gamma. HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting # this to NO can help when comparing the output of multiple runs. HTML_TIMESTAMP = YES # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. #HTML_ALIGN_MEMBERS = YES # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. For this to work a browser that supports # JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox # Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). HTML_DYNAMIC_SECTIONS = NO # If the GENERATE_DOCSET tag is set to YES, additional index files # will be generated that can be used as input for Apple's Xcode 3 # integrated development environment, introduced with OSX 10.5 (Leopard). # To create a documentation set, doxygen will generate a Makefile in the # HTML output directory. Running make will produce the docset in that # directory and running "make install" will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find # it at startup. # See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html # for more information. GENERATE_DOCSET = NO # When GENERATE_DOCSET tag is set to YES, this tag determines the name of the # feed. A documentation feed provides an umbrella under which multiple # documentation sets from a single provider (such as a company or product suite) # can be grouped. DOCSET_FEEDNAME = "Doxygen generated docs" # When GENERATE_DOCSET tag is set to YES, this tag specifies a string that # should uniquely identify the documentation set bundle. This should be a # reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen # will append .docset to the name. DOCSET_BUNDLE_ID = org.doxygen.Project # When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify # the documentation publisher. This should be a reverse domain-name style # string, e.g. com.mycompany.MyDocSet.documentation. DOCSET_PUBLISHER_ID = org.doxygen.Publisher # The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You # can add a path in front of the file if the result should not be # written to the html output directory. CHM_FILE = # If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can # be used to specify the location (absolute path including file name) of # the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. HHC_LOCATION = # If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag # controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO # If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING # is used to encode HtmlHelp index (hhk), content (hhc) and project file # content. CHM_INDEX_ENCODING = # If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag # controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO # The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated # that can be used as input for Qt's qhelpgenerator to generate a # Qt Compressed Help (.qch) of the generated HTML documentation. GENERATE_QHP = NO # If the QHG_LOCATION tag is specified, the QCH_FILE tag can # be used to specify the file name of the resulting .qch file. # The path specified is relative to the HTML output folder. QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#namespace QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating # Qt Help Project output. For more information please see # http://doc.trolltech.com/qthelpproject.html#virtual-folders QHP_VIRTUAL_FOLDER = doc # If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to # add. For more information please see # http://doc.trolltech.com/qthelpproject.html#custom-filters QHP_CUST_FILTER_NAME = # The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see # # Qt Help Project / Custom Filters. QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's # filter section matches. # # Qt Help Project / Filter Attributes. QHP_SECT_FILTER_ATTRS = # If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can # be used to specify the location of Qt's qhelpgenerator. # If non-empty doxygen will try to run qhelpgenerator on the generated # .qhp file. QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files # will be generated, which together with the HTML files, form an Eclipse help # plugin. To install this plugin and make it available under the help contents # menu in Eclipse, the contents of the directory containing the HTML and XML # files needs to be copied into the plugins directory of eclipse. The name of # the directory within the plugins directory should be the same as # the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before # the help appears. GENERATE_ECLIPSEHELP = NO # A unique identifier for the eclipse help plugin. When installing the plugin # the directory name containing the HTML and XML files should also have # this name. ECLIPSE_DOC_ID = org.doxygen.Project # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # The GENERATE_TREEVIEW tag is used to specify whether a tree-like index # structure should be generated to display hierarchical information. # If the tag value is set to YES, a side panel will be generated # containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). # Windows users are probably better off using the HTML help feature. GENERATE_TREEVIEW = NO # By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, # and Class Hierarchy pages using a tree view instead of an ordered list. #USE_INLINE_TREES = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 # When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open # links to external symbols imported via tag files in a separate window. EXT_LINKS_IN_WINDOW = NO # Use this tag to change the font size of Latex formulas included # as images in the HTML documentation. The default is 10. Note that # when you change the font size after a successful doxygen run you need # to manually remove any form_*.png images from the HTML output directory # to force them to be regenerated. FORMULA_FONTSIZE = 10 # Use the FORMULA_TRANPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are # not supported properly for IE 6.0, but are supported on all modern browsers. # Note that when changing this option you need to delete any form_*.png files # in the HTML output before the changes have effect. FORMULA_TRANSPARENT = YES # When the SEARCHENGINE tag is enabled doxygen will generate a search box # for the HTML output. The underlying search engine uses javascript # and DHTML and should work on any modern browser. Note that when using # HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets # (GENERATE_DOCSET) there is already a search function so this one should # typically be disabled. For large projects the javascript based search engine # can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. SEARCHENGINE = NO # When the SERVER_BASED_SEARCH tag is enabled the search engine will be # implemented using a PHP enabled web server instead of at the web client # using Javascript. Doxygen will generate the search PHP script and index # file to put on the web server. The advantage of the server # based approach is that it scales better to large projects and allows # full text search. The disadvances is that it is more difficult to setup # and does not have live searching capabilities. SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. # Note that when enabling USE_PDFLATEX this option is only used for # generating bitmaps for formulas in the HTML output, but not in the # Makefile that is written to the output directory. LATEX_CMD_NAME = latex # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to # generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO # If LATEX_HIDE_INDICES is set to YES then doxygen will not # include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO # If LATEX_SOURCE_CODE is set to YES then doxygen will include # source code with syntax highlighting in the LaTeX output. # Note that which sources are shown also depends on other settings # such as SOURCE_BROWSER. LATEX_SOURCE_CODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using WORD or other # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = # If the MAN_LINKS tag is set to YES and Doxygen generates man output, # then it will generate one additional man file for each entity # documented in the real man page(s). These additional files # only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO # The XML_OUTPUT tag is used to specify where the XML pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml # The XML_SCHEMA tag can be used to specify an XML schema, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_SCHEMA = # The XML_DTD tag can be used to specify an XML DTD, # which can be used by a validating XML parser to check the # syntax of the XML files. XML_DTD = # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will # generate an AutoGen Definitions (see autogen.sf.net) file # that captures the structure of the code including all # documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # configuration options related to the Perl module output #--------------------------------------------------------------------------- # If the GENERATE_PERLMOD tag is set to YES Doxygen will # generate a Perl module file that captures the structure of # the code including all documentation. Note that this # feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO # If the PERLMOD_LATEX tag is set to YES Doxygen will generate # the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO # If the PERLMOD_PRETTY tag is set to YES the Perl module output will be # nicely formatted so it can be parsed by a human reader. # This is useful # if you want to understand what is going on. # On the other hand, if this # tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES # The names of the make variables in the generated doxyrules.make file # are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. # This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = YES # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. To prevent a macro definition from being # undefined via #undef or recursively expanded use the := operator # instead of the = operator. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then # doxygen's preprocessor will remove all function-like macros that are alone # on a line, have an all uppercase name, and do not end with a semicolon. Such # function macros are typically used for boiler-plate code, and will confuse # the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration::additions related to external references #--------------------------------------------------------------------------- # The TAGFILES option can be used to specify one or more tagfiles. # Optionally an initial location of the external documentation # can be added for each tagfile. The format of a tag file without # this location is as follows: # # TAGFILES = file1 file2 ... # Adding location for the tag files is done as follows: # # TAGFILES = file1=loc1 "file2 = loc2" ... # where "loc1" and "loc2" can be relative or absolute paths or # URLs. If a location is present for each tag, the installdox tool # does not have to be run to correct the links. # Note that each tag file must have a unique name # (where the name does NOT include the path) # If a tag file is not located in the directory in which doxygen # is run, you must also specify the path to the tagfile here. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed # in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base # or super classes. Setting the tag to NO turns the diagrams off. Note that # this option is superseded by the HAVE_DOT option below. This is only a # fallback. It is recommended to install and use dot, since it yields more # powerful graphs. CLASS_DIAGRAMS = NO # You can define message sequence charts within doxygen comments using the \msc # command. Doxygen will then run the mscgen tool (see # http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the # documentation. The MSCGEN_PATH tag allows you to specify the directory where # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. MSCGEN_PATH = # If set to YES, the inheritance and collaboration graphs will hide # inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = @HAVE_DOT@ # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is # allowed to run in parallel. When set to 0 (the default) doxygen will # base this on the number of processors available in the system. You can set it # explicitly to a value larger than 0 to get control over the balance # between CPU load and processing speed. DOT_NUM_THREADS = 0 # By default doxygen will write a font called FreeSans.ttf to the output # directory and reference it in all dot files that doxygen generates. This # font does not include all possible unicode characters however, so when you need # these (or just want a differently looking font) you can specify the font name # using DOT_FONTNAME. You need need to make sure dot is able to find the font, # which can be done by putting it in a standard location or by setting the # DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory # containing the font. #DOT_FONTNAME = FreeSans.ttf # The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. # The default size is 10pt. DOT_FONTSIZE = 10 # By default doxygen will tell dot to use the output directory to look for the # FreeSans.ttf font (which doxygen will put there itself). If you specify a # different font using DOT_FONTNAME you can set the path where dot # can find it using this tag. DOT_FONTPATH = # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = YES # If the UML_LOOK tag is set to YES doxygen will generate inheritance and # collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = NO # If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT # tags are set to YES then doxygen will generate a graph for each documented # file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and # HAVE_DOT tags are set to YES then doxygen will generate a graph for each # documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = YES # If the CALL_GRAPH and HAVE_DOT options are set to YES then # doxygen will generate a call dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable call graphs # for selected functions only using the \callgraph command. CALL_GRAPH = NO # If the CALLER_GRAPH and HAVE_DOT tags are set to YES then # doxygen will generate a caller dependency graph for every global function # or class method. Note that enabling this option will significantly increase # the time of a run. So in most cases it will be better to enable caller # graphs for selected functions only using the \callergraph command. CALLER_GRAPH = NO # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES # then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. Possible values are png, jpg, or gif # If left blank png will be used. DOT_IMAGE_FORMAT = png # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the # \dotfile command). DOTFILE_DIRS = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of # nodes that will be shown in the graph. If the number of nodes in a graph # becomes larger than this value, doxygen will truncate the graph, which is # visualized by representing a node as a red box. Note that doxygen if the # number of direct children of the root node in a graph is already larger than # DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note # that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. DOT_GRAPH_MAX_NODES = 50 # The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the # graphs generated by dot. A depth value of 3 means that only nodes reachable # from the root by following a path via at most 3 edges will be shown. Nodes # that lay further from the root node will be omitted. Note that setting this # option to 1 or 2 may greatly reduce the computation time needed for large # code bases. Also note that the size of a graph can be further restricted by # DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. MAX_DOT_GRAPH_DEPTH = 0 # Set the DOT_TRANSPARENT tag to YES to generate images with a transparent # background. This is disabled by default, because dot on Windows does not # seem to support this out of the box. Warning: Depending on the platform used, # enabling this option may lead to badly anti-aliased labels on the edges of # a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO # Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES # If the DOT_CLEANUP tag is set to YES (the default) Doxygen will # remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES synergy-1.8.8-stable/res/openssl/000077500000000000000000000000001305627404700167645ustar00rootroot00000000000000synergy-1.8.8-stable/res/openssl/synergy.conf000066400000000000000000000031301305627404700213300ustar00rootroot00000000000000# # Synergy OpenSSL configuration file. # Used for generation of certificate requests. # dir = . [ca] default_ca = CA_default [CA_default] serial = $dir/serial database = $dir/certindex.txt new_certs_dir = $dir/certs certificate = $dir/cacert.pem private_key = $dir/private/cakey.pem default_days = 365 default_md = md5 preserve = no email_in_dn = no nameopt = default_ca certopt = default_ca policy = policy_match [policy_match] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional [req] default_bits = 1024 # Size of keys default_keyfile = key.pem # name of generated keys default_md = md5 # message digest algorithm string_mask = nombstr # permitted characters distinguished_name = req_distinguished_name req_extensions = v3_req [req_distinguished_name] 0.organizationName = Organization Name (company) organizationalUnitName = Organizational Unit Name (department, division) emailAddress = Email Address emailAddress_max = 40 localityName = Locality Name (city, district) stateOrProvinceName = State or Province Name (full name) countryName = Country Name (2 letter code) countryName_min = 2 countryName_max = 2 commonName = Common Name (hostname, IP, or your name) commonName_max = 64 0.organizationName_default = My Company localityName_default = My Town stateOrProvinceName_default = State or Providence countryName_default = US [v3_ca] basicConstraints = CA:TRUE subjectKeyIdentifier = hash authorityKeyIdentifier = keyid:always,issuer:always [v3_req] basicConstraints = CA:FALSE subjectKeyIdentifier = hash synergy-1.8.8-stable/res/synergy.desktop000066400000000000000000000002461305627404700203760ustar00rootroot00000000000000[Desktop Entry] Name=Synergy Comment=Share your keyboard and mouse over a network Exec=synergy Icon=/usr/share/icons/synergy.ico Type=Application Categories=Utility; synergy-1.8.8-stable/res/synergy.ico000066400000000000000000010622761305627404700175130ustar00rootroot00000000000000 ( V00 %~   &F V hV`( 2(OOOcyԀԀՃՃՀ~YE;2;2 2OրcY; 2Y׀щʾzzz|z~v{zsz}ry|rzzw{|x}{}~|~ЉycEEـwjxv_tqXqmId`JeaNgcUjgZmj_mk]ki]hfgromtqkrmgkfejalmdlnbmk`hgYgfXgeZki^sqg}{q{ÿ~;(2cѐ{stumnljjgii]hfZhfWliTmib}yotushomclj`ih^gf\fgcklhvwsӃEY~ܳ{outckjYa`FjdEvnU\]`ecjŶtѼȳ~qsm`b\]_Ycd`nok|}yΐc2(c˥otschgagfkqpu}|yqzǿľ|{|xstpjkgefbmnjz{w~O;Yy|zdolWni@ib5jaC}f~omlj^VMIIDBCPl۷զԙӋӇֆ؈ՐԗҠգ߭ٯԳĪzndrhangdokjxywſӃEyĻrnm][ZUXV\gdxxhffdZRIFFA?AMiձϠΓΆ΂ЀсΉˎɗ̑̚՚ڨخԳжɷxtsUVTZ][jqn}ΐщY Oΐ~Xoj8ZTFumcbgr|udRMB2144-)((,0/4E`{޷סҍ}mc]]`cgnt{~Յ؋ٕ޳ִĻ{upc\Yjefͥy2 EûszwZebczucuraWNK@0/33-)((,0/4E`{ݶ՟ь|lb[[^`cjvuqx~Ʌɍʕִ͢{xxstlllddd|{}Y;Y֐tywKmg?vm=xpnjTG:5/.)" #"(("""%*109Fb|ڵўψyk\UUWY]a_abbbcgnqԎםܬ߼ٺưe`Wlj`yupХnOԚxinl]b`nn_LA74,&! "!&& "(/-6C_yسН͆whXQRTW[_^bc``dinuxȂŋ’˨ԵDZ˽þea\ZXW|y{y(nVmiJnhhxrukXN>90(('&)*+/-022**('0216?Wm۽ԯ̙Ƅtg_Z[`bhid`^ZX[XV[]fstzփړ٩سسļ{vgge[}|׉O EϚ·ywwfqog~zyĽmgYP:4)%'(&''&(*.0/('&$ֿ+׿-վ+׻1ؽ:ڼRٿhշΩƓտ}ڽld[VW\_ܾeܾe]\^]YWVYYbcgnttǀͨ͝ϪϸljimlnY;͚_qpOplavĹ}zdD<73,)'&'++-,.-,&ڽ%ټ&ָ&ָظ׷յҳ$Ю%ѯ%ԯ&հ1ײDٷT޼|ڼٶٲ֦ϗŃҾqӻcӼYӺTѸPѸPӺTԹWַZնYԾUWZ\[\Z[\\\]^__^q{҆Ֆ٠ϭqtqi~}ڐ; ~glmpznZA962,)''%)(+)+׿*־)ս!ոӶ"Ҵ"ҴԴӳѱͮ!ͫ"ά Ϫ Ϫ)Ϫ;ЮKճsҷԶүЩ̜Čȼzʶi̴\̵RεOʹLʹLεOϴRѲUҳVϹPкQҼSӽT־TVWYYYZ[\]]]pw~Ɋ˒֪ڸ̵omluu{܉Y2րĿhvuTwsVetgV?5-('%$$$#'%ۼ(ۼ'ڹ&ٸ%ط#ֵճԲԬѪЩϨЧΥˣ!ȡ)ğ.Ġ-Ɵ2Ơ9ǢLʧ`ά}ͰδɰȫĜzj_TNIIHīKɭN˯PɴKʵL̶M͵QζRѸXֺ[ؼ]ۿ`a`_]^]]_`ems̀Փܧۯƥ{wlwtpِOԃwwwftswwVH<6.('$#"!ܽ!ٻ!׸$׸#ֵ!ԳұЯϭͫΦ̥ʣȡȟǞŝÜ&,ž.Ǡ7˥AϪVԱkٷػ׽ԻԷҪ˛ˆʹv˴iYOGCACF¦GîEįFDZHɱM˳O̳SдUдUԸYֺ[ռZZYZZZ]_`irvȓ̠ٸѹ|xmlpɰE(ΐ]xuXsvm\F.+($$+*&%ݿ#ܼ!ں ׵!Գ"ԯ$Ӯ%Ҭ"ϩΦˣʟɞ Ř&×'–&'–)Ę1›=OŢWȦ]έfӳpعؼϮǞÓι˳ymc]WSNHHIKèNŪPɫR˭TˮSͰUδVжXҹWԻYֿ[\YZUZbfhy~Бڦذswte}ǽO ;ԀgxuieO?0,'!!&ܾ%۽"ڼ غظյӱЯϪͨ˥ɣǟŝŚę$'–)Ę-Ȝ1̠<ͦJΩ[ѮbӱgطoܼxֵҩРʓŋԿӻyҹsϴjŪ`¤WHFCBDHåLƨOŨMǪOɯQ˱SʹRзUһWԽYSYWX]cfu|ąɕ֮ټüwum{{{E2ΐa|xZpyhNB51/+*(%ؿ*ֺ)չ$Զ"Ҵ!ұЯΩ ̨ ɢ!Ơ#ś#%%%%4:˜?śBȞEͣIѧRӬ`ԯpӳrյu׹y۽ٽԶϮͨƠĚؼӴ}ЮsǧfŢ^VNIHHGF§EƬHȮJȰLʲN͵QиT̼RXWVWVV[bq}ŇОٲÞuuuʥY ҃suun¹v\H=353('׿'$׾(Ը'ӷ!ѳϱέ̫ʥȤŞœ""#$7ę=śCɟF̢GϥJҨRӬ^ҭpӳrյtָwٻշέ˦ĞÙؿٽعض{׷vԱm˩c¢WNHD?@@B¨DªFëGƮJɱMɹOʺP˼NҾQUWY\_kzΧֱʵtttwwwO OՉJ}uIr;z_>1*''(ܿ'۾'ݻ$ڸ!ضִ$ժ&Ҩ"Ш#̥ ɢ şÚ!! $'+đ.ǔBŤKƦPȩUʫ[˩ZʨXʥSʤP̢OˡP̠VϣaѢiУpը׭ֳԴӬͥƙһҶѳzϱvΰu̴xи|ηϷѶβѱ̬ʬ{ŪqaTLC@ADFHŢLɤO˦QŮHȱK̴PϷSѹUԼXX[[[`go{Պۢȷt||nɰڀ(Yz|isȺnN@6%ֻ%ھ%ھ$ػ#׺!׵ճѯϭΣˡɡŞÜ!'+Ò/ȕ2˘AģG¢HKQPMG@=:@FIŨMȫPʭR̯TϴRѸRӽTԾUW\ӿ`Կdjw̔ݹѯt|А(Oevssk]LտA.ؼ!ո'۾"ع ַ Ӳ!Яά˩ʥȣŚØ &.1777-*&}#z yz{{}#1AĒHȗ]ɛ̚Ǘőxk[SEBA@;99~7ACJPSXƠ_Ơ_ş^œ[RI?=:=BDG¥JŨMȫP˰NʹNϹPѻRнTӿZҾ_Ӿcӿgսq̻Ȥӱη~}y~(nȽcxuYxǹvUH8׽,Ӹ)ܽ&ܽյӳԱ ү"ϩ#˦"ɢƟě™ $(**,+*yyzz|"&,/7>JVgpƨƬ˯ɬƪ{rf^ZUPOLH758>@ITÖYÖYėZXQF?;=@DGJKĢOǧNɪM̱OεOϹPѻRӾUW[]gv̍ԩʮzz~(щyzplLB9ؾ-Թ%ع"عֶԴүЭ̦ ȣŞ›"#$#$|%}%} x{$+0Ď8ǖ@ϞLѦX֬hٴvܹƽظЮˤǝվϴȭu¤i_[VP@;998=DFKPTRIA;:<@BFGJ¢IĥHȭKʱK˵LͷNιPҽTҿXӾ[ҿdӾsąØѵcϐ~fxc?ڿ/%׺"ع$ڻ׵ӱԮ կϧ!̥#ʟ$Ɯ"Ö|!|!{!{!{ }||z}'2?Q¡dƨuɱθοY( ((n̚Ѿǰ}re\QE=84;>CHKJGF>?@CEHIHĥJȪKɮL˲L˵KϹOҾQӿRӾQYi{̗մɼz( Yvy\>پ-ھ$ֹ!׸ ַҰҰҬȢȠƟę}|yzyxtxxz{$)5ś@ƢQϬhٸc22YyщӶťαȪ{oaRH@:989>DGGF;<<>@CCBB¤EŪHƭGDZG˵KϻNмOӾQѻRϺ_Ҿw˻ǦҼyԀ EZ{bcI;ٻ.ٹ#ٷ!׵ղӰҬϪ̤ʞƘ Ö{{yzxutuwy#}+19CVɨƾn(Yĺs_QGB:778?EG=<;:<8};?@9999:ػ0ݽ%Ҳ(ӳ'Ҳ!ѬϪ̦ɣƝÚ~}zytsvx{#2Mǡgӯ(O˥ٳïjWKB<667574369>@ADCDFĨIŬJǮL˵LͷN˸QʸYɻiʽ–ȯ¿Հ ؀rg{lCټ0ַ%״"Ա ү ά"ϩ#˦"ɠ"Ɲ#Ù# ~|zyxwuuy~%4AVpƮԀʼ~dTHA}:}:874358<>ACCCDGN§PǮNαNϳNѵPѹYϻf}ɓѪ~(2sŹd=Ӷ/նѮ%״ үɧ˥ ȣŜ™|{yxxwvvz~&;Pƣjβ2Oƽġ{_ME>}:~663248:;>@?@@BKLīK̯LβMϳNζV˷bȹtÍʣǯc(щup{cF׻9Ӷ.Ѳ(Ϯ&ҰͪʧȞŜ—~|zyxxwwwz%:Qrƪc~ϱƸs[PF>;43368:<>==<>IKĤK̪MӭMԮNӲQзUųZοvNjӪ½Ⱦ(Yʾyc?д7Ѵ&ɪ)ЯʨŢ˨Ɯ™}|{yxxwwwx0KǛfЬc2 ~޴n[NC=631457:<:98:DFFǥHΨHЪJϮM˲PųZĵlû™̳n EՀxhb9ܽ*ڵ%հ)Ϫ&̧%̥#ʣ!Ǟ!š%Í#~ x wts vxw$>V~ű;~_OC2~08{5}572446<=?BGKM©MƮJͰM̯LػXջaĂƗƯ2nvŷ[4׸'ײ#Ӯ'ͨ$ʥ#ʣ!ȡě#!} y wts v yz,J£kѵnsYI737{5}571235;==@DHJJĬHˮKˮKҵRδZҼz“ĭYϰwJܾ.ѱ&Ү"Ϊ$ˤ"ɢ!ȟŜ—}ytussy}#;`˸(ΐʾ{cG<9~5~9:89878:;=BEFG¦GũJʭKʭKȮTʹnпß˰OOzAӵ,ϯ"Ϊ˧"ɢ ǠŜ™{xtust{!,Gsеy2ĚëwRB=9:~97875478:>@BCD¦GȫIǪHƬRƭgȷ̼ϴ~փvXؿ0ϭ,Э#̥!ʣ!ǞŜę~|zywv!t"uty&Gwȯc щ˿xZGB:}8y;{=~;83568=?@DDEȨIȨIȫPêZŰl̻ɕĻɰ2쎟ʾtӿMʹ,˩*Ϋ ɢǠŜ™}{zyvu s st{!-T̩2ٽ˹iME;}8x:{=~;~72545;==AABťFƦGƩNTfƵ|ʼ˪cc³pѽRغ2ά$ʥ%˦#Ǟ!Ŝė~}zyutrrrvy%=eê(ƽkQ?9|6{9{9{86724:<>BCDDàFŦKM«[ưhκsϔӃ˼l͹Q׹2ά"ȣ!Ǣ"Ɲ ě•}|zyutrqt!y"~-IȡtҹyOȪy]F>~8{9z8y6~45139;=AABACĥJMì\`˷p‡(Eƶu׿Rָ/ѭ$ʥǝȞ Ö |z w s pqqsw1V̷EYħwSE:5}6}:<~:228;>@AA@AEINS̲^ӻoœŮՀ~ŵsսOӵ+ͩ!ǢƜƜ•~{z w s pqrux#9`Ǩ ܿͿ^L=8~7}:;~:227:<>??=?BFKPǭYζjƻɰ(Ͱtl̴^غ9Ѯ!ʣŞÚė{y zy t sssuy4_̼ېEг^E>7|3{8{85469;<>?@?BFGJɫRҳ^μ OY|nζZԶ3˨Ɵĝ™~zxyx s s rsu{&<ÛkͯcĖkLC:}4z7|954689:<=>>@DFHŧNˬWǵʾå؃Րu˳V׸CӰ*Ǣěě!• ~|ywywssrsz$>hê߉п³kSC7~467667899<;=@CDFŠKɣQêjȷȠ((|ҺUַ=ͪ&ÞÚ™|{xvywrsst}*DÜq̳cϐ¢w[F8~4~46~5~57887:9<>ACEHşMe±ƞOEfԸHӲ,ɤ$"˜~| zyu t wu#r$s tv'1bè߃ǽqR:/,}6|5~576669;=>@CFÛIĜJ]ïv¸~cbдBͬ(Š"!}{yxu s wu#r%t!u!y+6ęj˰cԀɹzX?2-|5{4}4666588:;=@DFGWnȸŻylʲ@ֲ4ʦ*Ü& }{yxvuurrq)x/3EǦû( OǹrT100}2}24778:;<<>>AACM̥aȲpŖ;̚rи<Ү1ǣ'$|zyxvvwttt-|4:MϮn (ƽ{[621~3~3576799;:=@BDƟUaμû~;~ijgе6ʤ,&$}|zxvuuuurvy,@PǠyؽyEμkF;74}4676~7~7898;:<>@C›Q\ȶƾ݀ OnȱPͭ,˟#–|{xwuuttvsw~,IsǪ;ʥwVC96}4~5~7~7~7~789:<;==?BFT¯rȽynȱLɩ)Ȝ!{zxvutttusx/M›wˮԀƿ~]H:6|3}4~7~7~7~7799;:<<>BBSkø( Ӄ|Z˯>ʥ'ŗ~{yxutssssrs{!5Uáɷ֐;ɷnS<7}2}2~5~5~5667689:;<>=OdĶú( ~Yʮ<ȣ$”}{xwutsstttu}%9ZȦμۃѿrU>8~3}2}4}4~5~5566789:;:8M`Ļ2(ɳJͬ:Ǡ'#}zzwwttsssstv~3BfĬE}`B6|144~3444434578:9?FUijzøƿY(ʴJͬ9Ɵ&"}zzwwttsssstv 4ChƮ2 ͚ûdD8}244~3443434578:9>ETwĽc;ʴMͪ4Ɯ!~{{xxwwvvvvx x*BT´҉ yƿnJ=675566567879<==DGVuųĻyEĿʴL̩2Ě!||zyyxxxxx{$|.FWæĶՀYijsMA997788789:9;=?>DHVrIJúڀE½ʳP̨8˜+'$$#! ~ ~{{{z{{{{$|-~:Wt»~;Ÿ|TH@?=>@?=>?@ACEFGHMWqIJ؃ E½˴RΪ;ś-*'&&$##""!~!~!!!!&~0>[£vüy2ƹYMFDBCECBCDEEFHIKKQZqų ;¾ͷVҮKȠQMKJJIHHGFFFDDDD9Wwc ۹skfefccedddddeffgjpڰŽ2ՃuHt{8ip-gn+jl*jl*jl*hj(ij(ij(ij(hi'hj(ik)hl*im+om,mk*ns.q{5}OqY(ؾl^\[[[ZYYZZZZZ[\\^hx沛Y~k@qu.jn'ei"cg fj#de!de!cd cd cd cd cg cg dh!dh!df eg!em&ht,wImȿ2l]ZYYYXWXXXXXYZZ[]eu屚Eyaz;mq*fj#ae`dbfabab`a`a`a`a_c`d`d`dacceck$gs+wIn(ĵ縝mZWUVVUUUUUUVVWXXW\mϩ2 cr|Q{4jn#dg`c^a`c^`^`________]_]_^a^a]`^a_hdo)uIo ~ȹ縝mZVSTUTTTTTUUVWWXWZkӭـsyNx|1hl!cf`c^a`c]_]_^^^^^^^^\^]_]`]`\_]`^gdo)vJr̚ cⷢr[WSSTTSSSTTUVWXXSVf~䰠(ΚmyGxz.ikefbc_b`c]_^`]_]_\^\^\_]`]`]``aab`h!gq.zOxӃE乤u]XSSTTSSSTUVWXXXTWf|糣;EivDuw+hjefcd_b`c]_^`]_]_\^\^\_\_]`]`_`abai"is0}R|y滪~`ZUTUUTTSTVWXYYYTVcxc~]v?rv*eicgae_cac]a]a\`\`[_[_\_\_]a]a]^`_ci"lu2UîO 转﬑a[UTUTTSSTUWXYYYUVbu;Xr;qu)eidhbf`dac]a^b]a]a\`\`]`]`]a]a^_bafl%qz7Zʵ( nŷ᭠f[VVTTTSSSTWXXXZ`c`s|㻞АnrAy0sr"nmffeecebd_c_c]`]`]`]`^_^_a_a_]a[dai-pxIo(OͿ沥h]WWTTTSSSTVXXXZ^daoz彠O(Κp?w}.sr"mlggffdfbd_c^b]`]`]`]`^_^_`^a_[_\eem1u}Nvщ (߼nbYWSSRQQQTVXXYZ]b`ku゙˫ۃ Yya7tz(pq!klhhggdfbd^b^b]`]`^a]`^_^_^_^_Y`^i jr6{Wĵc ӃõreZXSSRQRQTVWXY[^aajsֶ2؀uW{2qw%op klhhhhegbd^b]a]`]`^a^a_`^_]^]^[bbm$px<];Yⱡ{j^WQQQPRQSVWWY[^_`ioѰ݃; c}dCy'sxoqkkiihhegbd^b]a]`]`^a]`\_\_\_\_[ddo)r{Be͚ ;跧n`XQQQORQSUWWY[_^ajo{©ۺy 2_>u~#qvoqlliihhdfac]a]a]`]`]`]`\_\_\_]`^gfq+xHpy Հ¸wf]TPOMQSSUWWWY\]aglvEjH0x|swoqllgjfidfac]a^b]`]`\^\^Z^[_\`^b_j$gt6Uϸ2nɿzh^TPOMQSSUWWWY[^bflxټ߃2ʞb@~-w{txoqllhkfice`b]a^b]`]`\^[]Z^[_]a_ccn(ly;] 黣sfWQNNQSTVWWVX\\`ehoz˳ʥ;ՃsI3~(vwvwnr knhkehcfbc`a__\^^`[_[_\_Z]Z_af!`l0vRoy ~whYQNMQSTVVWVX\\`ehnyȰįӐ ciC/|&vwuvnr kngjdgcfab`a^^]_^`[_Z^[^Z]Z_ch#ht8~Z}γ;Eɸ浛棄q_SNMRSUWWUSU]^bfhiqžѲέ{nOxpoN5'}~ wxtsmp jmfidgbeab`a^^]_]_Z]Z]Y^X]\dfn(oyJoʥᄂuaTPORSUWWTSU\^bfgip|ŦƲ}¼OO҃yvwdC1}${|xytsmp jmfidgbeab`a__\^]_Z][^Z_Z_`h"mu/xS|ĩyԀƵ㰖~gWQPRSUWVTQS\_aedfks|α廨ǽ2~|ohD.)"{{vzrtlqjmfjdgcfbc`a__\^\^Z][^Y`Y`aj'py6fY븞暈kYQORSUVVSPS\^`ccfkq|Ũʷα~}ΐӃuwqzX;+(!{{vzrtkpileicfbeab`a__]_\^Z]\_Za[ben+x>sՀщıu_UQSTUVVSPR\^`cbfjmvz˵}̚EԀyyyV6+#}~{{vzqsjogjdhbead`a_`^^^_]^[^]`\c ah%ox5Kǽ(nλ|dWRSTUVVSPR\^`bafjmtttt˥2(yrrruN.)"{|{{uyprinficgad`c_`^_]]^_]^[^^a`g$gn+y?WnYijs`YVTUTRTUS[]_bdhilrw~Ƥήлzx˥c2ېtwnjdžcB8+%$$y{!uv oriqbn`l`f```] c[c]c^\] `fYbVd_m+drb҃Ȱ櫋xk^Z_\XUWY]]^]`bfkovz~ˆĎÓƙȠ̧ѭմʶsaXNe\YypmփyYE2 (EOn~ЉssydfgWUTa_WŞʓԉu]G:1*%+*&&$"}|!|z"vw!poikggdgbe_d`d]^`a`dX_Xa[f _h)gp=zYϸ(;qa\`a^ZZZ\\][]_bglsvz~ėƞɤձѰѵtkhWPM_XUtpovuqkjfTTZZZ`wyzϨčp_L;1*&#''$$"~zyzx tuonhjggcf_b^cbfcdbcbf[d_j$ir3yOräЉ2ǽ廤榇qdbgfea][XXYZ\_flsuz|ŠƎȔƑ˙ѡЧӰ˻znxkwjsg]j`Vnf_rpfzvq~{vswkkq`ciV`fSfnWsv`zzhwաޗxaO>80)(''(%%$$"yytusr!kmjjgjghdf`a``ccgi#ac`d]e_h%dm5u|Ow~nй{haefhfa]XWXYY\cioqvy~ōǓɔ˙ϟЧЭϳҺxpf\f^Wig]kgbmjeokjqmluqpyut|xwtrqusrstrrsqpqopqoptoquphlfek``dXY_NZ`MoubͻϽť{eP8/)#!&'&$"" !}~ xxrsqpkmiicfabaccdhh"kk%jl&acaeai"en+mv>`Ȱnζsjfhklib]XWWX]bioqruy~Ljʋ͍̌̒͛ѦϬбԸӻӿͽ˺Ǻɹ|xngk_]eZVcWW\ZZZXXWWWZZZ[\X\]Y`d^gmbwâĞȟ͢ЀpaWH72-0.//.) }{y| uwornoilfh`b]^cdnm)sq0sq0fi$adcg%fn/qy=[ҽ(ʥ£~tfhkoojd\WVW\`gnonqv{~ƒÄʊ͍̒ʘˠȥǨ̰ϷмӼ˿ǭ˭̫ɣÚs`PF6/2&*+-+&!xv{uxrtlojkbebdacdeop({z6yw6pn-`cadhl*nv7Mw˫OyТkfgoyxyzni^XX]__jnqux{}Çȋʑ͕ЗҘәҝҢ֥ת٭ٲڳڷ޻߾ݗ؈|qh[PF?A<620.,-/.****%$}*wz$qvpultiqenek`eeg%kl.st6{|<|}=or-_cMeZr$av8wZĸ; ~뽵{oimy{{{uri`ZZ[\gikosx|ćƍȐ˒ΔЖΙ͝ПѤҦҫӬӰ״طٻ״ԤЕʄsg]TJB;662.++*(*&(''$ wz$vy#tyqvjrfndmgmlq&qs1~ALFtu5eh#_c%k5wNxɫcӃèzrsuvvyyxsnkgedgimpsuv|~ĉȍ̐Β͔͘ϗϛМРҟңңҧիִټ߲ٙՅq\NA<5...*+)'&'(&'&&&%## ~!qw os!kohkghjj$qq+xv5>BJIu|9bi&[d!bk(dv;{ZzĪn2ťwqrvy{zyz{{rkffegimprxz~Ŋɍˏ˒̗ϗϛМϟўѢСХҨԲ׺ޱ֖ЀkTI<60*+,)*)'&&&#$" y|tukqjnhljmqr(||6?GNOIvz8cj'^e"fo,qz7sJpÝϐ n뫒wons|tqligkostvz}NJʌ͏ВғғԓԓՖ՚֟קٱܻ۫ԍrV?1+(&).30'&%%$##$#"$}$w|!sv kqgkhpot)xy5~BPXYYZN|JV]cddce^WElq4`f+fo7p{IdԶ2˥Ϋ~wzwtuwy~~ƃȅʇʋʎ˗΢ѭ׵ոѠɃhO;,&#$%*-)"!~z~z|"{+~1=LZddeghdejk[Ill0hm0kq6vG`ݲnO﷤|žžœĞȪʵйػո֪ϖ{gP>/*%&$$ "~)-.15>KU]lwxvxwvwxukc[~@jr,ci0kn=y|UsȰ( nǽ}˜ś šǣǡǡȡȡɠǞǛƚ­ȱϲ̯̠ƍr]G6)%"&'**.;AGQ[eou}}||~~}pW~@lt.ks-sy@UwɰӃ˷㳗꧆ĞŨħ¤ƫȭƫʮ˯ͯϱввѱаѰЯϭ̪˦ȣǞƝڙĪdzɵж̲ʪĜwj^USSVX\aezzZq};ht2hv6s~FdιY~ӷƩʭ̮ȪŪƫǬŪʮ˯̮ͯϱвѱҲմ׶ڸ۹ܷڵٰ׮د׮կԱԷּۻذѠ͓ɉ~~Ɂˁ̓чԊ͑˓ɑŒ}_mv=am+lx6}KdܽO(̚䮗਋婌ĦгѴ̯ȯɯɳ˴˴ʵ̷θѻӽԾԹպ׿ٿټضӱ̪˩ʨɧƧäâģĞÝÜƙĕx}VhrCirGr|QeӃ(Ӄй믒樊쮐ǪҵռջҼййϺϺѻҼԾտپپ۾ڸִҰЮϭϭ̭ȩƥƥƠǡȡţá¤áȡˢ•}hv~Ogo@hrC{Yuֶ~(ϐкƨжӺԾۻ۵زӭέ̭̲̲ɴƳƳ˫˫ɫȪƪũĨ¦ϱάˤśmQpyAp|@OtƶEnۺ˪찒©ѻ޾߹ܶ۵մҳѷҸι̹˸ϯͭ˭ΰѵԸԸӷѳĢsVs{FxIWaxӨȰ2cɶ⹣⮗ìͶֽռԺӹԵԵԵնϾ־ؼ۷Ǖn}VuQrSvYo̚n2nʥ̵¬̷ٿٿܽ޿Ϊ™nZ{SuN~ZsЧ;ϐݿἦḡ浟DzҾصЫzhby\z`tcE~ʥϸ빣︣ȸqh|]}^myѲ̚n;~±빥﹢«ɲѺ޺ѫÝwom~ik{ȱy(OӃǽйʳﻤヲ齥©ȮʰͲеպپڼҴɩ}rljmqtҴщO;Yʹôݼ们纬뺬ﻮôѼ̷î~̲ջ˥yE (;YnՀЉʥƽƽǽƽƽӾҽӽѻʹɰεռ҃̚yY;??????????????????????????????????????????(0` 6j䞣ধ®r4 *}څwgkȁ'1pjfͼ`VMfګَ֕Κǿ󶸸,ǚiiǹYA-(#(MшYYgo؁ӛöȔ6soĸY8%&()!%ֺ=ڼԳxTZ^YW`tӖû:Vl\8$"%ڼ$ַѭͥɢ+ƢEЬջͨʷsëPIƭI̴NպX[Y^xКP\nP*$$عҰ ʤę"–6ƜHͦiӳѫеyƨ_LHƫKʹRTVeА[ukƸD$ھ#عѭɡ):ėF›C9IÕˣk^åiɧsƨiQDDĪI͵QտT]̀ƸY0kôD"عԲ ʥ˜ * z'9^ʥӳǡ跛aM>@PSA?JɫMϹOҾV}2rBֶѬȝ{vvFßޫؖm& F}èɷo?8B>>DĦH̵KӼOǁLJvB"ԲΨ Ěxt{FZAΧi=55:CFɯK͹RƇɉ,]Խ(Գ̧Ù}xu#vϴvRǹ槅F34<=HͬKϷZ!ħp+ص"ɤ–vt'2Ž˫B}267?GȬGӻj˖"Vз˥Ù~xr~ҹ:̼ئ@z866?DƪRȺvy.ЬęxqwdȪM/{6|74=@Eʳdm¿UˮǞztq8هʆU}4~59=@ťLŴ2:̩{vry}Ϲ ĵ੄8}169>CŬn0\vð)ŝyus5۟ʒU~/68;=ãV`цZè{uswZŠ<@x5}479;F؏δHĢ~wsq}Ͷ<|1447Cai%\gN{|vw}ɇ͎өըL $! }, ۼΩ˜!.68oˢa_[KEɮLUu}5;پղƜxz. !define product "Synergy" !define productOld "Synergy+" !define packageName "synergy" !define packageNameOld "synergy-plus" !define platform "Windows" !define publisher "The Synergy Project" !define publisherOld "The Synergy+ Project" !define helpUrl "http://symless.com/support" !define vcRedistFile "vcredist_${arch}.exe" !define startMenuApp "synergy.exe" !define binDir "..\bin" !define uninstall "uninstall.exe" !define icon "..\res\synergy.ico" !define controlPanelReg "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" !addplugindir "..\res" !define MUI_ICON ${icon} !define MUI_UNICON ${icon} !include "MUI2.nsh" !include "DefineIfExist.nsh" !include "Library.nsh" !insertmacro MUI_PAGE_LICENSE "..\\res\\License.rtf" !insertmacro MUI_PAGE_DIRECTORY !insertmacro MUI_PAGE_INSTFILES !insertmacro MUI_UNPAGE_WELCOME !insertmacro MUI_UNPAGE_INSTFILES !insertmacro MUI_LANGUAGE "English" Name ${product} OutFile "..\bin\${packageName}-${version}-${platform}-${arch}.exe" InstallDir "${installDirVar}\${product}" InstallDirRegKey HKEY_LOCAL_MACHINE "SOFTWARE\${product}" "" ; delete files we installed, and then dir if it's empty !macro DeleteFiles dir Delete "${dir}\synergy.exe" Delete "${dir}\synergyc.exe" Delete "${dir}\synergys.exe" Delete "${dir}\synergyd.exe" Delete "${dir}\synergyd.log" Delete "${dir}\launcher.exe" Delete "${dir}\syntool.exe" Delete "${dir}\synrgyhk.dll" Delete "${dir}\synwinhk.dll" Delete "${dir}\synwinxt.dll" Delete "${dir}\libgcc_s_dw2-1.dll" Delete "${dir}\mingwm10.dll" Delete "${dir}\QtCore4.dll" Delete "${dir}\QtGui4.dll" Delete "${dir}\QtNetwork4.dll" Delete "${dir}\Uninstall.exe" Delete "${dir}\uninstall.exe" RMDir "${dir}" !macroend Function .onInit IfFileExists $WINDIR\SYSWOW64\*.* end is32bit is32bit: ${If} ${arch} == "x64" MessageBox MB_OK "It is not possible to use the 64-bit Synergy installer \ on a 32-bit system. Please download the 32-bit Synergy installer." Abort ${EndIf} end: FunctionEnd Section SetShellVarContext all SetOutPath "$INSTDIR" ; stops and removes all services (including legacy) ExecWait "$INSTDIR\synergyd.exe /uninstall" ; give the daemon a chance to close cleanly. Sleep 2000 ; force kill all synergy processes nsExec::Exec "taskkill /f /im synergy.exe" nsExec::Exec "taskkill /f /im qsynergy.exe" nsExec::Exec "taskkill /f /im launcher.exe" nsExec::Exec "taskkill /f /im synergys.exe" nsExec::Exec "taskkill /f /im synergyc.exe" nsExec::Exec "taskkill /f /im synergyd.exe" nsExec::Exec "taskkill /f /im syntool.exe" ; clean up legacy files that may exist (but leave user files) !insertmacro DeleteFiles "$PROGRAMFILES32\${product}\bin" !insertmacro DeleteFiles "$PROGRAMFILES64\${product}\bin" !insertmacro DeleteFiles "$PROGRAMFILES32\${productOld}\bin" !insertmacro DeleteFiles "$PROGRAMFILES64\${productOld}\bin" !insertmacro DeleteFiles "$PROGRAMFILES32\${product}" !insertmacro DeleteFiles "$PROGRAMFILES64\${product}" !insertmacro DeleteFiles "$PROGRAMFILES32\${productOld}" !insertmacro DeleteFiles "$PROGRAMFILES64\${productOld}" ; clean up legacy start menu entries RMDir /R "$SMPROGRAMS\${product}" RMDir /R "$SMPROGRAMS\${productOld}" ; always delete any existing uninstall info DeleteRegKey HKLM "${controlPanelReg}\${product}" DeleteRegKey HKLM "${controlPanelReg}\${productOld}" DeleteRegKey HKLM "${controlPanelReg}\${publisher}" DeleteRegKey HKLM "${controlPanelReg}\${publisherOld}" DeleteRegKey HKLM "${controlPanelReg}\${packageNameOld}" DeleteRegKey HKLM "SOFTWARE\${product}" DeleteRegKey HKLM "SOFTWARE\${productOld}" DeleteRegKey HKLM "SOFTWARE\${publisher}" DeleteRegKey HKLM "SOFTWARE\${publisherOld}" ; create uninstaller (used for control panel icon) WriteUninstaller "$INSTDIR\${uninstall}" ; add new uninstall info WriteRegStr HKLM "${controlPanelReg}\${product}" "" $INSTDIR WriteRegStr HKLM "${controlPanelReg}\${product}" "DisplayName" "${product}" WriteRegStr HKLM "${controlPanelReg}\${product}" "DisplayVersion" "${version}" WriteRegStr HKLM "${controlPanelReg}\${product}" "DisplayIcon" "$INSTDIR\uninstall.exe" WriteRegStr HKLM "${controlPanelReg}\${product}" "Publisher" "${publisher}" WriteRegStr HKLM "${controlPanelReg}\${product}" "UninstallString" "$INSTDIR\uninstall.exe" WriteRegStr HKLM "${controlPanelReg}\${product}" "URLInfoAbout" "${helpUrl}" SectionEnd Section "Visual C++ Redistributable" vcredist ; this must run first, as some sections run ; binaries that require a vcredist to be installed. ; copy redist file, run it, then delete when done File "${vcRedistDir}\${vcRedistFile}" ExecWait "$INSTDIR\${vcRedistFile} /install /q /norestart" Delete $INSTDIR\${vcRedistFile} SectionEnd Section "Server and Client" core ; client and server files File "${binDir}\Release\synergys.exe" File "${binDir}\Release\synergyc.exe" File "${binDir}\Release\synergyd.exe" File "${binDir}\Release\syntool.exe" ; if the hook file exists, skip, assuming it couldn't be deleted ; because it was in use by some process. ${If} ${FileExists} "synwinhk.dll" DetailPrint "Skipping synwinhk.dll, file already exists." ${Else} File "${binDir}\Release\synwinhk.dll" ${EndIf} ; if the shell ex file exists, skip, assuming it couldn't be deleted ; because it was in use by some process. ${If} ${FileExists} "synwinxt.dll" DetailPrint "Skipping synwinxt.dll, file already exists." ${Else} File "${binDir}\Release\synwinxt.dll" ${EndIf} ; windows firewall exception DetailPrint "Adding firewall exception" nsExec::ExecToStack "netsh firewall add allowedprogram $\"$INSTDIR\synergys.exe$\" Synergy ENABLE" ; install the windows shell extension ExecWait "regsvr32 /s $\"$INSTDIR\synwinxt.dll$\"" ; install and run the service ExecWait "$INSTDIR\synergyd.exe /install" SectionEnd Section "Graphical User Interface" gui ; gui and qt libs File "${binDir}\Release\synergy.exe" File "${qtDir}\qt\bin\libgcc_s_dw2-1.dll" File "${qtDir}\qt\bin\mingwm10.dll" File "${qtDir}\qt\bin\QtGui4.dll" File "${qtDir}\qt\bin\QtCore4.dll" File "${qtDir}\qt\bin\QtNetwork4.dll" ; gui start menu shortcut SetShellVarContext all CreateShortCut "$SMPROGRAMS\${product}.lnk" "$INSTDIR\${startMenuApp}" SectionEnd Section Uninstall SetShellVarContext all ; stop and uninstall the service ExecWait "$INSTDIR\synergyd.exe /uninstall" ; give the daemon a chance to close cleanly. Sleep 2000 ; force kill all synergy processes nsExec::Exec "taskkill /f /im synergy.exe" nsExec::Exec "taskkill /f /im qsynergy.exe" nsExec::Exec "taskkill /f /im launcher.exe" nsExec::Exec "taskkill /f /im synergys.exe" nsExec::Exec "taskkill /f /im synergyc.exe" nsExec::Exec "taskkill /f /im synergyd.exe" nsExec::Exec "taskkill /f /im syntool.exe" ; delete start menu shortcut Delete "$SMPROGRAMS\${product}.lnk" ; delete all registry keys DeleteRegKey HKLM "SOFTWARE\${product}" DeleteRegKey HKLM "${controlPanelReg}\${product}" ; uninstall the windows shell extension ExecWait "regsvr32 /s /u $\"$INSTDIR\synwinxt.dll$\"" ; note: edit macro to delete more files. !insertmacro DeleteFiles $INSTDIR Delete "$INSTDIR\${uninstall}" ; delete (only if empty, so we don't delete user files) RMDir "$INSTDIR" SectionEnd Function .onInstSuccess ; relies on !addplugindir ShellExecAsUser::ShellExecAsUser "" "$INSTDIR\synergy.exe" SW_SHOWNORMAL FunctionEnd synergy-1.8.8-stable/res/synergy.spec.in000066400000000000000000000024311305627404700202620ustar00rootroot00000000000000# -*- rpm-spec -*- Summary: Keyboard and mouse sharing utility Name: synergy Release: 1 License: GPLv2 Group: Applications/Productivity URL: http://symless.com/ Source: http://symless.com/download/ Vendor: The Synergy Project Packager: Nick Bolton Version: ${in:version} %description Synergy is free and open source software for sharing one mouse and keyboard between multiple computers. Works on Windows, Mac OS X, Linux. %prep source=%{_topdir}/../.. mkdir -p %{buildroot}/%{_datarootdir}/applications mkdir -p %{buildroot}/%{_datarootdir}/icons mkdir -p %{buildroot}/%{_bindir} cp $source/bin/synergy %{buildroot}%{_bindir} cp $source/bin/synergyc %{buildroot}%{_bindir} cp $source/bin/synergys %{buildroot}%{_bindir} cp $source/bin/synergyd %{buildroot}%{_bindir} cp $source/bin/syntool %{buildroot}%{_bindir} cp $source/res/synergy.desktop %{buildroot}%{_datarootdir}/applications cp $source/res/synergy.ico %{buildroot}%{_datarootdir}/icons %files %defattr(755,root,root,-) %{_bindir}/synergy %{_bindir}/synergyc %{_bindir}/synergys %{_bindir}/synergyd %{_bindir}/syntool %attr(644,-,-) %{_datarootdir}/applications/synergy.desktop %attr(644,-,-) %{_datarootdir}/icons/synergy.ico %changelog * Thu Mar 20 2014 Nick Bolton - Initial version of the package synergy-1.8.8-stable/src/000077500000000000000000000000001305627404700152775ustar00rootroot00000000000000synergy-1.8.8-stable/src/CMakeLists.txt000066400000000000000000000030661305627404700200440ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2011 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . if (WIN32) if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(OPENSSL_PLAT_DIR openssl-win64) else() set(OPENSSL_PLAT_DIR openssl-win32) endif() set(OPENSSL_INCLUDE ${CMAKE_SOURCE_DIR}/ext/${OPENSSL_PLAT_DIR}/inc32) endif() if (APPLE) set(OPENSSL_PLAT_DIR openssl-osx) set(OPENSSL_INCLUDE ${CMAKE_SOURCE_DIR}/ext/${OPENSSL_PLAT_DIR}/include) endif() if (WIN32) set(OPENSSL_LIBS ${CMAKE_SOURCE_DIR}/ext/${OPENSSL_PLAT_DIR}/out32dll/libeay32.lib ${CMAKE_SOURCE_DIR}/ext/${OPENSSL_PLAT_DIR}/out32dll/ssleay32.lib ) endif() if (UNIX) if (APPLE) set(OPENSSL_LIBS ${CMAKE_SOURCE_DIR}/ext/${OPENSSL_PLAT_DIR}/libssl.a ${CMAKE_SOURCE_DIR}/ext/${OPENSSL_PLAT_DIR}/libcrypto.a ) else() set(OPENSSL_LIBS ssl crypto) endif() endif() add_subdirectory(lib) add_subdirectory(cmd) add_subdirectory(micro) if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "IRIX") add_subdirectory(test) endif() synergy-1.8.8-stable/src/cmd/000077500000000000000000000000001305627404700160425ustar00rootroot00000000000000synergy-1.8.8-stable/src/cmd/CMakeLists.txt000066400000000000000000000015701305627404700206050ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2011 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . add_subdirectory(synergyc) add_subdirectory(synergys) add_subdirectory(synergyd) add_subdirectory(usynergy) add_subdirectory(syntool) if (WIN32) add_subdirectory(synergyp) endif() synergy-1.8.8-stable/src/cmd/synergyc/000077500000000000000000000000001305627404700177055ustar00rootroot00000000000000synergy-1.8.8-stable/src/cmd/synergyc/.gitignore000066400000000000000000000000071305627404700216720ustar00rootroot00000000000000/*.aps synergy-1.8.8-stable/src/cmd/synergyc/CMakeLists.txt000066400000000000000000000031231305627404700224440ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(sources synergyc.cpp ) if (WIN32) file(GLOB arch_headers "MSWindows*.h") file(GLOB arch_sources "MSWindows*.cpp") list(APPEND sources resource.h synergyc.ico synergyc.rc tb_error.ico tb_idle.ico tb_run.ico tb_wait.ico ) elseif (APPLE) file(GLOB arch_headers "OSX*.h") file(GLOB arch_sources "OSX*.cpp") elseif (UNIX) file(GLOB arch_headers "XWindows*.h") file(GLOB arch_sources "XWindows*.cpp") endif() list(APPEND sources ${arch_sources}) list(APPEND headers ${arch_headers}) if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ../../lib/ ) if (UNIX) include_directories( ../../.. ) endif() add_executable(synergyc ${sources}) target_link_libraries(synergyc arch base client common io mt net ipc platform server synergy ${libs} ${OPENSSL_LIBS}) if (CONF_CPACK) install(TARGETS synergyc COMPONENT core DESTINATION bin) endif() synergy-1.8.8-stable/src/cmd/synergyc/MSWindowsClientTaskBarReceiver.cpp000066400000000000000000000212541305627404700264030ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergyc/MSWindowsClientTaskBarReceiver.h" #include "resource.h" #include "client/Client.h" #include "platform/MSWindowsClipboard.h" #include "platform/MSWindowsScreen.h" #include "arch/win32/ArchTaskBarWindows.h" #include "arch/win32/ArchMiscWindows.h" #include "arch/Arch.h" #include "base/EventQueue.h" #include "base/log_outputters.h" #include "base/EventTypes.h" // // MSWindowsClientTaskBarReceiver // const UINT MSWindowsClientTaskBarReceiver::s_stateToIconID[kMaxState] = { IDI_TASKBAR_NOT_RUNNING, IDI_TASKBAR_NOT_WORKING, IDI_TASKBAR_NOT_CONNECTED, IDI_TASKBAR_NOT_CONNECTED, IDI_TASKBAR_CONNECTED }; MSWindowsClientTaskBarReceiver::MSWindowsClientTaskBarReceiver( HINSTANCE appInstance, const BufferedLogOutputter* logBuffer, IEventQueue* events) : ClientTaskBarReceiver(events), m_appInstance(appInstance), m_window(NULL), m_logBuffer(logBuffer) { for (UInt32 i = 0; i < kMaxState; ++i) { m_icon[i] = loadIcon(s_stateToIconID[i]); } m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR)); // don't create the window yet. we'll create it on demand. this // has the side benefit of being created in the thread used for // the task bar. that's good because it means the existence of // the window won't prevent changing the main thread's desktop. // add ourself to the task bar ARCH->addReceiver(this); } MSWindowsClientTaskBarReceiver::~MSWindowsClientTaskBarReceiver() { cleanup(); } void MSWindowsClientTaskBarReceiver::cleanup() { ARCH->removeReceiver(this); for (UInt32 i = 0; i < kMaxState; ++i) { deleteIcon(m_icon[i]); } DestroyMenu(m_menu); destroyWindow(); } void MSWindowsClientTaskBarReceiver::showStatus() { // create the window createWindow(); // lock self while getting status lock(); // get the current status std::string status = getToolTip(); // done getting status unlock(); // update dialog HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS); SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str()); if (!IsWindowVisible(m_window)) { // position it by the mouse POINT cursorPos; GetCursorPos(&cursorPos); RECT windowRect; GetWindowRect(m_window, &windowRect); int x = cursorPos.x; int y = cursorPos.y; int fw = GetSystemMetrics(SM_CXDLGFRAME); int fh = GetSystemMetrics(SM_CYDLGFRAME); int ww = windowRect.right - windowRect.left; int wh = windowRect.bottom - windowRect.top; int sw = GetSystemMetrics(SM_CXFULLSCREEN); int sh = GetSystemMetrics(SM_CYFULLSCREEN); if (fw < 1) { fw = 1; } if (fh < 1) { fh = 1; } if (x + ww - fw > sw) { x -= ww - fw; } else { x -= fw; } if (x < 0) { x = 0; } if (y + wh - fh > sh) { y -= wh - fh; } else { y -= fh; } if (y < 0) { y = 0; } SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh, SWP_SHOWWINDOW); } } void MSWindowsClientTaskBarReceiver::runMenu(int x, int y) { // do popup menu. we need a window to pass to TrackPopupMenu(). // the SetForegroundWindow() and SendMessage() calls around // TrackPopupMenu() are to get the menu to be dismissed when // another window gets activated and are just one of those // win32 weirdnesses. createWindow(); SetForegroundWindow(m_window); HMENU menu = GetSubMenu(m_menu, 0); SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE); HMENU logLevelMenu = GetSubMenu(menu, 3); CheckMenuRadioItem(logLevelMenu, 0, 6, CLOG->getFilter() - kERROR, MF_BYPOSITION); int n = TrackPopupMenu(menu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, 0, m_window, NULL); SendMessage(m_window, WM_NULL, 0, 0); // perform the requested operation switch (n) { case IDC_TASKBAR_STATUS: showStatus(); break; case IDC_TASKBAR_LOG: copyLog(); break; case IDC_TASKBAR_SHOW_LOG: ARCH->showConsole(true); break; case IDC_TASKBAR_LOG_LEVEL_ERROR: CLOG->setFilter(kERROR); break; case IDC_TASKBAR_LOG_LEVEL_WARNING: CLOG->setFilter(kWARNING); break; case IDC_TASKBAR_LOG_LEVEL_NOTE: CLOG->setFilter(kNOTE); break; case IDC_TASKBAR_LOG_LEVEL_INFO: CLOG->setFilter(kINFO); break; case IDC_TASKBAR_LOG_LEVEL_DEBUG: CLOG->setFilter(kDEBUG); break; case IDC_TASKBAR_LOG_LEVEL_DEBUG1: CLOG->setFilter(kDEBUG1); break; case IDC_TASKBAR_LOG_LEVEL_DEBUG2: CLOG->setFilter(kDEBUG2); break; case IDC_TASKBAR_QUIT: quit(); break; } } void MSWindowsClientTaskBarReceiver::primaryAction() { showStatus(); } const IArchTaskBarReceiver::Icon MSWindowsClientTaskBarReceiver::getIcon() const { return static_cast(m_icon[getStatus()]); } void MSWindowsClientTaskBarReceiver::copyLog() const { if (m_logBuffer != NULL) { // collect log buffer String data; for (BufferedLogOutputter::const_iterator index = m_logBuffer->begin(); index != m_logBuffer->end(); ++index) { data += *index; data += "\n"; } // copy log to clipboard if (!data.empty()) { MSWindowsClipboard clipboard(m_window); clipboard.open(0); clipboard.emptyUnowned(); clipboard.add(IClipboard::kText, data); clipboard.close(); } } } void MSWindowsClientTaskBarReceiver::onStatusChanged() { if (IsWindowVisible(m_window)) { showStatus(); } } HICON MSWindowsClientTaskBarReceiver::loadIcon(UINT id) { HANDLE icon = LoadImage(m_appInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); return static_cast(icon); } void MSWindowsClientTaskBarReceiver::deleteIcon(HICON icon) { if (icon != NULL) { DestroyIcon(icon); } } void MSWindowsClientTaskBarReceiver::createWindow() { // ignore if already created if (m_window != NULL) { return; } // get the status dialog m_window = CreateDialogParam(m_appInstance, MAKEINTRESOURCE(IDD_TASKBAR_STATUS), NULL, (DLGPROC)&MSWindowsClientTaskBarReceiver::staticDlgProc, reinterpret_cast( static_cast(this))); // window should appear on top of everything, including (especially) // the task bar. LONG_PTR style = GetWindowLongPtr(m_window, GWL_EXSTYLE); style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST; SetWindowLongPtr(m_window, GWL_EXSTYLE, style); // tell the task bar about this dialog ArchTaskBarWindows::addDialog(m_window); } void MSWindowsClientTaskBarReceiver::destroyWindow() { if (m_window != NULL) { ArchTaskBarWindows::removeDialog(m_window); DestroyWindow(m_window); m_window = NULL; } } BOOL MSWindowsClientTaskBarReceiver::dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM) { switch (msg) { case WM_INITDIALOG: // use default focus return TRUE; case WM_ACTIVATE: // hide when another window is activated if (LOWORD(wParam) == WA_INACTIVE) { ShowWindow(hwnd, SW_HIDE); } break; } return FALSE; } BOOL CALLBACK MSWindowsClientTaskBarReceiver::staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // if msg is WM_INITDIALOG, extract the MSWindowsClientTaskBarReceiver* // and put it in the extra window data then forward the call. MSWindowsClientTaskBarReceiver* self = NULL; if (msg == WM_INITDIALOG) { self = static_cast( reinterpret_cast(lParam)); SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR) lParam); } else { // get the extra window data and forward the call LONG_PTR data = GetWindowLongPtr(hwnd, GWLP_USERDATA); if (data != 0) { self = (MSWindowsClientTaskBarReceiver*) data; } } // forward the message if (self != NULL) { return self->dlgProc(hwnd, msg, wParam, lParam); } else { return (msg == WM_INITDIALOG) ? TRUE : FALSE; } } IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) { ArchMiscWindows::setIcons( (HICON)LoadImage(ArchMiscWindows::instanceWin32(), MAKEINTRESOURCE(IDI_SYNERGY), IMAGE_ICON, 32, 32, LR_SHARED), (HICON)LoadImage(ArchMiscWindows::instanceWin32(), MAKEINTRESOURCE(IDI_SYNERGY), IMAGE_ICON, 16, 16, LR_SHARED)); return new MSWindowsClientTaskBarReceiver( MSWindowsScreen::getWindowInstance(), logBuffer, events); } synergy-1.8.8-stable/src/cmd/synergyc/MSWindowsClientTaskBarReceiver.h000066400000000000000000000036351305627404700260530ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/ClientTaskBarReceiver.h" #define WIN32_LEAN_AND_MEAN #include class BufferedLogOutputter; class IEventQueue; //! Implementation of ClientTaskBarReceiver for Microsoft Windows class MSWindowsClientTaskBarReceiver : public ClientTaskBarReceiver { public: MSWindowsClientTaskBarReceiver(HINSTANCE, const BufferedLogOutputter*, IEventQueue* events); virtual ~MSWindowsClientTaskBarReceiver(); // IArchTaskBarReceiver overrides virtual void showStatus(); virtual void runMenu(int x, int y); virtual void primaryAction(); virtual const Icon getIcon() const; void cleanup(); protected: void copyLog() const; // ClientTaskBarReceiver overrides virtual void onStatusChanged(); private: HICON loadIcon(UINT); void deleteIcon(HICON); void createWindow(); void destroyWindow(); BOOL dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); static BOOL CALLBACK staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); private: HINSTANCE m_appInstance; HWND m_window; HMENU m_menu; HICON m_icon[kMaxState]; const BufferedLogOutputter* m_logBuffer; static const UINT s_stateToIconID[]; }; synergy-1.8.8-stable/src/cmd/synergyc/OSXClientTaskBarReceiver.cpp000066400000000000000000000031031305627404700251530ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergyc/OSXClientTaskBarReceiver.h" #include "arch/Arch.h" // // OSXClientTaskBarReceiver // OSXClientTaskBarReceiver::OSXClientTaskBarReceiver( const BufferedLogOutputter*, IEventQueue* events) : ClientTaskBarReceiver(events) { // add ourself to the task bar ARCH->addReceiver(this); } OSXClientTaskBarReceiver::~OSXClientTaskBarReceiver() { ARCH->removeReceiver(this); } void OSXClientTaskBarReceiver::showStatus() { // do nothing } void OSXClientTaskBarReceiver::runMenu(int, int) { // do nothing } void OSXClientTaskBarReceiver::primaryAction() { // do nothing } const IArchTaskBarReceiver::Icon OSXClientTaskBarReceiver::getIcon() const { return NULL; } IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) { return new OSXClientTaskBarReceiver(logBuffer, events); } synergy-1.8.8-stable/src/cmd/synergyc/OSXClientTaskBarReceiver.h000066400000000000000000000023451305627404700246270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/ClientTaskBarReceiver.h" class BufferedLogOutputter; class IEventQueue; //! Implementation of ClientTaskBarReceiver for OS X class OSXClientTaskBarReceiver : public ClientTaskBarReceiver { public: OSXClientTaskBarReceiver(const BufferedLogOutputter*, IEventQueue* events); virtual ~OSXClientTaskBarReceiver(); // IArchTaskBarReceiver overrides virtual void showStatus(); virtual void runMenu(int x, int y); virtual void primaryAction(); virtual const Icon getIcon() const; }; synergy-1.8.8-stable/src/cmd/synergyc/XWindowsClientTaskBarReceiver.cpp000066400000000000000000000031641305627404700262730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergyc/XWindowsClientTaskBarReceiver.h" #include "arch/Arch.h" // // CXWindowsClientTaskBarReceiver // CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver( const BufferedLogOutputter*, IEventQueue* events) : ClientTaskBarReceiver(events) { // add ourself to the task bar ARCH->addReceiver(this); } CXWindowsClientTaskBarReceiver::~CXWindowsClientTaskBarReceiver() { ARCH->removeReceiver(this); } void CXWindowsClientTaskBarReceiver::showStatus() { // do nothing } void CXWindowsClientTaskBarReceiver::runMenu(int, int) { // do nothing } void CXWindowsClientTaskBarReceiver::primaryAction() { // do nothing } const IArchTaskBarReceiver::Icon CXWindowsClientTaskBarReceiver::getIcon() const { return NULL; } IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) { return new CXWindowsClientTaskBarReceiver(logBuffer, events); } synergy-1.8.8-stable/src/cmd/synergyc/XWindowsClientTaskBarReceiver.h000066400000000000000000000023771305627404700257450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/ClientTaskBarReceiver.h" class BufferedLogOutputter; class IEventQueue; //! Implementation of ClientTaskBarReceiver for X Windows class CXWindowsClientTaskBarReceiver : public ClientTaskBarReceiver { public: CXWindowsClientTaskBarReceiver( const BufferedLogOutputter*, IEventQueue* events); virtual ~CXWindowsClientTaskBarReceiver(); // IArchTaskBarReceiver overrides virtual void showStatus(); virtual void runMenu(int x, int y); virtual void primaryAction(); virtual const Icon getIcon() const; }; synergy-1.8.8-stable/src/cmd/synergyc/resource.h000066400000000000000000000025461305627404700217140ustar00rootroot00000000000000//{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by synergyc.rc // #define IDS_FAILED 1 #define IDS_INIT_FAILED 2 #define IDS_UNCAUGHT_EXCEPTION 3 #define IDI_SYNERGY 101 #define IDI_TASKBAR_NOT_RUNNING 102 #define IDI_TASKBAR_NOT_WORKING 103 #define IDI_TASKBAR_NOT_CONNECTED 104 #define IDI_TASKBAR_CONNECTED 105 #define IDR_TASKBAR 107 #define IDD_TASKBAR_STATUS 108 #define IDC_TASKBAR_STATUS_STATUS 1000 #define IDC_TASKBAR_QUIT 40001 #define IDC_TASKBAR_STATUS 40002 #define IDC_TASKBAR_LOG 40003 #define IDC_TASKBAR_SHOW_LOG 40004 #define IDC_TASKBAR_LOG_LEVEL_ERROR 40009 #define IDC_TASKBAR_LOG_LEVEL_WARNING 40010 #define IDC_TASKBAR_LOG_LEVEL_NOTE 40011 #define IDC_TASKBAR_LOG_LEVEL_INFO 40012 #define IDC_TASKBAR_LOG_LEVEL_DEBUG 40013 #define IDC_TASKBAR_LOG_LEVEL_DEBUG1 40014 #define IDC_TASKBAR_LOG_LEVEL_DEBUG2 40015 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 109 #define _APS_NEXT_COMMAND_VALUE 40016 #define _APS_NEXT_CONTROL_VALUE 1001 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif synergy-1.8.8-stable/src/cmd/synergyc/synergyc.cpp000066400000000000000000000025711305627404700222610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ClientApp.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/EventQueue.h" #if WINAPI_MSWINDOWS #include "synergyc/MSWindowsClientTaskBarReceiver.h" #elif WINAPI_XWINDOWS #include "synergyc/XWindowsClientTaskBarReceiver.h" #elif WINAPI_CARBON #include "synergyc/OSXClientTaskBarReceiver.h" #else #error Platform not supported. #endif int main(int argc, char** argv) { #if SYSAPI_WIN32 // record window instance for tray icon, etc ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif Arch arch; arch.init(); Log log; EventQueue events; ClientApp app(&events, createTaskBarReceiver); return app.run(argc, argv); } synergy-1.8.8-stable/src/cmd/synergyc/synergyc.ico000066400000000000000000010622761305627404700222620ustar00rootroot00000000000000 ( V00 %~   &F V hV`( 2(OOOcyԀԀՃՃՀ~YE;2;2 2OրcY; 2Y׀щʾzzz|z~v{zsz}ry|rzzw{|x}{}~|~ЉycEEـwjxv_tqXqmId`JeaNgcUjgZmj_mk]ki]hfgromtqkrmgkfejalmdlnbmk`hgYgfXgeZki^sqg}{q{ÿ~;(2cѐ{stumnljjgii]hfZhfWliTmib}yotushomclj`ih^gf\fgcklhvwsӃEY~ܳ{outckjYa`FjdEvnU\]`ecjŶtѼȳ~qsm`b\]_Ycd`nok|}yΐc2(c˥otschgagfkqpu}|yqzǿľ|{|xstpjkgefbmnjz{w~O;Yy|zdolWni@ib5jaC}f~omlj^VMIIDBCPl۷զԙӋӇֆ؈ՐԗҠգ߭ٯԳĪzndrhangdokjxywſӃEyĻrnm][ZUXV\gdxxhffdZRIFFA?AMiձϠΓΆ΂ЀсΉˎɗ̑̚՚ڨخԳжɷxtsUVTZ][jqn}ΐщY Oΐ~Xoj8ZTFumcbgr|udRMB2144-)((,0/4E`{޷סҍ}mc]]`cgnt{~Յ؋ٕ޳ִĻ{upc\Yjefͥy2 EûszwZebczucuraWNK@0/33-)((,0/4E`{ݶ՟ь|lb[[^`cjvuqx~Ʌɍʕִ͢{xxstlllddd|{}Y;Y֐tywKmg?vm=xpnjTG:5/.)" #"(("""%*109Fb|ڵўψyk\UUWY]a_abbbcgnqԎםܬ߼ٺưe`Wlj`yupХnOԚxinl]b`nn_LA74,&! "!&& "(/-6C_yسН͆whXQRTW[_^bc``dinuxȂŋ’˨ԵDZ˽þea\ZXW|y{y(nVmiJnhhxrukXN>90(('&)*+/-022**('0216?Wm۽ԯ̙Ƅtg_Z[`bhid`^ZX[XV[]fstzփړ٩سسļ{vgge[}|׉O EϚ·ywwfqog~zyĽmgYP:4)%'(&''&(*.0/('&$ֿ+׿-վ+׻1ؽ:ڼRٿhշΩƓտ}ڽld[VW\_ܾeܾe]\^]YWVYYbcgnttǀͨ͝ϪϸljimlnY;͚_qpOplavĹ}zdD<73,)'&'++-,.-,&ڽ%ټ&ָ&ָظ׷յҳ$Ю%ѯ%ԯ&հ1ײDٷT޼|ڼٶٲ֦ϗŃҾqӻcӼYӺTѸPѸPӺTԹWַZնYԾUWZ\[\Z[\\\]^__^q{҆Ֆ٠ϭqtqi~}ڐ; ~glmpznZA962,)''%)(+)+׿*־)ս!ոӶ"Ҵ"ҴԴӳѱͮ!ͫ"ά Ϫ Ϫ)Ϫ;ЮKճsҷԶүЩ̜Čȼzʶi̴\̵RεOʹLʹLεOϴRѲUҳVϹPкQҼSӽT־TVWYYYZ[\]]]pw~Ɋ˒֪ڸ̵omluu{܉Y2րĿhvuTwsVetgV?5-('%$$$#'%ۼ(ۼ'ڹ&ٸ%ط#ֵճԲԬѪЩϨЧΥˣ!ȡ)ğ.Ġ-Ɵ2Ơ9ǢLʧ`ά}ͰδɰȫĜzj_TNIIHīKɭN˯PɴKʵL̶M͵QζRѸXֺ[ؼ]ۿ`a`_]^]]_`ems̀Փܧۯƥ{wlwtpِOԃwwwftswwVH<6.('$#"!ܽ!ٻ!׸$׸#ֵ!ԳұЯϭͫΦ̥ʣȡȟǞŝÜ&,ž.Ǡ7˥AϪVԱkٷػ׽ԻԷҪ˛ˆʹv˴iYOGCACF¦GîEįFDZHɱM˳O̳SдUдUԸYֺ[ռZZYZZZ]_`irvȓ̠ٸѹ|xmlpɰE(ΐ]xuXsvm\F.+($$+*&%ݿ#ܼ!ں ׵!Գ"ԯ$Ӯ%Ҭ"ϩΦˣʟɞ Ř&×'–&'–)Ę1›=OŢWȦ]έfӳpعؼϮǞÓι˳ymc]WSNHHIKèNŪPɫR˭TˮSͰUδVжXҹWԻYֿ[\YZUZbfhy~Бڦذswte}ǽO ;ԀgxuieO?0,'!!&ܾ%۽"ڼ غظյӱЯϪͨ˥ɣǟŝŚę$'–)Ę-Ȝ1̠<ͦJΩ[ѮbӱgطoܼxֵҩРʓŋԿӻyҹsϴjŪ`¤WHFCBDHåLƨOŨMǪOɯQ˱SʹRзUһWԽYSYWX]cfu|ąɕ֮ټüwum{{{E2ΐa|xZpyhNB51/+*(%ؿ*ֺ)չ$Զ"Ҵ!ұЯΩ ̨ ɢ!Ơ#ś#%%%%4:˜?śBȞEͣIѧRӬ`ԯpӳrյu׹y۽ٽԶϮͨƠĚؼӴ}ЮsǧfŢ^VNIHHGF§EƬHȮJȰLʲN͵QиT̼RXWVWVV[bq}ŇОٲÞuuuʥY ҃suun¹v\H=353('׿'$׾(Ը'ӷ!ѳϱέ̫ʥȤŞœ""#$7ę=śCɟF̢GϥJҨRӬ^ҭpӳrյtָwٻշέ˦ĞÙؿٽعض{׷vԱm˩c¢WNHD?@@B¨DªFëGƮJɱMɹOʺP˼NҾQUWY\_kzΧֱʵtttwwwO OՉJ}uIr;z_>1*''(ܿ'۾'ݻ$ڸ!ضִ$ժ&Ҩ"Ш#̥ ɢ şÚ!! $'+đ.ǔBŤKƦPȩUʫ[˩ZʨXʥSʤP̢OˡP̠VϣaѢiУpը׭ֳԴӬͥƙһҶѳzϱvΰu̴xи|ηϷѶβѱ̬ʬ{ŪqaTLC@ADFHŢLɤO˦QŮHȱK̴PϷSѹUԼXX[[[`go{Պۢȷt||nɰڀ(Yz|isȺnN@6%ֻ%ھ%ھ$ػ#׺!׵ճѯϭΣˡɡŞÜ!'+Ò/ȕ2˘AģG¢HKQPMG@=:@FIŨMȫPʭR̯TϴRѸRӽTԾUW\ӿ`Կdjw̔ݹѯt|А(Oevssk]LտA.ؼ!ո'۾"ع ַ Ӳ!Яά˩ʥȣŚØ &.1777-*&}#z yz{{}#1AĒHȗ]ɛ̚Ǘőxk[SEBA@;99~7ACJPSXƠ_Ơ_ş^œ[RI?=:=BDG¥JŨMȫP˰NʹNϹPѻRнTӿZҾ_Ӿcӿgսq̻Ȥӱη~}y~(nȽcxuYxǹvUH8׽,Ӹ)ܽ&ܽյӳԱ ү"ϩ#˦"ɢƟě™ $(**,+*yyzz|"&,/7>JVgpƨƬ˯ɬƪ{rf^ZUPOLH758>@ITÖYÖYėZXQF?;=@DGJKĢOǧNɪM̱OεOϹPѻRӾUW[]gv̍ԩʮzz~(щyzplLB9ؾ-Թ%ع"عֶԴүЭ̦ ȣŞ›"#$#$|%}%} x{$+0Ď8ǖ@ϞLѦX֬hٴvܹƽظЮˤǝվϴȭu¤i_[VP@;998=DFKPTRIA;:<@BFGJ¢IĥHȭKʱK˵LͷNιPҽTҿXӾ[ҿdӾsąØѵcϐ~fxc?ڿ/%׺"ع$ڻ׵ӱԮ կϧ!̥#ʟ$Ɯ"Ö|!|!{!{!{ }||z}'2?Q¡dƨuɱθοY( ((n̚Ѿǰ}re\QE=84;>CHKJGF>?@CEHIHĥJȪKɮL˲L˵KϹOҾQӿRӾQYi{̗մɼz( Yvy\>پ-ھ$ֹ!׸ ַҰҰҬȢȠƟę}|yzyxtxxz{$)5ś@ƢQϬhٸc22YyщӶťαȪ{oaRH@:989>DGGF;<<>@CCBB¤EŪHƭGDZG˵KϻNмOӾQѻRϺ_Ҿw˻ǦҼyԀ EZ{bcI;ٻ.ٹ#ٷ!׵ղӰҬϪ̤ʞƘ Ö{{yzxutuwy#}+19CVɨƾn(Yĺs_QGB:778?EG=<;:<8};?@9999:ػ0ݽ%Ҳ(ӳ'Ҳ!ѬϪ̦ɣƝÚ~}zytsvx{#2Mǡgӯ(O˥ٳïjWKB<667574369>@ADCDFĨIŬJǮL˵LͷN˸QʸYɻiʽ–ȯ¿Հ ؀rg{lCټ0ַ%״"Ա ү ά"ϩ#˦"ɠ"Ɲ#Ù# ~|zyxwuuy~%4AVpƮԀʼ~dTHA}:}:874358<>ACCCDGN§PǮNαNϳNѵPѹYϻf}ɓѪ~(2sŹd=Ӷ/նѮ%״ үɧ˥ ȣŜ™|{yxxwvvz~&;Pƣjβ2Oƽġ{_ME>}:~663248:;>@?@@BKLīK̯LβMϳNζV˷bȹtÍʣǯc(щup{cF׻9Ӷ.Ѳ(Ϯ&ҰͪʧȞŜ—~|zyxxwwwz%:Qrƪc~ϱƸs[PF>;43368:<>==<>IKĤK̪MӭMԮNӲQзUųZοvNjӪ½Ⱦ(Yʾyc?д7Ѵ&ɪ)ЯʨŢ˨Ɯ™}|{yxxwwwx0KǛfЬc2 ~޴n[NC=631457:<:98:DFFǥHΨHЪJϮM˲PųZĵlû™̳n EՀxhb9ܽ*ڵ%հ)Ϫ&̧%̥#ʣ!Ǟ!š%Í#~ x wts vxw$>V~ű;~_OC2~08{5}572446<=?BGKM©MƮJͰM̯LػXջaĂƗƯ2nvŷ[4׸'ײ#Ӯ'ͨ$ʥ#ʣ!ȡě#!} y wts v yz,J£kѵnsYI737{5}571235;==@DHJJĬHˮKˮKҵRδZҼz“ĭYϰwJܾ.ѱ&Ү"Ϊ$ˤ"ɢ!ȟŜ—}ytussy}#;`˸(ΐʾ{cG<9~5~9:89878:;=BEFG¦GũJʭKʭKȮTʹnпß˰OOzAӵ,ϯ"Ϊ˧"ɢ ǠŜ™{xtust{!,Gsеy2ĚëwRB=9:~97875478:>@BCD¦GȫIǪHƬRƭgȷ̼ϴ~փvXؿ0ϭ,Э#̥!ʣ!ǞŜę~|zywv!t"uty&Gwȯc щ˿xZGB:}8y;{=~;83568=?@DDEȨIȨIȫPêZŰl̻ɕĻɰ2쎟ʾtӿMʹ,˩*Ϋ ɢǠŜ™}{zyvu s st{!-T̩2ٽ˹iME;}8x:{=~;~72545;==AABťFƦGƩNTfƵ|ʼ˪cc³pѽRغ2ά$ʥ%˦#Ǟ!Ŝė~}zyutrrrvy%=eê(ƽkQ?9|6{9{9{86724:<>BCDDàFŦKM«[ưhκsϔӃ˼l͹Q׹2ά"ȣ!Ǣ"Ɲ ě•}|zyutrqt!y"~-IȡtҹyOȪy]F>~8{9z8y6~45139;=AABACĥJMì\`˷p‡(Eƶu׿Rָ/ѭ$ʥǝȞ Ö |z w s pqqsw1V̷EYħwSE:5}6}:<~:228;>@AA@AEINS̲^ӻoœŮՀ~ŵsսOӵ+ͩ!ǢƜƜ•~{z w s pqrux#9`Ǩ ܿͿ^L=8~7}:;~:227:<>??=?BFKPǭYζjƻɰ(Ͱtl̴^غ9Ѯ!ʣŞÚė{y zy t sssuy4_̼ېEг^E>7|3{8{85469;<>?@?BFGJɫRҳ^μ OY|nζZԶ3˨Ɵĝ™~zxyx s s rsu{&<ÛkͯcĖkLC:}4z7|954689:<=>>@DFHŧNˬWǵʾå؃Րu˳V׸CӰ*Ǣěě!• ~|ywywssrsz$>hê߉п³kSC7~467667899<;=@CDFŠKɣQêjȷȠ((|ҺUַ=ͪ&ÞÚ™|{xvywrsst}*DÜq̳cϐ¢w[F8~4~46~5~57887:9<>ACEHşMe±ƞOEfԸHӲ,ɤ$"˜~| zyu t wu#r$s tv'1bè߃ǽqR:/,}6|5~576669;=>@CFÛIĜJ]ïv¸~cbдBͬ(Š"!}{yxu s wu#r%t!u!y+6ęj˰cԀɹzX?2-|5{4}4666588:;=@DFGWnȸŻylʲ@ֲ4ʦ*Ü& }{yxvuurrq)x/3EǦû( OǹrT100}2}24778:;<<>>AACM̥aȲpŖ;̚rи<Ү1ǣ'$|zyxvvwttt-|4:MϮn (ƽ{[621~3~3576799;:=@BDƟUaμû~;~ijgе6ʤ,&$}|zxvuuuurvy,@PǠyؽyEμkF;74}4676~7~7898;:<>@C›Q\ȶƾ݀ OnȱPͭ,˟#–|{xwuuttvsw~,IsǪ;ʥwVC96}4~5~7~7~7~789:<;==?BFT¯rȽynȱLɩ)Ȝ!{zxvutttusx/M›wˮԀƿ~]H:6|3}4~7~7~7~7799;:<<>BBSkø( Ӄ|Z˯>ʥ'ŗ~{yxutssssrs{!5Uáɷ֐;ɷnS<7}2}2~5~5~5667689:;<>=OdĶú( ~Yʮ<ȣ$”}{xwutsstttu}%9ZȦμۃѿrU>8~3}2}4}4~5~5566789:;:8M`Ļ2(ɳJͬ:Ǡ'#}zzwwttsssstv~3BfĬE}`B6|144~3444434578:9?FUijzøƿY(ʴJͬ9Ɵ&"}zzwwttsssstv 4ChƮ2 ͚ûdD8}244~3443434578:9>ETwĽc;ʴMͪ4Ɯ!~{{xxwwvvvvx x*BT´҉ yƿnJ=675566567879<==DGVuųĻyEĿʴL̩2Ě!||zyyxxxxx{$|.FWæĶՀYijsMA997788789:9;=?>DHVrIJúڀE½ʳP̨8˜+'$$#! ~ ~{{{z{{{{$|-~:Wt»~;Ÿ|TH@?=>@?=>?@ACEFGHMWqIJ؃ E½˴RΪ;ś-*'&&$##""!~!~!!!!&~0>[£vüy2ƹYMFDBCECBCDEEFHIKKQZqų ;¾ͷVҮKȠQMKJJIHHGFFFDDDD9Wwc ۹skfefccedddddeffgjpڰŽ2ՃuHt{8ip-gn+jl*jl*jl*hj(ij(ij(ij(hi'hj(ik)hl*im+om,mk*ns.q{5}OqY(ؾl^\[[[ZYYZZZZZ[\\^hx沛Y~k@qu.jn'ei"cg fj#de!de!cd cd cd cd cg cg dh!dh!df eg!em&ht,wImȿ2l]ZYYYXWXXXXXYZZ[]eu屚Eyaz;mq*fj#ae`dbfabab`a`a`a`a_c`d`d`dacceck$gs+wIn(ĵ縝mZWUVVUUUUUUVVWXXW\mϩ2 cr|Q{4jn#dg`c^a`c^`^`________]_]_^a^a]`^a_hdo)uIo ~ȹ縝mZVSTUTTTTTUUVWWXWZkӭـsyNx|1hl!cf`c^a`c]_]_^^^^^^^^\^]_]`]`\_]`^gdo)vJr̚ cⷢr[WSSTTSSSTTUVWXXSVf~䰠(ΚmyGxz.ikefbc_b`c]_^`]_]_\^\^\_]`]`]``aab`h!gq.zOxӃE乤u]XSSTTSSSTUVWXXXTWf|糣;EivDuw+hjefcd_b`c]_^`]_]_\^\^\_\_]`]`_`abai"is0}R|y滪~`ZUTUUTTSTVWXYYYTVcxc~]v?rv*eicgae_cac]a]a\`\`[_[_\_\_]a]a]^`_ci"lu2UîO 转﬑a[UTUTTSSTUWXYYYUVbu;Xr;qu)eidhbf`dac]a^b]a]a\`\`]`]`]a]a^_bafl%qz7Zʵ( nŷ᭠f[VVTTTSSSTWXXXZ`c`s|㻞АnrAy0sr"nmffeecebd_c_c]`]`]`]`^_^_a_a_]a[dai-pxIo(OͿ沥h]WWTTTSSSTVXXXZ^daoz彠O(Κp?w}.sr"mlggffdfbd_c^b]`]`]`]`^_^_`^a_[_\eem1u}Nvщ (߼nbYWSSRQQQTVXXYZ]b`ku゙˫ۃ Yya7tz(pq!klhhggdfbd^b^b]`]`^a]`^_^_^_^_Y`^i jr6{Wĵc ӃõreZXSSRQRQTVWXY[^aajsֶ2؀uW{2qw%op klhhhhegbd^b]a]`]`^a^a_`^_]^]^[bbm$px<];Yⱡ{j^WQQQPRQSVWWY[^_`ioѰ݃; c}dCy'sxoqkkiihhegbd^b]a]`]`^a]`\_\_\_\_[ddo)r{Be͚ ;跧n`XQQQORQSUWWY[_^ajo{©ۺy 2_>u~#qvoqlliihhdfac]a]a]`]`]`]`\_\_\_]`^gfq+xHpy Հ¸wf]TPOMQSSUWWWY\]aglvEjH0x|swoqllgjfidfac]a^b]`]`\^\^Z^[_\`^b_j$gt6Uϸ2nɿzh^TPOMQSSUWWWY[^bflxټ߃2ʞb@~-w{txoqllhkfice`b]a^b]`]`\^[]Z^[_]a_ccn(ly;] 黣sfWQNNQSTVWWVX\\`ehoz˳ʥ;ՃsI3~(vwvwnr knhkehcfbc`a__\^^`[_[_\_Z]Z_af!`l0vRoy ~whYQNMQSTVVWVX\\`ehnyȰįӐ ciC/|&vwuvnr kngjdgcfab`a^^]_^`[_Z^[^Z]Z_ch#ht8~Z}γ;Eɸ浛棄q_SNMRSUWWUSU]^bfhiqžѲέ{nOxpoN5'}~ wxtsmp jmfidgbeab`a^^]_]_Z]Z]Y^X]\dfn(oyJoʥᄂuaTPORSUWWTSU\^bfgip|ŦƲ}¼OO҃yvwdC1}${|xytsmp jmfidgbeab`a__\^]_Z][^Z_Z_`h"mu/xS|ĩyԀƵ㰖~gWQPRSUWVTQS\_aedfks|α廨ǽ2~|ohD.)"{{vzrtlqjmfjdgcfbc`a__\^\^Z][^Y`Y`aj'py6fY븞暈kYQORSUVVSPS\^`ccfkq|Ũʷα~}ΐӃuwqzX;+(!{{vzrtkpileicfbeab`a__]_\^Z]\_Za[ben+x>sՀщıu_UQSTUVVSPR\^`cbfjmvz˵}̚EԀyyyV6+#}~{{vzqsjogjdhbead`a_`^^^_]^[^]`\c ah%ox5Kǽ(nλ|dWRSTUVVSPR\^`bafjmtttt˥2(yrrruN.)"{|{{uyprinficgad`c_`^_]]^_]^[^^a`g$gn+y?WnYijs`YVTUTRTUS[]_bdhilrw~Ƥήлzx˥c2ېtwnjdžcB8+%$$y{!uv oriqbn`l`f```] c[c]c^\] `fYbVd_m+drb҃Ȱ櫋xk^Z_\XUWY]]^]`bfkovz~ˆĎÓƙȠ̧ѭմʶsaXNe\YypmփyYE2 (EOn~ЉssydfgWUTa_WŞʓԉu]G:1*%+*&&$"}|!|z"vw!poikggdgbe_d`d]^`a`dX_Xa[f _h)gp=zYϸ(;qa\`a^ZZZ\\][]_bglsvz~ėƞɤձѰѵtkhWPM_XUtpovuqkjfTTZZZ`wyzϨčp_L;1*&#''$$"~zyzx tuonhjggcf_b^cbfcdbcbf[d_j$ir3yOräЉ2ǽ廤榇qdbgfea][XXYZ\_flsuz|ŠƎȔƑ˙ѡЧӰ˻znxkwjsg]j`Vnf_rpfzvq~{vswkkq`ciV`fSfnWsv`zzhwաޗxaO>80)(''(%%$$"yytusr!kmjjgjghdf`a``ccgi#ac`d]e_h%dm5u|Ow~nй{haefhfa]XWXYY\cioqvy~ōǓɔ˙ϟЧЭϳҺxpf\f^Wig]kgbmjeokjqmluqpyut|xwtrqusrstrrsqpqopqoptoquphlfek``dXY_NZ`MoubͻϽť{eP8/)#!&'&$"" !}~ xxrsqpkmiicfabaccdhh"kk%jl&acaeai"en+mv>`Ȱnζsjfhklib]XWWX]bioqruy~Ljʋ͍̌̒͛ѦϬбԸӻӿͽ˺Ǻɹ|xngk_]eZVcWW\ZZZXXWWWZZZ[\X\]Y`d^gmbwâĞȟ͢ЀpaWH72-0.//.) }{y| uwornoilfh`b]^cdnm)sq0sq0fi$adcg%fn/qy=[ҽ(ʥ£~tfhkoojd\WVW\`gnonqv{~ƒÄʊ͍̒ʘˠȥǨ̰ϷмӼ˿ǭ˭̫ɣÚs`PF6/2&*+-+&!xv{uxrtlojkbebdacdeop({z6yw6pn-`cadhl*nv7Mw˫OyТkfgoyxyzni^XX]__jnqux{}Çȋʑ͕ЗҘәҝҢ֥ת٭ٲڳڷ޻߾ݗ؈|qh[PF?A<620.,-/.****%$}*wz$qvpultiqenek`eeg%kl.st6{|<|}=or-_cMeZr$av8wZĸ; ~뽵{oimy{{{uri`ZZ[\gikosx|ćƍȐ˒ΔЖΙ͝ПѤҦҫӬӰ״طٻ״ԤЕʄsg]TJB;662.++*(*&(''$ wz$vy#tyqvjrfndmgmlq&qs1~ALFtu5eh#_c%k5wNxɫcӃèzrsuvvyyxsnkgedgimpsuv|~ĉȍ̐Β͔͘ϗϛМРҟңңҧիִټ߲ٙՅq\NA<5...*+)'&'(&'&&&%## ~!qw os!kohkghjj$qq+xv5>BJIu|9bi&[d!bk(dv;{ZzĪn2ťwqrvy{zyz{{rkffegimprxz~Ŋɍˏ˒̗ϗϛМϟўѢСХҨԲ׺ޱ֖ЀkTI<60*+,)*)'&&&#$" y|tukqjnhljmqr(||6?GNOIvz8cj'^e"fo,qz7sJpÝϐ n뫒wons|tqligkostvz}NJʌ͏ВғғԓԓՖ՚֟קٱܻ۫ԍrV?1+(&).30'&%%$##$#"$}$w|!sv kqgkhpot)xy5~BPXYYZN|JV]cddce^WElq4`f+fo7p{IdԶ2˥Ϋ~wzwtuwy~~ƃȅʇʋʎ˗΢ѭ׵ոѠɃhO;,&#$%*-)"!~z~z|"{+~1=LZddeghdejk[Ill0hm0kq6vG`ݲnO﷤|žžœĞȪʵйػո֪ϖ{gP>/*%&$$ "~)-.15>KU]lwxvxwvwxukc[~@jr,ci0kn=y|UsȰ( nǽ}˜ś šǣǡǡȡȡɠǞǛƚ­ȱϲ̯̠ƍr]G6)%"&'**.;AGQ[eou}}||~~}pW~@lt.ks-sy@UwɰӃ˷㳗꧆ĞŨħ¤ƫȭƫʮ˯ͯϱввѱаѰЯϭ̪˦ȣǞƝڙĪdzɵж̲ʪĜwj^USSVX\aezzZq};ht2hv6s~FdιY~ӷƩʭ̮ȪŪƫǬŪʮ˯̮ͯϱвѱҲմ׶ڸ۹ܷڵٰ׮د׮կԱԷּۻذѠ͓ɉ~~Ɂˁ̓чԊ͑˓ɑŒ}_mv=am+lx6}KdܽO(̚䮗਋婌ĦгѴ̯ȯɯɳ˴˴ʵ̷θѻӽԾԹպ׿ٿټضӱ̪˩ʨɧƧäâģĞÝÜƙĕx}VhrCirGr|QeӃ(Ӄй믒樊쮐ǪҵռջҼййϺϺѻҼԾտپپ۾ڸִҰЮϭϭ̭ȩƥƥƠǡȡţá¤áȡˢ•}hv~Ogo@hrC{Yuֶ~(ϐкƨжӺԾۻ۵زӭέ̭̲̲ɴƳƳ˫˫ɫȪƪũĨ¦ϱάˤśmQpyAp|@OtƶEnۺ˪찒©ѻ޾߹ܶ۵մҳѷҸι̹˸ϯͭ˭ΰѵԸԸӷѳĢsVs{FxIWaxӨȰ2cɶ⹣⮗ìͶֽռԺӹԵԵԵնϾ־ؼ۷Ǖn}VuQrSvYo̚n2nʥ̵¬̷ٿٿܽ޿Ϊ™nZ{SuN~ZsЧ;ϐݿἦḡ浟DzҾصЫzhby\z`tcE~ʥϸ빣︣ȸqh|]}^myѲ̚n;~±빥﹢«ɲѺ޺ѫÝwom~ik{ȱy(OӃǽйʳﻤヲ齥©ȮʰͲеպپڼҴɩ}rljmqtҴщO;Yʹôݼ们纬뺬ﻮôѼ̷î~̲ջ˥yE (;YnՀЉʥƽƽǽƽƽӾҽӽѻʹɰεռ҃̚yY;??????????????????????????????????????????(0` 6j䞣ধ®r4 *}څwgkȁ'1pjfͼ`VMfګَ֕Κǿ󶸸,ǚiiǹYA-(#(MшYYgo؁ӛöȔ6soĸY8%&()!%ֺ=ڼԳxTZ^YW`tӖû:Vl\8$"%ڼ$ַѭͥɢ+ƢEЬջͨʷsëPIƭI̴NպX[Y^xКP\nP*$$عҰ ʤę"–6ƜHͦiӳѫеyƨ_LHƫKʹRTVeА[ukƸD$ھ#عѭɡ):ėF›C9IÕˣk^åiɧsƨiQDDĪI͵QտT]̀ƸY0kôD"عԲ ʥ˜ * z'9^ʥӳǡ跛aM>@PSA?JɫMϹOҾV}2rBֶѬȝ{vvFßޫؖm& F}èɷo?8B>>DĦH̵KӼOǁLJvB"ԲΨ Ěxt{FZAΧi=55:CFɯK͹RƇɉ,]Խ(Գ̧Ù}xu#vϴvRǹ槅F34<=HͬKϷZ!ħp+ص"ɤ–vt'2Ž˫B}267?GȬGӻj˖"Vз˥Ù~xr~ҹ:̼ئ@z866?DƪRȺvy.ЬęxqwdȪM/{6|74=@Eʳdm¿UˮǞztq8هʆU}4~59=@ťLŴ2:̩{vry}Ϲ ĵ੄8}169>CŬn0\vð)ŝyus5۟ʒU~/68;=ãV`цZè{uswZŠ<@x5}479;F؏δHĢ~wsq}Ͷ<|1447Cai%\gN{|vw}ɇ͎өըL $! }, ۼΩ˜!.68oˢa_[KEɮLUu}5;پղƜxz #if !defined(IDC_STATIC) #define IDC_STATIC (-1) #endif ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "#include \r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_SYNERGY ICON DISCARDABLE "synergyc.ico" IDI_TASKBAR_NOT_RUNNING ICON DISCARDABLE "tb_idle.ico" IDI_TASKBAR_NOT_WORKING ICON DISCARDABLE "tb_error.ico" IDI_TASKBAR_NOT_CONNECTED ICON DISCARDABLE "tb_wait.ico" IDI_TASKBAR_CONNECTED ICON DISCARDABLE "tb_run.ico" ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_TASKBAR_STATUS DIALOG DISCARDABLE 0, 0, 145, 18 STYLE DS_MODALFRAME | WS_POPUP FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_TASKBAR_STATUS_STATUS,3,3,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER END ///////////////////////////////////////////////////////////////////////////// // // Menu // IDR_TASKBAR MENU DISCARDABLE BEGIN POPUP "Synergy" BEGIN MENUITEM "Show Status", IDC_TASKBAR_STATUS MENUITEM "Show Log", IDC_TASKBAR_SHOW_LOG MENUITEM "Copy Log To Clipboard", IDC_TASKBAR_LOG POPUP "Set Log Level" BEGIN MENUITEM "Error", IDC_TASKBAR_LOG_LEVEL_ERROR MENUITEM "Warning", IDC_TASKBAR_LOG_LEVEL_WARNING MENUITEM "Note", IDC_TASKBAR_LOG_LEVEL_NOTE MENUITEM "Info", IDC_TASKBAR_LOG_LEVEL_INFO MENUITEM "Debug", IDC_TASKBAR_LOG_LEVEL_DEBUG MENUITEM "Debug1", IDC_TASKBAR_LOG_LEVEL_DEBUG1 MENUITEM "Debug2", IDC_TASKBAR_LOG_LEVEL_DEBUG2 END MENUITEM SEPARATOR MENUITEM "Quit", IDC_TASKBAR_QUIT END END ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE DISCARDABLE BEGIN IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK." IDS_INIT_FAILED "Synergy failed to initialize: %{1}" IDS_UNCAUGHT_EXCEPTION "Uncaught exception: %{1}" END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED synergy-1.8.8-stable/src/cmd/synergyc/tb_error.ico000066400000000000000000000004761305627404700222260ustar00rootroot00000000000000((   : 袠 :0 ~~ && ff~~p &&໻f`~~ && ff~p& f`synergy-1.8.8-stable/src/cmd/synergyc/tb_idle.ico000066400000000000000000000004761305627404700220120ustar00rootroot00000000000000((  9 9:虘90 9 y) iyi`y~& 癙fy f`0 psynergy-1.8.8-stable/src/cmd/synergyc/tb_run.ico000066400000000000000000000004761305627404700217010ustar00rootroot00000000000000((  :: :::::0袢:p fpp && ff`~~&&& fff~~&& f` 0synergy-1.8.8-stable/src/cmd/synergyc/tb_wait.ico000066400000000000000000000004761305627404700220410ustar00rootroot00000000000000((  :: :::::0袢::~~&&ff~~p&&ff`~~~&&& fff~~&& f`synergy-1.8.8-stable/src/cmd/synergyd/000077500000000000000000000000001305627404700177065ustar00rootroot00000000000000synergy-1.8.8-stable/src/cmd/synergyd/CMakeLists.txt000066400000000000000000000022121305627404700224430ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2012 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") include_directories( ../ ../../lib/ ) if (UNIX) include_directories( ../../.. ) endif() if (WIN32) add_executable(synergyd WIN32 ${sources}) else() add_executable(synergyd ${sources}) endif() target_link_libraries(synergyd arch base common io ipc mt net platform synergy shared ${libs} ${OPENSSL_LIBS}) if (CONF_CPACK) install(TARGETS synergyd COMPONENT core DESTINATION bin) endif() synergy-1.8.8-stable/src/cmd/synergyd/synergyd.cpp000066400000000000000000000020521305627404700222550ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/DaemonApp.h" #include #ifdef SYSAPI_UNIX int main(int argc, char** argv) { DaemonApp app; return app.run(argc, argv); } #elif SYSAPI_WIN32 #define WIN32_LEAN_AND_MEAN #include int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) { DaemonApp app; return app.run(__argc, __argv); } #endif synergy-1.8.8-stable/src/cmd/synergyp/000077500000000000000000000000001305627404700177225ustar00rootroot00000000000000synergy-1.8.8-stable/src/cmd/synergyp/CMakeLists.txt000066400000000000000000000032431305627404700224640ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(sources synergyp.cpp ) if (WIN32) file(GLOB arch_headers "MSWindows*.h") file(GLOB arch_sources "MSWindows*.cpp") list(APPEND sources resource.h synergyp.ico synergyp.rc tb_error.ico tb_idle.ico tb_run.ico tb_wait.ico ) elseif (APPLE) file(GLOB arch_headers "OSX*.h") file(GLOB arch_sources "OSX*.cpp") elseif (UNIX) file(GLOB arch_headers "XWindows*.h") file(GLOB arch_sources "XWindows*.cpp") endif() list(APPEND sources ${arch_sources}) list(APPEND headers ${arch_headers}) if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ../../lib/ ) if (UNIX) include_directories( ../../.. ) endif() if (WIN32) add_executable(synergyp WIN32 ${sources}) else() add_executable(synergyp ${sources}) endif() target_link_libraries(synergyp arch base client common io mt net ipc platform server synergy client ${libs} ${OPENSSL_LIBS}) if (CONF_CPACK) install(TARGETS synergyp COMPONENT core DESTINATION bin) endif() synergy-1.8.8-stable/src/cmd/synergyp/MSWindowsPortableTaskBarReceiver.cpp000066400000000000000000000224241305627404700267520ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergyp/MSWindowsPortableTaskBarReceiver.h" #include "resource.h" #include "platform/MSWindowsClipboard.h" #include "platform/MSWindowsScreen.h" #include "arch/win32/ArchTaskBarWindows.h" #include "arch/win32/ArchMiscWindows.h" #include "arch/Arch.h" #include "base/EventQueue.h" #include "base/IEventQueue.h" #include "base/log_outputters.h" #include "base/EventTypes.h" // // MSWindowsPortableTaskBarReceiver // const UINT MSWindowsPortableTaskBarReceiver::s_stateToIconID[kMaxState] = { IDI_TASKBAR_NOT_RUNNING, IDI_TASKBAR_NOT_WORKING, IDI_TASKBAR_NOT_CONNECTED, IDI_TASKBAR_CONNECTED }; MSWindowsPortableTaskBarReceiver::MSWindowsPortableTaskBarReceiver( HINSTANCE appInstance, const BufferedLogOutputter* logBuffer, IEventQueue* events) : PortableTaskBarReceiver(events), m_events(events), m_appInstance(appInstance), m_window(NULL), m_logBuffer(logBuffer) { for (UInt32 i = 0; i < kMaxState; ++i) { m_icon[i] = loadIcon(s_stateToIconID[i]); } m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR)); // don't create the window yet. we'll create it on demand. this // has the side benefit of being created in the thread used for // the task bar. that's good because it means the existence of // the window won't prevent changing the main thread's desktop. // add ourself to the task bar ARCH->addReceiver(this); } void MSWindowsPortableTaskBarReceiver::cleanup() { ARCH->removeReceiver(this); for (UInt32 i = 0; i < kMaxState; ++i) { deleteIcon(m_icon[i]); } DestroyMenu(m_menu); destroyWindow(); } MSWindowsPortableTaskBarReceiver::~MSWindowsPortableTaskBarReceiver() { cleanup(); } void MSWindowsPortableTaskBarReceiver::showStatus() { // create the window createWindow(); // lock self while getting status lock(); // get the current status std::string status = getToolTip(); // done getting status unlock(); // update dialog HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS); SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str()); child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_CLIENTS); SendMessage(child, LB_RESETCONTENT, 0, 0); if (!IsWindowVisible(m_window)) { // position it by the mouse POINT cursorPos; GetCursorPos(&cursorPos); RECT windowRect; GetWindowRect(m_window, &windowRect); int x = cursorPos.x; int y = cursorPos.y; int fw = GetSystemMetrics(SM_CXDLGFRAME); int fh = GetSystemMetrics(SM_CYDLGFRAME); int ww = windowRect.right - windowRect.left; int wh = windowRect.bottom - windowRect.top; int sw = GetSystemMetrics(SM_CXFULLSCREEN); int sh = GetSystemMetrics(SM_CYFULLSCREEN); if (fw < 1) { fw = 1; } if (fh < 1) { fh = 1; } if (x + ww - fw > sw) { x -= ww - fw; } else { x -= fw; } if (x < 0) { x = 0; } if (y + wh - fh > sh) { y -= wh - fh; } else { y -= fh; } if (y < 0) { y = 0; } SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh, SWP_SHOWWINDOW); } } void MSWindowsPortableTaskBarReceiver::runMenu(int x, int y) { // do popup menu. we need a window to pass to TrackPopupMenu(). // the SetForegroundWindow() and SendMessage() calls around // TrackPopupMenu() are to get the menu to be dismissed when // another window gets activated and are just one of those // win32 weirdnesses. createWindow(); SetForegroundWindow(m_window); HMENU menu = GetSubMenu(m_menu, 0); SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE); HMENU logLevelMenu = GetSubMenu(menu, 3); CheckMenuRadioItem(logLevelMenu, 0, 6, CLOG->getFilter() - kERROR, MF_BYPOSITION); int n = TrackPopupMenu(menu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, 0, m_window, NULL); SendMessage(m_window, WM_NULL, 0, 0); // perform the requested operation switch (n) { case IDC_TASKBAR_STATUS: showStatus(); break; case IDC_TASKBAR_LOG: copyLog(); break; case IDC_TASKBAR_SHOW_LOG: ARCH->showConsole(true); break; case IDC_RELOAD_CONFIG: m_events->addEvent(Event(m_events->forServerApp().reloadConfig(), m_events->getSystemTarget())); break; case IDC_FORCE_RECONNECT: m_events->addEvent(Event(m_events->forServerApp().forceReconnect(), m_events->getSystemTarget())); break; case ID_SYNERGY_RESETSERVER: m_events->addEvent(Event(m_events->forServerApp().resetServer(), m_events->getSystemTarget())); break; case IDC_TASKBAR_LOG_LEVEL_ERROR: CLOG->setFilter(kERROR); break; case IDC_TASKBAR_LOG_LEVEL_WARNING: CLOG->setFilter(kWARNING); break; case IDC_TASKBAR_LOG_LEVEL_NOTE: CLOG->setFilter(kNOTE); break; case IDC_TASKBAR_LOG_LEVEL_INFO: CLOG->setFilter(kINFO); break; case IDC_TASKBAR_LOG_LEVEL_DEBUG: CLOG->setFilter(kDEBUG); break; case IDC_TASKBAR_LOG_LEVEL_DEBUG1: CLOG->setFilter(kDEBUG1); break; case IDC_TASKBAR_LOG_LEVEL_DEBUG2: CLOG->setFilter(kDEBUG2); break; case IDC_TASKBAR_QUIT: quit(); break; } } void MSWindowsPortableTaskBarReceiver::primaryAction() { showStatus(); } const IArchTaskBarReceiver::Icon MSWindowsPortableTaskBarReceiver::getIcon() const { return static_cast(m_icon[getStatus()]); } void MSWindowsPortableTaskBarReceiver::copyLog() const { if (m_logBuffer != NULL) { // collect log buffer String data; for (BufferedLogOutputter::const_iterator index = m_logBuffer->begin(); index != m_logBuffer->end(); ++index) { data += *index; data += "\n"; } // copy log to clipboard if (!data.empty()) { MSWindowsClipboard clipboard(m_window); clipboard.open(0); clipboard.emptyUnowned(); clipboard.add(IClipboard::kText, data); clipboard.close(); } } } void MSWindowsPortableTaskBarReceiver::onStatusChanged() { if (IsWindowVisible(m_window)) { showStatus(); } } HICON MSWindowsPortableTaskBarReceiver::loadIcon(UINT id) { HANDLE icon = LoadImage(m_appInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); return static_cast(icon); } void MSWindowsPortableTaskBarReceiver::deleteIcon(HICON icon) { if (icon != NULL) { DestroyIcon(icon); } } void MSWindowsPortableTaskBarReceiver::createWindow() { // ignore if already created if (m_window != NULL) { return; } // get the status dialog m_window = CreateDialogParam(m_appInstance, MAKEINTRESOURCE(IDD_TASKBAR_STATUS), NULL, (DLGPROC)&MSWindowsPortableTaskBarReceiver::staticDlgProc, reinterpret_cast( static_cast(this))); // window should appear on top of everything, including (especially) // the task bar. LONG_PTR style = GetWindowLongPtr(m_window, GWL_EXSTYLE); style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST; SetWindowLongPtr(m_window, GWL_EXSTYLE, style); // tell the task bar about this dialog ArchTaskBarWindows::addDialog(m_window); } void MSWindowsPortableTaskBarReceiver::destroyWindow() { if (m_window != NULL) { ArchTaskBarWindows::removeDialog(m_window); DestroyWindow(m_window); m_window = NULL; } } BOOL MSWindowsPortableTaskBarReceiver::dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM) { switch (msg) { case WM_INITDIALOG: // use default focus return TRUE; case WM_ACTIVATE: // hide when another window is activated if (LOWORD(wParam) == WA_INACTIVE) { ShowWindow(hwnd, SW_HIDE); } break; } return FALSE; } BOOL CALLBACK MSWindowsPortableTaskBarReceiver::staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // if msg is WM_INITDIALOG, extract the MSWindowsPortableTaskBarReceiver* // and put it in the extra window data then forward the call. MSWindowsPortableTaskBarReceiver* self = NULL; if (msg == WM_INITDIALOG) { self = static_cast( reinterpret_cast(lParam)); SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); } else { // get the extra window data and forward the call LONG_PTR data = GetWindowLongPtr(hwnd, GWLP_USERDATA); if (data != 0) { self = static_cast( reinterpret_cast(data)); } } // forward the message if (self != NULL) { return self->dlgProc(hwnd, msg, wParam, lParam); } else { return (msg == WM_INITDIALOG) ? TRUE : FALSE; } } IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) { ArchMiscWindows::setIcons( (HICON)LoadImage(ArchMiscWindows::instanceWin32(), MAKEINTRESOURCE(IDI_SYNERGY), IMAGE_ICON, 32, 32, LR_SHARED), (HICON)LoadImage(ArchMiscWindows::instanceWin32(), MAKEINTRESOURCE(IDI_SYNERGY), IMAGE_ICON, 16, 16, LR_SHARED)); return new MSWindowsPortableTaskBarReceiver( MSWindowsScreen::getWindowInstance(), logBuffer, events); } synergy-1.8.8-stable/src/cmd/synergyp/MSWindowsPortableTaskBarReceiver.h000066400000000000000000000037041305627404700264170ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/PortableTaskBarReceiver.h" #define WIN32_LEAN_AND_MEAN #include class BufferedLogOutputter; class IEventQueue; //! Implementation of PortableTaskBarReceiver for Microsoft Windows class MSWindowsPortableTaskBarReceiver : public PortableTaskBarReceiver { public: MSWindowsPortableTaskBarReceiver(HINSTANCE, const BufferedLogOutputter*, IEventQueue* events); virtual ~MSWindowsPortableTaskBarReceiver(); // IArchTaskBarReceiver overrides virtual void showStatus(); virtual void runMenu(int x, int y); virtual void primaryAction(); virtual const Icon getIcon() const; void cleanup(); protected: void copyLog() const; // PortableTaskBarReceiver overrides virtual void onStatusChanged(); private: HICON loadIcon(UINT); void deleteIcon(HICON); void createWindow(); void destroyWindow(); BOOL dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); static BOOL CALLBACK staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); private: HINSTANCE m_appInstance; HWND m_window; HMENU m_menu; HICON m_icon[kMaxState]; const BufferedLogOutputter* m_logBuffer; IEventQueue* m_events; static const UINT s_stateToIconID[]; }; synergy-1.8.8-stable/src/cmd/synergyp/OSXPortableTaskBarReceiver.cpp000066400000000000000000000027401305627404700255300ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergys/OSXServerTaskBarReceiver.h" #include "arch/Arch.h" // // OSXServerTaskBarReceiver // OSXServerTaskBarReceiver::OSXServerTaskBarReceiver( const BufferedLogOutputter*) { // add ourself to the task bar ARCH->addReceiver(this); } OSXServerTaskBarReceiver::~OSXServerTaskBarReceiver() { ARCH->removeReceiver(this); } void OSXServerTaskBarReceiver::showStatus() { // do nothing } void OSXServerTaskBarReceiver::runMenu(int, int) { // do nothing } void OSXServerTaskBarReceiver::primaryAction() { // do nothing } const IArchTaskBarReceiver::Icon OSXServerTaskBarReceiver::getIcon() const { return NULL; } IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer) { return new OSXServerTaskBarReceiver(logBuffer); } synergy-1.8.8-stable/src/cmd/synergyp/OSXPortableTaskBarReceiver.h000066400000000000000000000023041305627404700251710ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergyp/PortableTaskBarReceiver.h" class BufferedLogOutputter; //! Implementation of PortableTaskBarReceiver for OS X class OSXServerTaskBarReceiver : public PortableTaskBarReceiver { public: OSXServerTaskBarReceiver(const BufferedLogOutputter*); virtual ~OSXServerTaskBarReceiver(); // IArchTaskBarReceiver overrides virtual void showStatus(); virtual void runMenu(int x, int y); virtual void primaryAction(); virtual const Icon getIcon() const; }; synergy-1.8.8-stable/src/cmd/synergyp/XWindowsPortableTaskBarReceiver.cpp000066400000000000000000000030411305627404700266340ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergys/XWindowsServerTaskBarReceiver.h" #include "arch/Arch.h" // // CXWindowsServerTaskBarReceiver // CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver( const BufferedLogOutputter*) { // add ourself to the task bar ARCH->addReceiver(this); } CXWindowsServerTaskBarReceiver::~CXWindowsServerTaskBarReceiver() { ARCH->removeReceiver(this); } void CXWindowsServerTaskBarReceiver::showStatus() { // do nothing } void CXWindowsServerTaskBarReceiver::runMenu(int, int) { // do nothing } void CXWindowsServerTaskBarReceiver::primaryAction() { // do nothing } const IArchTaskBarReceiver::Icon CXWindowsServerTaskBarReceiver::getIcon() const { return NULL; } IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer) { return new CXWindowsServerTaskBarReceiver(logBuffer); } synergy-1.8.8-stable/src/cmd/synergyp/XWindowsPortableTaskBarReceiver.h000066400000000000000000000023331305627404700263040ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergyp/PortableTaskBarReceiver.h" class BufferedLogOutputter; //! Implementation of PortableTaskBarReceiver for X Windows class CXWindowsServerTaskBarReceiver : public PortableTaskBarReceiver { public: CXWindowsServerTaskBarReceiver(const BufferedLogOutputter*); virtual ~CXWindowsServerTaskBarReceiver(); // IArchTaskBarReceiver overrides virtual void showStatus(); virtual void runMenu(int x, int y); virtual void primaryAction(); virtual const Icon getIcon() const; }; synergy-1.8.8-stable/src/cmd/synergyp/resource.h000066400000000000000000000031051305627404700217210ustar00rootroot00000000000000//{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by synergys.rc // #define IDS_FAILED 1 #define IDS_INIT_FAILED 2 #define IDS_UNCAUGHT_EXCEPTION 3 #define IDI_SYNERGY 101 #define IDI_TASKBAR_NOT_RUNNING 102 #define IDI_TASKBAR_NOT_WORKING 103 #define IDI_TASKBAR_NOT_CONNECTED 104 #define IDI_TASKBAR_CONNECTED 105 #define IDR_TASKBAR 107 #define IDD_TASKBAR_STATUS 108 #define IDC_TASKBAR_STATUS_STATUS 1000 #define IDC_TASKBAR_STATUS_CLIENTS 1001 #define IDC_TASKBAR_QUIT 40003 #define IDC_TASKBAR_STATUS 40004 #define IDC_TASKBAR_LOG 40005 #define IDC_RELOAD_CONFIG 40006 #define IDC_FORCE_RECONNECT 40007 #define IDC_TASKBAR_SHOW_LOG 40008 #define IDC_TASKBAR_LOG_LEVEL_ERROR 40009 #define IDC_TASKBAR_LOG_LEVEL_WARNING 40010 #define IDC_TASKBAR_LOG_LEVEL_NOTE 40011 #define IDC_TASKBAR_LOG_LEVEL_INFO 40012 #define IDC_TASKBAR_LOG_LEVEL_DEBUG 40013 #define IDC_TASKBAR_LOG_LEVEL_DEBUG1 40014 #define IDC_TASKBAR_LOG_LEVEL_DEBUG2 40015 #define ID_SYNERGY_RELOADSYSTEM 40016 #define ID_SYNERGY_RESETSERVER 40017 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 109 #define _APS_NEXT_COMMAND_VALUE 40018 #define _APS_NEXT_CONTROL_VALUE 1003 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif synergy-1.8.8-stable/src/cmd/synergyp/synergyp.cpp000066400000000000000000000044761305627404700223210ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ServerApp.h" #include "synergy/ClientApp.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/EventQueue.h" #if WINAPI_MSWINDOWS #include "MSWindowsPortableTaskBarReceiver.h" #elif WINAPI_XWINDOWS #include "XWindowsPortableTaskBarReceiver.h" #elif WINAPI_CARBON #include "OSXPortableTaskBarReceiver.h" #else #error Platform not supported. #endif #define WIN32_LEAN_AND_MEAN #include INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR lpCmdLine, INT nCmdShow) { #if SYSAPI_WIN32 // record window instance for tray icon, etc ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif Arch arch; arch.init(); Log log; EventQueue events; CLOG->insert(new MesssageBoxLogOutputter()); int argc = __argc; char** argv = __argv; bool server = false, client = false; for (int i = 0; i < argc; i++) { if (std::string(argv[i]) == "--server") { server = true; } else if (std::string(argv[i]) == "--client") { client = true; } } if (!server && !client) { MessageBox(NULL, "Either the --server argument or the --client argument must be provided.", "Server or client?", MB_OK); return 1; } if (argc <= 2) { MessageBox(NULL, "No additional arguments were provided. Append the --help argument for help.\n\n" "Hint: Create a shortcut and append the \"Target\" field with the arguments.", "No additional arguments", MB_OK); return 1; } if (server) { ServerApp app(&events, createTaskBarReceiver); return app.run(argc, argv); } else if (client) { ClientApp app(&events, createTaskBarReceiver); return app.run(argc, argv); } return 0; } synergy-1.8.8-stable/src/cmd/synergyp/synergyp.ico000066400000000000000000010622761305627404700223140ustar00rootroot00000000000000 ( V00 %~   &F V hV`( 2(OOOcyԀԀՃՃՀ~YE;2;2 2OրcY; 2Y׀щʾzzz|z~v{zsz}ry|rzzw{|x}{}~|~ЉycEEـwjxv_tqXqmId`JeaNgcUjgZmj_mk]ki]hfgromtqkrmgkfejalmdlnbmk`hgYgfXgeZki^sqg}{q{ÿ~;(2cѐ{stumnljjgii]hfZhfWliTmib}yotushomclj`ih^gf\fgcklhvwsӃEY~ܳ{outckjYa`FjdEvnU\]`ecjŶtѼȳ~qsm`b\]_Ycd`nok|}yΐc2(c˥otschgagfkqpu}|yqzǿľ|{|xstpjkgefbmnjz{w~O;Yy|zdolWni@ib5jaC}f~omlj^VMIIDBCPl۷զԙӋӇֆ؈ՐԗҠգ߭ٯԳĪzndrhangdokjxywſӃEyĻrnm][ZUXV\gdxxhffdZRIFFA?AMiձϠΓΆ΂ЀсΉˎɗ̑̚՚ڨخԳжɷxtsUVTZ][jqn}ΐщY Oΐ~Xoj8ZTFumcbgr|udRMB2144-)((,0/4E`{޷סҍ}mc]]`cgnt{~Յ؋ٕ޳ִĻ{upc\Yjefͥy2 EûszwZebczucuraWNK@0/33-)((,0/4E`{ݶ՟ь|lb[[^`cjvuqx~Ʌɍʕִ͢{xxstlllddd|{}Y;Y֐tywKmg?vm=xpnjTG:5/.)" #"(("""%*109Fb|ڵўψyk\UUWY]a_abbbcgnqԎםܬ߼ٺưe`Wlj`yupХnOԚxinl]b`nn_LA74,&! "!&& "(/-6C_yسН͆whXQRTW[_^bc``dinuxȂŋ’˨ԵDZ˽þea\ZXW|y{y(nVmiJnhhxrukXN>90(('&)*+/-022**('0216?Wm۽ԯ̙Ƅtg_Z[`bhid`^ZX[XV[]fstzփړ٩سسļ{vgge[}|׉O EϚ·ywwfqog~zyĽmgYP:4)%'(&''&(*.0/('&$ֿ+׿-վ+׻1ؽ:ڼRٿhշΩƓտ}ڽld[VW\_ܾeܾe]\^]YWVYYbcgnttǀͨ͝ϪϸljimlnY;͚_qpOplavĹ}zdD<73,)'&'++-,.-,&ڽ%ټ&ָ&ָظ׷յҳ$Ю%ѯ%ԯ&հ1ײDٷT޼|ڼٶٲ֦ϗŃҾqӻcӼYӺTѸPѸPӺTԹWַZնYԾUWZ\[\Z[\\\]^__^q{҆Ֆ٠ϭqtqi~}ڐ; ~glmpznZA962,)''%)(+)+׿*־)ս!ոӶ"Ҵ"ҴԴӳѱͮ!ͫ"ά Ϫ Ϫ)Ϫ;ЮKճsҷԶүЩ̜Čȼzʶi̴\̵RεOʹLʹLεOϴRѲUҳVϹPкQҼSӽT־TVWYYYZ[\]]]pw~Ɋ˒֪ڸ̵omluu{܉Y2րĿhvuTwsVetgV?5-('%$$$#'%ۼ(ۼ'ڹ&ٸ%ط#ֵճԲԬѪЩϨЧΥˣ!ȡ)ğ.Ġ-Ɵ2Ơ9ǢLʧ`ά}ͰδɰȫĜzj_TNIIHīKɭN˯PɴKʵL̶M͵QζRѸXֺ[ؼ]ۿ`a`_]^]]_`ems̀Փܧۯƥ{wlwtpِOԃwwwftswwVH<6.('$#"!ܽ!ٻ!׸$׸#ֵ!ԳұЯϭͫΦ̥ʣȡȟǞŝÜ&,ž.Ǡ7˥AϪVԱkٷػ׽ԻԷҪ˛ˆʹv˴iYOGCACF¦GîEįFDZHɱM˳O̳SдUдUԸYֺ[ռZZYZZZ]_`irvȓ̠ٸѹ|xmlpɰE(ΐ]xuXsvm\F.+($$+*&%ݿ#ܼ!ں ׵!Գ"ԯ$Ӯ%Ҭ"ϩΦˣʟɞ Ř&×'–&'–)Ę1›=OŢWȦ]έfӳpعؼϮǞÓι˳ymc]WSNHHIKèNŪPɫR˭TˮSͰUδVжXҹWԻYֿ[\YZUZbfhy~Бڦذswte}ǽO ;ԀgxuieO?0,'!!&ܾ%۽"ڼ غظյӱЯϪͨ˥ɣǟŝŚę$'–)Ę-Ȝ1̠<ͦJΩ[ѮbӱgطoܼxֵҩРʓŋԿӻyҹsϴjŪ`¤WHFCBDHåLƨOŨMǪOɯQ˱SʹRзUһWԽYSYWX]cfu|ąɕ֮ټüwum{{{E2ΐa|xZpyhNB51/+*(%ؿ*ֺ)չ$Զ"Ҵ!ұЯΩ ̨ ɢ!Ơ#ś#%%%%4:˜?śBȞEͣIѧRӬ`ԯpӳrյu׹y۽ٽԶϮͨƠĚؼӴ}ЮsǧfŢ^VNIHHGF§EƬHȮJȰLʲN͵QиT̼RXWVWVV[bq}ŇОٲÞuuuʥY ҃suun¹v\H=353('׿'$׾(Ը'ӷ!ѳϱέ̫ʥȤŞœ""#$7ę=śCɟF̢GϥJҨRӬ^ҭpӳrյtָwٻշέ˦ĞÙؿٽعض{׷vԱm˩c¢WNHD?@@B¨DªFëGƮJɱMɹOʺP˼NҾQUWY\_kzΧֱʵtttwwwO OՉJ}uIr;z_>1*''(ܿ'۾'ݻ$ڸ!ضִ$ժ&Ҩ"Ш#̥ ɢ şÚ!! $'+đ.ǔBŤKƦPȩUʫ[˩ZʨXʥSʤP̢OˡP̠VϣaѢiУpը׭ֳԴӬͥƙһҶѳzϱvΰu̴xи|ηϷѶβѱ̬ʬ{ŪqaTLC@ADFHŢLɤO˦QŮHȱK̴PϷSѹUԼXX[[[`go{Պۢȷt||nɰڀ(Yz|isȺnN@6%ֻ%ھ%ھ$ػ#׺!׵ճѯϭΣˡɡŞÜ!'+Ò/ȕ2˘AģG¢HKQPMG@=:@FIŨMȫPʭR̯TϴRѸRӽTԾUW\ӿ`Կdjw̔ݹѯt|А(Oevssk]LտA.ؼ!ո'۾"ع ַ Ӳ!Яά˩ʥȣŚØ &.1777-*&}#z yz{{}#1AĒHȗ]ɛ̚Ǘőxk[SEBA@;99~7ACJPSXƠ_Ơ_ş^œ[RI?=:=BDG¥JŨMȫP˰NʹNϹPѻRнTӿZҾ_Ӿcӿgսq̻Ȥӱη~}y~(nȽcxuYxǹvUH8׽,Ӹ)ܽ&ܽյӳԱ ү"ϩ#˦"ɢƟě™ $(**,+*yyzz|"&,/7>JVgpƨƬ˯ɬƪ{rf^ZUPOLH758>@ITÖYÖYėZXQF?;=@DGJKĢOǧNɪM̱OεOϹPѻRӾUW[]gv̍ԩʮzz~(щyzplLB9ؾ-Թ%ع"عֶԴүЭ̦ ȣŞ›"#$#$|%}%} x{$+0Ď8ǖ@ϞLѦX֬hٴvܹƽظЮˤǝվϴȭu¤i_[VP@;998=DFKPTRIA;:<@BFGJ¢IĥHȭKʱK˵LͷNιPҽTҿXӾ[ҿdӾsąØѵcϐ~fxc?ڿ/%׺"ع$ڻ׵ӱԮ կϧ!̥#ʟ$Ɯ"Ö|!|!{!{!{ }||z}'2?Q¡dƨuɱθοY( ((n̚Ѿǰ}re\QE=84;>CHKJGF>?@CEHIHĥJȪKɮL˲L˵KϹOҾQӿRӾQYi{̗մɼz( Yvy\>پ-ھ$ֹ!׸ ַҰҰҬȢȠƟę}|yzyxtxxz{$)5ś@ƢQϬhٸc22YyщӶťαȪ{oaRH@:989>DGGF;<<>@CCBB¤EŪHƭGDZG˵KϻNмOӾQѻRϺ_Ҿw˻ǦҼyԀ EZ{bcI;ٻ.ٹ#ٷ!׵ղӰҬϪ̤ʞƘ Ö{{yzxutuwy#}+19CVɨƾn(Yĺs_QGB:778?EG=<;:<8};?@9999:ػ0ݽ%Ҳ(ӳ'Ҳ!ѬϪ̦ɣƝÚ~}zytsvx{#2Mǡgӯ(O˥ٳïjWKB<667574369>@ADCDFĨIŬJǮL˵LͷN˸QʸYɻiʽ–ȯ¿Հ ؀rg{lCټ0ַ%״"Ա ү ά"ϩ#˦"ɠ"Ɲ#Ù# ~|zyxwuuy~%4AVpƮԀʼ~dTHA}:}:874358<>ACCCDGN§PǮNαNϳNѵPѹYϻf}ɓѪ~(2sŹd=Ӷ/նѮ%״ үɧ˥ ȣŜ™|{yxxwvvz~&;Pƣjβ2Oƽġ{_ME>}:~663248:;>@?@@BKLīK̯LβMϳNζV˷bȹtÍʣǯc(щup{cF׻9Ӷ.Ѳ(Ϯ&ҰͪʧȞŜ—~|zyxxwwwz%:Qrƪc~ϱƸs[PF>;43368:<>==<>IKĤK̪MӭMԮNӲQзUųZοvNjӪ½Ⱦ(Yʾyc?д7Ѵ&ɪ)ЯʨŢ˨Ɯ™}|{yxxwwwx0KǛfЬc2 ~޴n[NC=631457:<:98:DFFǥHΨHЪJϮM˲PųZĵlû™̳n EՀxhb9ܽ*ڵ%հ)Ϫ&̧%̥#ʣ!Ǟ!š%Í#~ x wts vxw$>V~ű;~_OC2~08{5}572446<=?BGKM©MƮJͰM̯LػXջaĂƗƯ2nvŷ[4׸'ײ#Ӯ'ͨ$ʥ#ʣ!ȡě#!} y wts v yz,J£kѵnsYI737{5}571235;==@DHJJĬHˮKˮKҵRδZҼz“ĭYϰwJܾ.ѱ&Ү"Ϊ$ˤ"ɢ!ȟŜ—}ytussy}#;`˸(ΐʾ{cG<9~5~9:89878:;=BEFG¦GũJʭKʭKȮTʹnпß˰OOzAӵ,ϯ"Ϊ˧"ɢ ǠŜ™{xtust{!,Gsеy2ĚëwRB=9:~97875478:>@BCD¦GȫIǪHƬRƭgȷ̼ϴ~փvXؿ0ϭ,Э#̥!ʣ!ǞŜę~|zywv!t"uty&Gwȯc щ˿xZGB:}8y;{=~;83568=?@DDEȨIȨIȫPêZŰl̻ɕĻɰ2쎟ʾtӿMʹ,˩*Ϋ ɢǠŜ™}{zyvu s st{!-T̩2ٽ˹iME;}8x:{=~;~72545;==AABťFƦGƩNTfƵ|ʼ˪cc³pѽRغ2ά$ʥ%˦#Ǟ!Ŝė~}zyutrrrvy%=eê(ƽkQ?9|6{9{9{86724:<>BCDDàFŦKM«[ưhκsϔӃ˼l͹Q׹2ά"ȣ!Ǣ"Ɲ ě•}|zyutrqt!y"~-IȡtҹyOȪy]F>~8{9z8y6~45139;=AABACĥJMì\`˷p‡(Eƶu׿Rָ/ѭ$ʥǝȞ Ö |z w s pqqsw1V̷EYħwSE:5}6}:<~:228;>@AA@AEINS̲^ӻoœŮՀ~ŵsսOӵ+ͩ!ǢƜƜ•~{z w s pqrux#9`Ǩ ܿͿ^L=8~7}:;~:227:<>??=?BFKPǭYζjƻɰ(Ͱtl̴^غ9Ѯ!ʣŞÚė{y zy t sssuy4_̼ېEг^E>7|3{8{85469;<>?@?BFGJɫRҳ^μ OY|nζZԶ3˨Ɵĝ™~zxyx s s rsu{&<ÛkͯcĖkLC:}4z7|954689:<=>>@DFHŧNˬWǵʾå؃Րu˳V׸CӰ*Ǣěě!• ~|ywywssrsz$>hê߉п³kSC7~467667899<;=@CDFŠKɣQêjȷȠ((|ҺUַ=ͪ&ÞÚ™|{xvywrsst}*DÜq̳cϐ¢w[F8~4~46~5~57887:9<>ACEHşMe±ƞOEfԸHӲ,ɤ$"˜~| zyu t wu#r$s tv'1bè߃ǽqR:/,}6|5~576669;=>@CFÛIĜJ]ïv¸~cbдBͬ(Š"!}{yxu s wu#r%t!u!y+6ęj˰cԀɹzX?2-|5{4}4666588:;=@DFGWnȸŻylʲ@ֲ4ʦ*Ü& }{yxvuurrq)x/3EǦû( OǹrT100}2}24778:;<<>>AACM̥aȲpŖ;̚rи<Ү1ǣ'$|zyxvvwttt-|4:MϮn (ƽ{[621~3~3576799;:=@BDƟUaμû~;~ijgе6ʤ,&$}|zxvuuuurvy,@PǠyؽyEμkF;74}4676~7~7898;:<>@C›Q\ȶƾ݀ OnȱPͭ,˟#–|{xwuuttvsw~,IsǪ;ʥwVC96}4~5~7~7~7~789:<;==?BFT¯rȽynȱLɩ)Ȝ!{zxvutttusx/M›wˮԀƿ~]H:6|3}4~7~7~7~7799;:<<>BBSkø( Ӄ|Z˯>ʥ'ŗ~{yxutssssrs{!5Uáɷ֐;ɷnS<7}2}2~5~5~5667689:;<>=OdĶú( ~Yʮ<ȣ$”}{xwutsstttu}%9ZȦμۃѿrU>8~3}2}4}4~5~5566789:;:8M`Ļ2(ɳJͬ:Ǡ'#}zzwwttsssstv~3BfĬE}`B6|144~3444434578:9?FUijzøƿY(ʴJͬ9Ɵ&"}zzwwttsssstv 4ChƮ2 ͚ûdD8}244~3443434578:9>ETwĽc;ʴMͪ4Ɯ!~{{xxwwvvvvx x*BT´҉ yƿnJ=675566567879<==DGVuųĻyEĿʴL̩2Ě!||zyyxxxxx{$|.FWæĶՀYijsMA997788789:9;=?>DHVrIJúڀE½ʳP̨8˜+'$$#! ~ ~{{{z{{{{$|-~:Wt»~;Ÿ|TH@?=>@?=>?@ACEFGHMWqIJ؃ E½˴RΪ;ś-*'&&$##""!~!~!!!!&~0>[£vüy2ƹYMFDBCECBCDEEFHIKKQZqų ;¾ͷVҮKȠQMKJJIHHGFFFDDDD9Wwc ۹skfefccedddddeffgjpڰŽ2ՃuHt{8ip-gn+jl*jl*jl*hj(ij(ij(ij(hi'hj(ik)hl*im+om,mk*ns.q{5}OqY(ؾl^\[[[ZYYZZZZZ[\\^hx沛Y~k@qu.jn'ei"cg fj#de!de!cd cd cd cd cg cg dh!dh!df eg!em&ht,wImȿ2l]ZYYYXWXXXXXYZZ[]eu屚Eyaz;mq*fj#ae`dbfabab`a`a`a`a_c`d`d`dacceck$gs+wIn(ĵ縝mZWUVVUUUUUUVVWXXW\mϩ2 cr|Q{4jn#dg`c^a`c^`^`________]_]_^a^a]`^a_hdo)uIo ~ȹ縝mZVSTUTTTTTUUVWWXWZkӭـsyNx|1hl!cf`c^a`c]_]_^^^^^^^^\^]_]`]`\_]`^gdo)vJr̚ cⷢr[WSSTTSSSTTUVWXXSVf~䰠(ΚmyGxz.ikefbc_b`c]_^`]_]_\^\^\_]`]`]``aab`h!gq.zOxӃE乤u]XSSTTSSSTUVWXXXTWf|糣;EivDuw+hjefcd_b`c]_^`]_]_\^\^\_\_]`]`_`abai"is0}R|y滪~`ZUTUUTTSTVWXYYYTVcxc~]v?rv*eicgae_cac]a]a\`\`[_[_\_\_]a]a]^`_ci"lu2UîO 转﬑a[UTUTTSSTUWXYYYUVbu;Xr;qu)eidhbf`dac]a^b]a]a\`\`]`]`]a]a^_bafl%qz7Zʵ( nŷ᭠f[VVTTTSSSTWXXXZ`c`s|㻞АnrAy0sr"nmffeecebd_c_c]`]`]`]`^_^_a_a_]a[dai-pxIo(OͿ沥h]WWTTTSSSTVXXXZ^daoz彠O(Κp?w}.sr"mlggffdfbd_c^b]`]`]`]`^_^_`^a_[_\eem1u}Nvщ (߼nbYWSSRQQQTVXXYZ]b`ku゙˫ۃ Yya7tz(pq!klhhggdfbd^b^b]`]`^a]`^_^_^_^_Y`^i jr6{Wĵc ӃõreZXSSRQRQTVWXY[^aajsֶ2؀uW{2qw%op klhhhhegbd^b]a]`]`^a^a_`^_]^]^[bbm$px<];Yⱡ{j^WQQQPRQSVWWY[^_`ioѰ݃; c}dCy'sxoqkkiihhegbd^b]a]`]`^a]`\_\_\_\_[ddo)r{Be͚ ;跧n`XQQQORQSUWWY[_^ajo{©ۺy 2_>u~#qvoqlliihhdfac]a]a]`]`]`]`\_\_\_]`^gfq+xHpy Հ¸wf]TPOMQSSUWWWY\]aglvEjH0x|swoqllgjfidfac]a^b]`]`\^\^Z^[_\`^b_j$gt6Uϸ2nɿzh^TPOMQSSUWWWY[^bflxټ߃2ʞb@~-w{txoqllhkfice`b]a^b]`]`\^[]Z^[_]a_ccn(ly;] 黣sfWQNNQSTVWWVX\\`ehoz˳ʥ;ՃsI3~(vwvwnr knhkehcfbc`a__\^^`[_[_\_Z]Z_af!`l0vRoy ~whYQNMQSTVVWVX\\`ehnyȰįӐ ciC/|&vwuvnr kngjdgcfab`a^^]_^`[_Z^[^Z]Z_ch#ht8~Z}γ;Eɸ浛棄q_SNMRSUWWUSU]^bfhiqžѲέ{nOxpoN5'}~ wxtsmp jmfidgbeab`a^^]_]_Z]Z]Y^X]\dfn(oyJoʥᄂuaTPORSUWWTSU\^bfgip|ŦƲ}¼OO҃yvwdC1}${|xytsmp jmfidgbeab`a__\^]_Z][^Z_Z_`h"mu/xS|ĩyԀƵ㰖~gWQPRSUWVTQS\_aedfks|α廨ǽ2~|ohD.)"{{vzrtlqjmfjdgcfbc`a__\^\^Z][^Y`Y`aj'py6fY븞暈kYQORSUVVSPS\^`ccfkq|Ũʷα~}ΐӃuwqzX;+(!{{vzrtkpileicfbeab`a__]_\^Z]\_Za[ben+x>sՀщıu_UQSTUVVSPR\^`cbfjmvz˵}̚EԀyyyV6+#}~{{vzqsjogjdhbead`a_`^^^_]^[^]`\c ah%ox5Kǽ(nλ|dWRSTUVVSPR\^`bafjmtttt˥2(yrrruN.)"{|{{uyprinficgad`c_`^_]]^_]^[^^a`g$gn+y?WnYijs`YVTUTRTUS[]_bdhilrw~Ƥήлzx˥c2ېtwnjdžcB8+%$$y{!uv oriqbn`l`f```] c[c]c^\] `fYbVd_m+drb҃Ȱ櫋xk^Z_\XUWY]]^]`bfkovz~ˆĎÓƙȠ̧ѭմʶsaXNe\YypmփyYE2 (EOn~ЉssydfgWUTa_WŞʓԉu]G:1*%+*&&$"}|!|z"vw!poikggdgbe_d`d]^`a`dX_Xa[f _h)gp=zYϸ(;qa\`a^ZZZ\\][]_bglsvz~ėƞɤձѰѵtkhWPM_XUtpovuqkjfTTZZZ`wyzϨčp_L;1*&#''$$"~zyzx tuonhjggcf_b^cbfcdbcbf[d_j$ir3yOräЉ2ǽ廤榇qdbgfea][XXYZ\_flsuz|ŠƎȔƑ˙ѡЧӰ˻znxkwjsg]j`Vnf_rpfzvq~{vswkkq`ciV`fSfnWsv`zzhwաޗxaO>80)(''(%%$$"yytusr!kmjjgjghdf`a``ccgi#ac`d]e_h%dm5u|Ow~nй{haefhfa]XWXYY\cioqvy~ōǓɔ˙ϟЧЭϳҺxpf\f^Wig]kgbmjeokjqmluqpyut|xwtrqusrstrrsqpqopqoptoquphlfek``dXY_NZ`MoubͻϽť{eP8/)#!&'&$"" !}~ xxrsqpkmiicfabaccdhh"kk%jl&acaeai"en+mv>`Ȱnζsjfhklib]XWWX]bioqruy~Ljʋ͍̌̒͛ѦϬбԸӻӿͽ˺Ǻɹ|xngk_]eZVcWW\ZZZXXWWWZZZ[\X\]Y`d^gmbwâĞȟ͢ЀpaWH72-0.//.) }{y| uwornoilfh`b]^cdnm)sq0sq0fi$adcg%fn/qy=[ҽ(ʥ£~tfhkoojd\WVW\`gnonqv{~ƒÄʊ͍̒ʘˠȥǨ̰ϷмӼ˿ǭ˭̫ɣÚs`PF6/2&*+-+&!xv{uxrtlojkbebdacdeop({z6yw6pn-`cadhl*nv7Mw˫OyТkfgoyxyzni^XX]__jnqux{}Çȋʑ͕ЗҘәҝҢ֥ת٭ٲڳڷ޻߾ݗ؈|qh[PF?A<620.,-/.****%$}*wz$qvpultiqenek`eeg%kl.st6{|<|}=or-_cMeZr$av8wZĸ; ~뽵{oimy{{{uri`ZZ[\gikosx|ćƍȐ˒ΔЖΙ͝ПѤҦҫӬӰ״طٻ״ԤЕʄsg]TJB;662.++*(*&(''$ wz$vy#tyqvjrfndmgmlq&qs1~ALFtu5eh#_c%k5wNxɫcӃèzrsuvvyyxsnkgedgimpsuv|~ĉȍ̐Β͔͘ϗϛМРҟңңҧիִټ߲ٙՅq\NA<5...*+)'&'(&'&&&%## ~!qw os!kohkghjj$qq+xv5>BJIu|9bi&[d!bk(dv;{ZzĪn2ťwqrvy{zyz{{rkffegimprxz~Ŋɍˏ˒̗ϗϛМϟўѢСХҨԲ׺ޱ֖ЀkTI<60*+,)*)'&&&#$" y|tukqjnhljmqr(||6?GNOIvz8cj'^e"fo,qz7sJpÝϐ n뫒wons|tqligkostvz}NJʌ͏ВғғԓԓՖ՚֟קٱܻ۫ԍrV?1+(&).30'&%%$##$#"$}$w|!sv kqgkhpot)xy5~BPXYYZN|JV]cddce^WElq4`f+fo7p{IdԶ2˥Ϋ~wzwtuwy~~ƃȅʇʋʎ˗΢ѭ׵ոѠɃhO;,&#$%*-)"!~z~z|"{+~1=LZddeghdejk[Ill0hm0kq6vG`ݲnO﷤|žžœĞȪʵйػո֪ϖ{gP>/*%&$$ "~)-.15>KU]lwxvxwvwxukc[~@jr,ci0kn=y|UsȰ( nǽ}˜ś šǣǡǡȡȡɠǞǛƚ­ȱϲ̯̠ƍr]G6)%"&'**.;AGQ[eou}}||~~}pW~@lt.ks-sy@UwɰӃ˷㳗꧆ĞŨħ¤ƫȭƫʮ˯ͯϱввѱаѰЯϭ̪˦ȣǞƝڙĪdzɵж̲ʪĜwj^USSVX\aezzZq};ht2hv6s~FdιY~ӷƩʭ̮ȪŪƫǬŪʮ˯̮ͯϱвѱҲմ׶ڸ۹ܷڵٰ׮د׮կԱԷּۻذѠ͓ɉ~~Ɂˁ̓чԊ͑˓ɑŒ}_mv=am+lx6}KdܽO(̚䮗਋婌ĦгѴ̯ȯɯɳ˴˴ʵ̷θѻӽԾԹպ׿ٿټضӱ̪˩ʨɧƧäâģĞÝÜƙĕx}VhrCirGr|QeӃ(Ӄй믒樊쮐ǪҵռջҼййϺϺѻҼԾտپپ۾ڸִҰЮϭϭ̭ȩƥƥƠǡȡţá¤áȡˢ•}hv~Ogo@hrC{Yuֶ~(ϐкƨжӺԾۻ۵زӭέ̭̲̲ɴƳƳ˫˫ɫȪƪũĨ¦ϱάˤśmQpyAp|@OtƶEnۺ˪찒©ѻ޾߹ܶ۵մҳѷҸι̹˸ϯͭ˭ΰѵԸԸӷѳĢsVs{FxIWaxӨȰ2cɶ⹣⮗ìͶֽռԺӹԵԵԵնϾ־ؼ۷Ǖn}VuQrSvYo̚n2nʥ̵¬̷ٿٿܽ޿Ϊ™nZ{SuN~ZsЧ;ϐݿἦḡ浟DzҾصЫzhby\z`tcE~ʥϸ빣︣ȸqh|]}^myѲ̚n;~±빥﹢«ɲѺ޺ѫÝwom~ik{ȱy(OӃǽйʳﻤヲ齥©ȮʰͲеպپڼҴɩ}rljmqtҴщO;Yʹôݼ们纬뺬ﻮôѼ̷î~̲ջ˥yE (;YnՀЉʥƽƽǽƽƽӾҽӽѻʹɰεռ҃̚yY;??????????????????????????????????????????(0` 6j䞣ধ®r4 *}څwgkȁ'1pjfͼ`VMfګَ֕Κǿ󶸸,ǚiiǹYA-(#(MшYYgo؁ӛöȔ6soĸY8%&()!%ֺ=ڼԳxTZ^YW`tӖû:Vl\8$"%ڼ$ַѭͥɢ+ƢEЬջͨʷsëPIƭI̴NպX[Y^xКP\nP*$$عҰ ʤę"–6ƜHͦiӳѫеyƨ_LHƫKʹRTVeА[ukƸD$ھ#عѭɡ):ėF›C9IÕˣk^åiɧsƨiQDDĪI͵QտT]̀ƸY0kôD"عԲ ʥ˜ * z'9^ʥӳǡ跛aM>@PSA?JɫMϹOҾV}2rBֶѬȝ{vvFßޫؖm& F}èɷo?8B>>DĦH̵KӼOǁLJvB"ԲΨ Ěxt{FZAΧi=55:CFɯK͹RƇɉ,]Խ(Գ̧Ù}xu#vϴvRǹ槅F34<=HͬKϷZ!ħp+ص"ɤ–vt'2Ž˫B}267?GȬGӻj˖"Vз˥Ù~xr~ҹ:̼ئ@z866?DƪRȺvy.ЬęxqwdȪM/{6|74=@Eʳdm¿UˮǞztq8هʆU}4~59=@ťLŴ2:̩{vry}Ϲ ĵ੄8}169>CŬn0\vð)ŝyus5۟ʒU~/68;=ãV`цZè{uswZŠ<@x5}479;F؏δHĢ~wsq}Ͷ<|1447Cai%\gN{|vw}ɇ͎өըL $! }, ۼΩ˜!.68oˢa_[KEɮLUu}5;پղƜxz ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include \r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_SYNERGY ICON "synergyp.ico" IDI_TASKBAR_NOT_RUNNING ICON "tb_idle.ico" IDI_TASKBAR_NOT_WORKING ICON "tb_error.ico" IDI_TASKBAR_NOT_CONNECTED ICON "tb_wait.ico" IDI_TASKBAR_CONNECTED ICON "tb_run.ico" ///////////////////////////////////////////////////////////////////////////// // // Menu // IDR_TASKBAR MENU BEGIN POPUP "Synergy" BEGIN MENUITEM "Show Status", IDC_TASKBAR_STATUS MENUITEM "Show Log", IDC_TASKBAR_SHOW_LOG MENUITEM "Copy Log To Clipboard", IDC_TASKBAR_LOG POPUP "Set Log Level" BEGIN MENUITEM "Error", IDC_TASKBAR_LOG_LEVEL_ERROR MENUITEM "Warning", IDC_TASKBAR_LOG_LEVEL_WARNING MENUITEM "Note", IDC_TASKBAR_LOG_LEVEL_NOTE MENUITEM "Info", IDC_TASKBAR_LOG_LEVEL_INFO MENUITEM "Debug", IDC_TASKBAR_LOG_LEVEL_DEBUG MENUITEM "Debug1", IDC_TASKBAR_LOG_LEVEL_DEBUG1 MENUITEM "Debug2", IDC_TASKBAR_LOG_LEVEL_DEBUG2 END MENUITEM "Reload Configuration", IDC_RELOAD_CONFIG MENUITEM "Force Reconnect", IDC_FORCE_RECONNECT MENUITEM "Reset", ID_SYNERGY_RESETSERVER MENUITEM SEPARATOR MENUITEM "Quit", IDC_TASKBAR_QUIT END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_TASKBAR_STATUS DIALOG 0, 0, 145, 60 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_TASKBAR_STATUS_STATUS,3,3,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER LISTBOX IDC_TASKBAR_STATUS_CLIENTS,3,17,139,40,NOT LBS_NOTIFY | LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP END ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK." IDS_INIT_FAILED "Synergy failed to initialize: %{1}" IDS_UNCAUGHT_EXCEPTION "Uncaught exception: %{1}" END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED synergy-1.8.8-stable/src/cmd/synergyp/tb_error.ico000066400000000000000000000004761305627404700222430ustar00rootroot00000000000000((   : 袠 :0 ~~ && ff~~p &&໻f`~~ && ff~p& f`synergy-1.8.8-stable/src/cmd/synergyp/tb_idle.ico000066400000000000000000000004761305627404700220270ustar00rootroot00000000000000((  9 9:虘90 9 y) iyi`y~& 癙fy f`0 psynergy-1.8.8-stable/src/cmd/synergyp/tb_run.ico000066400000000000000000000004761305627404700217160ustar00rootroot00000000000000((  :: :::::0袢:p fpp && ff`~~&&& fff~~&& f` 0synergy-1.8.8-stable/src/cmd/synergyp/tb_wait.ico000066400000000000000000000004761305627404700220560ustar00rootroot00000000000000((  :: :::::0袢::~~&&ff~~p&&ff`~~~&&& fff~~&& f`synergy-1.8.8-stable/src/cmd/synergys/000077500000000000000000000000001305627404700177255ustar00rootroot00000000000000synergy-1.8.8-stable/src/cmd/synergys/.gitignore000066400000000000000000000000071305627404700217120ustar00rootroot00000000000000/*.aps synergy-1.8.8-stable/src/cmd/synergys/CMakeLists.txt000066400000000000000000000031231305627404700224640ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . set(sources synergys.cpp ) if (WIN32) file(GLOB arch_headers "MSWindows*.h") file(GLOB arch_sources "MSWindows*.cpp") list(APPEND sources resource.h synergys.ico synergys.rc tb_error.ico tb_idle.ico tb_run.ico tb_wait.ico ) elseif (APPLE) file(GLOB arch_headers "OSX*.h") file(GLOB arch_sources "OSX*.cpp") elseif (UNIX) file(GLOB arch_headers "XWindows*.h") file(GLOB arch_sources "XWindows*.cpp") endif() list(APPEND sources ${arch_sources}) list(APPEND headers ${arch_headers}) if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ../../lib/ ) if (UNIX) include_directories( ../../.. ) endif() add_executable(synergys ${sources}) target_link_libraries(synergys arch base client common io mt net ipc platform server synergy ${libs} ${OPENSSL_LIBS}) if (CONF_CPACK) install(TARGETS synergys COMPONENT core DESTINATION bin) endif() synergy-1.8.8-stable/src/cmd/synergys/MSWindowsServerTaskBarReceiver.cpp000066400000000000000000000231711305627404700264530ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergys/MSWindowsServerTaskBarReceiver.h" #include "resource.h" #include "server/Server.h" #include "platform/MSWindowsClipboard.h" #include "platform/MSWindowsScreen.h" #include "arch/win32/ArchTaskBarWindows.h" #include "arch/win32/ArchMiscWindows.h" #include "arch/Arch.h" #include "base/EventQueue.h" #include "base/IEventQueue.h" #include "base/log_outputters.h" #include "base/EventTypes.h" // // MSWindowsServerTaskBarReceiver // const UINT MSWindowsServerTaskBarReceiver::s_stateToIconID[kMaxState] = { IDI_TASKBAR_NOT_RUNNING, IDI_TASKBAR_NOT_WORKING, IDI_TASKBAR_NOT_CONNECTED, IDI_TASKBAR_CONNECTED }; MSWindowsServerTaskBarReceiver::MSWindowsServerTaskBarReceiver( HINSTANCE appInstance, const BufferedLogOutputter* logBuffer, IEventQueue* events) : ServerTaskBarReceiver(events), m_events(events), m_appInstance(appInstance), m_window(NULL), m_logBuffer(logBuffer) { for (UInt32 i = 0; i < kMaxState; ++i) { m_icon[i] = loadIcon(s_stateToIconID[i]); } m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR)); // don't create the window yet. we'll create it on demand. this // has the side benefit of being created in the thread used for // the task bar. that's good because it means the existence of // the window won't prevent changing the main thread's desktop. // add ourself to the task bar ARCH->addReceiver(this); } void MSWindowsServerTaskBarReceiver::cleanup() { ARCH->removeReceiver(this); for (UInt32 i = 0; i < kMaxState; ++i) { deleteIcon(m_icon[i]); } DestroyMenu(m_menu); destroyWindow(); } MSWindowsServerTaskBarReceiver::~MSWindowsServerTaskBarReceiver() { cleanup(); } void MSWindowsServerTaskBarReceiver::showStatus() { // create the window createWindow(); // lock self while getting status lock(); // get the current status std::string status = getToolTip(); // get the connect clients, if any const Clients& clients = getClients(); // done getting status unlock(); // update dialog HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS); SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str()); child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_CLIENTS); SendMessage(child, LB_RESETCONTENT, 0, 0); for (Clients::const_iterator index = clients.begin(); index != clients.end(); ) { const char* client = index->c_str(); if (++index == clients.end()) { SendMessage(child, LB_ADDSTRING, 0, (LPARAM)client); } else { SendMessage(child, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)client); } } if (!IsWindowVisible(m_window)) { // position it by the mouse POINT cursorPos; GetCursorPos(&cursorPos); RECT windowRect; GetWindowRect(m_window, &windowRect); int x = cursorPos.x; int y = cursorPos.y; int fw = GetSystemMetrics(SM_CXDLGFRAME); int fh = GetSystemMetrics(SM_CYDLGFRAME); int ww = windowRect.right - windowRect.left; int wh = windowRect.bottom - windowRect.top; int sw = GetSystemMetrics(SM_CXFULLSCREEN); int sh = GetSystemMetrics(SM_CYFULLSCREEN); if (fw < 1) { fw = 1; } if (fh < 1) { fh = 1; } if (x + ww - fw > sw) { x -= ww - fw; } else { x -= fw; } if (x < 0) { x = 0; } if (y + wh - fh > sh) { y -= wh - fh; } else { y -= fh; } if (y < 0) { y = 0; } SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh, SWP_SHOWWINDOW); } } void MSWindowsServerTaskBarReceiver::runMenu(int x, int y) { // do popup menu. we need a window to pass to TrackPopupMenu(). // the SetForegroundWindow() and SendMessage() calls around // TrackPopupMenu() are to get the menu to be dismissed when // another window gets activated and are just one of those // win32 weirdnesses. createWindow(); SetForegroundWindow(m_window); HMENU menu = GetSubMenu(m_menu, 0); SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE); HMENU logLevelMenu = GetSubMenu(menu, 3); CheckMenuRadioItem(logLevelMenu, 0, 6, CLOG->getFilter() - kERROR, MF_BYPOSITION); int n = TrackPopupMenu(menu, TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, 0, m_window, NULL); SendMessage(m_window, WM_NULL, 0, 0); // perform the requested operation switch (n) { case IDC_TASKBAR_STATUS: showStatus(); break; case IDC_TASKBAR_LOG: copyLog(); break; case IDC_TASKBAR_SHOW_LOG: ARCH->showConsole(true); break; case IDC_RELOAD_CONFIG: m_events->addEvent(Event(m_events->forServerApp().reloadConfig(), m_events->getSystemTarget())); break; case IDC_FORCE_RECONNECT: m_events->addEvent(Event(m_events->forServerApp().forceReconnect(), m_events->getSystemTarget())); break; case ID_SYNERGY_RESETSERVER: m_events->addEvent(Event(m_events->forServerApp().resetServer(), m_events->getSystemTarget())); break; case IDC_TASKBAR_LOG_LEVEL_ERROR: CLOG->setFilter(kERROR); break; case IDC_TASKBAR_LOG_LEVEL_WARNING: CLOG->setFilter(kWARNING); break; case IDC_TASKBAR_LOG_LEVEL_NOTE: CLOG->setFilter(kNOTE); break; case IDC_TASKBAR_LOG_LEVEL_INFO: CLOG->setFilter(kINFO); break; case IDC_TASKBAR_LOG_LEVEL_DEBUG: CLOG->setFilter(kDEBUG); break; case IDC_TASKBAR_LOG_LEVEL_DEBUG1: CLOG->setFilter(kDEBUG1); break; case IDC_TASKBAR_LOG_LEVEL_DEBUG2: CLOG->setFilter(kDEBUG2); break; case IDC_TASKBAR_QUIT: quit(); break; } } void MSWindowsServerTaskBarReceiver::primaryAction() { showStatus(); } const IArchTaskBarReceiver::Icon MSWindowsServerTaskBarReceiver::getIcon() const { return static_cast(m_icon[getStatus()]); } void MSWindowsServerTaskBarReceiver::copyLog() const { if (m_logBuffer != NULL) { // collect log buffer String data; for (BufferedLogOutputter::const_iterator index = m_logBuffer->begin(); index != m_logBuffer->end(); ++index) { data += *index; data += "\n"; } // copy log to clipboard if (!data.empty()) { MSWindowsClipboard clipboard(m_window); clipboard.open(0); clipboard.emptyUnowned(); clipboard.add(IClipboard::kText, data); clipboard.close(); } } } void MSWindowsServerTaskBarReceiver::onStatusChanged() { if (IsWindowVisible(m_window)) { showStatus(); } } HICON MSWindowsServerTaskBarReceiver::loadIcon(UINT id) { HANDLE icon = LoadImage(m_appInstance, MAKEINTRESOURCE(id), IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR); return static_cast(icon); } void MSWindowsServerTaskBarReceiver::deleteIcon(HICON icon) { if (icon != NULL) { DestroyIcon(icon); } } void MSWindowsServerTaskBarReceiver::createWindow() { // ignore if already created if (m_window != NULL) { return; } // get the status dialog m_window = CreateDialogParam(m_appInstance, MAKEINTRESOURCE(IDD_TASKBAR_STATUS), NULL, (DLGPROC)&MSWindowsServerTaskBarReceiver::staticDlgProc, reinterpret_cast( static_cast(this))); // window should appear on top of everything, including (especially) // the task bar. LONG_PTR style = GetWindowLongPtr(m_window, GWL_EXSTYLE); style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST; SetWindowLongPtr(m_window, GWL_EXSTYLE, style); // tell the task bar about this dialog ArchTaskBarWindows::addDialog(m_window); } void MSWindowsServerTaskBarReceiver::destroyWindow() { if (m_window != NULL) { ArchTaskBarWindows::removeDialog(m_window); DestroyWindow(m_window); m_window = NULL; } } BOOL MSWindowsServerTaskBarReceiver::dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM) { switch (msg) { case WM_INITDIALOG: // use default focus return TRUE; case WM_ACTIVATE: // hide when another window is activated if (LOWORD(wParam) == WA_INACTIVE) { ShowWindow(hwnd, SW_HIDE); } break; } return FALSE; } BOOL CALLBACK MSWindowsServerTaskBarReceiver::staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // if msg is WM_INITDIALOG, extract the MSWindowsServerTaskBarReceiver* // and put it in the extra window data then forward the call. MSWindowsServerTaskBarReceiver* self = NULL; if (msg == WM_INITDIALOG) { self = static_cast( reinterpret_cast(lParam)); SetWindowLongPtr(hwnd, GWLP_USERDATA, lParam); } else { // get the extra window data and forward the call LONG_PTR data = GetWindowLongPtr(hwnd, GWLP_USERDATA); if (data != 0) { self = static_cast( reinterpret_cast(data)); } } // forward the message if (self != NULL) { return self->dlgProc(hwnd, msg, wParam, lParam); } else { return (msg == WM_INITDIALOG) ? TRUE : FALSE; } } IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) { ArchMiscWindows::setIcons( (HICON)LoadImage(ArchMiscWindows::instanceWin32(), MAKEINTRESOURCE(IDI_SYNERGY), IMAGE_ICON, 32, 32, LR_SHARED), (HICON)LoadImage(ArchMiscWindows::instanceWin32(), MAKEINTRESOURCE(IDI_SYNERGY), IMAGE_ICON, 16, 16, LR_SHARED)); return new MSWindowsServerTaskBarReceiver( MSWindowsScreen::getWindowInstance(), logBuffer, events); } synergy-1.8.8-stable/src/cmd/synergys/MSWindowsServerTaskBarReceiver.h000066400000000000000000000036661305627404700261270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/ServerTaskBarReceiver.h" #define WIN32_LEAN_AND_MEAN #include class BufferedLogOutputter; class IEventQueue; //! Implementation of ServerTaskBarReceiver for Microsoft Windows class MSWindowsServerTaskBarReceiver : public ServerTaskBarReceiver { public: MSWindowsServerTaskBarReceiver(HINSTANCE, const BufferedLogOutputter*, IEventQueue* events); virtual ~MSWindowsServerTaskBarReceiver(); // IArchTaskBarReceiver overrides virtual void showStatus(); virtual void runMenu(int x, int y); virtual void primaryAction(); virtual const Icon getIcon() const; void cleanup(); protected: void copyLog() const; // ServerTaskBarReceiver overrides virtual void onStatusChanged(); private: HICON loadIcon(UINT); void deleteIcon(HICON); void createWindow(); void destroyWindow(); BOOL dlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); static BOOL CALLBACK staticDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); private: HINSTANCE m_appInstance; HWND m_window; HMENU m_menu; HICON m_icon[kMaxState]; const BufferedLogOutputter* m_logBuffer; IEventQueue* m_events; static const UINT s_stateToIconID[]; }; synergy-1.8.8-stable/src/cmd/synergys/OSXServerTaskBarReceiver.cpp000066400000000000000000000030641305627404700252310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergys/OSXServerTaskBarReceiver.h" #include "arch/Arch.h" // // OSXServerTaskBarReceiver // OSXServerTaskBarReceiver::OSXServerTaskBarReceiver( const BufferedLogOutputter*, IEventQueue* events) : ServerTaskBarReceiver(events) { // add ourself to the task bar ARCH->addReceiver(this); } OSXServerTaskBarReceiver::~OSXServerTaskBarReceiver() { ARCH->removeReceiver(this); } void OSXServerTaskBarReceiver::showStatus() { // do nothing } void OSXServerTaskBarReceiver::runMenu(int, int) { // do nothing } void OSXServerTaskBarReceiver::primaryAction() { // do nothing } const IArchTaskBarReceiver::Icon OSXServerTaskBarReceiver::getIcon() const { return NULL; } IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) { return new OSXServerTaskBarReceiver(logBuffer, events); } synergy-1.8.8-stable/src/cmd/synergys/OSXServerTaskBarReceiver.h000066400000000000000000000023221305627404700246720ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/ServerTaskBarReceiver.h" class BufferedLogOutputter; //! Implementation of ServerTaskBarReceiver for OS X class OSXServerTaskBarReceiver : public ServerTaskBarReceiver { public: OSXServerTaskBarReceiver(const BufferedLogOutputter*, IEventQueue* events); virtual ~OSXServerTaskBarReceiver(); // IArchTaskBarReceiver overrides virtual void showStatus(); virtual void runMenu(int x, int y); virtual void primaryAction(); virtual const Icon getIcon() const; }; synergy-1.8.8-stable/src/cmd/synergys/XWindowsServerTaskBarReceiver.cpp000066400000000000000000000031621305627404700263410ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergys/XWindowsServerTaskBarReceiver.h" #include "arch/Arch.h" // // CXWindowsServerTaskBarReceiver // CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver( const BufferedLogOutputter*, IEventQueue* events) : ServerTaskBarReceiver(events) { // add ourself to the task bar ARCH->addReceiver(this); } CXWindowsServerTaskBarReceiver::~CXWindowsServerTaskBarReceiver() { ARCH->removeReceiver(this); } void CXWindowsServerTaskBarReceiver::showStatus() { // do nothing } void CXWindowsServerTaskBarReceiver::runMenu(int, int) { // do nothing } void CXWindowsServerTaskBarReceiver::primaryAction() { // do nothing } const IArchTaskBarReceiver::Icon CXWindowsServerTaskBarReceiver::getIcon() const { return NULL; } IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events) { return new CXWindowsServerTaskBarReceiver(logBuffer, events); } synergy-1.8.8-stable/src/cmd/synergys/XWindowsServerTaskBarReceiver.h000066400000000000000000000023771305627404700260150ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/ServerTaskBarReceiver.h" class BufferedLogOutputter; class IEventQueue; //! Implementation of ServerTaskBarReceiver for X Windows class CXWindowsServerTaskBarReceiver : public ServerTaskBarReceiver { public: CXWindowsServerTaskBarReceiver( const BufferedLogOutputter*, IEventQueue* events); virtual ~CXWindowsServerTaskBarReceiver(); // IArchTaskBarReceiver overrides virtual void showStatus(); virtual void runMenu(int x, int y); virtual void primaryAction(); virtual const Icon getIcon() const; }; synergy-1.8.8-stable/src/cmd/synergys/resource.h000066400000000000000000000031051305627404700217240ustar00rootroot00000000000000//{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by synergys.rc // #define IDS_FAILED 1 #define IDS_INIT_FAILED 2 #define IDS_UNCAUGHT_EXCEPTION 3 #define IDI_SYNERGY 101 #define IDI_TASKBAR_NOT_RUNNING 102 #define IDI_TASKBAR_NOT_WORKING 103 #define IDI_TASKBAR_NOT_CONNECTED 104 #define IDI_TASKBAR_CONNECTED 105 #define IDR_TASKBAR 107 #define IDD_TASKBAR_STATUS 108 #define IDC_TASKBAR_STATUS_STATUS 1000 #define IDC_TASKBAR_STATUS_CLIENTS 1001 #define IDC_TASKBAR_QUIT 40003 #define IDC_TASKBAR_STATUS 40004 #define IDC_TASKBAR_LOG 40005 #define IDC_RELOAD_CONFIG 40006 #define IDC_FORCE_RECONNECT 40007 #define IDC_TASKBAR_SHOW_LOG 40008 #define IDC_TASKBAR_LOG_LEVEL_ERROR 40009 #define IDC_TASKBAR_LOG_LEVEL_WARNING 40010 #define IDC_TASKBAR_LOG_LEVEL_NOTE 40011 #define IDC_TASKBAR_LOG_LEVEL_INFO 40012 #define IDC_TASKBAR_LOG_LEVEL_DEBUG 40013 #define IDC_TASKBAR_LOG_LEVEL_DEBUG1 40014 #define IDC_TASKBAR_LOG_LEVEL_DEBUG2 40015 #define ID_SYNERGY_RELOADSYSTEM 40016 #define ID_SYNERGY_RESETSERVER 40017 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 109 #define _APS_NEXT_COMMAND_VALUE 40018 #define _APS_NEXT_CONTROL_VALUE 1003 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif synergy-1.8.8-stable/src/cmd/synergys/synergys.cpp000066400000000000000000000025711305627404700223210ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ServerApp.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/EventQueue.h" #if WINAPI_MSWINDOWS #include "synergys/MSWindowsServerTaskBarReceiver.h" #elif WINAPI_XWINDOWS #include "synergys/XWindowsServerTaskBarReceiver.h" #elif WINAPI_CARBON #include "synergys/OSXServerTaskBarReceiver.h" #else #error Platform not supported. #endif int main(int argc, char** argv) { #if SYSAPI_WIN32 // record window instance for tray icon, etc ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif Arch arch; arch.init(); Log log; EventQueue events; ServerApp app(&events, createTaskBarReceiver); return app.run(argc, argv); } synergy-1.8.8-stable/src/cmd/synergys/synergys.ico000066400000000000000000010622761305627404700223220ustar00rootroot00000000000000 ( V00 %~   &F V hV`( 2(OOOcyԀԀՃՃՀ~YE;2;2 2OրcY; 2Y׀щʾzzz|z~v{zsz}ry|rzzw{|x}{}~|~ЉycEEـwjxv_tqXqmId`JeaNgcUjgZmj_mk]ki]hfgromtqkrmgkfejalmdlnbmk`hgYgfXgeZki^sqg}{q{ÿ~;(2cѐ{stumnljjgii]hfZhfWliTmib}yotushomclj`ih^gf\fgcklhvwsӃEY~ܳ{outckjYa`FjdEvnU\]`ecjŶtѼȳ~qsm`b\]_Ycd`nok|}yΐc2(c˥otschgagfkqpu}|yqzǿľ|{|xstpjkgefbmnjz{w~O;Yy|zdolWni@ib5jaC}f~omlj^VMIIDBCPl۷զԙӋӇֆ؈ՐԗҠգ߭ٯԳĪzndrhangdokjxywſӃEyĻrnm][ZUXV\gdxxhffdZRIFFA?AMiձϠΓΆ΂ЀсΉˎɗ̑̚՚ڨخԳжɷxtsUVTZ][jqn}ΐщY Oΐ~Xoj8ZTFumcbgr|udRMB2144-)((,0/4E`{޷סҍ}mc]]`cgnt{~Յ؋ٕ޳ִĻ{upc\Yjefͥy2 EûszwZebczucuraWNK@0/33-)((,0/4E`{ݶ՟ь|lb[[^`cjvuqx~Ʌɍʕִ͢{xxstlllddd|{}Y;Y֐tywKmg?vm=xpnjTG:5/.)" #"(("""%*109Fb|ڵўψyk\UUWY]a_abbbcgnqԎםܬ߼ٺưe`Wlj`yupХnOԚxinl]b`nn_LA74,&! "!&& "(/-6C_yسН͆whXQRTW[_^bc``dinuxȂŋ’˨ԵDZ˽þea\ZXW|y{y(nVmiJnhhxrukXN>90(('&)*+/-022**('0216?Wm۽ԯ̙Ƅtg_Z[`bhid`^ZX[XV[]fstzփړ٩سسļ{vgge[}|׉O EϚ·ywwfqog~zyĽmgYP:4)%'(&''&(*.0/('&$ֿ+׿-վ+׻1ؽ:ڼRٿhշΩƓտ}ڽld[VW\_ܾeܾe]\^]YWVYYbcgnttǀͨ͝ϪϸljimlnY;͚_qpOplavĹ}zdD<73,)'&'++-,.-,&ڽ%ټ&ָ&ָظ׷յҳ$Ю%ѯ%ԯ&հ1ײDٷT޼|ڼٶٲ֦ϗŃҾqӻcӼYӺTѸPѸPӺTԹWַZնYԾUWZ\[\Z[\\\]^__^q{҆Ֆ٠ϭqtqi~}ڐ; ~glmpznZA962,)''%)(+)+׿*־)ս!ոӶ"Ҵ"ҴԴӳѱͮ!ͫ"ά Ϫ Ϫ)Ϫ;ЮKճsҷԶүЩ̜Čȼzʶi̴\̵RεOʹLʹLεOϴRѲUҳVϹPкQҼSӽT־TVWYYYZ[\]]]pw~Ɋ˒֪ڸ̵omluu{܉Y2րĿhvuTwsVetgV?5-('%$$$#'%ۼ(ۼ'ڹ&ٸ%ط#ֵճԲԬѪЩϨЧΥˣ!ȡ)ğ.Ġ-Ɵ2Ơ9ǢLʧ`ά}ͰδɰȫĜzj_TNIIHīKɭN˯PɴKʵL̶M͵QζRѸXֺ[ؼ]ۿ`a`_]^]]_`ems̀Փܧۯƥ{wlwtpِOԃwwwftswwVH<6.('$#"!ܽ!ٻ!׸$׸#ֵ!ԳұЯϭͫΦ̥ʣȡȟǞŝÜ&,ž.Ǡ7˥AϪVԱkٷػ׽ԻԷҪ˛ˆʹv˴iYOGCACF¦GîEįFDZHɱM˳O̳SдUдUԸYֺ[ռZZYZZZ]_`irvȓ̠ٸѹ|xmlpɰE(ΐ]xuXsvm\F.+($$+*&%ݿ#ܼ!ں ׵!Գ"ԯ$Ӯ%Ҭ"ϩΦˣʟɞ Ř&×'–&'–)Ę1›=OŢWȦ]έfӳpعؼϮǞÓι˳ymc]WSNHHIKèNŪPɫR˭TˮSͰUδVжXҹWԻYֿ[\YZUZbfhy~Бڦذswte}ǽO ;ԀgxuieO?0,'!!&ܾ%۽"ڼ غظյӱЯϪͨ˥ɣǟŝŚę$'–)Ę-Ȝ1̠<ͦJΩ[ѮbӱgطoܼxֵҩРʓŋԿӻyҹsϴjŪ`¤WHFCBDHåLƨOŨMǪOɯQ˱SʹRзUһWԽYSYWX]cfu|ąɕ֮ټüwum{{{E2ΐa|xZpyhNB51/+*(%ؿ*ֺ)չ$Զ"Ҵ!ұЯΩ ̨ ɢ!Ơ#ś#%%%%4:˜?śBȞEͣIѧRӬ`ԯpӳrյu׹y۽ٽԶϮͨƠĚؼӴ}ЮsǧfŢ^VNIHHGF§EƬHȮJȰLʲN͵QиT̼RXWVWVV[bq}ŇОٲÞuuuʥY ҃suun¹v\H=353('׿'$׾(Ը'ӷ!ѳϱέ̫ʥȤŞœ""#$7ę=śCɟF̢GϥJҨRӬ^ҭpӳrյtָwٻշέ˦ĞÙؿٽعض{׷vԱm˩c¢WNHD?@@B¨DªFëGƮJɱMɹOʺP˼NҾQUWY\_kzΧֱʵtttwwwO OՉJ}uIr;z_>1*''(ܿ'۾'ݻ$ڸ!ضִ$ժ&Ҩ"Ш#̥ ɢ şÚ!! $'+đ.ǔBŤKƦPȩUʫ[˩ZʨXʥSʤP̢OˡP̠VϣaѢiУpը׭ֳԴӬͥƙһҶѳzϱvΰu̴xи|ηϷѶβѱ̬ʬ{ŪqaTLC@ADFHŢLɤO˦QŮHȱK̴PϷSѹUԼXX[[[`go{Պۢȷt||nɰڀ(Yz|isȺnN@6%ֻ%ھ%ھ$ػ#׺!׵ճѯϭΣˡɡŞÜ!'+Ò/ȕ2˘AģG¢HKQPMG@=:@FIŨMȫPʭR̯TϴRѸRӽTԾUW\ӿ`Կdjw̔ݹѯt|А(Oevssk]LտA.ؼ!ո'۾"ع ַ Ӳ!Яά˩ʥȣŚØ &.1777-*&}#z yz{{}#1AĒHȗ]ɛ̚Ǘőxk[SEBA@;99~7ACJPSXƠ_Ơ_ş^œ[RI?=:=BDG¥JŨMȫP˰NʹNϹPѻRнTӿZҾ_Ӿcӿgսq̻Ȥӱη~}y~(nȽcxuYxǹvUH8׽,Ӹ)ܽ&ܽյӳԱ ү"ϩ#˦"ɢƟě™ $(**,+*yyzz|"&,/7>JVgpƨƬ˯ɬƪ{rf^ZUPOLH758>@ITÖYÖYėZXQF?;=@DGJKĢOǧNɪM̱OεOϹPѻRӾUW[]gv̍ԩʮzz~(щyzplLB9ؾ-Թ%ع"عֶԴүЭ̦ ȣŞ›"#$#$|%}%} x{$+0Ď8ǖ@ϞLѦX֬hٴvܹƽظЮˤǝվϴȭu¤i_[VP@;998=DFKPTRIA;:<@BFGJ¢IĥHȭKʱK˵LͷNιPҽTҿXӾ[ҿdӾsąØѵcϐ~fxc?ڿ/%׺"ع$ڻ׵ӱԮ կϧ!̥#ʟ$Ɯ"Ö|!|!{!{!{ }||z}'2?Q¡dƨuɱθοY( ((n̚Ѿǰ}re\QE=84;>CHKJGF>?@CEHIHĥJȪKɮL˲L˵KϹOҾQӿRӾQYi{̗մɼz( Yvy\>پ-ھ$ֹ!׸ ַҰҰҬȢȠƟę}|yzyxtxxz{$)5ś@ƢQϬhٸc22YyщӶťαȪ{oaRH@:989>DGGF;<<>@CCBB¤EŪHƭGDZG˵KϻNмOӾQѻRϺ_Ҿw˻ǦҼyԀ EZ{bcI;ٻ.ٹ#ٷ!׵ղӰҬϪ̤ʞƘ Ö{{yzxutuwy#}+19CVɨƾn(Yĺs_QGB:778?EG=<;:<8};?@9999:ػ0ݽ%Ҳ(ӳ'Ҳ!ѬϪ̦ɣƝÚ~}zytsvx{#2Mǡgӯ(O˥ٳïjWKB<667574369>@ADCDFĨIŬJǮL˵LͷN˸QʸYɻiʽ–ȯ¿Հ ؀rg{lCټ0ַ%״"Ա ү ά"ϩ#˦"ɠ"Ɲ#Ù# ~|zyxwuuy~%4AVpƮԀʼ~dTHA}:}:874358<>ACCCDGN§PǮNαNϳNѵPѹYϻf}ɓѪ~(2sŹd=Ӷ/նѮ%״ үɧ˥ ȣŜ™|{yxxwvvz~&;Pƣjβ2Oƽġ{_ME>}:~663248:;>@?@@BKLīK̯LβMϳNζV˷bȹtÍʣǯc(щup{cF׻9Ӷ.Ѳ(Ϯ&ҰͪʧȞŜ—~|zyxxwwwz%:Qrƪc~ϱƸs[PF>;43368:<>==<>IKĤK̪MӭMԮNӲQзUųZοvNjӪ½Ⱦ(Yʾyc?д7Ѵ&ɪ)ЯʨŢ˨Ɯ™}|{yxxwwwx0KǛfЬc2 ~޴n[NC=631457:<:98:DFFǥHΨHЪJϮM˲PųZĵlû™̳n EՀxhb9ܽ*ڵ%հ)Ϫ&̧%̥#ʣ!Ǟ!š%Í#~ x wts vxw$>V~ű;~_OC2~08{5}572446<=?BGKM©MƮJͰM̯LػXջaĂƗƯ2nvŷ[4׸'ײ#Ӯ'ͨ$ʥ#ʣ!ȡě#!} y wts v yz,J£kѵnsYI737{5}571235;==@DHJJĬHˮKˮKҵRδZҼz“ĭYϰwJܾ.ѱ&Ү"Ϊ$ˤ"ɢ!ȟŜ—}ytussy}#;`˸(ΐʾ{cG<9~5~9:89878:;=BEFG¦GũJʭKʭKȮTʹnпß˰OOzAӵ,ϯ"Ϊ˧"ɢ ǠŜ™{xtust{!,Gsеy2ĚëwRB=9:~97875478:>@BCD¦GȫIǪHƬRƭgȷ̼ϴ~փvXؿ0ϭ,Э#̥!ʣ!ǞŜę~|zywv!t"uty&Gwȯc щ˿xZGB:}8y;{=~;83568=?@DDEȨIȨIȫPêZŰl̻ɕĻɰ2쎟ʾtӿMʹ,˩*Ϋ ɢǠŜ™}{zyvu s st{!-T̩2ٽ˹iME;}8x:{=~;~72545;==AABťFƦGƩNTfƵ|ʼ˪cc³pѽRغ2ά$ʥ%˦#Ǟ!Ŝė~}zyutrrrvy%=eê(ƽkQ?9|6{9{9{86724:<>BCDDàFŦKM«[ưhκsϔӃ˼l͹Q׹2ά"ȣ!Ǣ"Ɲ ě•}|zyutrqt!y"~-IȡtҹyOȪy]F>~8{9z8y6~45139;=AABACĥJMì\`˷p‡(Eƶu׿Rָ/ѭ$ʥǝȞ Ö |z w s pqqsw1V̷EYħwSE:5}6}:<~:228;>@AA@AEINS̲^ӻoœŮՀ~ŵsսOӵ+ͩ!ǢƜƜ•~{z w s pqrux#9`Ǩ ܿͿ^L=8~7}:;~:227:<>??=?BFKPǭYζjƻɰ(Ͱtl̴^غ9Ѯ!ʣŞÚė{y zy t sssuy4_̼ېEг^E>7|3{8{85469;<>?@?BFGJɫRҳ^μ OY|nζZԶ3˨Ɵĝ™~zxyx s s rsu{&<ÛkͯcĖkLC:}4z7|954689:<=>>@DFHŧNˬWǵʾå؃Րu˳V׸CӰ*Ǣěě!• ~|ywywssrsz$>hê߉п³kSC7~467667899<;=@CDFŠKɣQêjȷȠ((|ҺUַ=ͪ&ÞÚ™|{xvywrsst}*DÜq̳cϐ¢w[F8~4~46~5~57887:9<>ACEHşMe±ƞOEfԸHӲ,ɤ$"˜~| zyu t wu#r$s tv'1bè߃ǽqR:/,}6|5~576669;=>@CFÛIĜJ]ïv¸~cbдBͬ(Š"!}{yxu s wu#r%t!u!y+6ęj˰cԀɹzX?2-|5{4}4666588:;=@DFGWnȸŻylʲ@ֲ4ʦ*Ü& }{yxvuurrq)x/3EǦû( OǹrT100}2}24778:;<<>>AACM̥aȲpŖ;̚rи<Ү1ǣ'$|zyxvvwttt-|4:MϮn (ƽ{[621~3~3576799;:=@BDƟUaμû~;~ijgе6ʤ,&$}|zxvuuuurvy,@PǠyؽyEμkF;74}4676~7~7898;:<>@C›Q\ȶƾ݀ OnȱPͭ,˟#–|{xwuuttvsw~,IsǪ;ʥwVC96}4~5~7~7~7~789:<;==?BFT¯rȽynȱLɩ)Ȝ!{zxvutttusx/M›wˮԀƿ~]H:6|3}4~7~7~7~7799;:<<>BBSkø( Ӄ|Z˯>ʥ'ŗ~{yxutssssrs{!5Uáɷ֐;ɷnS<7}2}2~5~5~5667689:;<>=OdĶú( ~Yʮ<ȣ$”}{xwutsstttu}%9ZȦμۃѿrU>8~3}2}4}4~5~5566789:;:8M`Ļ2(ɳJͬ:Ǡ'#}zzwwttsssstv~3BfĬE}`B6|144~3444434578:9?FUijzøƿY(ʴJͬ9Ɵ&"}zzwwttsssstv 4ChƮ2 ͚ûdD8}244~3443434578:9>ETwĽc;ʴMͪ4Ɯ!~{{xxwwvvvvx x*BT´҉ yƿnJ=675566567879<==DGVuųĻyEĿʴL̩2Ě!||zyyxxxxx{$|.FWæĶՀYijsMA997788789:9;=?>DHVrIJúڀE½ʳP̨8˜+'$$#! ~ ~{{{z{{{{$|-~:Wt»~;Ÿ|TH@?=>@?=>?@ACEFGHMWqIJ؃ E½˴RΪ;ś-*'&&$##""!~!~!!!!&~0>[£vüy2ƹYMFDBCECBCDEEFHIKKQZqų ;¾ͷVҮKȠQMKJJIHHGFFFDDDD9Wwc ۹skfefccedddddeffgjpڰŽ2ՃuHt{8ip-gn+jl*jl*jl*hj(ij(ij(ij(hi'hj(ik)hl*im+om,mk*ns.q{5}OqY(ؾl^\[[[ZYYZZZZZ[\\^hx沛Y~k@qu.jn'ei"cg fj#de!de!cd cd cd cd cg cg dh!dh!df eg!em&ht,wImȿ2l]ZYYYXWXXXXXYZZ[]eu屚Eyaz;mq*fj#ae`dbfabab`a`a`a`a_c`d`d`dacceck$gs+wIn(ĵ縝mZWUVVUUUUUUVVWXXW\mϩ2 cr|Q{4jn#dg`c^a`c^`^`________]_]_^a^a]`^a_hdo)uIo ~ȹ縝mZVSTUTTTTTUUVWWXWZkӭـsyNx|1hl!cf`c^a`c]_]_^^^^^^^^\^]_]`]`\_]`^gdo)vJr̚ cⷢr[WSSTTSSSTTUVWXXSVf~䰠(ΚmyGxz.ikefbc_b`c]_^`]_]_\^\^\_]`]`]``aab`h!gq.zOxӃE乤u]XSSTTSSSTUVWXXXTWf|糣;EivDuw+hjefcd_b`c]_^`]_]_\^\^\_\_]`]`_`abai"is0}R|y滪~`ZUTUUTTSTVWXYYYTVcxc~]v?rv*eicgae_cac]a]a\`\`[_[_\_\_]a]a]^`_ci"lu2UîO 转﬑a[UTUTTSSTUWXYYYUVbu;Xr;qu)eidhbf`dac]a^b]a]a\`\`]`]`]a]a^_bafl%qz7Zʵ( nŷ᭠f[VVTTTSSSTWXXXZ`c`s|㻞АnrAy0sr"nmffeecebd_c_c]`]`]`]`^_^_a_a_]a[dai-pxIo(OͿ沥h]WWTTTSSSTVXXXZ^daoz彠O(Κp?w}.sr"mlggffdfbd_c^b]`]`]`]`^_^_`^a_[_\eem1u}Nvщ (߼nbYWSSRQQQTVXXYZ]b`ku゙˫ۃ Yya7tz(pq!klhhggdfbd^b^b]`]`^a]`^_^_^_^_Y`^i jr6{Wĵc ӃõreZXSSRQRQTVWXY[^aajsֶ2؀uW{2qw%op klhhhhegbd^b]a]`]`^a^a_`^_]^]^[bbm$px<];Yⱡ{j^WQQQPRQSVWWY[^_`ioѰ݃; c}dCy'sxoqkkiihhegbd^b]a]`]`^a]`\_\_\_\_[ddo)r{Be͚ ;跧n`XQQQORQSUWWY[_^ajo{©ۺy 2_>u~#qvoqlliihhdfac]a]a]`]`]`]`\_\_\_]`^gfq+xHpy Հ¸wf]TPOMQSSUWWWY\]aglvEjH0x|swoqllgjfidfac]a^b]`]`\^\^Z^[_\`^b_j$gt6Uϸ2nɿzh^TPOMQSSUWWWY[^bflxټ߃2ʞb@~-w{txoqllhkfice`b]a^b]`]`\^[]Z^[_]a_ccn(ly;] 黣sfWQNNQSTVWWVX\\`ehoz˳ʥ;ՃsI3~(vwvwnr knhkehcfbc`a__\^^`[_[_\_Z]Z_af!`l0vRoy ~whYQNMQSTVVWVX\\`ehnyȰįӐ ciC/|&vwuvnr kngjdgcfab`a^^]_^`[_Z^[^Z]Z_ch#ht8~Z}γ;Eɸ浛棄q_SNMRSUWWUSU]^bfhiqžѲέ{nOxpoN5'}~ wxtsmp jmfidgbeab`a^^]_]_Z]Z]Y^X]\dfn(oyJoʥᄂuaTPORSUWWTSU\^bfgip|ŦƲ}¼OO҃yvwdC1}${|xytsmp jmfidgbeab`a__\^]_Z][^Z_Z_`h"mu/xS|ĩyԀƵ㰖~gWQPRSUWVTQS\_aedfks|α廨ǽ2~|ohD.)"{{vzrtlqjmfjdgcfbc`a__\^\^Z][^Y`Y`aj'py6fY븞暈kYQORSUVVSPS\^`ccfkq|Ũʷα~}ΐӃuwqzX;+(!{{vzrtkpileicfbeab`a__]_\^Z]\_Za[ben+x>sՀщıu_UQSTUVVSPR\^`cbfjmvz˵}̚EԀyyyV6+#}~{{vzqsjogjdhbead`a_`^^^_]^[^]`\c ah%ox5Kǽ(nλ|dWRSTUVVSPR\^`bafjmtttt˥2(yrrruN.)"{|{{uyprinficgad`c_`^_]]^_]^[^^a`g$gn+y?WnYijs`YVTUTRTUS[]_bdhilrw~Ƥήлzx˥c2ېtwnjdžcB8+%$$y{!uv oriqbn`l`f```] c[c]c^\] `fYbVd_m+drb҃Ȱ櫋xk^Z_\XUWY]]^]`bfkovz~ˆĎÓƙȠ̧ѭմʶsaXNe\YypmփyYE2 (EOn~ЉssydfgWUTa_WŞʓԉu]G:1*%+*&&$"}|!|z"vw!poikggdgbe_d`d]^`a`dX_Xa[f _h)gp=zYϸ(;qa\`a^ZZZ\\][]_bglsvz~ėƞɤձѰѵtkhWPM_XUtpovuqkjfTTZZZ`wyzϨčp_L;1*&#''$$"~zyzx tuonhjggcf_b^cbfcdbcbf[d_j$ir3yOräЉ2ǽ廤榇qdbgfea][XXYZ\_flsuz|ŠƎȔƑ˙ѡЧӰ˻znxkwjsg]j`Vnf_rpfzvq~{vswkkq`ciV`fSfnWsv`zzhwաޗxaO>80)(''(%%$$"yytusr!kmjjgjghdf`a``ccgi#ac`d]e_h%dm5u|Ow~nй{haefhfa]XWXYY\cioqvy~ōǓɔ˙ϟЧЭϳҺxpf\f^Wig]kgbmjeokjqmluqpyut|xwtrqusrstrrsqpqopqoptoquphlfek``dXY_NZ`MoubͻϽť{eP8/)#!&'&$"" !}~ xxrsqpkmiicfabaccdhh"kk%jl&acaeai"en+mv>`Ȱnζsjfhklib]XWWX]bioqruy~Ljʋ͍̌̒͛ѦϬбԸӻӿͽ˺Ǻɹ|xngk_]eZVcWW\ZZZXXWWWZZZ[\X\]Y`d^gmbwâĞȟ͢ЀpaWH72-0.//.) }{y| uwornoilfh`b]^cdnm)sq0sq0fi$adcg%fn/qy=[ҽ(ʥ£~tfhkoojd\WVW\`gnonqv{~ƒÄʊ͍̒ʘˠȥǨ̰ϷмӼ˿ǭ˭̫ɣÚs`PF6/2&*+-+&!xv{uxrtlojkbebdacdeop({z6yw6pn-`cadhl*nv7Mw˫OyТkfgoyxyzni^XX]__jnqux{}Çȋʑ͕ЗҘәҝҢ֥ת٭ٲڳڷ޻߾ݗ؈|qh[PF?A<620.,-/.****%$}*wz$qvpultiqenek`eeg%kl.st6{|<|}=or-_cMeZr$av8wZĸ; ~뽵{oimy{{{uri`ZZ[\gikosx|ćƍȐ˒ΔЖΙ͝ПѤҦҫӬӰ״طٻ״ԤЕʄsg]TJB;662.++*(*&(''$ wz$vy#tyqvjrfndmgmlq&qs1~ALFtu5eh#_c%k5wNxɫcӃèzrsuvvyyxsnkgedgimpsuv|~ĉȍ̐Β͔͘ϗϛМРҟңңҧիִټ߲ٙՅq\NA<5...*+)'&'(&'&&&%## ~!qw os!kohkghjj$qq+xv5>BJIu|9bi&[d!bk(dv;{ZzĪn2ťwqrvy{zyz{{rkffegimprxz~Ŋɍˏ˒̗ϗϛМϟўѢСХҨԲ׺ޱ֖ЀkTI<60*+,)*)'&&&#$" y|tukqjnhljmqr(||6?GNOIvz8cj'^e"fo,qz7sJpÝϐ n뫒wons|tqligkostvz}NJʌ͏ВғғԓԓՖ՚֟קٱܻ۫ԍrV?1+(&).30'&%%$##$#"$}$w|!sv kqgkhpot)xy5~BPXYYZN|JV]cddce^WElq4`f+fo7p{IdԶ2˥Ϋ~wzwtuwy~~ƃȅʇʋʎ˗΢ѭ׵ոѠɃhO;,&#$%*-)"!~z~z|"{+~1=LZddeghdejk[Ill0hm0kq6vG`ݲnO﷤|žžœĞȪʵйػո֪ϖ{gP>/*%&$$ "~)-.15>KU]lwxvxwvwxukc[~@jr,ci0kn=y|UsȰ( nǽ}˜ś šǣǡǡȡȡɠǞǛƚ­ȱϲ̯̠ƍr]G6)%"&'**.;AGQ[eou}}||~~}pW~@lt.ks-sy@UwɰӃ˷㳗꧆ĞŨħ¤ƫȭƫʮ˯ͯϱввѱаѰЯϭ̪˦ȣǞƝڙĪdzɵж̲ʪĜwj^USSVX\aezzZq};ht2hv6s~FdιY~ӷƩʭ̮ȪŪƫǬŪʮ˯̮ͯϱвѱҲմ׶ڸ۹ܷڵٰ׮د׮կԱԷּۻذѠ͓ɉ~~Ɂˁ̓чԊ͑˓ɑŒ}_mv=am+lx6}KdܽO(̚䮗਋婌ĦгѴ̯ȯɯɳ˴˴ʵ̷θѻӽԾԹպ׿ٿټضӱ̪˩ʨɧƧäâģĞÝÜƙĕx}VhrCirGr|QeӃ(Ӄй믒樊쮐ǪҵռջҼййϺϺѻҼԾտپپ۾ڸִҰЮϭϭ̭ȩƥƥƠǡȡţá¤áȡˢ•}hv~Ogo@hrC{Yuֶ~(ϐкƨжӺԾۻ۵زӭέ̭̲̲ɴƳƳ˫˫ɫȪƪũĨ¦ϱάˤśmQpyAp|@OtƶEnۺ˪찒©ѻ޾߹ܶ۵մҳѷҸι̹˸ϯͭ˭ΰѵԸԸӷѳĢsVs{FxIWaxӨȰ2cɶ⹣⮗ìͶֽռԺӹԵԵԵնϾ־ؼ۷Ǖn}VuQrSvYo̚n2nʥ̵¬̷ٿٿܽ޿Ϊ™nZ{SuN~ZsЧ;ϐݿἦḡ浟DzҾصЫzhby\z`tcE~ʥϸ빣︣ȸqh|]}^myѲ̚n;~±빥﹢«ɲѺ޺ѫÝwom~ik{ȱy(OӃǽйʳﻤヲ齥©ȮʰͲеպپڼҴɩ}rljmqtҴщO;Yʹôݼ们纬뺬ﻮôѼ̷î~̲ջ˥yE (;YnՀЉʥƽƽǽƽƽӾҽӽѻʹɰεռ҃̚yY;??????????????????????????????????????????(0` 6j䞣ধ®r4 *}څwgkȁ'1pjfͼ`VMfګَ֕Κǿ󶸸,ǚiiǹYA-(#(MшYYgo؁ӛöȔ6soĸY8%&()!%ֺ=ڼԳxTZ^YW`tӖû:Vl\8$"%ڼ$ַѭͥɢ+ƢEЬջͨʷsëPIƭI̴NպX[Y^xКP\nP*$$عҰ ʤę"–6ƜHͦiӳѫеyƨ_LHƫKʹRTVeА[ukƸD$ھ#عѭɡ):ėF›C9IÕˣk^åiɧsƨiQDDĪI͵QտT]̀ƸY0kôD"عԲ ʥ˜ * z'9^ʥӳǡ跛aM>@PSA?JɫMϹOҾV}2rBֶѬȝ{vvFßޫؖm& F}èɷo?8B>>DĦH̵KӼOǁLJvB"ԲΨ Ěxt{FZAΧi=55:CFɯK͹RƇɉ,]Խ(Գ̧Ù}xu#vϴvRǹ槅F34<=HͬKϷZ!ħp+ص"ɤ–vt'2Ž˫B}267?GȬGӻj˖"Vз˥Ù~xr~ҹ:̼ئ@z866?DƪRȺvy.ЬęxqwdȪM/{6|74=@Eʳdm¿UˮǞztq8هʆU}4~59=@ťLŴ2:̩{vry}Ϲ ĵ੄8}169>CŬn0\vð)ŝyus5۟ʒU~/68;=ãV`цZè{uswZŠ<@x5}479;F؏δHĢ~wsq}Ͷ<|1447Cai%\gN{|vw}ɇ͎өըL $! }, ۼΩ˜!.68oˢa_[KEɮLUu}5;پղƜxz ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include \r\n" "\0" END 3 TEXTINCLUDE BEGIN "\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_SYNERGY ICON "synergys.ico" IDI_TASKBAR_NOT_RUNNING ICON "tb_idle.ico" IDI_TASKBAR_NOT_WORKING ICON "tb_error.ico" IDI_TASKBAR_NOT_CONNECTED ICON "tb_wait.ico" IDI_TASKBAR_CONNECTED ICON "tb_run.ico" ///////////////////////////////////////////////////////////////////////////// // // Menu // IDR_TASKBAR MENU BEGIN POPUP "Synergy" BEGIN MENUITEM "Show Status", IDC_TASKBAR_STATUS MENUITEM "Show Log", IDC_TASKBAR_SHOW_LOG MENUITEM "Copy Log To Clipboard", IDC_TASKBAR_LOG POPUP "Set Log Level" BEGIN MENUITEM "Error", IDC_TASKBAR_LOG_LEVEL_ERROR MENUITEM "Warning", IDC_TASKBAR_LOG_LEVEL_WARNING MENUITEM "Note", IDC_TASKBAR_LOG_LEVEL_NOTE MENUITEM "Info", IDC_TASKBAR_LOG_LEVEL_INFO MENUITEM "Debug", IDC_TASKBAR_LOG_LEVEL_DEBUG MENUITEM "Debug1", IDC_TASKBAR_LOG_LEVEL_DEBUG1 MENUITEM "Debug2", IDC_TASKBAR_LOG_LEVEL_DEBUG2 END MENUITEM "Reload Configuration", IDC_RELOAD_CONFIG MENUITEM "Force Reconnect", IDC_FORCE_RECONNECT MENUITEM "Reset Server", ID_SYNERGY_RESETSERVER MENUITEM SEPARATOR MENUITEM "Quit", IDC_TASKBAR_QUIT END END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_TASKBAR_STATUS DIALOG 0, 0, 145, 60 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_TASKBAR_STATUS_STATUS,3,3,139,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_BORDER LISTBOX IDC_TASKBAR_STATUS_CLIENTS,3,17,139,40,NOT LBS_NOTIFY | LBS_SORT | LBS_NOINTEGRALHEIGHT | LBS_NOSEL | WS_VSCROLL | WS_TABSTOP END ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE BEGIN IDS_FAILED "Synergy is about to quit with errors or warnings. Please check the log then click OK." IDS_INIT_FAILED "Synergy failed to initialize: %{1}" IDS_UNCAUGHT_EXCEPTION "Uncaught exception: %{1}" END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED synergy-1.8.8-stable/src/cmd/synergys/tb_error.ico000066400000000000000000000004761305627404700222460ustar00rootroot00000000000000((   : 袠 :0 ~~ && ff~~p &&໻f`~~ && ff~p& f`synergy-1.8.8-stable/src/cmd/synergys/tb_idle.ico000066400000000000000000000004761305627404700220320ustar00rootroot00000000000000((  9 9:虘90 9 y) iyi`y~& 癙fy f`0 psynergy-1.8.8-stable/src/cmd/synergys/tb_run.ico000066400000000000000000000004761305627404700217210ustar00rootroot00000000000000((  :: :::::0袢:p fpp && ff`~~&&& fff~~&& f` 0synergy-1.8.8-stable/src/cmd/synergys/tb_wait.ico000066400000000000000000000004761305627404700220610ustar00rootroot00000000000000((  :: :::::0袢::~~&&ff~~p&&ff`~~~&&& fff~~&& f`synergy-1.8.8-stable/src/cmd/syntool/000077500000000000000000000000001305627404700175515ustar00rootroot00000000000000synergy-1.8.8-stable/src/cmd/syntool/CMakeLists.txt000066400000000000000000000020461305627404700223130ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2014-2016 Symless Ltd. # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") include_directories( ../ ../../lib/ ) if (UNIX) include_directories( ../../.. ) endif() add_executable(syntool ${sources}) target_link_libraries(syntool synergy arch base client common io ipc mt net platform server ${libs} ${OPENSSL_LIBS}) if (CONF_CPACK) install(TARGETS syntool COMPONENT core DESTINATION bin) endif() synergy-1.8.8-stable/src/cmd/syntool/syntool.cpp000066400000000000000000000016741305627404700217740ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ToolApp.h" #include "arch/Arch.h" int main(int argc, char** argv) { #if SYSAPI_WIN32 // record window instance for tray icon, etc ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif ToolApp app; return app.run(argc, argv); } synergy-1.8.8-stable/src/cmd/usynergy/000077500000000000000000000000001305627404700177275ustar00rootroot00000000000000synergy-1.8.8-stable/src/cmd/usynergy/CMakeLists.txt000066400000000000000000000016111305627404700224660ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2012 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . if (WIN32) set(sources uSynergyWin32.c) elseif (UNIX) set(sources uSynergyUnix.c) endif() include_directories(../../micro) add_executable(usynergy ${sources}) target_link_libraries(usynergy micro) synergy-1.8.8-stable/src/cmd/usynergy/uSynergyUnix.c000066400000000000000000000022571305627404700225720ustar00rootroot00000000000000/* uSynergy client -- Implementation for the embedded Synergy client library version 1.0.0, July 7th, 2012 Copyright (c) 2012 Nick Bolton This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "uSynergy.h" // TODO: implement callbacks. int main(int argc, char** argv) { uSynergyContext context; uSynergyInit(&context); for(;;) { uSynergyUpdate(&context); } } synergy-1.8.8-stable/src/cmd/usynergy/uSynergyWin32.c000066400000000000000000000102511305627404700225420ustar00rootroot00000000000000/* uSynergy client -- Implementation for the embedded Synergy client library version 1.0.0, July 7th, 2012 Copyright (c) 2012 Nick Bolton This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "uSynergy.h" #include #include #define WIN32_LEAN_AND_MEAN #include uSynergyBool connect(uSynergyCookie cookie); uSynergyBool send(uSynergyCookie cookie, const uint8_t *buffer, int length); uSynergyBool receive(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength); void sleep(uSynergyCookie cookie, int timeMs); uint32_t getTime(); void trace(uSynergyCookie cookie, const char *text); void screenActive(uSynergyCookie cookie, uSynergyBool active); void mouse(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle); void keyboard(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat); void joystick(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY); void clipboard(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size); // TODO: implement callbacks. int main(char* argv, int argc) { uSynergyContext context; uSynergyInit(&context); context.m_connectFunc = &connect; context.m_sendFunc = &send; context.m_receiveFunc = &receive; context.m_sleepFunc = &sleep; context.m_getTimeFunc = &getTime; context.m_traceFunc = &trace; context.m_screenActiveCallback = &screenActive; context.m_mouseCallback = &mouse; context.m_keyboardCallback = &keyboard; context.m_joystickCallback = &joystick; context.m_clipboardCallback = &clipboard; for(;;) { uSynergyUpdate(&context); } } uSynergyBool connect(uSynergyCookie cookie) { printf("connect\n"); return USYNERGY_TRUE; } uSynergyBool send(uSynergyCookie cookie, const uint8_t *buffer, int length) { printf("send\n"); return USYNERGY_TRUE; } uSynergyBool receive(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength) { printf("receive\n"); return USYNERGY_TRUE; } void sleep(uSynergyCookie cookie, int timeMs) { printf("sleep, timeMs=%d\n", timeMs); Sleep(timeMs); } uint32_t getTime() { printf("getTime\n"); return 0; } void trace(uSynergyCookie cookie, const char *text) { printf("%s\n", text); } void screenActive(uSynergyCookie cookie, uSynergyBool active) { printf("screenActive, active=%d\n", active); } void mouse(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle) { printf("mouse, pos=%d,%d\n", x, y); } void keyboard(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat) { printf("keyboard, key=%d down=%d repeat=%d\n", key, down, repeat); } void joystick(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY) { printf("joystick, left=%d,%d right=%d,%d\n", leftStickX, leftStickY, rightStickX, rightStickY); } void clipboard(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size) { printf("clipboard, size=%d\n", size); } synergy-1.8.8-stable/src/gui/000077500000000000000000000000001305627404700160635ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/gui.pro000066400000000000000000000075351305627404700174030ustar00rootroot00000000000000QT += widgets \ network TEMPLATE = app TARGET = synergy DEFINES += VERSION_STAGE=\\\"$$QMAKE_VERSION_STAGE\\\" DEFINES += VERSION_REVISION=\\\"$$QMAKE_VERSION_REVISION\\\" DEPENDPATH += . \ res INCLUDEPATH += . \ src \ ../lib/shared/ FORMS += res/MainWindowBase.ui \ res/AboutDialogBase.ui \ res/ServerConfigDialogBase.ui \ res/ScreenSettingsDialogBase.ui \ res/ActionDialogBase.ui \ res/HotkeyDialogBase.ui \ res/SettingsDialogBase.ui \ res/SetupWizardBase.ui \ res/AddClientDialogBase.ui \ res/ActivationDialog.ui \ res/CancelActivationDialog.ui \ res/FailedLoginDialog.ui SOURCES += src/main.cpp \ src/MainWindow.cpp \ src/AboutDialog.cpp \ src/ServerConfig.cpp \ src/ServerConfigDialog.cpp \ src/ScreenSetupView.cpp \ src/Screen.cpp \ src/ScreenSetupModel.cpp \ src/NewScreenWidget.cpp \ src/TrashScreenWidget.cpp \ src/ScreenSettingsDialog.cpp \ src/BaseConfig.cpp \ src/HotkeyDialog.cpp \ src/ActionDialog.cpp \ src/Hotkey.cpp \ src/Action.cpp \ src/KeySequence.cpp \ src/KeySequenceWidget.cpp \ src/SettingsDialog.cpp \ src/AppConfig.cpp \ src/QSynergyApplication.cpp \ src/VersionChecker.cpp \ src/SetupWizard.cpp \ src/IpcClient.cpp \ src/IpcReader.cpp \ src/Ipc.cpp \ src/SynergyLocale.cpp \ src/QUtility.cpp \ src/ZeroconfServer.cpp \ src/ZeroconfThread.cpp \ src/ZeroconfRegister.cpp \ src/ZeroconfBrowser.cpp \ src/ZeroconfService.cpp \ src/DataDownloader.cpp \ src/AddClientDialog.cpp \ src/CommandProcess.cpp \ src/CoreInterface.cpp \ src/Fingerprint.cpp \ src/SslCertificate.cpp \ src/WebClient.cpp \ src/ActivationNotifier.cpp \ src/ActivationDialog.cpp \ src/CancelActivationDialog.cpp \ src/FailedLoginDialog.cpp \ ../lib/shared/SerialKey.cpp \ src/LicenseManager.cpp HEADERS += src/MainWindow.h \ src/AboutDialog.h \ src/ServerConfig.h \ src/ServerConfigDialog.h \ src/ScreenSetupView.h \ src/Screen.h \ src/ScreenSetupModel.h \ src/NewScreenWidget.h \ src/TrashScreenWidget.h \ src/ScreenSettingsDialog.h \ src/BaseConfig.h \ src/HotkeyDialog.h \ src/ActionDialog.h \ src/Hotkey.h \ src/Action.h \ src/KeySequence.h \ src/KeySequenceWidget.h \ src/SettingsDialog.h \ src/AppConfig.h \ src/QSynergyApplication.h \ src/VersionChecker.h \ src/SetupWizard.h \ src/IpcClient.h \ src/IpcReader.h \ src/Ipc.h \ src/SynergyLocale.h \ src/QUtility.h \ src/ZeroconfServer.h \ src/ZeroconfThread.h \ src/ZeroconfRegister.h \ src/ZeroconfRecord.h \ src/ZeroconfBrowser.h \ src/ZeroconfService.h \ src/DataDownloader.h \ src/AddClientDialog.h \ src/CommandProcess.h \ src/ProcessorArch.h \ src/CoreInterface.h \ src/Fingerprint.h \ src/SslCertificate.h \ src/WebClient.h \ src/ActivationNotifier.h \ src/ElevateMode.h \ src/ActivationDialog.h \ src/CancelActivationDialog.h \ src/FailedLoginDialog.h \ ../lib/shared/EditionType.h \ ../lib/shared/SerialKey.h \ src/LicenseManager.h RESOURCES += res/Synergy.qrc RC_FILE = res/win/Synergy.rc macx { QMAKE_INFO_PLIST = res/mac/Info.plist TARGET = Synergy QSYNERGY_ICON.files = res/mac/Synergy.icns QSYNERGY_ICON.path = Contents/Resources QMAKE_BUNDLE_DATA += QSYNERGY_ICON LIBS += $$MACX_LIBS } unix:!macx:LIBS += -ldns_sd debug { OBJECTS_DIR = tmp/debug MOC_DIR = tmp/debug RCC_DIR = tmp/debug } release { OBJECTS_DIR = tmp/release MOC_DIR = tmp/release RCC_DIR = tmp/release } win32 { Debug:DESTDIR = ../../bin/Debug Release:DESTDIR = ../../bin/Release LIBS += -L"../../ext/bonjour/x64" \ -ldnssd INCLUDEPATH += "$(BONJOUR_SDK_HOME)/Include" } else:DESTDIR = ../../bin synergy-1.8.8-stable/src/gui/gui.ts000066400000000000000000001603501305627404700172240ustar00rootroot00000000000000 AboutDialogBase About Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: &Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left right up down Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/lang.cmd000066400000000000000000000000461305627404700174710ustar00rootroot00000000000000lupdate -noobsolete gui.pro -ts gui.tssynergy-1.8.8-stable/src/gui/langbuild.cmd000066400000000000000000000000321305627404700205040ustar00rootroot00000000000000cd res/lang lrelease *.tssynergy-1.8.8-stable/src/gui/res/000077500000000000000000000000001305627404700166545ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/res/AboutDialogBase.ui000066400000000000000000000140261305627404700222030ustar00rootroot00000000000000 AboutDialogBase Qt::ApplicationModal true 0 0 450 300 0 0 450 300 450 300 About Synergy true 0 0 <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> 1 Qt::Vertical QSizePolicy::Preferred 20 100 :/res/image/about.png 0 Qt::Vertical QSizePolicy::Fixed 20 5 0 0 Version: 1 0 0 Unknown 1 Qt::Horizontal 40 20 Build Date: Unknown Qt::Horizontal 40 20 &Ok buttonOk clicked() AboutDialogBase accept() 315 374 301 3 synergy-1.8.8-stable/src/gui/res/ActionDialogBase.ui000066400000000000000000000352161305627404700223520ustar00rootroot00000000000000 ActionDialogBase 0 0 372 484 Configure Action Choose the action to perform Press a hotkey true Release a hotkey Press and release a hotkey 1 0 256 0 only on these screens true true Qt::Horizontal 40 20 128 64 QAbstractItemView::ExtendedSelection Qt::Horizontal Switch to screen Qt::Horizontal 40 20 false Switch in direction Qt::Horizontal 40 20 false left right up down Lock cursor to screen Qt::Horizontal 40 20 false toggle on off This action is performed when the hotkey is pressed true the hotkey is released Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok KeySequenceWidget QLineEdit
KeySequenceWidget.h
buttonBox accepted() ActionDialogBase accept() 245 474 157 274 buttonBox rejected() ActionDialogBase reject() 313 474 286 274 m_pGroupType toggled(bool) m_pKeySequenceWidgetHotkey setDisabled(bool) 104 194 110 132 m_pRadioSwitchInDirection toggled(bool) m_pKeySequenceWidgetHotkey setDisabled(bool) 118 322 81 129 m_pRadioLockCursorToScreen toggled(bool) m_pKeySequenceWidgetHotkey setDisabled(bool) 101 353 68 126 m_pRadioPress toggled(bool) m_pKeySequenceWidgetHotkey setEnabled(bool) 48 48 45 129 m_pRadioRelease toggled(bool) m_pKeySequenceWidgetHotkey setEnabled(bool) 135 70 148 125 m_pRadioPressAndRelease toggled(bool) m_pKeySequenceWidgetHotkey setEnabled(bool) 194 100 201 125 m_pRadioSwitchToScreen toggled(bool) m_pComboSwitchToScreen setEnabled(bool) 148 291 350 290 m_pRadioSwitchInDirection toggled(bool) m_pComboSwitchInDirection setEnabled(bool) 158 322 350 321 m_pRadioLockCursorToScreen toggled(bool) m_pComboLockCursorToScreen setEnabled(bool) 180 353 350 352 m_pRadioPress toggled(bool) m_pGroupBoxScreens setEnabled(bool) 25 47 33 155 m_pRadioSwitchToScreen toggled(bool) m_pGroupBoxScreens setDisabled(bool) 48 278 98 153 m_pRadioRelease toggled(bool) m_pGroupBoxScreens setEnabled(bool) 264 67 241 158 m_pRadioPressAndRelease toggled(bool) m_pGroupBoxScreens setEnabled(bool) 286 98 290 156 m_pRadioSwitchInDirection toggled(bool) m_pGroupBoxScreens setDisabled(bool) 38 313 64 195 m_pRadioLockCursorToScreen toggled(bool) m_pGroupBoxScreens setDisabled(bool) 48 339 79 234 m_pRadioSwitchToScreen toggled(bool) m_pKeySequenceWidgetHotkey setDisabled(bool) 84 280 185 123
synergy-1.8.8-stable/src/gui/res/ActivationDialog.ui000066400000000000000000000116451305627404700224430ustar00rootroot00000000000000 ActivationDialog 0 0 410 211 Activate Synergy 75 true Serial key <html><head/><body><p>This can be found on your <a href="https://symless.com/account/?source=gui"><span style=" text-decoration: underline; color:#0000ff;">account</span></a> page.</p></body></html> true true true <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Sans'; font-size:10pt; font-weight:400; font-style:normal;"> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> false 2 0 0 8 :/res/icons/16x16/money.png <html><head/><body><p>Your trial has expired. <a href="http://symless.com/pricing?src=gui"><span style=" text-decoration: underline; color:#0000ff;">Buy now!</span></a></p></body></html> true Qt::Horizontal 40 20 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok m_pTextEditSerialKey buttonBox accepted() ActivationDialog accept() 248 254 157 274 buttonBox rejected() ActivationDialog reject() 316 260 286 274 synergy-1.8.8-stable/src/gui/res/AddClientDialogBase.ui000066400000000000000000000067321305627404700227650ustar00rootroot00000000000000 AddClientDialog 0 0 400 350 0 0 Dialog 10 10 381 301 TextLabel true Qt::Horizontal 40 20 Qt::Horizontal 40 20 10 320 381 31 Ignore auto connect clients 0 0 Qt::Horizontal QDialogButtonBox::Ignore false m_pDialogButtonBox accepted() AddClientDialog accept() 248 254 157 274 m_pDialogButtonBox rejected() AddClientDialog reject() 316 260 286 274 synergy-1.8.8-stable/src/gui/res/CancelActivationDialog.ui000066400000000000000000000044501305627404700235450ustar00rootroot00000000000000 CancelActivationDialog 0 0 400 165 Cancel Activation Are you sure? If you don't activate Synergy you'll be missing out on some great features. true true <html><head/><body><p><a href="https://symless.com/pricing?source=gui"><span style=" text-decoration: underline; color:#0000ff;">Buy now</span></a></p></body></html> true Qt::Horizontal QDialogButtonBox::No|QDialogButtonBox::Yes buttonBox accepted() CancelActivationDialog accept() 248 254 157 274 buttonBox rejected() CancelActivationDialog reject() 316 260 286 274 synergy-1.8.8-stable/src/gui/res/FailedLoginDialog.ui000066400000000000000000000052111305627404700225070ustar00rootroot00000000000000 FailedLoginDialog 0 0 400 165 Activation Error 50 120 341 32 Qt::Horizontal QDialogButtonBox::Close 10 90 382 30 <html><head/><body><p><a href="https://symless.com/account/reset/?source=gui"><span style=" text-decoration: underline; color:#0000ff;">Forgotten your password?</span></a></p></body></html> true 10 10 382 72 An error occurred while trying to activate Synergy. The Symless server returned the following error: %1 true true label_2 messageLabel buttonBox buttonBox accepted() FailedLoginDialog accept() 248 254 157 274 buttonBox rejected() FailedLoginDialog reject() 316 260 286 274 synergy-1.8.8-stable/src/gui/res/HotkeyDialogBase.ui000066400000000000000000000036451305627404700224010ustar00rootroot00000000000000 HotkeyDialogBase 0 0 344 86 Hotkey Enter the specification for the hotkey: Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok KeySequenceWidget QLineEdit
KeySequenceWidget.h
buttonBox accepted() HotkeyDialogBase accept() 248 254 157 274 buttonBox rejected() HotkeyDialogBase reject() 316 260 286 274
synergy-1.8.8-stable/src/gui/res/MainWindowBase.ui000066400000000000000000000420271305627404700220670ustar00rootroot00000000000000 MainWindowBase 0 0 600 500 0 0 500 400 Synergy 2 0 0 8 :/res/icons/16x16/warning.png <html><head/><body><p><span style=" font-weight:600;">%1</span> days of your Synergy Pro trial remain. <a href="http://symless.com/pricing?src=gui"><span style=" text-decoration: underline; color:#0000ff;">Buy now!</span></a></p></body></html> true Qt::Horizontal 40 20 2 0 0 8 :/res/icons/16x16/warning.png m_pLabelUpdate true Qt::Horizontal 469 20 0 0 Ser&ver (share this computer's mouse and keyboard): true true QFormLayout::AllNonFixedFieldsGrow IP addresses: 0 0 SSL Fingerprint: Configure interactively: true &Configure Server... Qt::Horizontal 40 20 Use existing configuration: &Configuration file: m_pLineEditConfigFile false false &Browse... 0 0 &Client (use another computer's mouse and keyboard): true true QFormLayout::AllNonFixedFieldsGrow Screen name: &Server IP: m_pLineEditHostname Auto config 0 0 120 0 Log 0 0 Courier false false QTextEdit::NoWrap true QLayout::SetDefaultConstraint true :/res/icons/16x16/padlock.png Ready Qt::Horizontal 40 20 false &Apply &Start &About Synergy... &Quit Quit Ctrl+Q &Start Run Ctrl+S false S&top Stop Ctrl+T S&how Status Ctrl+H &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Ctrl+Alt+S Settings Edit settings Activate Activate m_pRadioExternalConfig toggled(bool) m_pLineEditConfigFile setEnabled(bool) 156 179 169 209 m_pRadioExternalConfig toggled(bool) m_pButtonBrowseConfigFile setEnabled(bool) 353 182 356 211 m_pRadioInternalConfig toggled(bool) m_pButtonConfigureServer setEnabled(bool) 204 244 212 274 m_pButtonToggleStart clicked() m_pActionStartSynergy trigger() 361 404 -1 -1 synergy-1.8.8-stable/src/gui/res/ScreenSettingsDialogBase.ui000066400000000000000000000362341305627404700240760ustar00rootroot00000000000000 ScreenSettingsDialogBase 0 0 434 437 Screen Settings Screen &name: m_pLineEditName true A&liases false false &Add QAbstractItemView::ExtendedSelection false &Remove Qt::Vertical 20 126 &Modifier keys false &Shift: m_pComboBoxShift Shift Ctrl Alt Meta Super None &Ctrl: m_pComboBoxCtrl 1 Shift Ctrl Alt Meta Super None Al&t: m_pComboBoxAlt 2 Shift Ctrl Alt Meta Super None M&eta: m_pComboBoxMeta 3 Shift Ctrl Alt Meta Super None S&uper: m_pComboBoxSuper 4 Shift Ctrl Alt Meta Super None Qt::Vertical 20 40 &Dead corners false Top-left Top-right Bottom-left Bottom-right Corner Si&ze: m_pSpinBoxSwitchCornerSize Qt::Horizontal 40 20 &Fixes false Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama false Qt::Vertical 20 40 Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok m_pButtonBox accepted() ScreenSettingsDialogBase accept() 222 502 157 274 m_pButtonBox rejected() ScreenSettingsDialogBase reject() 290 508 286 274 synergy-1.8.8-stable/src/gui/res/ServerConfigDialogBase.ui000066400000000000000000000564111305627404700235310ustar00rootroot00000000000000 ServerConfigDialogBase 0 0 795 534 Server Configuration 0 Screens and links true Drag a screen from the grid to the trashcan to remove it. QFrame::StyledPanel QFrame::Raised :/res/icons/64x64/user-trash.png 1 0 Configure the layout of your synergy server configuration. Qt::AlignCenter true Drag this button to the grid to add a new screen. QFrame::StyledPanel QFrame::Raised :/res/icons/64x64/video-display.png 0 273 16777215 273 true false QFrame::StyledPanel QFrame::Sunken 1 0 Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Qt::AlignCenter true Qt::Vertical 20 40 Hotkeys &Hotkeys true &New false &Edit false &Remove Qt::Vertical 75 161 A&ctions false Ne&w false E&dit false Re&move Qt::Vertical 20 40 Advanced server settings &Switch true Switch &after waiting Qt::Horizontal 40 20 false 10 10000 10 250 ms true Switch on double &tap within Qt::Horizontal 40 20 false 10 10000 10 250 ms Qt::Vertical 20 40 &Options true Don't take &foreground window on Windows servers true Use &relative mouse moves true S&ynchronize screen savers true &Check clients every Qt::Horizontal 40 20 false 1000 30000 1000 5000 ms Qt::Vertical 20 16 Enable drag and drop file transfers Ignore auto config clients Enable clipboard sharing true &Dead corners false To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Qt::Horizontal 40 20 Cor&ner Size: m_pSpinBoxSwitchCornerSize Qt::Horizontal 40 20 Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok ScreenSetupView QTableView
ScreenSetupView.h
1
NewScreenWidget QLabel
NewScreenWidget.h
TrashScreenWidget QLabel
TrashScreenWidget.h
m_pButtonBox accepted() ServerConfigDialogBase accept() 572 424 377 -8 m_pButtonBox rejected() ServerConfigDialogBase reject() 641 424 595 1 m_pCheckBoxSwitchDelay toggled(bool) m_pSpinBoxSwitchDelay setEnabled(bool) 110 63 110 63 m_pCheckBoxSwitchDoubleTap toggled(bool) m_pSpinBoxSwitchDoubleTap setEnabled(bool) 110 63 110 63 m_pCheckBoxHeartbeat toggled(bool) m_pSpinBoxHeartbeat setEnabled(bool) 110 63 110 63 m_pListHotkeys itemDoubleClicked(QListWidgetItem*) m_pButtonEditHotkey click() 197 115 304 115 m_pListActions itemDoubleClicked(QListWidgetItem*) m_pButtonEditAction click() 505 120 677 118
synergy-1.8.8-stable/src/gui/res/SettingsDialogBase.ui000066400000000000000000000244041305627404700227320ustar00rootroot00000000000000 SettingsDialogBase 0 0 368 380 Settings &Miscellaneous 75 0 Sc&reen name: m_pLineEditScreenName true P&ort: m_pSpinBoxPort true 0 0 65535 24800 &Interface: m_pLineEditInterface true 0 0 75 0 &Language: m_pComboLanguage &Hide on startup Specify when the Synergy service should run at an elevated privilege level 0 As Needed Always Never Elevate true 0 0 &Network Security QFormLayout::AllNonFixedFieldsGrow false Use &SSL encryption Qt::Horizontal 40 20 0 0 Logging Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter false 75 0 &Logging level: m_pComboLogLevel Error Warning Note Info Debug Debug1 Debug2 Log to file: false false Browse... Qt::Vertical 20 40 Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok m_pComboLanguage m_pLineEditScreenName m_pSpinBoxPort m_pLineEditInterface m_pComboElevate m_pCheckBoxAutoHide m_pCheckBoxEnableCrypto m_pComboLogLevel m_pCheckBoxLogToFile m_pLineEditLogFilename m_pButtonBrowseLog buttonBox accepted() SettingsDialogBase accept() 266 340 157 274 buttonBox rejected() SettingsDialogBase reject() 334 340 286 274 synergy-1.8.8-stable/src/gui/res/SetupWizardBase.ui000066400000000000000000000175601305627404700223000ustar00rootroot00000000000000 SetupWizardBase 0 0 556 464 0 0 500 390 Setup Synergy Welcome Thanks for installing Synergy! true Qt::Vertical QSizePolicy::Fixed 20 10 100 0 &Language: m_pComboLanguage 200 16777215 Qt::Vertical QSizePolicy::Fixed 20 10 Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). true 0 0 Server or Client? 75 true &Server (share this computer's mouse and keyboard) 0 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> true Qt::Vertical QSizePolicy::Fixed 20 20 75 true &Client (use another computer's mouse and keyboard) 0 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> true Qt::Vertical QSizePolicy::MinimumExpanding 0 0 m_pComboLanguage m_pServerRadioButton m_pClientRadioButton synergy-1.8.8-stable/src/gui/res/Synergy.qrc000066400000000000000000000042301305627404700210220ustar00rootroot00000000000000 icons/16x16/synergy-connected.png icons/16x16/synergy-disconnected.png icons/64x64/video-display.png icons/64x64/user-trash.png icons/16x16/warning.png icons/256x256/synergy.ico image/about.png lang/gui_ar.qm lang/gui_bg-BG.qm lang/gui_ca-AD.qm lang/gui_cs-CZ.qm lang/gui_cy.qm lang/gui_da.qm lang/gui_de.qm lang/gui_es.qm lang/gui_fi.qm lang/gui_fr.qm lang/gui_grk.qm lang/gui_he.qm lang/gui_hr-HR.qm lang/gui_hu-HU.qm lang/gui_id.qm lang/gui_it.qm lang/gui_ja-JP.qm lang/gui_ko.qm lang/gui_lt.qm lang/gui_lv.qm lang/gui_nl-NL.qm lang/gui_no.qm lang/gui_pes-IR.qm lang/gui_pl-PL.qm lang/gui_pt-BR.qm lang/gui_pt-PT.qm lang/gui_ro.qm lang/gui_ru.qm lang/gui_si.qm lang/gui_sk-SK.qm lang/gui_sl-SI.qm lang/gui_sq-AL.qm lang/gui_sr.qm lang/gui_sv.qm lang/gui_th-TH.qm lang/gui_tr-TR.qm lang/gui_uk.qm lang/gui_ur.qm lang/gui_mr.qm lang/gui_vi.qm lang/gui_zh-CN.qm lang/gui_zh-TW.qm lang/Languages.xml icons/16x16/money.png image/spinning-wheel.gif icons/16x16/padlock.png icons/16x16/synergy-transfering.png synergy-1.8.8-stable/src/gui/res/icons/000077500000000000000000000000001305627404700177675ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/res/icons/16x16/000077500000000000000000000000001305627404700205545ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/res/icons/16x16/money.png000066400000000000000000000013421305627404700224110ustar00rootroot00000000000000PNG  IHDRagAMA7tEXtSoftwareAdobe ImageReadyqe<tIDAT8˕OQǹ[.ukZ@MM˲rъ٤i"hZH ?Ip% %kmu~v~?W˩]`^0)PZ.@2cI0 0k0[[=Z_0^<0 ǒRLf=PHWmDP  BU¾hAg]h q~iL鵞"mm82,%]T?zZbZb~MCSbZfFP9.ڄ8cS"z9ɊVpYXTnáF63̡)B 'Z2wa4hleu=50<ԀJ Ed-a_43 ; Pe'A; M#pS+4jUegN4Q;$ԂXmL^rC?׎b T# 9;ol^u³_ Ȉ8]d?oQk+IT78K=sIENDB`synergy-1.8.8-stable/src/gui/res/icons/16x16/padlock.png000066400000000000000000000007021305627404700226760ustar00rootroot00000000000000PNG  IHDR(-S`PLTEѝJn݀]8Ăش!ԥɌ̒حܶ vv tRNS\\bKGDr +@hIST ;8`tEXtSoftwaregif2png 0.6 (beta)iqIDATx0 EQC I,TqWe 1A ;#I ,ιv@_pȳi̫uߋGfB&86{9R =v)QIENDB`synergy-1.8.8-stable/src/gui/res/icons/16x16/synergy-connected.png000066400000000000000000000012131305627404700247170ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<-IDATxb?2_H%+K ~Ļx jRӀ&5>qАe(52ً8  e TcӌDA00S7 I ^;.pH v@R 5XD%+ Bu bI[߃dHO4rf,Ud4N<~Gc¢= G˔4'?{otA&!,'rjW>\X} 3={4#[w 8nNy$/O 6bN Z ?^a`e44yE FRJO`7B kίa(ٟ )(S@ōH8^k?3|緿 Lgga#,%bl.۔`OCbʫ.`.n{%3]Ru ;-fx7;~ |fdz8y~8#zv"M@, _73\̶ sʦI[0̂IENDB`synergy-1.8.8-stable/src/gui/res/icons/16x16/synergy-connected.psd000066400000000000000000000720541305627404700247340ustar00rootroot000000000000008BPS_8BIM8BIM%\/{gdպ8BIM$A Adobe Photoshop CS4 Windows 2011-05-03T19:59:09+01:00 2012-03-11T14:29:41Z 2012-03-11T14:29:41Z application/vnd.adobe.photoshop 3 sRGB IEC61966-2.1 xmp.iid:9132E868866BE1118D1BB745DDA83F09 xmp.did:579ABF47846BE1118D1BB745DDA83F09 xmp.did:579ABF47846BE1118D1BB745DDA83F09 created xmp.iid:579ABF47846BE1118D1BB745DDA83F09 2012-03-11T14:26:44Z Adobe Photoshop CS4 Windows converted from image/png to application/vnd.adobe.photoshop saved xmp.iid:589ABF47846BE1118D1BB745DDA83F09 2012-03-11T14:26:44Z Adobe Photoshop CS4 Windows / saved xmp.iid:5A9ABF47846BE1118D1BB745DDA83F09 2012-03-11T14:27:23Z Adobe Photoshop CS4 Windows / saved xmp.iid:9132E868866BE1118D1BB745DDA83F09 2012-03-11T14:29:41Z Adobe Photoshop CS4 Windows / 1 720000/10000 720000/10000 2 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;25A20E76EFF43D7330A2499A28EB4938 16 16 1 36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;26EC271C894309D0BBA2E3379EE65237 8BIMHH8BIM&?8BIM Transparency8BIM Transparency8BIMd8BIM5d8BIM8BIM 8BIM8BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM8BIM8BIM08BIM-8BIM@@8BIM8BIMnullbaseNameTEXTUserboundsObjcRct1Top longLeftlongBtomlongRghtlongslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongRghtlongurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?8BIM H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km8BIM8BIM 0JFIFHH Adobe_CMAdobed            "?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ? g[Uwz8 %nj?Jn`Fk]ӲߚKsmWQ"eNǶVfE+i9hmok=ʿ%/vpC/{K d&x_8BIM!UAdobe PhotoshopAdobe Photoshop CS48BIM".MM*bj(1r2i ' 'Adobe Photoshop CS4 Windows2012:03:11 14:29:41&(.HH8BIMmopt4TargetSettingsMttCObjc NativeQuadBl longGrn longRd longTrnsbool fileFormatenum FileFormatPNG24 interlacedbool noMatteColorbooltransparencyDitherAlgorithmenumDitherAlgorithmNonetransparencyDitherAmountlong8BIM-msetnullVersionlong8BIMms4w8BIM maniIRFR8BIMAnDsnullAFStlongFrInVlLsObjcnullFrIDlongVnɡFrGAdoub@>FStsVlLsObjcnullFsIDlongAFrmlongFsFrVlLslongVnɡLCntlong8BIMRoll8BIMmfriX,~8BIMnorm <(Layer 08BIMluniLayer 08BIMlnsrlayr8BIMlyid8BIMclbl8BIMinfx8BIMknko8BIMlspf8BIMlclr8BIMshmdH8BIMcust4metadata layerTimedoubA+! K8BIMfxrp8BIMnorm(L(Layer 28BIMlfx2lnullScl UntF#Prc@YmasterFXSwitchboolebblObjcebblenabboolhglMenumBlnMScrnhglCObjcRGBCRd doub@oGrn doub@oBl doub@ohglOUntF#Prc@RsdwMenumBlnMMltpsdwCObjcRGBCRd doubGrn doubBl doubsdwOUntF#Prc@RbvlTenumbvlTSfBLbvlSenumBESlEmbsuglgboollaglUntF#Ang@^LaldUntF#Ang@>srgRUntF#Prc?blurUntF#Pxl?bvlDenumBESsIn TrnSObjcShpCNm TEXTLinearCrv VlLsObjcCrPtHrzndoubVrtcdoubObjcCrPtHrzndoub@oVrtcdoub@oantialiasGlossboolSftnUntF#Pxl@useShapebool useTexturebool8BIMlrFX8BIMcmnS8BIMdsdw3x8BIMmul 8BIMisdw3x8BIMmul 8BIMoglw*8BIMscrn8BIMiglw+8BIMscrn8BIMbevlNx8BIMscrn8BIMmul 8BIMsofi"8BIMnorm8BIMluniLayer 28BIMlnsrlayr8BIMlyid8BIMclbl8BIMinfx8BIMknko8BIMlspf8BIMlclr8BIMshmdH8BIMcust4metadata layerTimedoubA-{8BIMfxrpBBBB8BIMnorm<(Layer 38BIMluniLayer 38BIMlnsrlayr8BIMlyid8BIMclbl8BIMinfx8BIMknko8BIMlspf8BIMlclr8BIMshmdH8BIMcust4metadata layerTimedoubA-(8BIMfxrp@c@c           ~~ZZ~~!ff!33ffffx33xff~~rrr̺rV3V3V3V3V3V3V3V3::::::::ё*+)7,8MExlR_\xքPhYQeMsXO)Hө:#kC Z?C"4b \Ѽο̋󠢙èȌȐ𸗒;1i^AFCkx>G8JY9^613ҙ/ \:N0; &U O8BIMPatt8BIMFMsk 2~nPc`VVV333?VVVVV33333{VVVVVV333333ZVVVf3338VVVf333|VVV333\jVVV333DkC]TMR_\nzńPhYQ}򊄄lsXOA„Eө:;VC ȊT>C"Mȥa};8ȩזȏ񒏏ΤƏ礅΅ǭʹϻ޹ܹ̋󠢤ӹȌ༹ȐǞ͡桁́,_GKAFCvÏL>G8JL^^613Iҙ/ +g~:D; @Q@Ɖ,'~~ZZ~~!ff!33fffx3f~r7r8synergy-1.8.8-stable/src/gui/res/icons/16x16/synergy-disconnected.png000066400000000000000000000006721305627404700254270ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<\IDATxb?2_H%+K ~Ļx jRӀ&5>qАe(52ً8  e TcӌDA00S7 I ^;.pH v@R 5XD%+ Bu bI[߃dHO4rf,Ud4N<~Gc¢=VBX&rw@@l%hӺ}14&VƖh_@TL) x&f>Z[x1 )qTjfH5"{dgmÚAS A x @tukbojIENDB`synergy-1.8.8-stable/src/gui/res/icons/16x16/synergy-disconnected.psd000066400000000000000000000777741305627404700254520ustar00rootroot000000000000008BPSi8BIM8BIM%\/{gdպ8BIM$K Adobe Photoshop CS4 Windows 2011-05-03T19:59:09+01:00 2012-03-11T18:29:41Z 2012-03-11T18:29:41Z application/vnd.adobe.photoshop 3 sRGB IEC61966-2.1 xmp.iid:9332E868866BE1118D1BB745DDA83F09 xmp.did:529ABF47846BE1118D1BB745DDA83F09 xmp.did:529ABF47846BE1118D1BB745DDA83F09 created xmp.iid:529ABF47846BE1118D1BB745DDA83F09 2012-03-11T14:12:48Z Adobe Photoshop CS4 Windows converted from image/png to application/vnd.adobe.photoshop saved xmp.iid:539ABF47846BE1118D1BB745DDA83F09 2012-03-11T14:12:48Z Adobe Photoshop CS4 Windows / saved xmp.iid:549ABF47846BE1118D1BB745DDA83F09 2012-03-11T14:17:13Z Adobe Photoshop CS4 Windows / saved xmp.iid:559ABF47846BE1118D1BB745DDA83F09 2012-03-11T14:19:22Z Adobe Photoshop CS4 Windows / saved xmp.iid:569ABF47846BE1118D1BB745DDA83F09 2012-03-11T14:26:15Z Adobe Photoshop CS4 Windows / saved xmp.iid:599ABF47846BE1118D1BB745DDA83F09 2012-03-11T14:26:53Z Adobe Photoshop CS4 Windows / saved xmp.iid:5B9ABF47846BE1118D1BB745DDA83F09 2012-03-11T14:27:23Z Adobe Photoshop CS4 Windows / saved xmp.iid:9032E868866BE1118D1BB745DDA83F09 2012-03-11T14:28:02Z Adobe Photoshop CS4 Windows / saved xmp.iid:9232E868866BE1118D1BB745DDA83F09 2012-03-11T14:29:44Z Adobe Photoshop CS4 Windows / saved xmp.iid:9332E868866BE1118D1BB745DDA83F09 2012-03-11T18:29:41Z Adobe Photoshop CS4 Windows / 1 720000/10000 720000/10000 2 256,257,258,259,262,274,277,284,530,531,282,283,296,301,318,319,529,532,306,270,271,272,305,315,33432;596FF2EDC96B7B91322ECF19E669E51F 16 16 1 36864,40960,40961,37121,37122,40962,40963,37510,40964,36867,36868,33434,33437,34850,34852,34855,34856,37377,37378,37379,37380,37381,37382,37383,37384,37385,37386,37396,41483,41484,41486,41487,41488,41492,41493,41495,41728,41729,41730,41985,41986,41987,41988,41989,41990,41991,41992,41993,41994,41995,41996,42016,0,2,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,20,22,23,24,25,26,27,28,30;26EC271C894309D0BBA2E3379EE65237 8BIMHH8BIM&?8BIM Transparency8BIM Transparency8BIMd8BIM5d8BIM8BIM 8BIM28BIM 8BIM' 8BIMH/fflff/ff2Z5-8BIMp8BIM8BIM8BIM08BIM-8BIM@@8BIM8BIMnullbaseNameTEXTUserboundsObjcRct1Top longLeftlongBtomlongRghtlongslicesVlLsObjcslicesliceIDlonggroupIDlongoriginenum ESliceOrigin autoGeneratedTypeenum ESliceTypeImg boundsObjcRct1Top longLeftlongBtomlongRghtlongurlTEXTnullTEXTMsgeTEXTaltTagTEXTcellTextIsHTMLboolcellTextTEXT horzAlignenumESliceHorzAligndefault vertAlignenumESliceVertAligndefault bgColorTypeenumESliceBGColorTypeNone topOutsetlong leftOutsetlong bottomOutsetlong rightOutsetlong8BIM( ?8BIM H HLinomntrRGB XYZ  1acspMSFTIEC sRGB-HP cprtP3desclwtptbkptrXYZgXYZ,bXYZ@dmndTpdmddvuedLview$lumimeas $tech0 rTRC< gTRC< bTRC< textCopyright (c) 1998 Hewlett-Packard CompanydescsRGB IEC61966-2.1sRGB IEC61966-2.1XYZ QXYZ XYZ o8XYZ bXYZ $descIEC http://www.iec.chIEC http://www.iec.chdesc.IEC 61966-2.1 Default RGB colour space - sRGB.IEC 61966-2.1 Default RGB colour space - sRGBdesc,Reference Viewing Condition in IEC61966-2.1,Reference Viewing Condition in IEC61966-2.1view_. \XYZ L VPWmeassig CRT curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km8BIM8BIM 0JFIFHH Adobe_CMAdobed            "?   3!1AQa"q2B#$Rb34rC%Scs5&DTdE£t6UeuF'Vfv7GWgw5!1AQaq"2B#R3$brCScs4%&5DTdEU6teuFVfv'7GWgw ? g[Uwz8 %nj?Jn`Fk]ӲߚKsmWQ"eNǶU ΥQm0:1kXq@pzexYq8sQG1:/8BIM!UAdobe PhotoshopAdobe Photoshop CS48BIM".MM*bj(1r2i ' 'Adobe Photoshop CS4 Windows2012:03:11 18:29:41&(.HH8BIMmopt4TargetSettingsMttCObjc NativeQuadBl longGrn longRd longTrnsbool fileFormatenum FileFormatPNG24 interlacedbool noMatteColorbooltransparencyDitherAlgorithmenumDitherAlgorithmNonetransparencyDitherAmountlong8BIM-msetnullVersionlong8BIMms4w8BIM maniIRFR8BIMAnDsnullAFStlongFrInVlLsObjcnullFrIDlongVsFrGAdoub@>FrGLdoub@IFStsVlLsObjcnullFsIDlongAFrmlongFsFrVlLslongVsLCntlong8BIMRoll8BIMmfri8BIMnorm(L(Layer 48BIMlfx2lnullScl UntF#Prc@YmasterFXSwitchboolebblObjcebblenabboolhglMenumBlnMScrnhglCObjcRGBCRd doub@oGrn doub@oBl doub@ohglOUntF#Prc@RsdwMenumBlnMMltpsdwCObjcRGBCRd doubGrn doubBl doubsdwOUntF#Prc@RbvlTenumbvlTSfBLbvlSenumBESlEmbsuglgboollaglUntF#Ang@^LaldUntF#Ang@>srgRUntF#Prc?blurUntF#Pxl?bvlDenumBESsIn TrnSObjcShpCNm TEXTLinearCrv VlLsObjcCrPtHrzndoubVrtcdoubObjcCrPtHrzndoub@oVrtcdoub@oantialiasGlossboolSftnUntF#Pxl@useShapebool useTexturebool8BIMlrFX8BIMcmnS8BIMdsdw3x8BIMmul 8BIMisdw3x8BIMmul 8BIMoglw*8BIMscrn8BIMiglw+8BIMscrn8BIMbevlNx8BIMscrn8BIMmul 8BIMsofi"8BIMnorm8BIMluniLayer 48BIMlnsrlayr8BIMlyid8BIMclbl8BIMinfx8BIMknko8BIMlspf8BIMlclr8BIMshmdH8BIMcust4metadata layerTimedoubA-OX8BIMfxrp8BIMnorm*T(Layer 08BIMlfx2tnullScl UntF#Prc@YmasterFXSwitchboolebblObjcebblenabboolhglMenumBlnM lighterColorhglCObjcRGBCRd doub@oGrn doub@oBl doub@ohglOUntF#Prc@RsdwMenumBlnMMltpsdwCObjcRGBCRd doubGrn doubBl doubsdwOUntF#Prc@RbvlTenumbvlTSfBLbvlSenumBESlInrBuglgboollaglUntF#Ang@^LaldUntF#Ang@>srgRUntF#Prc?blurUntF#Pxl?bvlDenumBESsIn TrnSObjcShpCNm TEXTLinearCrv VlLsObjcCrPtHrzndoubVrtcdoubObjcCrPtHrzndoub@oVrtcdoub@oantialiasGlossboolSftnUntF#Pxl?useShapebool useTexturebool8BIMlrFX8BIMcmnS8BIMdsdw3x8BIMmul 8BIMisdw3x8BIMmul 8BIMoglw*8BIMscrn8BIMiglw+8BIMscrn8BIMbevlNx8BIMlgCl8BIMmul 8BIMsofi"8BIMnorm8BIMluniLayer 08BIMlnsrlayr8BIMlyid8BIMclbl8BIMinfx8BIMknko8BIMlspf8BIMlclr8BIMshmdH8BIMcust4metadata layerTimedoubA,_o8BIMfxrp~~ZZ~~!ff!33ffffx33xff~~rrr̺rV3V3V3V3V3V3V3V3::::::::   V3V3V3V3V3V3V3V3:::::::::  8BIMPatt8BIMFMsk 2~nPc`VVV333?VVVVV33333{VVVVVV333333ZVVVf3338VVVf333|VVV333\jVVV333D:::M:::hńk:::򊄄k:::C„:::::::::::Ȋ:::Cȥaoȩזȏ񒏏ΤƏ礅΅ʹφ޹礆Ϥܹӹ༹Ǟ͡桁́,KެLLgQ@~~ZZ~~!ff!33ffffx33xff~~rrr̺rsynergy-1.8.8-stable/src/gui/res/icons/16x16/synergy-transfering.png000066400000000000000000000362661305627404700253170ustar00rootroot00000000000000PNG  IHDRa pHYs  9iTXtXML:com.adobe.xmp Adobe Photoshop CC (Macintosh) 2015-02-09T15:32:52Z 2015-05-29T23:45:57+01:00 2015-05-29T23:45:57+01:00 image/png 3 xmp.iid:31a8d196-b2b6-4f75-9f9e-b6534b72abc6 xmp.did:dba7ae71-dfde-4aa4-965f-324425e44eea xmp.did:dba7ae71-dfde-4aa4-965f-324425e44eea created xmp.iid:dba7ae71-dfde-4aa4-965f-324425e44eea 2015-02-09T15:32:52Z Adobe Photoshop CC (Macintosh) saved xmp.iid:31a8d196-b2b6-4f75-9f9e-b6534b72abc6 2015-05-29T23:45:57+01:00 Adobe Photoshop CC (Macintosh) / 1 720000/10000 720000/10000 2 65535 16 16 R cHRMz%u0`:o_FeIDATxlMHTa;3޹3ߘJ%-*D-[QJ(WHAD0"DIL4Qǹg{[tnc;9/;#ض[Cv9p h,%U7/ :N b :l xtFӽso6 lc6",ew)t cPjΝl0Cj7IENDB`synergy-1.8.8-stable/src/gui/res/icons/16x16/warning.png000066400000000000000000000012651305627404700227330ustar00rootroot00000000000000PNG  IHDRatEXtSoftwareAdobe ImageReadyqe<WIDATxڤSMOA~f)`[K[ mmLpSɿWΞ ".=FILĈ߻;3;KZN|<0.N ̗J|n7TxAf 3犰PJ¸ \h2 \_J]RvL2"@Q* +@Avӯ @n@.A=cͧa!>@oԴ3KP{x}q&{iw{! * hCtT>39(̐EY #)/nc^ ;˴9hCEYtRIc!S;Eb&&qeyb8r!1݇oߠd 8ב`foHvvD'w=-EڸQ9cȕutbb!Bz^]/e#9Qb}usVO}R j%aCufwznct)hئG#oH&,HRxoLzT77)=O&`}_r0>8LtӤh΢qȢ,rD,ƛwx.WG&TJzy IENDB`synergy-1.8.8-stable/src/gui/res/icons/256x256/000077500000000000000000000000001305627404700207305ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/res/icons/256x256/synergy.ico000066400000000000000000010622761305627404700231420ustar00rootroot00000000000000 ( V00 %~   &F V hV`( 2(OOOcyԀԀՃՃՀ~YE;2;2 2OրcY; 2Y׀щʾzzz|z~v{zsz}ry|rzzw{|x}{}~|~ЉycEEـwjxv_tqXqmId`JeaNgcUjgZmj_mk]ki]hfgromtqkrmgkfejalmdlnbmk`hgYgfXgeZki^sqg}{q{ÿ~;(2cѐ{stumnljjgii]hfZhfWliTmib}yotushomclj`ih^gf\fgcklhvwsӃEY~ܳ{outckjYa`FjdEvnU\]`ecjŶtѼȳ~qsm`b\]_Ycd`nok|}yΐc2(c˥otschgagfkqpu}|yqzǿľ|{|xstpjkgefbmnjz{w~O;Yy|zdolWni@ib5jaC}f~omlj^VMIIDBCPl۷զԙӋӇֆ؈ՐԗҠգ߭ٯԳĪzndrhangdokjxywſӃEyĻrnm][ZUXV\gdxxhffdZRIFFA?AMiձϠΓΆ΂ЀсΉˎɗ̑̚՚ڨخԳжɷxtsUVTZ][jqn}ΐщY Oΐ~Xoj8ZTFumcbgr|udRMB2144-)((,0/4E`{޷סҍ}mc]]`cgnt{~Յ؋ٕ޳ִĻ{upc\Yjefͥy2 EûszwZebczucuraWNK@0/33-)((,0/4E`{ݶ՟ь|lb[[^`cjvuqx~Ʌɍʕִ͢{xxstlllddd|{}Y;Y֐tywKmg?vm=xpnjTG:5/.)" #"(("""%*109Fb|ڵўψyk\UUWY]a_abbbcgnqԎםܬ߼ٺưe`Wlj`yupХnOԚxinl]b`nn_LA74,&! "!&& "(/-6C_yسН͆whXQRTW[_^bc``dinuxȂŋ’˨ԵDZ˽þea\ZXW|y{y(nVmiJnhhxrukXN>90(('&)*+/-022**('0216?Wm۽ԯ̙Ƅtg_Z[`bhid`^ZX[XV[]fstzփړ٩سسļ{vgge[}|׉O EϚ·ywwfqog~zyĽmgYP:4)%'(&''&(*.0/('&$ֿ+׿-վ+׻1ؽ:ڼRٿhշΩƓտ}ڽld[VW\_ܾeܾe]\^]YWVYYbcgnttǀͨ͝ϪϸljimlnY;͚_qpOplavĹ}zdD<73,)'&'++-,.-,&ڽ%ټ&ָ&ָظ׷յҳ$Ю%ѯ%ԯ&հ1ײDٷT޼|ڼٶٲ֦ϗŃҾqӻcӼYӺTѸPѸPӺTԹWַZնYԾUWZ\[\Z[\\\]^__^q{҆Ֆ٠ϭqtqi~}ڐ; ~glmpznZA962,)''%)(+)+׿*־)ս!ոӶ"Ҵ"ҴԴӳѱͮ!ͫ"ά Ϫ Ϫ)Ϫ;ЮKճsҷԶүЩ̜Čȼzʶi̴\̵RεOʹLʹLεOϴRѲUҳVϹPкQҼSӽT־TVWYYYZ[\]]]pw~Ɋ˒֪ڸ̵omluu{܉Y2րĿhvuTwsVetgV?5-('%$$$#'%ۼ(ۼ'ڹ&ٸ%ط#ֵճԲԬѪЩϨЧΥˣ!ȡ)ğ.Ġ-Ɵ2Ơ9ǢLʧ`ά}ͰδɰȫĜzj_TNIIHīKɭN˯PɴKʵL̶M͵QζRѸXֺ[ؼ]ۿ`a`_]^]]_`ems̀Փܧۯƥ{wlwtpِOԃwwwftswwVH<6.('$#"!ܽ!ٻ!׸$׸#ֵ!ԳұЯϭͫΦ̥ʣȡȟǞŝÜ&,ž.Ǡ7˥AϪVԱkٷػ׽ԻԷҪ˛ˆʹv˴iYOGCACF¦GîEįFDZHɱM˳O̳SдUдUԸYֺ[ռZZYZZZ]_`irvȓ̠ٸѹ|xmlpɰE(ΐ]xuXsvm\F.+($$+*&%ݿ#ܼ!ں ׵!Գ"ԯ$Ӯ%Ҭ"ϩΦˣʟɞ Ř&×'–&'–)Ę1›=OŢWȦ]έfӳpعؼϮǞÓι˳ymc]WSNHHIKèNŪPɫR˭TˮSͰUδVжXҹWԻYֿ[\YZUZbfhy~Бڦذswte}ǽO ;ԀgxuieO?0,'!!&ܾ%۽"ڼ غظյӱЯϪͨ˥ɣǟŝŚę$'–)Ę-Ȝ1̠<ͦJΩ[ѮbӱgطoܼxֵҩРʓŋԿӻyҹsϴjŪ`¤WHFCBDHåLƨOŨMǪOɯQ˱SʹRзUһWԽYSYWX]cfu|ąɕ֮ټüwum{{{E2ΐa|xZpyhNB51/+*(%ؿ*ֺ)չ$Զ"Ҵ!ұЯΩ ̨ ɢ!Ơ#ś#%%%%4:˜?śBȞEͣIѧRӬ`ԯpӳrյu׹y۽ٽԶϮͨƠĚؼӴ}ЮsǧfŢ^VNIHHGF§EƬHȮJȰLʲN͵QиT̼RXWVWVV[bq}ŇОٲÞuuuʥY ҃suun¹v\H=353('׿'$׾(Ը'ӷ!ѳϱέ̫ʥȤŞœ""#$7ę=śCɟF̢GϥJҨRӬ^ҭpӳrյtָwٻշέ˦ĞÙؿٽعض{׷vԱm˩c¢WNHD?@@B¨DªFëGƮJɱMɹOʺP˼NҾQUWY\_kzΧֱʵtttwwwO OՉJ}uIr;z_>1*''(ܿ'۾'ݻ$ڸ!ضִ$ժ&Ҩ"Ш#̥ ɢ şÚ!! $'+đ.ǔBŤKƦPȩUʫ[˩ZʨXʥSʤP̢OˡP̠VϣaѢiУpը׭ֳԴӬͥƙһҶѳzϱvΰu̴xи|ηϷѶβѱ̬ʬ{ŪqaTLC@ADFHŢLɤO˦QŮHȱK̴PϷSѹUԼXX[[[`go{Պۢȷt||nɰڀ(Yz|isȺnN@6%ֻ%ھ%ھ$ػ#׺!׵ճѯϭΣˡɡŞÜ!'+Ò/ȕ2˘AģG¢HKQPMG@=:@FIŨMȫPʭR̯TϴRѸRӽTԾUW\ӿ`Կdjw̔ݹѯt|А(Oevssk]LտA.ؼ!ո'۾"ع ַ Ӳ!Яά˩ʥȣŚØ &.1777-*&}#z yz{{}#1AĒHȗ]ɛ̚Ǘőxk[SEBA@;99~7ACJPSXƠ_Ơ_ş^œ[RI?=:=BDG¥JŨMȫP˰NʹNϹPѻRнTӿZҾ_Ӿcӿgսq̻Ȥӱη~}y~(nȽcxuYxǹvUH8׽,Ӹ)ܽ&ܽյӳԱ ү"ϩ#˦"ɢƟě™ $(**,+*yyzz|"&,/7>JVgpƨƬ˯ɬƪ{rf^ZUPOLH758>@ITÖYÖYėZXQF?;=@DGJKĢOǧNɪM̱OεOϹPѻRӾUW[]gv̍ԩʮzz~(щyzplLB9ؾ-Թ%ع"عֶԴүЭ̦ ȣŞ›"#$#$|%}%} x{$+0Ď8ǖ@ϞLѦX֬hٴvܹƽظЮˤǝվϴȭu¤i_[VP@;998=DFKPTRIA;:<@BFGJ¢IĥHȭKʱK˵LͷNιPҽTҿXӾ[ҿdӾsąØѵcϐ~fxc?ڿ/%׺"ع$ڻ׵ӱԮ կϧ!̥#ʟ$Ɯ"Ö|!|!{!{!{ }||z}'2?Q¡dƨuɱθοY( ((n̚Ѿǰ}re\QE=84;>CHKJGF>?@CEHIHĥJȪKɮL˲L˵KϹOҾQӿRӾQYi{̗մɼz( Yvy\>پ-ھ$ֹ!׸ ַҰҰҬȢȠƟę}|yzyxtxxz{$)5ś@ƢQϬhٸc22YyщӶťαȪ{oaRH@:989>DGGF;<<>@CCBB¤EŪHƭGDZG˵KϻNмOӾQѻRϺ_Ҿw˻ǦҼyԀ EZ{bcI;ٻ.ٹ#ٷ!׵ղӰҬϪ̤ʞƘ Ö{{yzxutuwy#}+19CVɨƾn(Yĺs_QGB:778?EG=<;:<8};?@9999:ػ0ݽ%Ҳ(ӳ'Ҳ!ѬϪ̦ɣƝÚ~}zytsvx{#2Mǡgӯ(O˥ٳïjWKB<667574369>@ADCDFĨIŬJǮL˵LͷN˸QʸYɻiʽ–ȯ¿Հ ؀rg{lCټ0ַ%״"Ա ү ά"ϩ#˦"ɠ"Ɲ#Ù# ~|zyxwuuy~%4AVpƮԀʼ~dTHA}:}:874358<>ACCCDGN§PǮNαNϳNѵPѹYϻf}ɓѪ~(2sŹd=Ӷ/նѮ%״ үɧ˥ ȣŜ™|{yxxwvvz~&;Pƣjβ2Oƽġ{_ME>}:~663248:;>@?@@BKLīK̯LβMϳNζV˷bȹtÍʣǯc(щup{cF׻9Ӷ.Ѳ(Ϯ&ҰͪʧȞŜ—~|zyxxwwwz%:Qrƪc~ϱƸs[PF>;43368:<>==<>IKĤK̪MӭMԮNӲQзUųZοvNjӪ½Ⱦ(Yʾyc?д7Ѵ&ɪ)ЯʨŢ˨Ɯ™}|{yxxwwwx0KǛfЬc2 ~޴n[NC=631457:<:98:DFFǥHΨHЪJϮM˲PųZĵlû™̳n EՀxhb9ܽ*ڵ%հ)Ϫ&̧%̥#ʣ!Ǟ!š%Í#~ x wts vxw$>V~ű;~_OC2~08{5}572446<=?BGKM©MƮJͰM̯LػXջaĂƗƯ2nvŷ[4׸'ײ#Ӯ'ͨ$ʥ#ʣ!ȡě#!} y wts v yz,J£kѵnsYI737{5}571235;==@DHJJĬHˮKˮKҵRδZҼz“ĭYϰwJܾ.ѱ&Ү"Ϊ$ˤ"ɢ!ȟŜ—}ytussy}#;`˸(ΐʾ{cG<9~5~9:89878:;=BEFG¦GũJʭKʭKȮTʹnпß˰OOzAӵ,ϯ"Ϊ˧"ɢ ǠŜ™{xtust{!,Gsеy2ĚëwRB=9:~97875478:>@BCD¦GȫIǪHƬRƭgȷ̼ϴ~փvXؿ0ϭ,Э#̥!ʣ!ǞŜę~|zywv!t"uty&Gwȯc щ˿xZGB:}8y;{=~;83568=?@DDEȨIȨIȫPêZŰl̻ɕĻɰ2쎟ʾtӿMʹ,˩*Ϋ ɢǠŜ™}{zyvu s st{!-T̩2ٽ˹iME;}8x:{=~;~72545;==AABťFƦGƩNTfƵ|ʼ˪cc³pѽRغ2ά$ʥ%˦#Ǟ!Ŝė~}zyutrrrvy%=eê(ƽkQ?9|6{9{9{86724:<>BCDDàFŦKM«[ưhκsϔӃ˼l͹Q׹2ά"ȣ!Ǣ"Ɲ ě•}|zyutrqt!y"~-IȡtҹyOȪy]F>~8{9z8y6~45139;=AABACĥJMì\`˷p‡(Eƶu׿Rָ/ѭ$ʥǝȞ Ö |z w s pqqsw1V̷EYħwSE:5}6}:<~:228;>@AA@AEINS̲^ӻoœŮՀ~ŵsսOӵ+ͩ!ǢƜƜ•~{z w s pqrux#9`Ǩ ܿͿ^L=8~7}:;~:227:<>??=?BFKPǭYζjƻɰ(Ͱtl̴^غ9Ѯ!ʣŞÚė{y zy t sssuy4_̼ېEг^E>7|3{8{85469;<>?@?BFGJɫRҳ^μ OY|nζZԶ3˨Ɵĝ™~zxyx s s rsu{&<ÛkͯcĖkLC:}4z7|954689:<=>>@DFHŧNˬWǵʾå؃Րu˳V׸CӰ*Ǣěě!• ~|ywywssrsz$>hê߉п³kSC7~467667899<;=@CDFŠKɣQêjȷȠ((|ҺUַ=ͪ&ÞÚ™|{xvywrsst}*DÜq̳cϐ¢w[F8~4~46~5~57887:9<>ACEHşMe±ƞOEfԸHӲ,ɤ$"˜~| zyu t wu#r$s tv'1bè߃ǽqR:/,}6|5~576669;=>@CFÛIĜJ]ïv¸~cbдBͬ(Š"!}{yxu s wu#r%t!u!y+6ęj˰cԀɹzX?2-|5{4}4666588:;=@DFGWnȸŻylʲ@ֲ4ʦ*Ü& }{yxvuurrq)x/3EǦû( OǹrT100}2}24778:;<<>>AACM̥aȲpŖ;̚rи<Ү1ǣ'$|zyxvvwttt-|4:MϮn (ƽ{[621~3~3576799;:=@BDƟUaμû~;~ijgе6ʤ,&$}|zxvuuuurvy,@PǠyؽyEμkF;74}4676~7~7898;:<>@C›Q\ȶƾ݀ OnȱPͭ,˟#–|{xwuuttvsw~,IsǪ;ʥwVC96}4~5~7~7~7~789:<;==?BFT¯rȽynȱLɩ)Ȝ!{zxvutttusx/M›wˮԀƿ~]H:6|3}4~7~7~7~7799;:<<>BBSkø( Ӄ|Z˯>ʥ'ŗ~{yxutssssrs{!5Uáɷ֐;ɷnS<7}2}2~5~5~5667689:;<>=OdĶú( ~Yʮ<ȣ$”}{xwutsstttu}%9ZȦμۃѿrU>8~3}2}4}4~5~5566789:;:8M`Ļ2(ɳJͬ:Ǡ'#}zzwwttsssstv~3BfĬE}`B6|144~3444434578:9?FUijzøƿY(ʴJͬ9Ɵ&"}zzwwttsssstv 4ChƮ2 ͚ûdD8}244~3443434578:9>ETwĽc;ʴMͪ4Ɯ!~{{xxwwvvvvx x*BT´҉ yƿnJ=675566567879<==DGVuųĻyEĿʴL̩2Ě!||zyyxxxxx{$|.FWæĶՀYijsMA997788789:9;=?>DHVrIJúڀE½ʳP̨8˜+'$$#! ~ ~{{{z{{{{$|-~:Wt»~;Ÿ|TH@?=>@?=>?@ACEFGHMWqIJ؃ E½˴RΪ;ś-*'&&$##""!~!~!!!!&~0>[£vüy2ƹYMFDBCECBCDEEFHIKKQZqų ;¾ͷVҮKȠQMKJJIHHGFFFDDDD9Wwc ۹skfefccedddddeffgjpڰŽ2ՃuHt{8ip-gn+jl*jl*jl*hj(ij(ij(ij(hi'hj(ik)hl*im+om,mk*ns.q{5}OqY(ؾl^\[[[ZYYZZZZZ[\\^hx沛Y~k@qu.jn'ei"cg fj#de!de!cd cd cd cd cg cg dh!dh!df eg!em&ht,wImȿ2l]ZYYYXWXXXXXYZZ[]eu屚Eyaz;mq*fj#ae`dbfabab`a`a`a`a_c`d`d`dacceck$gs+wIn(ĵ縝mZWUVVUUUUUUVVWXXW\mϩ2 cr|Q{4jn#dg`c^a`c^`^`________]_]_^a^a]`^a_hdo)uIo ~ȹ縝mZVSTUTTTTTUUVWWXWZkӭـsyNx|1hl!cf`c^a`c]_]_^^^^^^^^\^]_]`]`\_]`^gdo)vJr̚ cⷢr[WSSTTSSSTTUVWXXSVf~䰠(ΚmyGxz.ikefbc_b`c]_^`]_]_\^\^\_]`]`]``aab`h!gq.zOxӃE乤u]XSSTTSSSTUVWXXXTWf|糣;EivDuw+hjefcd_b`c]_^`]_]_\^\^\_\_]`]`_`abai"is0}R|y滪~`ZUTUUTTSTVWXYYYTVcxc~]v?rv*eicgae_cac]a]a\`\`[_[_\_\_]a]a]^`_ci"lu2UîO 转﬑a[UTUTTSSTUWXYYYUVbu;Xr;qu)eidhbf`dac]a^b]a]a\`\`]`]`]a]a^_bafl%qz7Zʵ( nŷ᭠f[VVTTTSSSTWXXXZ`c`s|㻞АnrAy0sr"nmffeecebd_c_c]`]`]`]`^_^_a_a_]a[dai-pxIo(OͿ沥h]WWTTTSSSTVXXXZ^daoz彠O(Κp?w}.sr"mlggffdfbd_c^b]`]`]`]`^_^_`^a_[_\eem1u}Nvщ (߼nbYWSSRQQQTVXXYZ]b`ku゙˫ۃ Yya7tz(pq!klhhggdfbd^b^b]`]`^a]`^_^_^_^_Y`^i jr6{Wĵc ӃõreZXSSRQRQTVWXY[^aajsֶ2؀uW{2qw%op klhhhhegbd^b]a]`]`^a^a_`^_]^]^[bbm$px<];Yⱡ{j^WQQQPRQSVWWY[^_`ioѰ݃; c}dCy'sxoqkkiihhegbd^b]a]`]`^a]`\_\_\_\_[ddo)r{Be͚ ;跧n`XQQQORQSUWWY[_^ajo{©ۺy 2_>u~#qvoqlliihhdfac]a]a]`]`]`]`\_\_\_]`^gfq+xHpy Հ¸wf]TPOMQSSUWWWY\]aglvEjH0x|swoqllgjfidfac]a^b]`]`\^\^Z^[_\`^b_j$gt6Uϸ2nɿzh^TPOMQSSUWWWY[^bflxټ߃2ʞb@~-w{txoqllhkfice`b]a^b]`]`\^[]Z^[_]a_ccn(ly;] 黣sfWQNNQSTVWWVX\\`ehoz˳ʥ;ՃsI3~(vwvwnr knhkehcfbc`a__\^^`[_[_\_Z]Z_af!`l0vRoy ~whYQNMQSTVVWVX\\`ehnyȰįӐ ciC/|&vwuvnr kngjdgcfab`a^^]_^`[_Z^[^Z]Z_ch#ht8~Z}γ;Eɸ浛棄q_SNMRSUWWUSU]^bfhiqžѲέ{nOxpoN5'}~ wxtsmp jmfidgbeab`a^^]_]_Z]Z]Y^X]\dfn(oyJoʥᄂuaTPORSUWWTSU\^bfgip|ŦƲ}¼OO҃yvwdC1}${|xytsmp jmfidgbeab`a__\^]_Z][^Z_Z_`h"mu/xS|ĩyԀƵ㰖~gWQPRSUWVTQS\_aedfks|α廨ǽ2~|ohD.)"{{vzrtlqjmfjdgcfbc`a__\^\^Z][^Y`Y`aj'py6fY븞暈kYQORSUVVSPS\^`ccfkq|Ũʷα~}ΐӃuwqzX;+(!{{vzrtkpileicfbeab`a__]_\^Z]\_Za[ben+x>sՀщıu_UQSTUVVSPR\^`cbfjmvz˵}̚EԀyyyV6+#}~{{vzqsjogjdhbead`a_`^^^_]^[^]`\c ah%ox5Kǽ(nλ|dWRSTUVVSPR\^`bafjmtttt˥2(yrrruN.)"{|{{uyprinficgad`c_`^_]]^_]^[^^a`g$gn+y?WnYijs`YVTUTRTUS[]_bdhilrw~Ƥήлzx˥c2ېtwnjdžcB8+%$$y{!uv oriqbn`l`f```] c[c]c^\] `fYbVd_m+drb҃Ȱ櫋xk^Z_\XUWY]]^]`bfkovz~ˆĎÓƙȠ̧ѭմʶsaXNe\YypmփyYE2 (EOn~ЉssydfgWUTa_WŞʓԉu]G:1*%+*&&$"}|!|z"vw!poikggdgbe_d`d]^`a`dX_Xa[f _h)gp=zYϸ(;qa\`a^ZZZ\\][]_bglsvz~ėƞɤձѰѵtkhWPM_XUtpovuqkjfTTZZZ`wyzϨčp_L;1*&#''$$"~zyzx tuonhjggcf_b^cbfcdbcbf[d_j$ir3yOräЉ2ǽ廤榇qdbgfea][XXYZ\_flsuz|ŠƎȔƑ˙ѡЧӰ˻znxkwjsg]j`Vnf_rpfzvq~{vswkkq`ciV`fSfnWsv`zzhwաޗxaO>80)(''(%%$$"yytusr!kmjjgjghdf`a``ccgi#ac`d]e_h%dm5u|Ow~nй{haefhfa]XWXYY\cioqvy~ōǓɔ˙ϟЧЭϳҺxpf\f^Wig]kgbmjeokjqmluqpyut|xwtrqusrstrrsqpqopqoptoquphlfek``dXY_NZ`MoubͻϽť{eP8/)#!&'&$"" !}~ xxrsqpkmiicfabaccdhh"kk%jl&acaeai"en+mv>`Ȱnζsjfhklib]XWWX]bioqruy~Ljʋ͍̌̒͛ѦϬбԸӻӿͽ˺Ǻɹ|xngk_]eZVcWW\ZZZXXWWWZZZ[\X\]Y`d^gmbwâĞȟ͢ЀpaWH72-0.//.) }{y| uwornoilfh`b]^cdnm)sq0sq0fi$adcg%fn/qy=[ҽ(ʥ£~tfhkoojd\WVW\`gnonqv{~ƒÄʊ͍̒ʘˠȥǨ̰ϷмӼ˿ǭ˭̫ɣÚs`PF6/2&*+-+&!xv{uxrtlojkbebdacdeop({z6yw6pn-`cadhl*nv7Mw˫OyТkfgoyxyzni^XX]__jnqux{}Çȋʑ͕ЗҘәҝҢ֥ת٭ٲڳڷ޻߾ݗ؈|qh[PF?A<620.,-/.****%$}*wz$qvpultiqenek`eeg%kl.st6{|<|}=or-_cMeZr$av8wZĸ; ~뽵{oimy{{{uri`ZZ[\gikosx|ćƍȐ˒ΔЖΙ͝ПѤҦҫӬӰ״طٻ״ԤЕʄsg]TJB;662.++*(*&(''$ wz$vy#tyqvjrfndmgmlq&qs1~ALFtu5eh#_c%k5wNxɫcӃèzrsuvvyyxsnkgedgimpsuv|~ĉȍ̐Β͔͘ϗϛМРҟңңҧիִټ߲ٙՅq\NA<5...*+)'&'(&'&&&%## ~!qw os!kohkghjj$qq+xv5>BJIu|9bi&[d!bk(dv;{ZzĪn2ťwqrvy{zyz{{rkffegimprxz~Ŋɍˏ˒̗ϗϛМϟўѢСХҨԲ׺ޱ֖ЀkTI<60*+,)*)'&&&#$" y|tukqjnhljmqr(||6?GNOIvz8cj'^e"fo,qz7sJpÝϐ n뫒wons|tqligkostvz}NJʌ͏ВғғԓԓՖ՚֟קٱܻ۫ԍrV?1+(&).30'&%%$##$#"$}$w|!sv kqgkhpot)xy5~BPXYYZN|JV]cddce^WElq4`f+fo7p{IdԶ2˥Ϋ~wzwtuwy~~ƃȅʇʋʎ˗΢ѭ׵ոѠɃhO;,&#$%*-)"!~z~z|"{+~1=LZddeghdejk[Ill0hm0kq6vG`ݲnO﷤|žžœĞȪʵйػո֪ϖ{gP>/*%&$$ "~)-.15>KU]lwxvxwvwxukc[~@jr,ci0kn=y|UsȰ( nǽ}˜ś šǣǡǡȡȡɠǞǛƚ­ȱϲ̯̠ƍr]G6)%"&'**.;AGQ[eou}}||~~}pW~@lt.ks-sy@UwɰӃ˷㳗꧆ĞŨħ¤ƫȭƫʮ˯ͯϱввѱаѰЯϭ̪˦ȣǞƝڙĪdzɵж̲ʪĜwj^USSVX\aezzZq};ht2hv6s~FdιY~ӷƩʭ̮ȪŪƫǬŪʮ˯̮ͯϱвѱҲմ׶ڸ۹ܷڵٰ׮د׮կԱԷּۻذѠ͓ɉ~~Ɂˁ̓чԊ͑˓ɑŒ}_mv=am+lx6}KdܽO(̚䮗਋婌ĦгѴ̯ȯɯɳ˴˴ʵ̷θѻӽԾԹպ׿ٿټضӱ̪˩ʨɧƧäâģĞÝÜƙĕx}VhrCirGr|QeӃ(Ӄй믒樊쮐ǪҵռջҼййϺϺѻҼԾտپپ۾ڸִҰЮϭϭ̭ȩƥƥƠǡȡţá¤áȡˢ•}hv~Ogo@hrC{Yuֶ~(ϐкƨжӺԾۻ۵زӭέ̭̲̲ɴƳƳ˫˫ɫȪƪũĨ¦ϱάˤśmQpyAp|@OtƶEnۺ˪찒©ѻ޾߹ܶ۵մҳѷҸι̹˸ϯͭ˭ΰѵԸԸӷѳĢsVs{FxIWaxӨȰ2cɶ⹣⮗ìͶֽռԺӹԵԵԵնϾ־ؼ۷Ǖn}VuQrSvYo̚n2nʥ̵¬̷ٿٿܽ޿Ϊ™nZ{SuN~ZsЧ;ϐݿἦḡ浟DzҾصЫzhby\z`tcE~ʥϸ빣︣ȸqh|]}^myѲ̚n;~±빥﹢«ɲѺ޺ѫÝwom~ik{ȱy(OӃǽйʳﻤヲ齥©ȮʰͲеպپڼҴɩ}rljmqtҴщO;Yʹôݼ们纬뺬ﻮôѼ̷î~̲ջ˥yE (;YnՀЉʥƽƽǽƽƽӾҽӽѻʹɰεռ҃̚yY;??????????????????????????????????????????(0` 6j䞣ধ®r4 *}څwgkȁ'1pjfͼ`VMfګَ֕Κǿ󶸸,ǚiiǹYA-(#(MшYYgo؁ӛöȔ6soĸY8%&()!%ֺ=ڼԳxTZ^YW`tӖû:Vl\8$"%ڼ$ַѭͥɢ+ƢEЬջͨʷsëPIƭI̴NպX[Y^xКP\nP*$$عҰ ʤę"–6ƜHͦiӳѫеyƨ_LHƫKʹRTVeА[ukƸD$ھ#عѭɡ):ėF›C9IÕˣk^åiɧsƨiQDDĪI͵QտT]̀ƸY0kôD"عԲ ʥ˜ * z'9^ʥӳǡ跛aM>@PSA?JɫMϹOҾV}2rBֶѬȝ{vvFßޫؖm& F}èɷo?8B>>DĦH̵KӼOǁLJvB"ԲΨ Ěxt{FZAΧi=55:CFɯK͹RƇɉ,]Խ(Գ̧Ù}xu#vϴvRǹ槅F34<=HͬKϷZ!ħp+ص"ɤ–vt'2Ž˫B}267?GȬGӻj˖"Vз˥Ù~xr~ҹ:̼ئ@z866?DƪRȺvy.ЬęxqwdȪM/{6|74=@Eʳdm¿UˮǞztq8هʆU}4~59=@ťLŴ2:̩{vry}Ϲ ĵ੄8}169>CŬn0\vð)ŝyus5۟ʒU~/68;=ãV`цZè{uswZŠ<@x5}479;F؏δHĢ~wsq}Ͷ<|1447Cai%\gN{|vw}ɇ͎өըL $! }, ۼΩ˜!.68oˢa_[KEɮLUu}5;پղƜxzF}kkk$  *}qiiEBaFYl((jiinnY&_x[O^λ.OTzج,tZ|M7NwP=tcc?6\3}U~7bFGFο?tn _7ع RZckT:RK1dʕ{x%{] pAQ +!FLEP@ƹWf3hI[(.h4j @C4q*Xylx>5͝K&H$dঅ|~; P*`MKrf;'TW X_[CSWڱ\}(`%>rxc] (h!RIT{-Ecf}:Sf_pΞ9&zZجRWt}z0p0z{zsߣ3##455YMpT霆y (4Չhoo'<Q|"zl"=c'?.cAcRX39,|% , ~EDXv6C.pX4C}9BhܞpWr* AQ((=Z[ ޚ~VA նzr߾}BO?J,a=L u<'9= !poK@P0HMMMFMm&S_]e2f-ص{T^imm'P!0-tݻvz\pdPd=T?_S&aa7YՅS,ڵL{wܩYۥ;ahqoAq=jYP{- R)?$?(Εejg%@ ]-6i݁k\Y )'aY笽+ky@k0 Ojy|bXi0JSc^.J3DSF&QVk Pci p{'͂HBp`@^k( `9NH( fxn9A h(ݑ ޗ`_T {ohAIP]<}lrvZkju :zsQ@! H4J_@QG]XG8OH2Z~x{.`XIdu_Z|L\|2Nկ󤈗(a/= DyE\.ShU-cBry%^?Ah<Ǽ~L)o0\nTEI֑X^*81+.]hEQ;AE*96 8&BjaV0 йc&M ڥH& ݠ9!r5dG(K07K`cD%NU3&.ca㷚`yDdVkm-"{+F jdp:Y(8MQw ʼnA[t=r- LkᣀExy<$AU  4 QZͅHz^y)F5@C5#HBMyH-" @A*P԰QT1.XO5m ֪onnuBaQN+9JPd Ԝ~&ap.>. w".or$Ex=CA;τD JSwO P\@O&`6%h)!9Nrɔ:,%X6S£jtFȭ.bd3P Ȑ- tuZYc(gad0zZŐJ‘ei&HXz(Zx2 FCHo y8~G&hu.]<}!79YJpgps8s|@Ú/Nlzba&oZ޺dVRYaLwSLP g陌,%iIA\W؜&WxW fP A%9P4ia)FIUP" TՅVEUaCP{Vg$ U>rvZL ?lPlBs 8J_XLdj|킻4& X7^7~^ rNF &`y0 m VT96j}_U gϜND4lpzo} |\5QX}xH~O|_isDWԃMƵ_~͑iSB7nڟT_'1ٷDILfK(u^[BM2 cm:q:?3f'H0HJu1hi1!O[*UYf R⅋W^91:z"8SPQtd̽K瞃nlQ ^ S>2ܓ=H&7 .]Zݹ\%"m)U?|y˜q8c/Ƀ}CCCg/JVG{;IENDB`synergy-1.8.8-stable/src/gui/res/icons/64x64/video-display.png000066400000000000000000000050231305627404700240410ustar00rootroot00000000000000PNG  IHDR@@iqsBIT|d pHYsu85tEXtSoftwarewww.inkscape.org< IDATx[kݣ4|ΎVFb8N 8 >d! "b샯9|eb0X4ߟ][F?FӒ 75NLͥ٢(%h?nn޼%p9seSVp84LF>6>5 5":0 heeeŔJ%ng@7l,j FD7`H)2A/6=Wm9L?ͬn}"xn4< wkL$ _͗_᷿cPMglr(alõ0HlGigH0QB\Hnގ=Ћ?šrl)h[p`t\otHPG HǬVQ\Ƹd Qh7#0*!_O㔌'!lYy{z(j`F껢䑼(c8}鸬}js=D/1B鈬)(V ɿ;+koO\ڤ3bE*瀄T2+aiX G ?@{WV$0 RPa Ntr!0+P:K%l)iVeX92+`P+T!Ǥ4(tBCB0͊~a9@aI>iVzt̰Ɯ|S/\yBף c^/ Ç}z@&4bmooyyY˽"d {ⅼ#8SО={fv\.k׮%hB2NG^U^gvwwco:yWkOvOW^o7FmHo߿#"z277g]٠}jYi6}̉o>$>7+5P(ȫ콽=˼3??* $b8ĭr/Xu$|˲g,NpE gggBho_k___7_xݟ̼{׼sNLצK=*yS뼩o:OH̖XN bA-1n wos$``C%A jKZ>ܿafy,/9~[~_>XZ][5˜Ke3ϛmMN;8Ӈ,7ӧO {dXlπrj0>0.\0kkk0coA30&1C=+{5>4w_Th208+$#FOW?xҏʥ bP,;b& Y33?fJ@)gZ`i;fo=a??g: 7I,apq.}WV2oX Jis@Q/x q7y0Gp^K={:_lhj6kޠFU{N͓'Η-14A,{D&1`-`bƓz'|ؙX^(rr! XR8W*-W*+˕FQU^Wo5ZG\ݎ,]I-^CKF(gp{۾@<IENDB`synergy-1.8.8-stable/src/gui/res/image/000077500000000000000000000000001305627404700177365ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/res/image/about.png000066400000000000000000000115151305627404700215610ustar00rootroot00000000000000PNG  IHDR$_ztEXtSoftwareAdobe ImageReadyqe<IDATx\ypUz鞫g4$K3,K,[2ȇǂ ,0؄T?IU dl.f.bl6YXY26>$[%[5zP{vf4 =W37~}#`0BzX;)U/߃jq,Ã]EkV,6qFt|>Rdt+@tdx'$I|j20 O@,U-_YZZfXmUW1W|>?cqI!GVښL: 5NqXR`X̒, 9ʊTGw78޼zΖg**k7[Khtd`!3PPIOR%4ഖ0Zs6tQyIpxL_GQgMWF$ BV΢pb*8A`2`ھ$>!Xh4(qp~ LEAl]=}I?38FPX zetЫ^PL@&(! ) H0HF@`'I"Rseؿ݃:NRH| (,V`Lf+4k޳恧I$Xf Ђ@EddDI _Q|2q (0>:mtС]z{'xz3?B_Uc:&} -÷?n{ QNNŌbCV3cG|0dhH %AGr%M%9/+6?G펓>@h|BU2z(\tۿi-(&=6X>?zK߿y6βA d8 ZO7߹ҵqE'!GpoYtP:N gnckxd|C~7'q"-;tJu!ؑ=g׻Zx9¤(zQ]P{[awXvc(\HIFp];g|Y22g8d{=z\ @f'LM^?Ȝ(.<&5~#5.fR8 U~)﫿>UߴrG p094 IeO2_'˜043`W>ҧ|n2PdtAJ*;#)G<$\8Ɔ{g2^Yɹ ,NQG>ƿ؆}~ U;  CU~:h*м|v|/-\[T@*IYZAӢ)ِ yS hyF]d;}d_~"Nq#8+).'-] /?',4s\׆s~oyfU[Xϗq22tGzMiZUlJa٠ ^~{ 8L>aV5٭f{[o_5A[8U}6<3GpΛqq-%AQiu@y~L<'<71[KyO#92ŋk8~[ ez),^,dtzWac&>MIiTK*uAzc4m; lKK=L^ִk[N*pܪ0:;kǯ^$ΖKN*YPx yF6'%)?4r7Rr29qJK|۞!0\V7OERio_Si*cЬWԽ26@PUbಪKoJ݃ބQ`jPnzDѴg>*/ڠl(XnW`)éګz 䦹NhAՃ^Rt*䔧94)!˽WyLZbb)uJLU>`ŧY6|ٲ[(3jvvB8T~U9c!Ϊu@lˠjuך$K3nSRiťfzֵLrp洺X\Gڽn2d? nb2j۩i&S6éOL$\Hp D' σ@W9.~AfDRbrb*W Cp|4-8$MAyR䀙l/GL :3 ` hYmR3# F,V=yNikU9ޚ#fU #iD! >@qDeHA8ʬ%׈Enym{aCA5T8 ^AZ笖!?Qĥ" qǔmIIN4)7Π@fi澊>%>HNQ`6:{hA!1 @˃]' G vYT/pD2c_ D"n )};6!`di`+E6Dyymݐ\N}sWt6ŝG+ΖL^2pqs /8"$4. П{DicDCaڻn1p.eWP&8'- " x责hXsl)nY t ^xlj/T߭ӕi=KɅq1Rr 6U֭Mf]@7i2f8)!%63= TLFC#>>jw836-y̰z6ö9 Q-˓-9m#ْN&]Y\wZ\ #P"!AP/ z"YPXZ'^ xL]jQMul3G=u.S:)VG. u+7}CK.K$ e޼tW܆JIi#ZdND$d~~fԵ/$XXY !s~ڵG51gT n|)Ƚy\j{F5i<^q{_s[m]) S eYoB M>kL<솩ԇN͝7xT Q|ebp"mOnضDCQ"~:~mf($qd1^:T$Le"6{c;`*#';rn,?6=wx߾.Z+kť E`#:Lā !q?:xdѺ%Klvryu8QxCiH籐u(LůLL*}Ls'US9kkYcd8R<EIx(د555ֻV.Z4*+7{?pv\p;|~eYN哧Ӗ8%{!zlԣ/zZg| z1 h z}fyK]ecNg⸰0SWdHIENDB`synergy-1.8.8-stable/src/gui/res/image/spinning-wheel.gif000066400000000000000000000227311305627404700233610ustar00rootroot00000000000000GIF89a<<nnn'''111bbbJJJCBB潽˭zzzɲŖ;;;𢡡uuuꚙhhhTTT~~~qqq]]]ܞFEEςΤYXXü666ZZZۙOOOwww! NETSCAPE2.0! ,<<#efe$fYg_VhaYcVe`ǂ:`Yf7-τbah ܂_0vƝ?(\@ޘo:I2q&ML20Cl,(4jDL,7Ha ,ܡ+4(-aP):Iv@o 6i*N `iET{ !i hrv̠00pY"nHU):4&7d.kTPRS>׭W/2@mڸ[7 MwpÉF͓+-QdI|ТE '^4WXċ},x>JO'G1\b! E:0H PDHE(4b0|E!Aip bH\W"YE"" |J $ eFpd$dK^!_\`l!|ė=$a%%2'e\C V'蜅TeOV D@—ڼ3 VBaȠef JS$ q>ǹɃ|X"Ѓ ;ȅ5N߃_MM_b;HB! nd!D:$`  ڐ))=7%ȠR6yǀse!N"۰D8FL,afc 0dQ6B3&,g-)f d ahLxzx"B _"d0 p)d) ň7> 13?!=l~^`#P xp @^n";EwbF ,"2un]4j c,С)oԹb0(!'ťAviFzФA6j!#ʦA\Pg*!cBQ$b!wG߈iz,!ri6T*QIp 8a!F 9Ѡ~*}J" 7[ ! ,<<o1ed a]V MI@$f #gS{ȹʃν(уrɅ_**_rQ6>B5Q53vP|rȫY$Q톈A M3gȄJ 5EL"|3f;}R(̢$&81G 4AJ@Jl }lFV6U ) S5Q {lJ &0@^:Ʋ!3 jxғZJojCQZ -FQ"4VͻA oD.(_Y`HN=Bɛ7n*z e׾(ߧDB\'JQe0O0cʖC։&t(FKdEB`I&}yM. `S5~deW(d!i i"&3 dRͻw G[ȓ+gЃ-УKb; سk0ӫo}{w"_>yCvlȟOF;+л&Ad`DS$t(gdF&A ^$cdag%I `hbl`$q$p"H ceB0 BP( b(1c 5HHL8+(!``^h"nb8 &Ƈa \Q!hᡖQ"`?Q nržI\!!*h@(gUzjg`ǞjR뭂4@_bĞQV9jj4"N 3F!_fkcIl(l-&j"e! Wl?! ,<<ZfZdoPpM p c0Y| 7oʂO"ӂ{zڂ_zV&,҄o7IpՠwPЈ΢B5pDi@(_)fMB"R5Ȱ%=Cd\8àڱ y0`GubDL-/dQDC}AҡK5u90(4jHH ASl{I[ıǔ4*;` Jt bC՞LAeKJmKe0lH6/#r=BmCqN ]S&(_|BA?*yE>(חge@ohK,` %FA/ tXdF'` &a%@ !,` 0GXR$8!QЉ( %2 v_.G)pQ:\cF!o@!r @"_E҃H^TN\r dye9&XĘ q1\4 hlD`( BV#5ţE Covh!bdC(ĹB0TҪM,Ĺ!~jz':s)DZz *!`z.ĩZHz2JBpy!>KHc2d Knbx [;_#f pl! ,<<|a&+_"6[r&Z ;;[zb_Z [ ÃPZ0(ʂN…q*Jڂfv҅Jqj[50}pF }X{1&8N kZVxÁF~ 75)dxK ጃ`48@ pA 'd ؒ4CgЂЗ{ hp E]Hap ;0Z.ܭO Hl)@7p  HYUV7"TM)CR}歨ȓ{ ÀУhKȸrY9. בg;tXϾ}(GGO]Ɋ + Љ1 D}0`% {Ub# o|XR 8bF ~(Deu22N0@x(QHCH:p6H { D#xH8GL@ 10H, e!i|eŞf1R}v"`V#Ffސ⁝\)f1Bpnu`'i!*0`' uSoD@np("Ä%讆āZO᪨lPD\ƗEm1#䠤!" PȊB=Zlqg 7L\ ! ,<<[[Yp_)_)6]::o]Udf< dU]OP/#ǂ:$ Qւ`!τ|(](݂"/=IJ G y l{,JC=Dv`3P>$j /^X8T2H{P 0h4JREYgȈ -P%$LO!L##J !Y-xre"<8 GDzbă3 %Pa$0'B`]-$X*ªw, ENxQI5J)1b˞'۸m^߽qNpD e w^س_NÃw$hYpKN 6ۧdb0aC6 It\B,8@>H Jh8@4r8FcH pD0E#E䇀ya2L!_Ia% l|FH~L1"hq@`'1Ř$"Tw9cNVlhqluYH c`FlefvC"n^R!9dq[6rj(!V0 㘁ۥjMifA!RFc0FVG$0l)"bxȂk! ,<<#`6]be:_]`&'!^jr[6"r^!wbz[;bǹɃ [Ѓ'#ȅN߂`==vf#^(ٶ%>BU3 0T}8H(qd-CY(!!Ύ7A,#(̏m=pȃ1SAEs(/~1#MƢ0=2laaL>i@ӛB"deQ #]qf t6GU`"˦0 ^`m; 5)& 2d@ nG vW,k%!Cq2h/jå\toʢZ btMԱc~{w)o!&%˟_"+ϿB_a$"@0`Egƒ-` c i"|qƅ v$`AaI6``"#he$g .h@ 4b%Hӈ/6*)G# .xFz*@F( Ѕ!_TG|8Fadhb"9@7#_y y JD* Y, @*)! 9@F!@"E~61)Nxj :2@Xji`7Z9AjH>x!BS9&+!YO! P_Ⱦ 7! ,<<V_^i_E^;d) ']6)` BycH]Oc; 2ȥ+]$у# ql6p`jj Uq!E>B2P%( B; j"%ŋ-S$Q?Fz<#L3g  .%XR E)y;d!Ė )q&1"(!9P0$ƈ-`4"Ӧ6& ,㨌KwKRFf)6Er{0q)N[t">v/3r4e)H] L)( [dG;([ЗF[Q,ȓ+ϢvУK˛kz>}zCױ'N{ 9þ3'?O# ;T:FX@Ё(RhM,0B&+ha.I Dadp$X!I*x>"x_DZ@#;o@1 a@H !L0#(P!FpD~q^z9a">i@a0`#FsY 0 F zf[AdDڐȱS !BJ*詂U8Q A @(!DPlj!#g)!yyllPg x a4!.u{! ̑ H' ! ,<<aY`) b`_ xwC\3"^!'W\9}_Q^ k\Dȹʂs^Iу\gɅb!L%h !n߄p;Ѯj4T   ӆڭ2fY̠jRÌDD\"f-nvbK\$f4\rDy u; }ah*d\z)yfdTfǘB4x2dm4e!\!@24/H*T g! ,<<k\cch\__gYe )cYY``r A`ab ,Yʂ;(قhg߅(BfYY,daJ 'hN59-'k`A) ꂑDe%sX,y=2iY"jX9$F/0 8 9 ⦗ s‡BhtcTE<:h&P؛Q=b0-r)Yam9[ɀmK+z -TX& 4 I[ 3 S^]&װSYHĄ۸sO IwZȶnݼ[.8!q'9pFν{N߼x Aqh%\3"X|ÃnʂNo…u48قb҅8mu =y\ 0C("ֆL3ۆƓp% |`X+RJģ&s(B^Y̡1(X(Ј͔)%X1 )!0 V(*g!@ Ap;!"S*p) uZ%w ̔ЩVHʐW%wY V"CX,t)؊@җ_ɞMK۸s0A{Q AW/ȓ+zË:|ysAϡ.zdBy-Wݣ dts@NOtaCU|Q$hD@B%UvO… %_`C]Ada]|#ph5a2< !R`[dT HpbqC y+Et$`nA7Qb}PM/G$ flg,ġjW v)bGt5̨ by"9 0>jHy^<<'Al9? 97)¦bIAzt$7 {ho#dH,;synergy-1.8.8-stable/src/gui/res/lang/000077500000000000000000000000001305627404700175755ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/res/lang/Languages.xml000066400000000000000000000042041305627404700222250ustar00rootroot00000000000000 synergy-1.8.8-stable/src/gui/res/lang/gui_af-ZA.qm000066400000000000000000000000201305627404700216660ustar00rootroot00000000000000 AboutDialogBase About Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: &Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left right up down Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_ar.qm000066400000000000000000000166661305627404700214210ustar00rootroot00000000000000 (Z bv ;H}H]VEnl0 [e"QJ@d攄HJ( n4.dzu G 3=T y%wnP ք~ ȹ C ȹ] ȹ KG@ RVv RV RV T V4  s s( FS Ҫ/ ^ i! $ r1 zk Pe ¦e]^1\=i -3FK'&OkAboutDialogBase9F 3JFJ1,J About SynergyAboutDialogBase:J1 E91HAUnknownAboutDialogBase'D%5/'1Version:AboutDialogBase"'.*'1 'D'E1 DD9EDChoose the action to performActionDialogBase*CHJF 'D9EDConfigure ActionActionDialogBase :DB 'DE$41 D4'4)Lock cursor to screenActionDialogBase:'6:7 9DI EA*'- 'D*4:JD 'D31J9Press a hotkeyActionDialogBaseD'6:7 H'A1, 9F EA*'- 'D*4:JD 'D31J9Press and release a hotkeyActionDialogBase'D'A1', 9FGRelease a hotkeyActionDialogBase*:JJ1 'D'*,'GSwitch in directionActionDialogBase*:JJ1 'D4'4)Switch to screenActionDialogBase.G0' 'D'E1 *E 9EDG 9F/E'This action is performed whenActionDialogBase'3ADdownActionDialogBase4E'DleftActionDialogBase *97JDoffActionDialogBase *4:JDonActionDialogBase&AB7 9DI G0G 'D4'4'*only on these screensActionDialogBaseJEJFrightActionDialogBase2EA*'- 'D*4:JD 'D31J9 6O:7the hotkey is pressedActionDialogBase:EA*'- 'D*4:JD 'D31J9 'A1, 9FGthe hotkey is releasedActionDialogBase *(/JDtoggleActionDialogBase'9DIupActionDialogBase>'/.D 5A'* EA*'- 'D*4:JD 'D31J9:'Enter the specification for the hotkey:HotkeyDialogBase(EA*'- 'D*4:JD 'D31J9HotkeyHotkeyDialogBase *9/JD&Edit MainWindowEDA&File MainWindow E3'9/)&Help MainWindow4('C&Window MainWindow2D' JECF C*'() EDA 'D*CHJFCannot write configuration file MainWindow'DE6JA A'1:Hostname is empty MainWindowV 'D1,'! ED! '3E 'DE6JA D9'ED'D*"21 DD'*5'D.?Please fill in a hostname for the synergy client to connect to. MainWindow2'D(1F', D' J3*7J9 'F J(/#Program can not be started MainWindow 3JFJ1,JSynergy MainWindow<9'ED 'D*"21 DE J*E 'D9+H1 9DJGSynergy client not found MainWindowVD' H,H/ DD*FAJ0 D'F 9'ED 'D*"21 :J1 EH,H/.5The executable for the synergy client does not exist. MainWindow>The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindow:J1 E91HAUnknown MainWindow*5A- &Browse...MainWindowBase.1H,&QuitMainWindowBase./E) 'D IP : &Server IP:MainWindowBase*CHJF *('/DJConfigure interactively:MainWindowBase*9/JD 'D%9/'/'* Edit settingsMainWindowBase %.A'!HideMainWindowBase9FH'F 'D IP IP addresses:MainWindowBase3,DLogMainWindowBase.1H,QuitMainWindowBase,'G2ReadyMainWindowBase *4:DJRunMainWindowBase *4:JDJ Run WizardMainWindowBase'3E 'D4'4): Screen name:MainWindowBase%9/'/'*SettingsMainWindowBase'8G1ShowMainWindowBase*HBAStopMainWindowBase 3JFJ1,JSynergyMainWindowBase:J1 E3EIUnnamedNewScreenWidget*5DJ-'*&FixesScreenSettingsDialogBaseJ3'1 Bottom-leftScreenSettingsDialogBaseJEJF Bottom-rightScreenSettingsDialogBase4E'DTop-leftScreenSettingsDialogBase'DJEJF 'D'9DI Top-rightScreenSettingsDialogBase *9/JD&EditServerConfigDialogBase 'DD:): &Language:SettingsDialogBase *5-J-DebugSettingsDialogBase *5-J-1Debug1SettingsDialogBase *5-J-2Debug2SettingsDialogBase.7#ErrorSettingsDialogBaseE9DHE'*InfoSettingsDialogBase*3,JD 'D/.HDLoggingSettingsDialogBase ED'-8)NoteSettingsDialogBase%9/'/'*SettingsSettingsDialogBase *-0J1WarningSettingsDialogBase&'D1,'! '.*J'1 .J'1.Please select an option. SetupWizard|'D*"21 J*J- DC (3GHD) E4'1C) 'DE'H3 HDH-) 'DEA'*J- (JF 'D9/J/ EF #,G2) 'DCE(JH*1 AJ EC*(C H'FG' D'D-1) H'DEA*H-) 'DE5/1. E,1/ *-1C 'DE'H3 EF 9DI -'A) 4'4) ,G'2 CE(JH*1 H'-/ 9DI ".1. JECFC -*I #F -5) CD EF 'D#DH'- 'DC*'() 'D.'5) (C. CD E' *-*',G GH '*5'D ('D4(C). 'D*"21 GH 9(1 EF5) (J9ED 9DI HJF/H2 HE'CF*H4 HDJFC3).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBase&4C1' D*F2JD 'D3F:1JThanks for installing Synergy!SetupWizardBase'GDK' H3GDK'WelcomeSetupWizardBase:J1 E91HAUnknownVersionChecker 3JFJ1,JSynergyZeroconfService$ ,synergy-1.8.8-stable/src/gui/res/lang/gui_ar.ts000066400000000000000000001644441305627404700214300ustar00rootroot00000000000000 AboutDialogBase About Synergy عن سينيرجي <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown غير معروف Version: الإصدار &Ok حسنًا ActionDialogBase Configure Action تكوين العمل Choose the action to perform اختار الامر للعمل Press a hotkey اضغط على مفتاح التشغيل السريع Release a hotkey الافراج عنه Press and release a hotkey اضغط وافرج عن مفتاح التشغيل السريع only on these screens فقط على هذه الشاشات Switch to screen تغيير الشاشة Switch in direction تغيير الاتجاه left شمال right يمين up اعلى down اسفل Lock cursor to screen غلق المؤشر لشاشة toggle تبديل on تشغيل off تعطيل This action is performed when هذا الامر تم عمله عندما the hotkey is pressed مفتاح التشغيل السريع ضُغط the hotkey is released مفتاح التشغيل السريع افرج عنه AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey مفتاح التشغيل السريع Enter the specification for the hotkey: ادخل صفات مفتاح التشغيل السريع: MainWindow &Start &File ملف &Edit تعديل &Window شباك &Help مساعدة <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started البرناج لا يستطيع ان يبدأ The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found عامل التآزر لم يتم العثور عليه The executable for the synergy client does not exist. لا وجود للتنفيذ لان عامل التآزر غير موجود. Hostname is empty المضيف فارغ Please fill in a hostname for the synergy client to connect to. الرجاء ملء اسم المضيف لعاملالتآزر للاتصال. Cannot write configuration file لا يمكن كتابة ملف التكوين The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown غير معروف Synergy سينيرجي Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy سينيرجي Ser&ver (share this computer's mouse and keyboard): Screen name: اسم الشاشة: &Server IP: خدمة ال IP : &Start Use existing configuration: &Configuration file: &Browse... تصفح Configure interactively: تكوين تبادلي &Configure Server... Ready جاهز Log سجل &Apply IP addresses: عنوان ال IP Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit خروج Quit خروج Run تشغلي S&top Stop توقف S&how Status &Hide Hide إخفاء &Show Show اظهر Save configuration &as... Save the interactively generated server configuration to a file. Settings إعدادات Edit settings تعديل الإعدادات Run Wizard تشغيلي NewScreenWidget Unnamed غير مسمى PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left شمال Top-right اليمين الاعلى Bottom-left يسار Bottom-right يمين Corner Si&ze: &Fixes تصليحات Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit تعديل &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings إعدادات Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging تسجيل الدخول &Logging level: Log to file: Browse... Error خطأ &Language: اللغة: &Miscellaneous Warning تحذير Note ملاحظة Info معلومات Debug تصحيح Debug1 تصحيح1 Debug2 تصحيح2 SetupWizard Setup Synergy Please select an option. الرجاء اختيار خيار. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome اهلًا وسهلًا Thanks for installing Synergy! شكرا لتنزيل السنغري Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). التآزر يتيح لك بسهولة مشاركة الماوس ولوحة المفاتيح بين العديد من أجهزة الكمبيوتر في مكتبك، وانها لالحرة والمفتوحة المصدر. مجرد تحرك الماوس من على حافة شاشة جهاز كمبيوتر واحد على آخر. يمكنك حتى أن حصة كل من الألواح الكتابة الخاصة بك. كل ما تحتاجه هو اتصال بالشبكة. التآزر هو عبر منصة (يعمل على ويندوز، وماكنتوش ولينكس). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown غير معروف WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy سينيرجي Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_bg-BG.qm000066400000000000000000000525711305627404700216700ustar00rootroot000000000000004}Su>(Z = nbj 4wE/1vGZN_#Ne9w9 '/_;H}H.O !}O FO G<]D|&VE :-UN*Yu:Cl_ } !*<"l1B 5:':1 e A$ZAJ,o"QJq-izD@d)ol -攄{J(F:S$^( n4.d.@Ty+L#@U{2_zb>JBg@` 3=Tk@d0ycME%@~ "}F9OnC 4rbun=2y~E$ r?/7+~kC8k2>*iO&OkAboutDialogBase0 !8=5@468 About SynergyAboutDialogBase58725AB=>UnknownAboutDialogBase5@A8O:Version:AboutDialogBaseV715@5B5 459AB285, :>5B> 40 1J45 87?J;=5=>.Choose the action to performActionDialogBase2>=D83C@8@0=5 =0 459AB285Configure ActionActionDialogBase20:;NG8 :C@A>@0 =0 5:@0=0Lock cursor to screenActionDialogBase*0B8A=8 3>@5I :;028H.Press a hotkeyActionDialogBase80B8A=8 8 ?CA=8 3>@5I :;028HPress and release a hotkeyActionDialogBase0B?CA=8 3>@5I8OB :;028H.Release a hotkeyActionDialogBase$@52:;NG8 2 ?>A>:0Switch in directionActionDialogBase&@52:;NG8 :J< 5:@0=Switch to screenActionDialogBase:59AB285B> A5 872J@H20 :>30B>This action is performed whenActionDialogBase4>;CdownActionDialogBase;O2>leftActionDialogBase 87:;.offActionDialogBase2:;.onActionDialogBase&A0<> =0 B578 5:@0=8only on these screensActionDialogBase 4OA=>rightActionDialogBase<3>@5I8OB :;028H 1J45 =0B8A=0B the hotkey is pressedActionDialogBase<3>@5I8OB :;028H 1J45 >B?CA=0B.the hotkey is releasedActionDialogBase?@52:;NG8toggleActionDialogBase3>@5upActionDialogBaseFJ2548 A?5F8D8:0F8O 70 3>@5I :;028H'Enter the specification for the hotkey:HotkeyDialogBase 540:F8O&Edit MainWindow$09;&File MainWindow ><>I&Help MainWindow !B0@B&Start MainWindow!B>?&Stop MainWindow@>7>@5F&Window MainWindow<p>0H0B0 25@A8O =0 !8=5@468 =5 5 0:BC0;=0. 5@A8O <b>%1</b> 5 4>ABJ?=0 70 <a href="%2">A20;O=5</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowz@0C7209B5 70 40 =0<5@8B5 :>=D83C@0F8>==8O D09; =0 ?@>3@0<0B0!Browse for a synergys config file MainWindow\>=D83C@0F8>==8OB D09; =5 <>65 40 1J45 70?8A0=Cannot write configuration file MainWindowT<5B> =0 :>=D83C@0F8>==8O D09; 5 =520;84=>Configuration filename invalid MainWindow^>=D83C@0F8>==8OB D09; =5 <>60 40 1J45 70?8A0=.%Could not save configuration to file. MainWindow6<5B> =0 ?@85<=8:0 5 ?@07=>Hostname is empty MainWindow>;O ?>?J;=5B5 8<5 =0 ?@85<=8:0 70 40 <>65 A8=5@468 :;85=BJB 40 A5 A2J@65.?Please fill in a hostname for the synergy client to connect to. MainWindowJ@>3@0<0B0 =5 <>65 40 1J45 AB0@B8@0=0Program can not be started MainWindowF0?8A20=5 =0 :>=D83C@0F8OB0 :0B>...Save configuration as... MainWindow,0?8A20=5B> A5 ?@>20;8 Save failed MainWindow!8=5@468Synergy MainWindow>!8=5@468 :;85=BJB =5 5 =0<5@5=.Synergy client not found MainWindow,!8=5@468 =5 5 0:B82=0.Synergy is not running. MainWindow&!8=5@468 5 0:B82=0.Synergy is running. MainWindow*!8=5@468 A5 AB0@B8@0.Synergy is starting. MainWindow<!8=5@468 AJ@2J@JB =5 5 =0<5@5=Synergy server not found MainWindow!8=5@468 15H5 =5>G0:20=> 87:;NG5=0 A 87E>45= :>4 %1.<br><br> >;O 70 45B09;8 286B5 @538AB@0F8>==8O D09;.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowJ!8=5@468 15H5 87:;NG5=0 ?>@048 3@5H:0 Synergy terminated with an error MainWindowXThe executable<br><br>%1<br><br>could not be successfully started, although it does exist. >;O ?@>25@5B5 40;8 8<0B5 =5>1E>48<8B5 ?@02><>I8O 70 AB0@B8@0=5 =0 B078 ?@>3@0<0.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindow@5<5==8OB :>=D83C@0F8>=5= D09;, =5>1E>48< 70 AB0@B8@0=5 =0 A8=5@468, =5 <>65 40 1J45 70?8A0=.NThe temporary configuration file required to start synergy can not be written. MainWindow58725AB=>Unknown MainWindow5 AB5 70?8A0;8 20;84=> 8<5 =0 :>=D83C@0F8>==8O D09; 70 A8=5@468 AJ@2J@0. A:0B5 ;8 40 =0?@028B5 B>20 A530?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow B=>A=> !8=5@468&About Synergy...MainWindowBase@8;>68&ApplyMainWindowBase@0C7209... &Browse...MainWindowBase*>=D83C@0F8>=5= D09;:&Configuration file:MainWindowBase,>=D83C@8@09 AJ@2J@...&Configure Server...MainWindowBase !:@89&HideMainWindowBase@5:@0B8&QuitMainWindowBaseIP =0 AJ@2J@0: &Server IP:MainWindowBase >:068&ShowMainWindowBase !B0@B&StartMainWindowBase6=B5@0:B82=> :>=D83C@8@0=5:Configure interactively:MainWindowBase, 540:B8@09 =0AB@>9:8B5 Edit settingsMainWindowBase !:@89HideMainWindowBaseIP 04@5A8: IP addresses:MainWindowBase 538ABJ@LogMainWindowBase@5:@0B8QuitMainWindowBase >B>2ReadyMainWindowBase!B0@B8@09RunMainWindowBase$!B0@B8@09 ?><>I=8: Run WizardMainWindowBase>:068 AB0BCA S&how StatusMainWindowBase!B>?S&topMainWindowBaseF0?8A20=5 =0 :>=D83C@0F8OB0 :0B>...Save configuration &as...MainWindowBasez0?8A20=5 =0 8=B5@0:B82=> 35=5@8@0=0B0 :>=D83C@0F8O 2J2 D09;.@Save the interactively generated server configuration to a file.MainWindowBase:@0==> 8<5: Screen name:MainWindowBase0AB@>9:8SettingsMainWindowBase >:068ShowMainWindowBase!B>?StopMainWindowBase!8=5@468SynergyMainWindowBase>7?>;7209 =0;8G=0 :>=D83C@0F8O:Use existing configuration:MainWindowBase578<5=5=UnnamedNewScreenWidget*0AB@>9:0 =0 !8=5@468 Setup SynergyPluginWizardPagep>=D83C@0F88 =0 !8=5@468 (*.conf);; A8G:8 D09;>25 (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectn>=D83C@0F88 =0 !8=5@468 (*.sgc);; A8G:8 D09;>25 (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectj!8AB5<=8OB :>=B59=5@ (B@59) =5 5 4>ABJ?5=, 70B20@O=5.%System tray is unavailable, quitting.QObject(:@0==>B> 8<5 ;8?A20Screen name is emptyScreenSettingsDialogP:@0==>B> 8<5 A5 ?@8?>:@820 A ?A524>=8<0Screen name matches aliasScreenSettingsDialog:@0==>B> 8<5 =5 <>65 40 5 ?@07=>. >;O 2J2545B5 8<5 8;8 >B:065B5 480;>30.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialog:@0==>B> 8<5 =5 <>65 40 5 AJI>B> :0B> ?A524>=8<0. >;O ?@5<0E=5B5 ?A524>=8<0 8;8 A<5=5B5 5:@0==>B> 8<5.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog >1028&AddScreenSettingsDialogBaseJ@BJ2 J3J; &Dead cornersScreenSettingsDialogBase Fixes&FixesScreenSettingsDialogBase@5<0E=8&RemoveScreenSettingsDialogBase 538ABJ@:&Shift:ScreenSettingsDialogBaseA524>=8<A&liasesScreenSettingsDialogBaseAlt:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase>;C-4OA=> Bottom-leftScreenSettingsDialogBase>;C-4OA=> Bottom-rightScreenSettingsDialogBase" 07<5@ =0 J3;8B5: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase4>@838@09 :;028H CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase2>@838@09 :;028H NUM LOCKFix NUM LOCK keyScreenSettingsDialogBase8>@838@09 :;028H SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase6>@838@09 XTest 70 XineramaFix XTest for XineramaScreenSettingsDialogBase Meta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseO<0NoneScreenSettingsDialogBase Super:S&uper:ScreenSettingsDialogBase:@0==> 8<5: Screen &name:ScreenSettingsDialogBase&0AB@>9:8 =0 5:@0=0Screen SettingsScreenSettingsDialogBase Shift ( 538ABJ@)ShiftScreenSettingsDialogBase !C?5@SuperScreenSettingsDialogBase>@5-;O2>Top-leftScreenSettingsDialogBase>@5-4OA=> Top-rightScreenSettingsDialogBase <center>:@0= <b>%1</b></center><br>0 @540:F8O =0 =0AB@>9:8B5 H@0:=5B5 42C:@0B=><br>0 40 ?@5<0E=5B5 5:@0= 3> ?@82;0G5B5 :J< :>HG5B>o
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel>;C ;O2> &Bottom-leftServerConfigDialogBase:@>25@O209 :;85=B8B5 =0 2A5:8&Check clients everyServerConfigDialogBaseJ@BJ2 J3J; &Dead cornersServerConfigDialogBase 540:F8O&EditServerConfigDialogBase>@5I :;028H&HotkeysServerConfigDialogBase>2>&NewServerConfigDialogBase ?F88&OptionsServerConfigDialogBase@5<0E=8&RemoveServerConfigDialogBase@52:;NG8&SwitchServerConfigDialogBase59AB28OA&ctionsServerConfigDialogBase< 07H8@5=8 =0AB@>9:8 =0 AJ@2J@0Advanced server settingsServerConfigDialogBase>;C 4OA=> Bottom-ri&ghtServerConfigDialogBase  07<5@ =0 J3J;0: Cor&ner Size:ServerConfigDialogBaseb0 40 ?@5<0E=5B5 5:@0=, 3> 87B53;5B5 :J< :>HG5B>.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBasej@82;0G5B5 =>28 5:@0=8 :J< <@560B0 8;8 @07<5AB5B5 AJI5AB2C20I8B5. 0 40 87B@85B5 5:@0=, 3> ?@82;0G5B5 :J< :>HG5B>. )@0:=5B5 42C:@0B=> 2J@EC 5:@0=0, 70 40 @540:B8@0B5 =0AB@>9:8B5 <C.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasex@82;5G5B5 :J< <@560B0 B>78 1CB>=, 70 40 4>1028B5 =>2 5:@0=.1Drag this button to the grid to add a new screen.ServerConfigDialogBase 540:F8OE&ditServerConfigDialogBase>@5I :;028HHotkeysServerConfigDialogBase>2>Ne&wServerConfigDialogBase@5<0E20=5Re&moveServerConfigDialogBase:!8=E@>=878@09 A:@89=A592J@8B5S&ynchronize screen saversServerConfigDialogBase$:@0=8 8 ?@5?@0B:8Screens and linksServerConfigDialogBase.>=D83C@0F8O =0 AJ@2J@0Server ConfigurationServerConfigDialogBase0@52:;NG8 A;54 87G0:20=5Switch &after waitingServerConfigDialogBaseD@52:;NG8 ?@8 42>9=> I@0:0=5 2JB@5Switch on double &tap withinServerConfigDialogBase>@5 ;O2> To&p-leftServerConfigDialogBase>@5 4OA=> Top-rig&htServerConfigDialogBaseR7?>;7209 >B=>A8B5;=8 42865=8O =0 <8H:0B0Use &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBase*!83C@=8 ;8 AB5 G5 8A:0B5 40 ?>28H8B5 ?@548<AB2>B> =0 !8=5@468? ">20 I5 ?>72>;8 =0 !8=5@468 40 >1IC20 A ?@>F5A8 A ?>-3>;O<> ?@548<AB2> 8 UAC 480;>3>28B5 ?@>7>@F8, => <>65 40 ?@548728:0 ?@>1;5<8 A ?@>F5A8 A ?>-=8AJ: ?@>@8B5B. 483=5B5 ?@548<AB2>B> A0<> 0:> 5 =08AB8=0 =5>1E>48<>.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogF4830=5 =0 ?@548<AB2>B> =0 !8=5@468Elevate SynergySettingsDialogD0?8A20=5 =0 @538ABJ@0 2J2 D09;...Save log file to...SettingsDialog=B5@D59A: &Interface:SettingsDialogBase 78:: &Language:SettingsDialogBase*82> =0 @538AB@8@0=5:&Logging level:SettingsDialogBase @C38&MiscellaneousSettingsDialogBase@53;5640=5... Browse...SettingsDialogBase51J320=5DebugSettingsDialogBase51J320=51Debug1SettingsDialogBase @5H:0ErrorSettingsDialogBase=D>@<0F8OInfoSettingsDialogBase$ 538ABJ@ :J< D09;: Log to file:SettingsDialogBase 538AB@8@0=5LoggingSettingsDialogBase5;56:0NoteSettingsDialogBase >@B:P&ort:SettingsDialogBase:@0==> 8<5: Sc&reen name:SettingsDialogBase0AB@>9:8SettingsSettingsDialogBase@54C?@5645=85WarningSettingsDialogBaseR>;O 2J2545B5 20H8O 8<59; 04@5A 8 ?0@>;0.-Please enter your email address and password. SetupWizard(>;O 8715@5B5 >?F8O.Please select an option. SetupWizard*0AB@>9:0 =0 !8=5@468 Setup Synergy SetupWizard$!J@2J@ 8;8 :;85=B?Server or Client?SetupWizardBase*0AB@>9:0 =0 !8=5@468 Setup SynergySetupWizardBased!8=5@468 B8 ?><030 ;5A=> 40 A?>45;8H <8H:0B0 8 :;0280BC@0B0 A8 A <=>65AB2> :><?NB@8 =0 @01>B=>B> B8 <OAB> 8 5 157?;0B5= 8 A >B2>@5= :>4. @>AB> <5AB8H <8H:0 >B @J10 =0 5:@0=0 =0 548= >B :><?NB@8B5 =0 4@C3. >65H 40 ?>;720H 4>@8 :;8?1>@4 DC=:F8OB0 =0 2A8G:8 :><?NB@8 A2J@70=8 G@57 !8=5@468. A8G:>, >B :>5B> 8<0H =C640 5 <@56>20 2@J7:0 <564C :><?NB@8B5, :>8B> ?>;720H. !8=5@468 5 <C;B8?;0BD>@<5=0 (@01>B8 =0 Windows, Mac OS X 8 Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseJ;03>40@8<, G5 8=AB0;8@0EB5 !8=5@468!Thanks for installing Synergy!SetupWizardBase>1@5 4>H;8WelcomeSetupWizardBase58725AB=>UnknownVersionCheckerV?8A20=5B> 5 =5CA?5H=>, 2J7=8:=0 3@5H:0. %1$Login failed, an error occurred. %1 WebClient|?8A20=5B> 5 =5CA?5H=>, 2J7=8:=0 3@5H:0. !J@2J@JB >B3>20@O: %16Login failed, an error occurred. Server response: %1 WebClientb?8A20=5B> 5 =5CA?5H=>, =520;84=> 8<5 8;8 ?0@>;0.(Login failed, invalid email or password. WebClient!8=5@468SynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_bg-BG.ts000066400000000000000000002006431305627404700216740ustar00rootroot00000000000000 AboutDialogBase About Synergy За Синерджи <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Неизвестно Version: Версия: &Ok ОК ActionDialogBase Configure Action Конфигуриране на действие Choose the action to perform Изберете действие, което да бъде изпълнено. Press a hotkey Натисни горещ клавиш. Release a hotkey Отпусни горещият клавиш. Press and release a hotkey Натисни и пусни горещ клавиш only on these screens само на тези екрани Switch to screen Превключи към екран Switch in direction Превключи в посока left ляво right дясно up горе down долу Lock cursor to screen Заключи курсора на екрана toggle превключи on вкл. off изкл. This action is performed when Действието се извършва когато the hotkey is pressed горещият клавиш бъде натиснат the hotkey is released горещият клавиш бъде отпуснат. AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: Въведи спецификация за горещ клавиш MainWindow &Start Старт &File Файл &Edit Редакция &Window Прозорец &Help Помощ <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Вашата версия на Синерджи не е актуална. Версия <b>%1</b> е достъпна за <a href="%2">сваляне</a>.</p> Program can not be started Програмата не може да бъде стартирана The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Моля проверете дали имате необходимите правомощия за стартиране на тази програма. Synergy client not found Синерджи клиентът не е намерен. The executable for the synergy client does not exist. Hostname is empty Името на приемника е празно Please fill in a hostname for the synergy client to connect to. Моля попълнете име на приемника за да може синерджи клиентът да се свърже. Cannot write configuration file Конфигурационният файл не може да бъде записан The temporary configuration file required to start synergy can not be written. Временният конфигурационен файл, необходим за стартиране на синерджи, не може да бъде записан. Configuration filename invalid Името на конфигурационния файл е невалидно You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Не сте записали валидно име на конфигурационния файл за синерджи сървъра. Искате ли да направите това сега? Synergy server not found Синерджи сървърът не е намерен The executable for the synergy server does not exist. Synergy terminated with an error Синерджи беше изключена поради грешка Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Синерджи беше неочаквано изключена с изходен код %1.<br><br> Моля за детайли вижте регистрационния файл. &Stop Стоп Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Синерджи се стартира. Synergy is running. Синерджи е активна. Synergy is not running. Синерджи не е активна. Unknown Неизвестно Synergy Синерджи Browse for a synergys config file Браузвайте за да намерите конфигурационния файл на програмата Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Записване на конфигурацията като... Save failed Записването се провали Could not save configuration to file. Конфигурационният файл не можа да бъде записан. MainWindowBase Synergy Синерджи Ser&ver (share this computer's mouse and keyboard): Screen name: Екранно име: &Server IP: IP на сървъра: &Start Старт Use existing configuration: Използвай налична конфигурация: &Configuration file: Конфигурационен файл: &Browse... Браузвай... Configure interactively: Интерактивно конфигуриране: &Configure Server... Конфигурирай сървър... Ready Готов Log Регистър &Apply Приложи IP addresses: IP адреси: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Относно Синерджи &Quit Прекрати Quit Прекрати Run Стартирай S&top Стоп Stop Стоп S&how Status Покажи статус &Hide Скрий Hide Скрий &Show Покажи Show Покажи Save configuration &as... Записване на конфигурацията като... Save the interactively generated server configuration to a file. Записване на интерактивно генерираната конфигурация във файл. Settings Настройки Edit settings Редактирай настройките Run Wizard Стартирай помощник NewScreenWidget Unnamed Безименен PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Настройка на Синерджи Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Конфигурации на Синерджи (*.sgc);; Всички файлове (*.*) Synergy Configurations (*.conf);;All files (*.*) Конфигурации на Синерджи (*.conf);; Всички файлове (*.*) System tray is unavailable, quitting. Системният контейнер (трей) не е достъпен, затваряне. ScreenSettingsDialog Screen name is empty Екранното име липсва The screen name cannot be empty. Please either fill in a name or cancel the dialog. Екранното име не може да е празно. Моля въведете име или откажете диалога. Screen name matches alias Екранното име се припокрива с псевдонима The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Екранното име не може да е същото като псевдонима. Моля премахнете псевдонима или сменете екранното име. ScreenSettingsDialogBase Screen Settings Настройки на екрана Screen &name: Екранно име: A&liases Псевдоним &Add Добави &Remove Премахни &Modifier keys &Shift: Регистър: Shift Shift (Регистър) Ctrl Ctrl Alt Alt Meta Meta Super Супер None Няма &Ctrl: Al&t: Alt: M&eta: Meta: S&uper: Super: &Dead corners Мъртъв ъгъл Top-left Горе-ляво Top-right Горе-дясно Bottom-left Долу-дясно Bottom-right Долу-дясно Corner Si&ze: Размер на ъглите: &Fixes Fixes Fix CAPS LOCK key Коригирай клавиш CAPS LOCK Fix NUM LOCK key Коригирай клавиш NUM LOCK Fix SCROLL LOCK key Коригирай клавиш SCROLL LOCK Fix XTest for Xinerama Коригирай XTest за Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Екран <b>%1</b></center><br>За редакция на настройките шракнете двукратно<br>За да премахнете екран го привлачете към кошчето ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Конфигурация на сървъра Screens and links Екрани и препратки Drag a screen from the grid to the trashcan to remove it. За да премахнете екран, го изтеглете към кошчето. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Привлечете към мрежата този бутон, за да добавите нов екран. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Привлачете нови екрани към мрежата или разместете съществуващите. За да изтриете екран, го привлачете към кошчето. Щракнете двукратно върху екрана, за да редактирате настройките му. Hotkeys Горещ клавиш &Hotkeys Горещ клавиш &New Ново &Edit Редакция &Remove Премахни A&ctions Действия Ne&w Ново E&dit Редакция Re&move Премахване Advanced server settings Разширени настройки на сървъра &Switch Превключи Switch &after waiting Превключи след изчакване ms ms Switch on double &tap within Превключи при двойно щракане вътре &Options Опции &Check clients every Проверявай клиентите на всеки Use &relative mouse moves Използвай относителни движения на мишката S&ynchronize screen savers Синхронизирай скрийнсейвърите Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners Мъртъв ъгъл To&p-left Горе ляво Top-rig&ht Горе дясно &Bottom-left Долу ляво Bottom-ri&ght Долу дясно Cor&ner Size: Размер на ъгъла: SettingsDialog Save log file to... Записване на регистъра във файл... Elevate Synergy Вдигане на предимството на Синерджи Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Сигурни ли сте че искате да повишите предимството на Синерджи? Това ще позволи на Синерджи да общува с процеси с по-голямо предимство и UAC диалоговите прозорци, но може да предизвика проблеми с процеси с по-нисък проритет. Вдигнете предимството само ако е наистина необходимо. SettingsDialogBase Settings Настройки Sc&reen name: Екранно име: P&ort: Порт: &Interface: Интерфейс: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Регистриране &Logging level: Ниво на регистриране: Log to file: Регистър към файл: Browse... Преглеждане... Error Грешка &Language: Език: &Miscellaneous Други Warning Предупреждение Note Бележка Info Информация Debug Дебъгване Debug1 Дебъгване1 Debug2 SetupWizard Setup Synergy Настройка на Синерджи Please select an option. Моля изберете опция. Please enter your email address and password. Моля въведете вашия имейл адрес и парола. SetupWizardBase Setup Synergy Настройка на Синерджи Welcome Добре дошли Thanks for installing Synergy! Благодарим, че инсталирахте Синерджи! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Синерджи ти помага лесно да споделиш мишката и клавиатурата си с множество компютри на работното ти място и е безплатен и с отворен код. Просто местиш мишка от ръба на екрана на един от компютрите на друг. Можеш да ползваш дори клипборд функцията на всички компютри свързани чрез Синерджи. Всичко, от което имаш нужда е мрежова връзка между компютрите, които ползваш. Синерджи е мултиплатформена (работи на Windows, Mac OS X и Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Сървър или клиент? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Неизвестно WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Вписването е неуспешно, невалидно име или парола. Login failed, an error occurred. %1 Вписването е неуспешно, възникна грешка. %1 Login failed, an error occurred. Server response: %1 Вписването е неуспешно, възникна грешка. Сървърът отговаря: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Синерджи Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_ca-AD.qm000066400000000000000000000550431305627404700216540ustar00rootroot00000000000000mVE0<VHUg"`"+**58*%*0 *++g|+` yG=Gz,XJG:LbGU` XY1qZ1xx.$>9}S ?u>5(Z = nbj#U4Pc2vLAZS@Ev._%e>w9*X* D4;H}H2:O $O KBO K]H|(VE 1 UN-Yu:HKl_ } $h*Aql4sGpG ::*:4 2 F$ZFSqJ/"QJ-izI@d,l 0s攄J"+(K:S&( n4.d1@Ty.lL#E{5!4z>IJF 3\=Tk@d4ycQ %O@~ C+4}F>nlCA7% I_ JzI> k#9 v~= @> -5 { Pn? d&z ~5?q ~qR^ ք~ ȹd ȹ# ȹT aEf |0 F+ F6; Z+ 6 KG @{ RV RVd RVQ~ R T# V4J  |*E c6 s"t sI c@ F- Ҫ. ^ /, 4pA d/K i!. r+ zk5 PI ¦eQA x47 ]^^J1\P==> 8bunBwy~J'y rB/_7.kC>%k5v.7>-miT9Ok&OkAboutDialogBase$En quant a Synergy About SynergyAboutDialogBaseDesconegut UnknownAboutDialogBaseVersi:Version:AboutDialogBase0Tria l'acci a realitzarChoose the action to performActionDialogBase Configurar AcciConfigure ActionActionDialogBaseBBloquejar el cursor a la pantallaLock cursor to screenActionDialogBase8Prem una tecla d'accs rpidPress a hotkeyActionDialogBaseNPrem i allibera una tecla d'accs rpidPress and release a hotkeyActionDialogBase@Allibera una tecla d'accs rpidRelease a hotkeyActionDialogBase&Canviar de direcciSwitch in directionActionDialogBase&Canviar de pantallaSwitch to screenActionDialogBase<Aquesta acci es realitza quanThis action is performed whenActionDialogBase avalldownActionDialogBaseesquerraleftActionDialogBaseoffoffActionDialogBaseononActionDialogBase6noms en aquestes pantallesonly on these screensActionDialogBase dretarightActionDialogBaseDs'ha premut la tecla d'accs rpidthe hotkey is pressedActionDialogBaseLs'ha allibrerat la tecla d'accs rpidthe hotkey is releasedActionDialogBaseintercanviartoggleActionDialogBase amuntupActionDialogBasebEntrar l'especificaci per la tecla d'accs rpid'Enter the specification for the hotkey:HotkeyDialogBaseAccs RpidHotkeyHotkeyDialogBase&Editar&Edit MainWindow &Arxiu&File MainWindow &Ajuda&Help MainWindow&Engegar&Start MainWindowA&turar&Stop MainWindow&Finestra&Window MainWindow <p>La teva versi de Synergy est desactualitzada. La nova versi <b>%1</b> est ara disponible per <a href="%2">descarregar</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowXMostrar el fitxer de configuraci de Sygergy!Browse for a synergys config file MainWindowXNo es pot escriure el fitxer de configuraciCannot write configuration file MainWindowLNom del fitxer de configuraci invlidConfiguration filename invalid MainWindowXNo es pot guardar la configuraci a l'arxiu.%Could not save configuration to file. MainWindow0El nom de Host est buitHostname is empty MainWindowSi us plau completa el camp nom de host per al client de Synergy per connectar-t'hi.?Please fill in a hostname for the synergy client to connect to. MainWindowDEl programa no ha pogut iniciar-seProgram can not be started MainWindow2Desar configuraci com...Save configuration as... MainWindow Error al guardar Save failed MainWindowSynergySynergy MainWindowHNo s'ha trobat cap client de SynergySynergy client not found MainWindow8Synergy no s'est executant.Synergy is not running. MainWindow4Synergy est executant-se.Synergy is running. MainWindow2Synergy est engegant-se.Synergy is starting. MainWindowJNo s'ha trobat el Servidor de SynergySynergy server not found MainWindowSynergy ha finalitzat inesperadament amb el codi d'error %1.<br><br>Si us plau mira el log de sortida per ms detalls.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowLSynergy ha finalitzat degut a un error Synergy terminated with an error MainWindow^L'executable del client de Synergy no existeix.5The executable for the synergy client does not exist. MainWindowbL'executable del servidor de Synergy no existeix.5The executable for the synergy server does not exist. MainWindowVL'executable <br><br>%1<br><br>no ha pogut ser iniciat correctament, tot i que aquest existeix. Si us plau revisa si tens permisos suficients per executar aquest programa.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowNo s'ha pogut escriure al fitxer de configuraci temporal requerit per iniciar Synergy NThe temporary configuration file required to start synergy can not be written. MainWindowDesconegut Unknown MainWindowNo has omplert un arxiu de configuraci vlid per al servidor de Synergy. Vols veure ara el fitxer de configuraci?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow,En &quant a Synergy...&About Synergy...MainWindowBaseAplicar&ApplyMainWindowBase&Mostrar... &Browse...MainWindowBase*Fitxer &configuraci:&Configuration file:MainWindowBase.&Configurar Servidor...&Configure Server...MainWindowBase A&maga&HideMainWindowBase&Sortir&QuitMainWindowBase IP del Servidor: &Server IP:MainWindowBaseMo&stra&ShowMainWindowBase&Engegar&StartMainWindowBase6Configurar interactivament:Configure interactively:MainWindowBase&Editar configuraci Edit settingsMainWindowBase AmagaHideMainWindowBaseAdreces IP: IP addresses:MainWindowBaseLogLogMainWindowBase SortirQuitMainWindowBase LlestReadyMainWindowBaseExecutaRunMainWindowBase$Executar Assistent Run WizardMainWindowBase&Mostrar Estat S&how StatusMainWindowBaseA&turarS&topMainWindowBase8&Guardar configuraci com...Save configuration &as...MainWindowBaseGuardar la configuraci del servidor generada interactivament a un fitxer.@Save the interactively generated server configuration to a file.MainWindowBaseNom pantalla: Screen name:MainWindowBaseConfiguraciSettingsMainWindowBase MostraShowMainWindowBase AturarStopMainWindowBaseSynergySynergyMainWindowBaseBUtilitzar la configuraci actual:Use existing configuration:MainWindowBaseSense nomUnnamedNewScreenWidget$Configurar Synergy Setup SynergyPluginWizardPagelConfiguracions Synergy (*.conf);;Tots els arxius (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectjConfiguracions Synergy (*.sgc);;Tots els arxius (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectdLa safata del sistema no est disponible, sortint.%System tray is unavailable, quitting.QObject4El nom de pantalla s buitScreen name is emptyScreenSettingsDialogLNom de pantalla coincideix amb l'liesScreen name matches aliasScreenSettingsDialogEl nom de pantalla no pot estar buit. Si us plau introdueix un nom o cancella el dileg.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogEl nom de pantalla no pot ser el mateix que un lies. Si us plau treu l'lies o b canvia el nom de la pantalla.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialogA&fegir&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBase$&Cantonades mortes &Dead cornersScreenSettingsDialogBase &Fixes&FixesScreenSettingsDialogBase &Modificar claus&Modifier keysScreenSettingsDialogBaseElimina&r&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBase &liesA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseAvall-esquerra Bottom-leftScreenSettingsDialogBaseAvall-dreta Bottom-rightScreenSettingsDialogBaseMida cantonada: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase0Arreglar tecla CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase.Arreglar tecla NUM LOCKFix NUM LOCK keyScreenSettingsDialogBase4Arreglar tecla SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase6Arreglar XTest per XineramaFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseCapNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBase&Nom pantalla: Screen &name:ScreenSettingsDialogBase*Configuraci PantallaScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBaseAmunt-esquerraTop-leftScreenSettingsDialogBaseAmunt-dreta Top-rightScreenSettingsDialogBase<center>Pantalla: <b>%1</b></center><br>Doble clic per editar configuraci <br>Arrossega la pantalla a la paperera per eliminar-lao
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelAvall-&esquerra &Bottom-leftServerConfigDialogBase*Comprova clients cada&Check clients everyServerConfigDialogBase$&Cantonades mortes &Dead cornersServerConfigDialogBase&Editar&EditServerConfigDialogBase&Accs rpid&HotkeysServerConfigDialogBase&Nou&NewServerConfigDialogBase&Opcions&OptionsServerConfigDialogBaseElimina&r&RemoveServerConfigDialogBaseCan&viar&SwitchServerConfigDialogBaseA&ccionsA&ctionsServerConfigDialogBaseJConfiguracions avanades del servidorAdvanced server settingsServerConfigDialogBaseAvall-&dreta Bottom-ri&ghtServerConfigDialogBaseConfigura la disposici de configuraci del teu servidor synergy.:Configure the layout of your synergy server configuration.ServerConfigDialogBase Mida ca&ntonada: Cor&ner Size:ServerConfigDialogBasepNo prenguis la finestra en primer pla en Windows servers0Don't take &foreground window on Windows serversServerConfigDialogBaseArrossega una pantalla de la graella a la paperera per eliminar-la.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBasevArrossega noves pantalles a la graella o mou les actuals al voltant. Arrossega una pantalla a la paperera per eliminar-la. Fes doble clic a una pantalla per editar la seva configuraci.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBaseArrossega aquest bot a la graella per afegir una nova pantalla.1Drag this button to the grid to add a new screen.ServerConfigDialogBaseE&ditarE&ditServerConfigDialogBaseAccs rpidHotkeysServerConfigDialogBaseNo&uNe&wServerConfigDialogBaseEli&minarRe&moveServerConfigDialogBaseDSincronitza protectors de pantallaS&ynchronize screen saversServerConfigDialogBase(Pantalles i enllaosScreens and linksServerConfigDialogBase*Configuraci ServidorServer ConfigurationServerConfigDialogBase0Canvia desprs d'esperarSwitch &after waitingServerConfigDialogBase*Canvia a doble &toc aSwitch on double &tap withinServerConfigDialogBaseAmunt-&esquerra To&p-leftServerConfigDialogBaseAmunt-&dreta Top-rig&htServerConfigDialogBaseDUtilitza moviments relatius ratolUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseEstas segur que vols elevar Synergy? Aix permet a Synergy interactuar amb processos elevats i el dileg del UAC, per pot causar problemes amb processos no elevats. Eleva Synergy noms si realment ho necessites.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogElevar SynergyElevate SynergySettingsDialog.Guardar fitxer log a...Save log file to...SettingsDialog&Interfcie: &Interface:SettingsDialogBaseIdioma: &Language:SettingsDialogBase Nivell &logging:&Logging level:SettingsDialogBaseMiscellnia&MiscellaneousSettingsDialogBaseMostrar... Browse...SettingsDialogBase DebugDebugSettingsDialogBase Debug1Debug1SettingsDialogBase Debug2Debug2SettingsDialogBase ErrorErrorSettingsDialogBaseInfoInfoSettingsDialogBaseLog a fitxer: Log to file:SettingsDialogBaseLoggingLoggingSettingsDialogBaseNotaNoteSettingsDialogBase Port:P&ort:SettingsDialogBaseNom pantalla: Sc&reen name:SettingsDialogBaseConfiguraciSettingsSettingsDialogBaseAdvertnciaWarningSettingsDialogBasevSi us plau introdueix la teva adrea d'email i contrasenya.-Please enter your email address and password. SetupWizard0Siusplau tria una opci.Please select an option. SetupWizard$Configurar Synergy Setup Synergy SetupWizard$Servidor o Client?Server or Client?SetupWizardBase$Configurar Synergy Setup SynergySetupWizardBaseSynergy et permet compartir fcilment el ratol i teclat entre diversos ordinadors al teu escriptori, i s lliure i de codi obert. Noms cal moure el punter del ratol per la vora de la pantalla d'un ordinador a un altre. Fins i tot pots compartir el portapapers. nicament el que necessites s una connexi de xarxa. Synergy s multiplataforma (funciona en Windows, Mac OS X i Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBase>Grcies per installar Synergy!Thanks for installing Synergy!SetupWizardBaseBenvingutWelcomeSetupWizardBaseDesconegut UnknownVersionChecker^Error inici de sessi, hi ha hagut un error. %1$Login failed, an error occurred. %1 WebClientError inici de sessi, hi ha hagut un error. Resposta del servidor: %16Login failed, an error occurred. Server response: %1 WebClientzHa fallat l'inici de sessi, email o contrasenya incorrectes.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_ca-AD.ts000066400000000000000000001722261305627404700216700ustar00rootroot00000000000000 AboutDialogBase About Synergy En quant a Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Desconegut Version: Versió: &Ok Ok ActionDialogBase Configure Action Configurar Acció Choose the action to perform Tria l'acció a realitzar Press a hotkey Prem una tecla d'accés ràpid Release a hotkey Allibera una tecla d'accés ràpid Press and release a hotkey Prem i allibera una tecla d'accés ràpid only on these screens només en aquestes pantalles Switch to screen Canviar de pantalla Switch in direction Canviar de direcció left esquerra right dreta up amunt down avall Lock cursor to screen Bloquejar el cursor a la pantalla toggle intercanviar on on off off This action is performed when Aquesta acció es realitza quan the hotkey is pressed s'ha premut la tecla d'accés ràpid the hotkey is released s'ha allibrerat la tecla d'accés ràpid AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Accés Ràpid Enter the specification for the hotkey: Entrar l'especificació per la tecla d'accés ràpid MainWindow &Start &Engegar &File &Arxiu &Edit &Editar &Window &Finestra &Help &Ajuda <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>La teva versió de Synergy està desactualitzada. La nova versió <b>%1</b> està ara disponible per <a href="%2">descarregar</a>.</p> Program can not be started El programa no ha pogut iniciar-se The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. L'executable <br><br>%1<br><br>no ha pogut ser iniciat correctament, tot i que aquest existeix. Si us plau revisa si tens permisos suficients per executar aquest programa. Synergy client not found No s'ha trobat cap client de Synergy The executable for the synergy client does not exist. L'executable del client de Synergy no existeix. Hostname is empty El nom de Host està buit Please fill in a hostname for the synergy client to connect to. Si us plau completa el camp nom de host per al client de Synergy per connectar-t'hi. Cannot write configuration file No es pot escriure el fitxer de configuració The temporary configuration file required to start synergy can not be written. No s'ha pogut escriure al fitxer de configuració temporal requerit per iniciar Synergy Configuration filename invalid Nom del fitxer de configuració invàlid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? No has omplert un arxiu de configuració vàlid per al servidor de Synergy. Vols veure ara el fitxer de configuració? Synergy server not found No s'ha trobat el Servidor de Synergy The executable for the synergy server does not exist. L'executable del servidor de Synergy no existeix. Synergy terminated with an error Synergy ha finalitzat degut a un error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy ha finalitzat inesperadament amb el codi d'error %1.<br><br>Si us plau mira el log de sortida per més detalls. &Stop A&turar Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy està engegant-se. Synergy is running. Synergy està executant-se. Synergy is not running. Synergy no s'està executant. Unknown Desconegut Synergy Synergy Browse for a synergys config file Mostrar el fitxer de configuració de Sygergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Desar configuració com... Save failed Error al guardar Could not save configuration to file. No es pot guardar la configuració a l'arxiu. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Nom pantalla: &Server IP: IP del Servidor: &Start &Engegar Use existing configuration: Utilitzar la configuració actual: &Configuration file: Fitxer &configuració: &Browse... &Mostrar... Configure interactively: Configurar interactivament: &Configure Server... &Configurar Servidor... Ready Llest Log Log &Apply Aplicar IP addresses: Adreces IP: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... En &quant a Synergy... &Quit &Sortir Quit Sortir Run Executa S&top A&turar Stop Aturar S&how Status &Mostrar Estat &Hide A&maga Hide Amaga &Show Mo&stra Show Mostra Save configuration &as... &Guardar configuració com... Save the interactively generated server configuration to a file. Guardar la configuració del servidor generada interactivament a un fitxer. Settings Configuració Edit settings Editar configuració Run Wizard Executar Assistent NewScreenWidget Unnamed Sense nom PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Configurar Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Configuracions Synergy (*.sgc);;Tots els arxius (*.*) Synergy Configurations (*.conf);;All files (*.*) Configuracions Synergy (*.conf);;Tots els arxius (*.*) System tray is unavailable, quitting. La safata del sistema no està disponible, sortint. ScreenSettingsDialog Screen name is empty El nom de pantalla és buit The screen name cannot be empty. Please either fill in a name or cancel the dialog. El nom de pantalla no pot estar buit. Si us plau introdueix un nom o cancel·la el diàleg. Screen name matches alias Nom de pantalla coincideix amb l'àlies The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. El nom de pantalla no pot ser el mateix que un àlies. Si us plau treu l'àlies o bé canvia el nom de la pantalla. ScreenSettingsDialogBase Screen Settings Configuració Pantalla Screen &name: &Nom pantalla: A&liases À&lies &Add A&fegir &Remove Elimina&r &Modifier keys &Modificar claus &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Cap &Ctrl: &Ctrl: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners &Cantonades mortes Top-left Amunt-esquerra Top-right Amunt-dreta Bottom-left Avall-esquerra Bottom-right Avall-dreta Corner Si&ze: Mida cantonada: &Fixes &Fixes Fix CAPS LOCK key Arreglar tecla CAPS LOCK Fix NUM LOCK key Arreglar tecla NUM LOCK Fix SCROLL LOCK key Arreglar tecla SCROLL LOCK Fix XTest for Xinerama Arreglar XTest per Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Pantalla: <b>%1</b></center><br>Doble clic per editar configuració <br>Arrossega la pantalla a la paperera per eliminar-la ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Configuració Servidor Screens and links Pantalles i enllaços Drag a screen from the grid to the trashcan to remove it. Arrossega una pantalla de la graella a la paperera per eliminar-la. Configure the layout of your synergy server configuration. Configura la disposició de configuració del teu servidor synergy. Drag this button to the grid to add a new screen. Arrossega aquest botó a la graella per afegir una nova pantalla. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Arrossega noves pantalles a la graella o mou les actuals al voltant. Arrossega una pantalla a la paperera per eliminar-la. Fes doble clic a una pantalla per editar la seva configuració. Hotkeys Accés ràpid &Hotkeys &Accés ràpid &New &Nou &Edit &Editar &Remove Elimina&r A&ctions A&ccions Ne&w No&u E&dit E&ditar Re&move Eli&minar Advanced server settings Configuracions avançades del servidor &Switch Can&viar Switch &after waiting Canvia després d'esperar ms ms Switch on double &tap within Canvia a doble &toc a &Options &Opcions &Check clients every Comprova clients cada Use &relative mouse moves Utilitza moviments relatius ratolí S&ynchronize screen savers Sincronitza protectors de pantalla Don't take &foreground window on Windows servers No prenguis la finestra en primer pla en Windows servers Ignore auto config clients &Dead corners &Cantonades mortes To&p-left Amunt-&esquerra Top-rig&ht Amunt-&dreta &Bottom-left Avall-&esquerra Bottom-ri&ght Avall-&dreta Cor&ner Size: Mida ca&ntonada: SettingsDialog Save log file to... Guardar fitxer log a... Elevate Synergy Elevar Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Estas segur que vols elevar Synergy? Això permet a Synergy interactuar amb processos elevats i el diàleg del UAC, però pot causar problemes amb processos no elevats. Eleva Synergy només si realment ho necessites. SettingsDialogBase Settings Configuració Sc&reen name: Nom pantalla: P&ort: Port: &Interface: &Interfície: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Logging &Logging level: Nivell &logging: Log to file: Log a fitxer: Browse... Mostrar... Error Error &Language: Idioma: &Miscellaneous Miscel·lània Warning Advertència Note Nota Info Info Debug Debug Debug1 Debug1 Debug2 Debug2 SetupWizard Setup Synergy Configurar Synergy Please select an option. Siusplau tria una opció. Please enter your email address and password. Si us plau introdueix la teva adreça d'email i contrasenya. SetupWizardBase Setup Synergy Configurar Synergy Welcome Benvingut Thanks for installing Synergy! Gràcies per instal·lar Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy et permet compartir fàcilment el ratolí i teclat entre diversos ordinadors al teu escriptori, i és lliure i de codi obert. Només cal moure el punter del ratolí per la vora de la pantalla d'un ordinador a un altre. Fins i tot pots compartir el portapapers. Únicament el que necessites és una connexió de xarxa. Synergy és multiplataforma (funciona en Windows, Mac OS X i Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Servidor o Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Desconegut WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Ha fallat l'inici de sessió, email o contrasenya incorrectes. Login failed, an error occurred. %1 Error inici de sessió, hi ha hagut un error. %1 Login failed, an error occurred. Server response: %1 Error inici de sessió, hi ha hagut un error. Resposta del servidor: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_cs-CZ.qm000066400000000000000000000545451305627404700217340ustar00rootroot000000000000008en}Su>(Z (= nbj!4J=|1dvKSZRjEv./_#e= w9()= z;H}H1O "LO JRO J]G|' VE /UN,jYu:Gml_ } "*?l3!FF 97:(:3  E$ZEOJ."QJ-izHS@d+>l /[攄LJ _(J:S%O( n4.d0@Ty,L#C{4T@zC>JF/ 3=Tk@d2ycQ%@~ C)~}F<nPC?5#P I_ JzH k#7 v~;! >X -5 Pn= d$ ~5= ~qQ ք~g ȹ ȹ!Y ȹSB aDZ |/ F) F4 Z*/ 5E KG W @{ RVn RV RVP R5 T" V4  |*D c5 s sH c> F+ Ҫz ^ /*q 4p?I d- i! r+ zk PI# ¦eP x46= ]^^I1\O=> 7Xbun@y~Ia% r/7-ckC<;k4*.6>+iS{Ok&OkAboutDialogBaseO Synergy About SynergyAboutDialogBaseNeznmUnknownAboutDialogBase Verze:Version:AboutDialogBase0Vyberte akci k provedenChoose the action to performActionDialogBaseNastavit akciConfigure ActionActionDialogBase8Uzamknout kurzor k obrazovceLock cursor to screenActionDialogBase8Stisknout klvesovou zkratkuPress a hotkeyActionDialogBaseXStisknout a pustit (uvolnit) klvesy zkratkyPress and release a hotkeyActionDialogBase@Pustit (uvolnit) klvesy zkratkyRelease a hotkeyActionDialogBasePYepnout smremSwitch in directionActionDialogBase*PYepnout na obrazovkuSwitch to screenActionDialogBase0Tato akce se spust kdy~This action is performed whenActionDialogBasedolodownActionDialogBase vlevoleftActionDialogBasevypoffActionDialogBasezaponActionDialogBase6pouze na tchto obrazovkchonly on these screensActionDialogBase vpravorightActionDialogBase<je stisknuta klvesov zkratkathe hotkey is pressedActionDialogBaseNjsou puatny (uvolnny) klvesy zkratkythe hotkey is releasedActionDialogBasepYepnouttoggleActionDialogBase nahoruupActionDialogBase8VytvoYte klvesovou zkratku:'Enter the specification for the hotkey:HotkeyDialogBase"Klvesov zkratkaHotkeyHotkeyDialogBaseUpra&vit&Edit MainWindow Soubor&File MainWindow&Npovda&Help MainWindow&Spustit&Start MainWindowZa&stavit&Stop MainWindow O&kno&Window MainWindow<p>Pou~vte starou verzi aplikace Synergy. Ke <a href="%2">sta~en</a> je nyn ji~ verze <b>%1</b>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowfOtevYt existujc soubor s nastavenmi pro synergy!Browse for a synergys config file MainWindowPDo souboru s nastavenmi nelze zapisovatCannot write configuration file MainWindowJNeplatn nzev souboru s nastavenmi.Configuration filename invalid MainWindowDNelze ulo~it nastaven do souboru.%Could not save configuration to file. MainWindow0Nevyplnn clov po ta Hostname is empty MainWindowVyplHte adresu clovho po ta e ke ktermu se Synergy klient m pYipojit.?Please fill in a hostname for the synergy client to connect to. MainWindow*Program nelze spustitProgram can not be started MainWindow,Ulo~it nastaven jako &Save configuration as... MainWindow(Ulo~en se nezdaYilo Save failed MainWindowSynergySynergy MainWindow8Synergy klient nebyl nalezenSynergy client not found MainWindow,Synergy nen spuatn.Synergy is not running. MainWindow(Synergy je spuatn.Synergy is running. MainWindow&Synergy se spouat.Synergy is starting. MainWindow8Synergy server nebyl nalezenSynergy server not found MainWindowNeo ekvan ukon en Synergy. Bh skon il s kdem %1. <br><br>Podrobnosti viz protokol.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow<Synergy bylo ukon eno s chybou Synergy terminated with an error MainWindowtSpustiteln soubor s programem Synergy klienta neexistuje.5The executable for the synergy client does not exist. MainWindowtSpustiteln soubor s programem synergy serveru neexistuje.5The executable for the synergy server does not exist. MainWindowProgram <br><br>%1<br><br> existuje, ale nelze jej spustit. OvYte, zda mte potYebn (souborov) oprvnn ke spuatn tohoto programu.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowDo do asnho souboru s nastavenmi, potYebnho pro spuatn Synergy, nelze zapisovat.NThe temporary configuration file required to start synergy can not be written. MainWindowNeznmUnknown MainWindowNevyplnili jste platn soubor s nastavenmi pro synergy server. Chcete nyn ur it umstn souboru s nastavenmi?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow&O Synergy &&About Synergy...MainWindowBase&Pou~t&ApplyMainWindowBasePr&ochzet & &Browse...MainWindowBase,Sou&bor s nastavenmi:&Configuration file:MainWindowBase"N&astavit Server &&Configure Server...MainWindowBase Skrt&HideMainWindowBase&Ukon it&QuitMainWindowBase(IP &adresa &serveru: &Server IP:MainWindowBase&Zobrazit&ShowMainWindowBase&Spustit&StartMainWindowBase.Interaktivn nastaven:Configure interactively:MainWindowBase"Upravit nastaven Edit settingsMainWindowBase SkrtHideMainWindowBaseIP adresy: IP addresses:MainWindowBaseProtokolLogMainWindowBaseUkon itQuitMainWindowBasePYipravenReadyMainWindowBaseSpustitRunMainWindowBase Spustit provodce Run WizardMainWindowBaseZobrazit stav S&how StatusMainWindowBaseZas&tavitS&topMainWindowBase.Ulo~it nastaven j&ako &Save configuration &as...MainWindowBasevUlo~it interaktivn vytvoYen nastaven serveru do souboru.@Save the interactively generated server configuration to a file.MainWindowBase Nzev obrazovky: Screen name:MainWindowBaseNastavenSettingsMainWindowBaseZobrazitShowMainWindowBaseZastavitStopMainWindowBaseSynergySynergyMainWindowBase8Pou~t existujc nastaven:Use existing configuration:MainWindowBaseNepojmenovnoUnnamedNewScreenWidget$Instalovat Synergy Setup SynergyPluginWizardPagebNastaven Synergy (*.conf);;Vaechny soubory (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObject`Nastaven Synergy (*.sgc);;Vaechny soubory (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectOznamovac oblast systmov liaty je nedostupn, aplikace proto bude ukon ena.%System tray is unavailable, quitting.QObject:Nzev obrazovky nebyl vyplnnScreen name is emptyScreenSettingsDialogjNzev obrazovky koliduje s jejm alternativnm nzvemScreen name matches aliasScreenSettingsDialogNzev obrazovky nemo~e zostat przdn. Bu jej vyplHte, nebo dialog zruate.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogNzev obrazovky a zstupn nzev bt stejn. Bu zstupn nzev odeberte nebo zmHte nzev obrazovky.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialogPYid&at&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBaseNevyu~it rohy &Dead cornersScreenSettingsDialogBase&Opravy&FixesScreenSettingsDialogBase.&Modifiktory (klvesy)&Modifier keysScreenSettingsDialogBaseOdst&ranit&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBase&A&lternativn nzvyA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseVlevo dole Bottom-leftScreenSettingsDialogBaseVpravo dole Bottom-rightScreenSettingsDialogBaseVelikost ro&hu: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase@Oprava chovn klvesy Caps LockFix CAPS LOCK keyScreenSettingsDialogBase>Oprava chovn klvesy Num LockFix NUM LOCK keyScreenSettingsDialogBaseDOprava chovn klvesy Scroll LockFix SCROLL LOCK keyScreenSettingsDialogBaseOprava chovn rozaYen grafickho serveru X  XTest a XineramaFix XTest for XineramaScreenSettingsDialogBase Meta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBase }dnNoneScreenSettingsDialogBase Super:S&uper:ScreenSettingsDialogBaseNzev &plochy Screen &name:ScreenSettingsDialogBase$Nataven obrazovkyScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBaseVlevo nahoYeTop-leftScreenSettingsDialogBaseVpravo nahoYe Top-rightScreenSettingsDialogBase<center>Obrazovka: <b>%1</b></center><br>Dvojklikem upravte nastaven<br>PYeta~enm do koae obrazovku sma~eteo
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelSpodn lev &Bottom-leftServerConfigDialogBase6Kontrolovat klienty ka~dch&Check clients everyServerConfigDialogBaseNevyu~it rohy &Dead cornersServerConfigDialogBaseUpra&vit&EditServerConfigDialogBase$&Klvesov zkratky&HotkeysServerConfigDialogBase &Nov&NewServerConfigDialogBaseM&o~nosti&OptionsServerConfigDialogBaseOdst&ranit&RemoveServerConfigDialogBasePYepnout&SwitchServerConfigDialogBase Ak&ceA&ctionsServerConfigDialogBase6Pokro il nastaven serveruAdvanced server settingsServerConfigDialogBaseSpodn prav Bottom-ri&ghtServerConfigDialogBasefNastavte rozlo~en svho nastaven serveru synergy.:Configure the layout of your synergy server configuration.ServerConfigDialogBaseVelikost rohu: Cor&ner Size:ServerConfigDialogBase^Na serverech s Windows se nepYepnat do popYed0Don't take &foreground window on Windows serversServerConfigDialogBasenObrazovku odstrante jejm pYeta~enm z mY~ky do koae.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase*PYethnte nov obrazovky do mY~ky nebo pYesuHte stvajc. PYethnutm obrazovky do koae ji sma~ete. Nastaven obrazovky upravte dvojklikem na ni.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBase~Novou obrazovku vytvoYte pYeta~enm tohoto tla tka do mY~ky.1Drag this button to the grid to add a new screen.ServerConfigDialogBaseUpravi&tE&ditServerConfigDialogBase"Klvesov zkratkyHotkeysServerConfigDialogBase No&vNe&wServerConfigDialogBaseOde&bratRe&moveServerConfigDialogBaseBS&ynchronizovat aetYi e obrazovkyS&ynchronize screen saversServerConfigDialogBase*Obrazovky a propojenScreens and linksServerConfigDialogBase"Nastaven serveruServer ConfigurationServerConfigDialogBase(PYepnout po prodlevSwitch &after waitingServerConfigDialogBaseBPYepnout po dvojitm doteku bhemSwitch on double &tap withinServerConfigDialogBaseLev horn To&p-leftServerConfigDialogBasePrav &horn Top-rig&htServerConfigDialogBase<Pou~vat relativn pohyby myaiUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseZOpravdu chcete zvait stupeH oprvnn pro Synergy? Sice to Synergy umo~n pracovat s procesy, kter maj tak takov stupeH a s dialogem Yzen u~ivatelskch  to (UAC), mo~e ale posobit problmy aplikacm s b~nmi oprvnnmi. Tuto mo~nost byste tedy mli vyu~t pouze pokud ji opravdu potYebujete.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogFZvait stupeH oprvnn pro SynergyElevate SynergySettingsDialog<Ulo~it soubor s protokolem do &Save log file to...SettingsDialogRozhran: &Interface:SettingsDialogBase&Jazyk: &Language:SettingsDialogBaseDStupeH podrobnosti protoko&lovn:&Logging level:SettingsDialogBase Rozn&MiscellaneousSettingsDialogBaseProchzet & Browse...SettingsDialogBase LadnDebugSettingsDialogBaseLadn1Debug1SettingsDialogBaseLadn2Debug2SettingsDialogBase ChybaErrorSettingsDialogBaseInformaceInfoSettingsDialogBase0Protokolovat do souboru: Log to file:SettingsDialogBaseProtokolovnLoggingSettingsDialogBasePoznmkaNoteSettingsDialogBase P&ort:P&ort:SettingsDialogBase"Nzev ob&razovky: Sc&reen name:SettingsDialogBaseNastavenSettingsSettingsDialogBaseVarovnWarningSettingsDialogBaseNZadejte svou e-mailovou adresu a heslo.-Please enter your email address and password. SetupWizardZvolte mo~nost.Please select an option. SetupWizard$Instalovat Synergy Setup Synergy SetupWizard&Server nebo klient?Server or Client?SetupWizardBase$Instalovat Synergy Setup SynergySetupWizardBase*Synergy vm umo~n snadno sdlet mya a klvesnici napY vcero po ta i na vaaem stole. Aplikace je svobodn a s otevYenm zdrojovm kdem. Sta jen pYesunout kurzor myai mimo okraj obrazovky jednoho po ta e na obrazovku dalaho. Mezi po ta i mo~ete dokonce sdlet obsahy jejich schrnek. Jedin, co je potYeba, je propojen st. Synergy je multiplatformn (funguje na Windows, Mac OS X a GNU/Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseVTa ns, ~e jste si nainstalovali Synergy!Thanks for installing Synergy!SetupWizardBaseVtejteWelcomeSetupWizardBaseNeznmUnknownVersionCheckerTPYihlaen se nezdaYilo, doalo k chyb. %1$Login failed, an error occurred. %1 WebClient|PYihlaen se nezdaYilo, doalo k chyb. Odpov ze serveru: %16Login failed, an error occurred. Server response: %1 WebClientPYihlaen se nezdaYilo, e-mailov adresa  i heslo nebylo zadno sprvn.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_cs-CZ.ts000066400000000000000000001726111305627404700217400ustar00rootroot00000000000000 AboutDialogBase About Synergy O Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Neznámá Version: Verze: &Ok Ok ActionDialogBase Configure Action Nastavit akci Choose the action to perform Vyberte akci k provedení Press a hotkey Stisknout klávesovou zkratku Release a hotkey Pustit (uvolnit) klávesy zkratky Press and release a hotkey Stisknout a pustit (uvolnit) klávesy zkratky only on these screens pouze na těchto obrazovkách Switch to screen Přepnout na obrazovku Switch in direction Přepnout směrem left vlevo right vpravo up nahoru down dolů Lock cursor to screen Uzamknout kurzor k obrazovce toggle přepnout on zap off vyp This action is performed when Tato akce se spustí když the hotkey is pressed je stisknuta klávesová zkratka the hotkey is released jsou puštěny (uvolněny) klávesy zkratky AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Klávesová zkratka Enter the specification for the hotkey: Vytvořte klávesovou zkratku: MainWindow &Start &Spustit &File Soubor &Edit Upra&vit &Window O&kno &Help &Nápověda <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Používáte starou verzi aplikace Synergy. Ke <a href="%2">stažení</a> je nyní již verze <b>%1</b>.</p> Program can not be started Program nelze spustit The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Program <br><br>%1<br><br> existuje, ale nelze jej spustit. Ověřte, zda máte potřebná (souborová) oprávnění ke spuštění tohoto programu. Synergy client not found Synergy klient nebyl nalezen The executable for the synergy client does not exist. Spustitelný soubor s programem Synergy klienta neexistuje. Hostname is empty Nevyplněn cílový počítač Please fill in a hostname for the synergy client to connect to. Vyplňte adresu cílového počítače ke kterému se Synergy klient má připojit. Cannot write configuration file Do souboru s nastaveními nelze zapisovat The temporary configuration file required to start synergy can not be written. Do dočasného souboru s nastaveními, potřebného pro spuštění Synergy, nelze zapisovat. Configuration filename invalid Neplatný název souboru s nastaveními. You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Nevyplnili jste platný soubor s nastaveními pro synergy server. Chcete nyní určit umístění souboru s nastaveními? Synergy server not found Synergy server nebyl nalezen The executable for the synergy server does not exist. Spustitelný soubor s programem synergy serveru neexistuje. Synergy terminated with an error Synergy bylo ukončeno s chybou Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Neočekávané ukončení Synergy. Běh skončil s kódem %1. <br><br>Podrobnosti viz protokol. &Stop Za&stavit Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy se spouští. Synergy is running. Synergy je spuštěné. Synergy is not running. Synergy není spuštěné. Unknown Neznámá Synergy Synergy Browse for a synergys config file Otevřít existující soubor s nastaveními pro synergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Uložit nastavení jako… Save failed Uložení se nezdařilo Could not save configuration to file. Nelze uložit nastavení do souboru. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Název obrazovky: &Server IP: IP &adresa &serveru: &Start &Spustit Use existing configuration: Použít existující nastavení: &Configuration file: Sou&bor s nastaveními: &Browse... Pr&ocházet… Configure interactively: Interaktivní nastavení: &Configure Server... N&astavit Server… Ready Připraven Log Protokol &Apply &Použít IP addresses: IP adresy: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &O Synergy… &Quit &Ukončit Quit Ukončit Run Spustit S&top Zas&tavit Stop Zastavit S&how Status Zobrazit stav &Hide Skrýt Hide Skrýt &Show &Zobrazit Show Zobrazit Save configuration &as... Uložit nastavení j&ako… Save the interactively generated server configuration to a file. Uložit interaktivně vytvořené nastavení serveru do souboru. Settings Nastavení Edit settings Upravit nastavení Run Wizard Spustit průvodce NewScreenWidget Unnamed Nepojmenováno PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Instalovat Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Nastavení Synergy (*.sgc);;Všechny soubory (*.*) Synergy Configurations (*.conf);;All files (*.*) Nastavení Synergy (*.conf);;Všechny soubory (*.*) System tray is unavailable, quitting. Oznamovací oblast systémové lišty je nedostupná, aplikace proto bude ukončena. ScreenSettingsDialog Screen name is empty Název obrazovky nebyl vyplněn The screen name cannot be empty. Please either fill in a name or cancel the dialog. Název obrazovky nemůže zůstat prázdný. Buď jej vyplňte, nebo dialog zrušte. Screen name matches alias Název obrazovky koliduje s jejím alternativním názvem The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Název obrazovky a zástupný název být stejné. Buď zástupný název odeberte nebo změňte název obrazovky. ScreenSettingsDialogBase Screen Settings Natavení obrazovky Screen &name: Název &plochy A&liases A&lternativní názvy &Add Přid&at &Remove Odst&ranit &Modifier keys &Modifikátory (klávesy) &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Žádné &Ctrl: &Ctrl: Al&t: Al&t: M&eta: Meta: S&uper: Super: &Dead corners Nevyužité rohy Top-left Vlevo nahoře Top-right Vpravo nahoře Bottom-left Vlevo dole Bottom-right Vpravo dole Corner Si&ze: Velikost ro&hu: &Fixes &Opravy Fix CAPS LOCK key Oprava chování klávesy Caps Lock Fix NUM LOCK key Oprava chování klávesy Num Lock Fix SCROLL LOCK key Oprava chování klávesy Scroll Lock Fix XTest for Xinerama Oprava chování rozšíření grafického serveru X – XTest a Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Obrazovka: <b>%1</b></center><br>Dvojklikem upravíte nastavení<br>Přetažením do koše obrazovku smažete ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Nastavení serveru Screens and links Obrazovky a propojení Drag a screen from the grid to the trashcan to remove it. Obrazovku odstraníte jejím přetažením z mřížky do koše. Configure the layout of your synergy server configuration. Nastavte rozložení svého nastavení serveru synergy. Drag this button to the grid to add a new screen. Novou obrazovku vytvoříte přetažením tohoto tlačítka do mřížky. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Přetáhněte nové obrazovky do mřížky nebo přesuňte stávající. Přetáhnutím obrazovky do koše ji smažete. Nastavení obrazovky upravíte dvojklikem na ni. Hotkeys Klávesové zkratky &Hotkeys &Klávesové zkratky &New &Nová &Edit Upra&vit &Remove Odst&ranit A&ctions Ak&ce Ne&w No&vá E&dit Upravi&t Re&move Ode&brat Advanced server settings Pokročilé nastavení serveru &Switch Přepnout Switch &after waiting Přepnout po prodlevě ms ms Switch on double &tap within Přepnout po dvojitém doteku během &Options M&ožnosti &Check clients every Kontrolovat klienty každých Use &relative mouse moves Používat relativní pohyby myši S&ynchronize screen savers S&ynchronizovat šetřiče obrazovky Don't take &foreground window on Windows servers Na serverech s Windows se nepřepínat do popředí Ignore auto config clients &Dead corners Nevyužité rohy To&p-left Levý horní Top-rig&ht Pravý &horní &Bottom-left Spodní levý Bottom-ri&ght Spodní pravý Cor&ner Size: Velikost rohu: SettingsDialog Save log file to... Uložit soubor s protokolem do… Elevate Synergy Zvýšit stupeň oprávnění pro Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Opravdu chcete zvýšit stupeň oprávnění pro Synergy? Sice to Synergy umožní pracovat s procesy, které mají také takový stupeň a s dialogem řízení uživatelských účtů (UAC), může ale působit problémy aplikacím s běžnými oprávněními. Tuto možnost byste tedy měli využít pouze pokud ji opravdu potřebujete. SettingsDialogBase Settings Nastavení Sc&reen name: Název ob&razovky: P&ort: P&ort: &Interface: Rozhraní: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Protokolování &Logging level: Stupeň podrobnosti protoko&lování: Log to file: Protokolovat do souboru: Browse... Procházet… Error Chyba &Language: &Jazyk: &Miscellaneous Různé Warning Varování Note Poznámka Info Informace Debug Ladění Debug1 Ladění1 Debug2 Ladění2 SetupWizard Setup Synergy Instalovat Synergy Please select an option. Zvolte možnost. Please enter your email address and password. Zadejte svou e-mailovou adresu a heslo. SetupWizardBase Setup Synergy Instalovat Synergy Welcome Vítejte Thanks for installing Synergy! Těší nás, že jste si nainstalovali Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy vám umožní snadno sdílet myš a klávesnici napříč vícero počítači na vašem stole. Aplikace je svobodná a s otevřeným zdrojovým kódem. Stačí jen přesunout kurzor myši mimo okraj obrazovky jednoho počítače na obrazovku dalšího. Mezi počítači můžete dokonce sdílet obsahy jejich schránek. Jediné, co je potřeba, je propojení sítí. Synergy je multiplatformní (funguje na Windows, Mac OS X a GNU/Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Server nebo klient? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Neznámá WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Přihlášení se nezdařilo, e-mailová adresa či heslo nebylo zadáno správně. Login failed, an error occurred. %1 Přihlášení se nezdařilo, došlo k chybě. %1 Login failed, an error occurred. Server response: %1 Přihlášení se nezdařilo, došlo k chybě. Odpověď ze serveru: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_cy.qm000066400000000000000000000353351305627404700214240ustar00rootroot00000000000000(;}Sfu>N(Z += nbj4OOv1Ev.v_ b e;H}H$VO yO 0O 1pVE #l_ &} l5$/ ( "QJ@d"7攄!(1( n4.d$ {%x6>M 5z>JJ.= 3=T A%C![}F,nn3C.@&u I_] v~* -m -5 Pn- d ~5, ք~ ȹ w ȹ ȹ6 |#e F! F& &L KG @{ R( T8 V4  c& s s/ c- F" ^ /! i! r/ zk P0: ]^^0v= r/kC+k%A.'L>"i6Iawn&OkAboutDialogBase Ynghylch Synergy About SynergyAboutDialogBaseFersiwn:Version:AboutDialogBase6Dewiswch y weithred i wneudChoose the action to performActionDialogBase$Cyflunio GweithredConfigure ActionActionDialogBase.Cloi cyrchydd i'r sgrnLock cursor to screenActionDialogBase(Gwasgwch fysell brysPress a hotkeyActionDialogBaseDGwasgwch a ryddhewch y bysell frysPress and release a hotkeyActionDialogBase.Ryddhewch y bysell frysRelease a hotkeyActionDialogBaseNewid cyfeiriadSwitch in directionActionDialogBaseNewid i sgrnSwitch to screenActionDialogBaseNMae'r weithred hwn yn cael ei wneud ganThis action is performed whenActionDialogBaselawrdownActionDialogBase chwithleftActionDialogBasei ffwrddoffActionDialogBase ymlaenonActionDialogBase2ar y sgriniau yma yn unigonly on these screensActionDialogBasedderightActionDialogBase0pan wasgir y bysell frysthe hotkey is pressedActionDialogBase4pan ryddheir y bysell frysthe hotkey is releasedActionDialogBase toglotoggleActionDialogBasefynyupActionDialogBaseXRhowch y manyleb ar gyfer y bysell frws hwn:'Enter the specification for the hotkey:HotkeyDialogBaseBysell frysHotkeyHotkeyDialogBase Golygu&Edit MainWindow Ffeil&File MainWindowCymorth&Help MainWindowDechrau&Start MainWindow Stopio&Stop MainWindowFfenest&Window MainWindowBProfi am ffeil gyfluniad synergys!Browse for a synergys config file MainWindowFMethu sgrifennu i'r ffeil gyfluniadCannot write configuration file MainWindowHMae enw'r ffeil gyfluniad yn annilysConfiguration filename invalid MainWindow<Methwyd cadw'r ffeil gyfluniad%Could not save configuration to file. MainWindow:Mae'r enw gwesteiwr yn bodoliHostname is empty MainWindowrRhowch enw gwesteiwr i'r cleient synergy i gysylltu iddo.?Please fill in a hostname for the synergy client to connect to. MainWindow2Methwyd cychwyn y rhaglenProgram can not be started MainWindow.Cadw'r cyfluniad fel...Save configuration as... MainWindowMethwyd cadw Save failed MainWindowSynergySynergy MainWindowFMethwyd dod o hyd i gleient SynergySynergy client not found MainWindow2Nid yw Synergy yn rhedeg.Synergy is not running. MainWindow,Mae Synergy yn rhedeg.Synergy is running. MainWindow.Mae Synergy yn dechrau.Synergy is starting. MainWindowFMethwyd dod o hyd i weinydd SynergySynergy server not found MainWindowFe wnaeth Synergy derfynnu yn annisgwyl gyda cod gorffen %1.<br><br>Gwelwch allbwn log am fanylion.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowJFe wnaeth Synergy derfynnu gyda gwall Synergy terminated with an error MainWindowNid yw'r ffeil weithredadwy ar gyfer y cleient synergy yn bodoli.5The executable for the synergy client does not exist. MainWindowNid yw'r ffeil weithredadwy ar gyfer y gweinydd synergy yn bodoli.5The executable for the synergy server does not exist. MainWindow>Nid oedd yn bosib cychwyn y rhaglen <br><br>%1<br><br>yn llwyddiannus er ei fod yn bodoli. Gwnewch yn siwr fod ganddoch yr hawliau cywir i redeg y rhaglen yma.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowNid yw'n bosib sgrifennu i'r ffeil gyfluniad dros dro sydd angen i ddechrau synergyNThe temporary configuration file required to start synergy can not be written. MainWindowNid ydych wedi llenwi mewn ffeil gyfluniad dilys ar gyfer y gweinydd synergy. Hoffech chi bori am ffeil gyfluniad nawr?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow Ynghylch Synergy&About Synergy...MainWindowBasePori... &Browse...MainWindowBase Ffeil Cyfluniad:&Configuration file:MainWindowBase(Cyflunio Gweinydd...&Configure Server...MainWindowBase Gadael&QuitMainWindowBaseDechrau&StartMainWindowBase2Cyflunio'n rhyngweithiol:Configure interactively:MainWindowBase"Golygu gosodiadau Edit settingsMainWindowBaseLogLogMainWindowBase GadaelQuitMainWindowBaseYn barodReadyMainWindowBase RhedegRunMainWindowBaseRhedeg Dewin Run WizardMainWindowBaseDangos Statws S&how StatusMainWindowBase StopioS&topMainWindowBase.Cadw'r cyfluniad fel...Save configuration &as...MainWindowBase`Cadw'r cyfluniad gweinydd a gynhyrchwyd i ffeil:@Save the interactively generated server configuration to a file.MainWindowBaseGosodiadauSettingsMainWindowBase StopopStopMainWindowBaseSynergySynergyMainWindowBase@Defnyddio'r cyfluniad presennol:Use existing configuration:MainWindowBaseHeb ei enwiUnnamedNewScreenWidget$Gosod fyny Synergy Setup SynergyPluginWizardPageZCyfluniadau Synergy (*.conf);;Pob ffeil (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectXCyfluniadau Synergy (*.sgc);;Pob ffeil (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectVNid yw'r gilfach system ar gael, yn gadael.%System tray is unavailable, quitting.QObject,Mae enw'r sgrn yn wagScreen name is emptyScreenSettingsDialogYchwanegu&AddScreenSettingsDialogBaseBysellau newid&Modifier keysScreenSettingsDialogBase Dileu&RemoveScreenSettingsDialogBaseFfugenwauA&liasesScreenSettingsDialogBaseGwaelod-chwith Bottom-leftScreenSettingsDialogBaseGwaelod-dde Bottom-rightScreenSettingsDialogBaseMaint Cornel: Corner Si&ze:ScreenSettingsDialogBaseDimNoneScreenSettingsDialogBaseEnw sgrn Screen &name:ScreenSettingsDialogBase Gosodiadau SgrnScreen SettingsScreenSettingsDialogBaseTop-chwithTop-leftScreenSettingsDialogBaseTop-dde Top-rightScreenSettingsDialogBase,Gwirio cleientiaid bob&Check clients everyServerConfigDialogBase Golygu&EditServerConfigDialogBaseBysellau brys&HotkeysServerConfigDialogBase Newydd&NewServerConfigDialogBaseDewisiadau&OptionsServerConfigDialogBase Dileu&RemoveServerConfigDialogBase Newid&SwitchServerConfigDialogBaseGweithredoeddA&ctionsServerConfigDialogBase4Gosodiadau uwch y gweinyddAdvanced server settingsServerConfigDialogBasedCyfluniwch gynllun eich cyfluniad gweinydd synergy:Configure the layout of your synergy server configuration.ServerConfigDialogBasenLlusgwch sgrn o'r grid neu i'r bin sbwriel i'w ddileu.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaseBLlusgwch sgrn newydd i'r grid neu symudwch y rhai presennol o gwmpas. Llusgwch sgrn i'r bin sbwriel i'w ddileu. Rhowch glic dwbl ar sgrn i newid ei osodiadau.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasefLlusgwch y botwm i'r grid i ychwanegu sgrn newydd.1Drag this button to the grid to add a new screen.ServerConfigDialogBase GolyguE&ditServerConfigDialogBaseBysellau brysHotkeysServerConfigDialogBase NewyddNe&wServerConfigDialogBase DileuRe&moveServerConfigDialogBase$Sgriniau a dolenniScreens and linksServerConfigDialogBase$Cyfluniad GweinyddServer ConfigurationServerConfigDialogBase Newid ar l arosSwitch &after waitingServerConfigDialogBase,Newid ar l tap dwl ynSwitch on double &tap withinServerConfigDialogBaseNDefnyddio symudiadau llygoden perthynolUse &relative mouse movesServerConfigDialogBasePori... Browse...SettingsDialogBaseDadfygioDebug2SettingsDialogBase GwallErrorSettingsDialogBaseGwybodaethInfoSettingsDialogBase NodynNoteSettingsDialogBaseGosodiadauSettingsSettingsDialogBaseRhybuddWarningSettingsDialogBaseDewiswch.Please select an option. SetupWizard$Gosod fyny Synergy Setup Synergy SetupWizard*Gweinydd neu Gleient?Server or Client?SetupWizardBase$Gosod fyny Synergy Setup SynergySetupWizardBaseFMae Synergy yn gadael i chi rhannu eich llygoden a'r bysellfwrdd yn hawdd rhwng nifer o gyfrifiaduron ar eich desg, ac mae'n rhad ac am ddim a Ffynhonnell Agored. Dyna gyd sydd angen yw symud eich llygoden dros ymyl sgrn un cyfrifiadur i un arall. Gallwch hyd yn oed rannu eich holl clipfyrddau. Y cyfan sydd ei angen yw cysylltiad rhwydwaith. Mae Synergy yn draws-lwyfan (mae'n gweithio ar Windows, Mac OS X a Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseSynergySynergyZeroconfService synergy-1.8.8-stable/src/gui/res/lang/gui_cy.ts000066400000000000000000001660671305627404700214440ustar00rootroot00000000000000 AboutDialogBase About Synergy Ynghylch Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: Fersiwn: &Ok Iawn ActionDialogBase Configure Action Cyflunio Gweithred Choose the action to perform Dewiswch y weithred i wneud Press a hotkey Gwasgwch fysell brys Release a hotkey Ryddhewch y bysell frys Press and release a hotkey Gwasgwch a ryddhewch y bysell frys only on these screens ar y sgriniau yma yn unig Switch to screen Newid i sgrîn Switch in direction Newid cyfeiriad left chwith right dde up fyny down lawr Lock cursor to screen Cloi cyrchydd i'r sgrîn toggle toglo on ymlaen off i ffwrdd This action is performed when Mae'r weithred hwn yn cael ei wneud gan the hotkey is pressed pan wasgir y bysell frys the hotkey is released pan ryddheir y bysell frys AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Bysell frys Enter the specification for the hotkey: Rhowch y manyleb ar gyfer y bysell frws hwn: MainWindow &Start Dechrau &File Ffeil &Edit Golygu &Window Ffenest &Help Cymorth <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started Methwyd cychwyn y rhaglen The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Nid oedd yn bosib cychwyn y rhaglen <br><br>%1<br><br>yn llwyddiannus er ei fod yn bodoli. Gwnewch yn siwr fod ganddoch yr hawliau cywir i redeg y rhaglen yma. Synergy client not found Methwyd dod o hyd i gleient Synergy The executable for the synergy client does not exist. Nid yw'r ffeil weithredadwy ar gyfer y cleient synergy yn bodoli. Hostname is empty Mae'r enw gwesteiwr yn bodoli Please fill in a hostname for the synergy client to connect to. Rhowch enw gwesteiwr i'r cleient synergy i gysylltu iddo. Cannot write configuration file Methu sgrifennu i'r ffeil gyfluniad The temporary configuration file required to start synergy can not be written. Nid yw'n bosib sgrifennu i'r ffeil gyfluniad dros dro sydd angen i ddechrau synergy Configuration filename invalid Mae enw'r ffeil gyfluniad yn annilys You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Nid ydych wedi llenwi mewn ffeil gyfluniad dilys ar gyfer y gweinydd synergy. Hoffech chi bori am ffeil gyfluniad nawr? Synergy server not found Methwyd dod o hyd i weinydd Synergy The executable for the synergy server does not exist. Nid yw'r ffeil weithredadwy ar gyfer y gweinydd synergy yn bodoli. Synergy terminated with an error Fe wnaeth Synergy derfynnu gyda gwall Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Fe wnaeth Synergy derfynnu yn annisgwyl gyda cod gorffen %1.<br><br>Gwelwch allbwn log am fanylion. &Stop Stopio Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Mae Synergy yn dechrau. Synergy is running. Mae Synergy yn rhedeg. Synergy is not running. Nid yw Synergy yn rhedeg. Unknown Synergy Synergy Browse for a synergys config file Profi am ffeil gyfluniad synergys Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Cadw'r cyfluniad fel... Save failed Methwyd cadw Could not save configuration to file. Methwyd cadw'r ffeil gyfluniad MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Dechrau Use existing configuration: Defnyddio'r cyfluniad presennol: &Configuration file: Ffeil Cyfluniad: &Browse... Pori... Configure interactively: Cyflunio'n rhyngweithiol: &Configure Server... Cyflunio Gweinydd... Ready Yn barod Log Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Ynghylch Synergy &Quit Gadael Quit Gadael Run Rhedeg S&top Stopio Stop Stopop S&how Status Dangos Statws &Hide Hide &Show Show Save configuration &as... Cadw'r cyfluniad fel... Save the interactively generated server configuration to a file. Cadw'r cyfluniad gweinydd a gynhyrchwyd i ffeil: Settings Gosodiadau Edit settings Golygu gosodiadau Run Wizard Rhedeg Dewin NewScreenWidget Unnamed Heb ei enwi PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Gosod fyny Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Cyfluniadau Synergy (*.sgc);;Pob ffeil (*.*) Synergy Configurations (*.conf);;All files (*.*) Cyfluniadau Synergy (*.conf);;Pob ffeil (*.*) System tray is unavailable, quitting. Nid yw'r gilfach system ar gael, yn gadael. ScreenSettingsDialog Screen name is empty Mae enw'r sgrîn yn wag The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Gosodiadau Sgrîn Screen &name: Enw sgrîn A&liases Ffugenwau &Add Ychwanegu &Remove Dileu &Modifier keys Bysellau newid &Shift: Shift Ctrl Alt Meta Super None Dim &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-chwith Top-right Top-dde Bottom-left Gwaelod-chwith Bottom-right Gwaelod-dde Corner Si&ze: Maint Cornel: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Cyfluniad Gweinydd Screens and links Sgriniau a dolenni Drag a screen from the grid to the trashcan to remove it. Llusgwch sgrîn o'r grid neu i'r bin sbwriel i'w ddileu. Configure the layout of your synergy server configuration. Cyfluniwch gynllun eich cyfluniad gweinydd synergy Drag this button to the grid to add a new screen. Llusgwch y botwm i'r grid i ychwanegu sgrîn newydd. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Llusgwch sgrîn newydd i'r grid neu symudwch y rhai presennol o gwmpas. Llusgwch sgrîn i'r bin sbwriel i'w ddileu. Rhowch glic dwbl ar sgrîn i newid ei osodiadau. Hotkeys Bysellau brys &Hotkeys Bysellau brys &New Newydd &Edit Golygu &Remove Dileu A&ctions Gweithredoedd Ne&w Newydd E&dit Golygu Re&move Dileu Advanced server settings Gosodiadau uwch y gweinydd &Switch Newid Switch &after waiting Newid ar ôl aros ms Switch on double &tap within Newid ar ôl tap dwl yn &Options Dewisiadau &Check clients every Gwirio cleientiaid bob Use &relative mouse moves Defnyddio symudiadau llygoden perthynol S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Gosodiadau Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Pori... Error Gwall &Language: &Miscellaneous Warning Rhybudd Note Nodyn Info Gwybodaeth Debug Debug1 Debug2 Dadfygio SetupWizard Setup Synergy Gosod fyny Synergy Please select an option. Dewiswch. Please enter your email address and password. SetupWizardBase Setup Synergy Gosod fyny Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Mae Synergy yn gadael i chi rhannu eich llygoden a'r bysellfwrdd yn hawdd rhwng nifer o gyfrifiaduron ar eich desg, ac mae'n rhad ac am ddim a Ffynhonnell Agored. Dyna gyd sydd angen yw symud eich llygoden dros ymyl sgrîn un cyfrifiadur i un arall. Gallwch hyd yn oed rannu eich holl clipfyrddau. Y cyfan sydd ei angen yw cysylltiad rhwydwaith. Mae Synergy yn draws-lwyfan (mae'n gweithio ar Windows, Mac OS X a Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Gweinydd neu Gleient? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_da.qm000066400000000000000000000530601305627404700213700ustar00rootroot00000000000000h^+[H4)0SWY u&2O*{D<,G:VE,VEg` E+t**1*%*0*>+r+g+`aG:!Gz(JCLbDU`XY-Z.9xtx.>6I}Su>(Z `= nbj i4h/$vHZOdEv.__"e;w9&'0 ;H}H.O !&O GO H]E`|%kVE -UN*Yu:El_ C} !r*=l$1D"Da 7-:'=:1z  B$ZCiJ,X"QJ-izE@d)fl - 攄LJM(H/:S#( n4.d.u@Ty+L#A{2~p~zQ>JC9I 3=Tk@d0ycN2 %m@~C'}F:n\C=3"" I_: JzF k#5 v~9M  5:bun>y~F$M r,/7+}kC:ak2 .4u>/*iP?&Ok&OkAboutDialogBaseOm Synergy About SynergyAboutDialogBase UkendtUnknownAboutDialogBaseVersion:Version:AboutDialogBase6Vlg handling til udfrelseChoose the action to performActionDialogBase&Konfigurer handlingConfigure ActionActionDialogBase(Ls markr til skrmLock cursor to screenActionDialogBaseTast en hotkeyPress a hotkeyActionDialogBase,Tryk og slip en hotkeyPress and release a hotkeyActionDialogBaseSlip en hotkeyRelease a hotkeyActionDialogBaseSkift i retningSwitch in directionActionDialogBaseSkift til skrmSwitch to screenActionDialogBase6Denne handling udfres, nrThis action is performed whenActionDialogBaseneddownActionDialogBasevenstreleftActionDialogBasefraoffActionDialogBasetilonActionDialogBase4kun p disse skrmbillederonly on these screensActionDialogBase hjrerightActionDialogBase(hotkey'en er trykketthe hotkey is pressedActionDialogBase(hotkey'en er sluppetthe hotkey is releasedActionDialogBaseskift mellemtoggleActionDialogBaseopupActionDialogBaseBIndtast beskrivelse af hotkey'en:'Enter the specification for the hotkey:HotkeyDialogBase HotkeyHotkeyHotkeyDialogBase&Rediger&Edit MainWindow&Fil&File MainWindow &Hjlp&Help MainWindow &Start&Start MainWindow &Stop&Stop MainWindow&Vindue&Window MainWindow<p>Din version af Synergy er forldet. Version <b>%1</b> er nu tilgngelig som <a href="%2">download</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowLSg efter en Synergy-konfigurationsfil!Browse for a synergys config file MainWindowNKan ikke skrive til konfigurationsfilenCannot write configuration file MainWindowJUgyldigt navn for konfigurationsfilenConfiguration filename invalid MainWindowRKunne ikke gemme konfigurationen i filen.%Could not save configuration to file. MainWindow6Vrtsnavnet er ikke angivetHostname is empty MainWindowIndtast det vrtsnavn, som Synergy-klienten skal forbinde sig til.?Please fill in a hostname for the synergy client to connect to. MainWindow6Programmet kan ikke startesProgram can not be started MainWindow0Gem konfiguration som...Save configuration as... MainWindowGem fejlede Save failed MainWindowSynergySynergy MainWindowBSynergy-klienten blev ikke fundetSynergy client not found MainWindow.Synergy er ikke startetSynergy is not running. MainWindow.Synergy krer allerede.Synergy is running. MainWindow Synergy starter.Synergy is starting. MainWindowBSynergy-serveren blev ikke fundetSynergy server not found MainWindowSynergy afsluttede uventet med fejlkoden %1.<br><br>Se venligst logfilen for detaljer.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow<Synergy afsluttede med en fejl Synergy terminated with an error MainWindowdProgramfilen til Synergy-klienten eksisterer ikke.5The executable for the synergy client does not exist. MainWindowdProgramfilen til Synergy-klienten eksisterer ikke.5The executable for the synergy server does not exist. MainWindow Programfilen<br><br>%1<br><br>kunne ikke startes, eller den eksisterer ikke. Kontroller, at du har rettigheder til at kre programmet.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowDen midlertidige konfigurationsfil, som skal bruges for at starte Synergy, kan ikke oprettes.NThe temporary configuration file required to start synergy can not be written. MainWindow UkendtUnknown MainWindowDu har ikke oprettet en gyldig konfigurationsfil til Synergy-serveren. Vil du sge efter konfigurationsfilen?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow&Om Synergy...&About Synergy...MainWindowBase&Anvend&ApplyMainWindowBase&Gennemse... &Browse...MainWindowBase(&Konfigurations fil:&Configuration file:MainWindowBase*&Konfigurer Server...&Configure Server...MainWindowBase &Skjul&HideMainWindowBase&Afslut&QuitMainWindowBase&Server-IP: &Server IP:MainWindowBase&Vis&ShowMainWindowBase &Start&StartMainWindowBase2Interaktiv konfiguration:Configure interactively:MainWindowBase*Rediger indstillinger Edit settingsMainWindowBase SkjulHideMainWindowBaseIP-adresser: IP addresses:MainWindowBaseLogLogMainWindowBase AfslutQuitMainWindowBaseKlarReadyMainWindowBaseKrRunMainWindowBaseKr guide Run WizardMainWindowBaseV&is Status S&how StatusMainWindowBase S&topS&topMainWindowBase2Gem konfiguration &som...Save configuration &as...MainWindowBasezGem den interaktivt genererede server-konfiguration i en fil.@Save the interactively generated server configuration to a file.MainWindowBaseSkrmnavn: Screen name:MainWindowBaseIndstillingerSettingsMainWindowBaseVisShowMainWindowBaseStopStopMainWindowBaseSynergySynergyMainWindowBase@Brug eksisterende konfiguration:Use existing configuration:MainWindowBaseUnavngivetUnnamedNewScreenWidgetOpst Synergy Setup SynergyPluginWizardPagedSynergy-konfigurationer (*.conf);;Alle filer (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectbSynergy-konfigurationer (*.sgc);;Alle filer (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectXSystembakken er ikke tilgngelig. Afslutter.%System tray is unavailable, quitting.QObject2Skrmnavn er ikke angivetScreen name is emptyScreenSettingsDialog4Skrm navnet matcher aliasScreen name matches aliasScreenSettingsDialogSkrm navnet kan ikke vre tomt. Enten skriv et navn eller annuller denne dialog.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogSkrm navnet kan ikke vre det samme som et alias. Enten fjern alias'et eller skift skrm navnet.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog&Tilfj&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBase&Dde hjrner &Dead cornersScreenSettingsDialogBase&Rettelser&FixesScreenSettingsDialogBase&ndre-taster&Modifier keysScreenSettingsDialogBase &Fjern&RemoveScreenSettingsDialogBase&Skift:&Shift:ScreenSettingsDialogBaseA&liaserA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase&Nederst til venstre Bottom-leftScreenSettingsDialogBase"Nederst til hjre Bottom-rightScreenSettingsDialogBase"Hjrnest&rrelse: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase(Fix CAPS LOCK-tastenFix CAPS LOCK keyScreenSettingsDialogBase&Fix NUM LOCK-tastenFix NUM LOCK keyScreenSettingsDialogBase,Fix SCROLL LOCK-tastenFix SCROLL LOCK keyScreenSettingsDialogBase,Fix Xtest for XineramaFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBase IngenNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBaseSkrm&navn: Screen &name:ScreenSettingsDialogBase$SkrmindstillingerScreen SettingsScreenSettingsDialogBase SkiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBase$verst til venstreTop-leftScreenSettingsDialogBase verst til hjre Top-rightScreenSettingsDialogBase<center>Skrm: <b>%1</b></center><br>Dobbeltklik for at redigere indstillinger<br>Trk skrm til Papirkurven for at slette deno
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel(&Nederst til venstre &Bottom-leftServerConfigDialogBase(&Check klienter hver&Check clients everyServerConfigDialogBase&Dde hjrner &Dead cornersServerConfigDialogBase&Rediger&EditServerConfigDialogBase&Hotkeys&HotkeysServerConfigDialogBase&Ny&NewServerConfigDialogBase&Indstillinger&OptionsServerConfigDialogBase &Fjern&RemoveServerConfigDialogBase &Skift&SwitchServerConfigDialogBaseH&andlingerA&ctionsServerConfigDialogBase>Avancerede server-indstillingerAdvanced server settingsServerConfigDialogBase$Nederst til h&jre Bottom-ri&ghtServerConfigDialogBase`Indstil Synergy-serverens konfigurations-layout.:Configure the layout of your synergy server configuration.ServerConfigDialogBase"Hj&rnestrrelse: Cor&ner Size:ServerConfigDialogBaseZTag ikke &forgrundsvinduer p Windows-servere0Don't take &foreground window on Windows serversServerConfigDialogBaseSlet en skrm ved at trkke den fra gitteret over i Papirkurven.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase`Trk nye skrme over p gitteret eller ryk eksisterende skrme rundt slet en skrm ved at trkke den over i Papirkurven. Dobbeltklik p skrmen for at redigere indstillingerne.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasexTrk denne knap over p gitteret for at tilfje en ny skrm.1Drag this button to the grid to add a new screen.ServerConfigDialogBaseR&edigerE&ditServerConfigDialogBaseHotkeysHotkeysServerConfigDialogBaseN&yNe&wServerConfigDialogBase S&letRe&moveServerConfigDialogBase4S&ynkroniser screen-savereS&ynchronize screen saversServerConfigDialogBaseSkrme og linksScreens and linksServerConfigDialogBase(Server-konfigurationServer ConfigurationServerConfigDialogBase6Skift &efter at have ventetSwitch &after waitingServerConfigDialogBase<Aktivr dobbelt &tap inden forSwitch on double &tap withinServerConfigDialogBase&v&erst til venstre To&p-leftServerConfigDialogBase"verst til h&jre Top-rig&htServerConfigDialogBase.Brug &relative museflytUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBase4Er du sikker p, at du vil ophje Synergy's rettigheder? Det giver Synergy rettigheder til at interagere med andre ophjede processer og UAC-dialogboksen, men det kan give problemer med processer, som ikke har samme rettigheder. Ophj kun Synergy, hvis du virkelig har brug for det.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialog6Ophj Synergy's rettighederElevate SynergySettingsDialogGem logfil i:Save log file to...SettingsDialog&Brugerflade &Interface:SettingsDialogBase Sprog: &Language:SettingsDialogBase"&Lognings niveau:&Logging level:SettingsDialogBaseDiverse&MiscellaneousSettingsDialogBaseGennemse... Browse...SettingsDialogBaseFejlfindDebugSettingsDialogBaseFejlfind1Debug1SettingsDialogBaseFejlfind2Debug2SettingsDialogBaseFejlErrorSettingsDialogBaseInformationInfoSettingsDialogBaseLog til fil: Log to file:SettingsDialogBaseLogningLoggingSettingsDialogBase BemrkNoteSettingsDialogBase P&ort:P&ort:SettingsDialogBaseSk&rmnavn: Sc&reen name:SettingsDialogBaseIndstillingerSettingsSettingsDialogBaseAdvarselWarningSettingsDialogBasefVr sd at skrive din email adresse og adgangskode.-Please enter your email address and password. SetupWizard"Vlg en mulighed.Please select an option. SetupWizardOpst Synergy Setup Synergy SetupWizard(Server eller Klient?Server or Client?SetupWizardBaseOpst Synergy Setup SynergySetupWizardBaseSynergy lader dig nemt dele din mus og tastatur mellem flere computere p dit skrivebord, og det er gratis og Open Source. Flyt blot din mus forbi skrmkanten p en computers skrm til en anden. Du kan endda dele din udklipsholder ogs. Det eneste du behver er en netvrksforbindelse. Desuden fungere Synergy p flere platforme (Virker p Windows, Mac OS X samt Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseDTak fordi du installerede Synergy!Thanks for installing Synergy!SetupWizardBaseVelkommenWelcomeSetupWizardBase UkendtUnknownVersionChecker@Fejl i login, en fejl opstod. %1$Login failed, an error occurred. %1 WebClient\Fejl i login, en fejl opstod. Server svar: %16Login failed, an error occurred. Server response: %1 WebClient\Fejl i login, forkert email eller adgangskode.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_da.ts000066400000000000000000001712771305627404700214140ustar00rootroot00000000000000 AboutDialogBase About Synergy Om Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Ukendt Version: Version: &Ok &Ok ActionDialogBase Configure Action Konfigurer handling Choose the action to perform Vælg handling til udførelse Press a hotkey Tast en hotkey Release a hotkey Slip en hotkey Press and release a hotkey Tryk og slip en hotkey only on these screens kun på disse skærmbilleder Switch to screen Skift til skærm Switch in direction Skift i retning left venstre right højre up op down ned Lock cursor to screen Lås markør til skærm toggle skift mellem on til off fra This action is performed when Denne handling udføres, når the hotkey is pressed hotkey'en er trykket the hotkey is released hotkey'en er sluppet AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Hotkey Enter the specification for the hotkey: Indtast beskrivelse af hotkey'en: MainWindow &Start &Start &File &Fil &Edit &Rediger &Window &Vindue &Help &Hjælp <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Din version af Synergy er forældet. Version <b>%1</b> er nu tilgængelig som <a href="%2">download</a>.</p> Program can not be started Programmet kan ikke startes The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Programfilen<br><br>%1<br><br>kunne ikke startes, eller den eksisterer ikke. Kontroller, at du har rettigheder til at køre programmet. Synergy client not found Synergy-klienten blev ikke fundet The executable for the synergy client does not exist. Programfilen til Synergy-klienten eksisterer ikke. Hostname is empty Værtsnavnet er ikke angivet Please fill in a hostname for the synergy client to connect to. Indtast det værtsnavn, som Synergy-klienten skal forbinde sig til. Cannot write configuration file Kan ikke skrive til konfigurationsfilen The temporary configuration file required to start synergy can not be written. Den midlertidige konfigurationsfil, som skal bruges for at starte Synergy, kan ikke oprettes. Configuration filename invalid Ugyldigt navn for konfigurationsfilen You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Du har ikke oprettet en gyldig konfigurationsfil til Synergy-serveren. Vil du søge efter konfigurationsfilen? Synergy server not found Synergy-serveren blev ikke fundet The executable for the synergy server does not exist. Programfilen til Synergy-klienten eksisterer ikke. Synergy terminated with an error Synergy afsluttede med en fejl Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy afsluttede uventet med fejlkoden %1.<br><br>Se venligst logfilen for detaljer. &Stop &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy starter. Synergy is running. Synergy kører allerede. Synergy is not running. Synergy er ikke startet Unknown Ukendt Synergy Synergy Browse for a synergys config file Søg efter en Synergy-konfigurationsfil Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Gem konfiguration som... Save failed Gem fejlede Could not save configuration to file. Kunne ikke gemme konfigurationen i filen. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Skærmnavn: &Server IP: &Server-IP: &Start &Start Use existing configuration: Brug eksisterende konfiguration: &Configuration file: &Konfigurations fil: &Browse... &Gennemse... Configure interactively: Interaktiv konfiguration: &Configure Server... &Konfigurer Server... Ready Klar Log Log &Apply &Anvend IP addresses: IP-adresser: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Om Synergy... &Quit &Afslut Quit Afslut Run Kør S&top S&top Stop Stop S&how Status V&is Status &Hide &Skjul Hide Skjul &Show &Vis Show Vis Save configuration &as... Gem konfiguration &som... Save the interactively generated server configuration to a file. Gem den interaktivt genererede server-konfiguration i en fil. Settings Indstillinger Edit settings Rediger indstillinger Run Wizard Kør guide NewScreenWidget Unnamed Unavngivet PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Opsæt Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy-konfigurationer (*.sgc);;Alle filer (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy-konfigurationer (*.conf);;Alle filer (*.*) System tray is unavailable, quitting. Systembakken er ikke tilgængelig. Afslutter. ScreenSettingsDialog Screen name is empty Skærmnavn er ikke angivet The screen name cannot be empty. Please either fill in a name or cancel the dialog. Skærm navnet kan ikke være tomt. Enten skriv et navn eller annuller denne dialog. Screen name matches alias Skærm navnet matcher alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Skærm navnet kan ikke være det samme som et alias. Enten fjern alias'et eller skift skærm navnet. ScreenSettingsDialogBase Screen Settings Skærmindstillinger Screen &name: Skærm&navn: A&liases A&liaser &Add &Tilføj &Remove &Fjern &Modifier keys &Ændre-taster &Shift: &Skift: Shift Skift Ctrl Ctrl Alt Alt Meta Meta Super Super None Ingen &Ctrl: &Ctrl: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners &Døde hjørner Top-left Øverst til venstre Top-right Øverst til højre Bottom-left Nederst til venstre Bottom-right Nederst til højre Corner Si&ze: Hjørnest&ørrelse: &Fixes &Rettelser Fix CAPS LOCK key Fix CAPS LOCK-tasten Fix NUM LOCK key Fix NUM LOCK-tasten Fix SCROLL LOCK key Fix SCROLL LOCK-tasten Fix XTest for Xinerama Fix Xtest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Skærm: <b>%1</b></center><br>Dobbeltklik for at redigere indstillinger<br>Træk skærm til Papirkurven for at slette den ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Server-konfiguration Screens and links Skærme og links Drag a screen from the grid to the trashcan to remove it. Slet en skærm ved at trække den fra gitteret over i Papirkurven. Configure the layout of your synergy server configuration. Indstil Synergy-serverens konfigurations-layout. Drag this button to the grid to add a new screen. Træk denne knap over på gitteret for at tilføje en ny skærm. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Træk nye skærme over på gitteret eller ryk eksisterende skærme rundt slet en skærm ved at trække den over i Papirkurven. Dobbeltklik på skærmen for at redigere indstillingerne. Hotkeys Hotkeys &Hotkeys &Hotkeys &New &Ny &Edit &Rediger &Remove &Fjern A&ctions H&andlinger Ne&w N&y E&dit R&ediger Re&move S&let Advanced server settings Avancerede server-indstillinger &Switch &Skift Switch &after waiting Skift &efter at have ventet ms ms Switch on double &tap within Aktivér dobbelt &tap inden for &Options &Indstillinger &Check clients every &Check klienter hver Use &relative mouse moves Brug &relative museflyt S&ynchronize screen savers S&ynkroniser screen-savere Don't take &foreground window on Windows servers Tag ikke &forgrundsvinduer på Windows-servere Ignore auto config clients &Dead corners &Døde hjørner To&p-left Øv&erst til venstre Top-rig&ht Øverst til hø&jre &Bottom-left &Nederst til venstre Bottom-ri&ght Nederst til hø&jre Cor&ner Size: Hjø&rnestørrelse: SettingsDialog Save log file to... Gem logfil i: Elevate Synergy Ophøj Synergy's rettigheder Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Er du sikker på, at du vil ophøje Synergy's rettigheder? Det giver Synergy rettigheder til at interagere med andre ophøjede processer og UAC-dialogboksen, men det kan give problemer med processer, som ikke har samme rettigheder. Ophøj kun Synergy, hvis du virkelig har brug for det. SettingsDialogBase Settings Indstillinger Sc&reen name: Sk&rmnavn: P&ort: P&ort: &Interface: &Brugerflade Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Logning &Logging level: &Lognings niveau: Log to file: Log til fil: Browse... Gennemse... Error Fejl &Language: Sprog: &Miscellaneous Diverse Warning Advarsel Note Bemærk Info Information Debug Fejlfind Debug1 Fejlfind1 Debug2 Fejlfind2 SetupWizard Setup Synergy Opsæt Synergy Please select an option. Vælg en mulighed. Please enter your email address and password. Vær sød at skrive din email adresse og adgangskode. SetupWizardBase Setup Synergy Opsæt Synergy Welcome Velkommen Thanks for installing Synergy! Tak fordi du installerede Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy lader dig nemt dele din mus og tastatur mellem flere computere på dit skrivebord, og det er gratis og Open Source. Flyt blot din mus forbi skærmkanten på en computers skærm til en anden. Du kan endda dele din udklipsholder også. Det eneste du behøver er en netværksforbindelse. Desuden fungere Synergy på flere platforme (Virker på Windows, Mac OS X samt Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Server eller Klient? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Ukendt WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Fejl i login, forkert email eller adgangskode. Login failed, an error occurred. %1 Fejl i login, en fejl opstod. %1 Login failed, an error occurred. Server response: %1 Fejl i login, en fejl opstod. Server svar: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_de.qm000066400000000000000000000561161305627404700214010ustar00rootroot00000000000000Gz,JHLbIU` XY1Z1xx.V>:_|}S u>9(Z = onbj#432vMZUhEv.k_& e?w9*+/;H}H2O $PO LO M]J0|(VE 1QUN.4Yu:Il_ 1} $*B]lx4IIG ;U:*:5j  G$ZGJ0"QJ-izJ@d-l 0攄 0J"g(MK:S'( n4.d27@Ty.L#F{6|0!z>eJH# 3=Tvk@d4ycS!%@~ C+z}F?TnCB7%Z I_ JzJ k#9 v~= @ -5 Pn@ d& ~5@# ~qT ք~ ȹB ȹ#Y ȹV$ aG |0 F+ F6 Z, 7 KG I @{m RVv RV RVS R T$ V4"  |*Gn c7I s" sK< cAf F-b Ҫn ^ /,_ 4pB d/ i! r- zk# PK ¦eSi x48 ]^^L1\R=]> 9FbunCay~K' r/7/kC>k6.8[>-iV]&Ok&OkAboutDialogBaseber Synergy About SynergyAboutDialogBaseUnbekanntUnknownAboutDialogBaseVersion:Version:AboutDialogBaseZWhle eine Aktion, die ausgefhrt werden sollChoose the action to performActionDialogBase(Aktion konfigurierenConfigure ActionActionDialogBase<Cursor auf Anzeige beschrnkenLock cursor to screenActionDialogBaseHotkey drckenPress a hotkeyActionDialogBase8Hotkey drcken und loslassenPress and release a hotkeyActionDialogBase Hotkey loslassenRelease a hotkeyActionDialogBase(In Richtung wechselnSwitch in directionActionDialogBase&Zu Anzeige WechselnSwitch to screenActionDialogBaseDDiese Aktion wird ausgefhrt, wennThis action is performed whenActionDialogBase runterdownActionDialogBase linksleftActionDialogBaseausoffActionDialogBaseeinonActionDialogBase6Nur auf diesen Bildschirmenonly on these screensActionDialogBase rechtsrightActionDialogBase:wenn der Hotkey gedrckt wirdthe hotkey is pressedActionDialogBase@wenn der Hotkey losgelassen wirdthe hotkey is releasedActionDialogBaseumschaltentoggleActionDialogBasehochupActionDialogBaseLGib die Definition fr den Hotkey ein:'Enter the specification for the hotkey:HotkeyDialogBase HotkeyHotkeyHotkeyDialogBase&Bearbeiten&Edit MainWindow &Datei&File MainWindow &Hilfe&Help MainWindow &Start&Start MainWindow &Stopp&Stop MainWindow&Fenster&Window MainWindow<p>Ihre Synergy Version ist veraltet. Version <b>%1</b> ist jetzt zum <a href="%2">Download</a> verfgbar.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowdNach einer Konfigurationsdatei fr Synergy suchen.!Browse for a synergys config file MainWindowfKonfigurationsdatei konnte nicht geschrieben werdenCannot write configuration file MainWindowfDer Dateiname der Konfigurationsdatei ist ungltig.Configuration filename invalid MainWindowlKonfiguration konnte nicht in Datei gespeichert werden%Could not save configuration to file. MainWindow(Der Hostname is leerHostname is empty MainWindowBitte tragen Sie einen Hostnamen ein, zu dem sich der Synergy-Client verbinden soll.?Please fill in a hostname for the synergy client to connect to. MainWindowTDas Programm konnte nicht gestartet werdenProgram can not be started MainWindowBKonfiguration speichern unter ...Save configuration as... MainWindow0Speichern fehlgeschlagen Save failed MainWindowSynergySynergy MainWindowNDer Synergy Client wurde nicht gefundenSynergy client not found MainWindow<Synergy wird nicht ausgefhrt.Synergy is not running. MainWindowSynergy luft.Synergy is running. MainWindow.Synergy wird gestartet.Synergy is starting. MainWindowPDer Synergy Server wurde nicht gefunden.Synergy server not found MainWindowSynergy wurde unerwartet mit Abbruchcode %1 beendet. <br><br> Weitere Informationen knnen dem Log entnommen werden.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowNSynergy wurde mit einem Fehler beendet. Synergy terminated with an error MainWindowzDie ausfhrbare Datei fr den Synergy Client existiert nicht.5The executable for the synergy client does not exist. MainWindowzDie ausfhrbare Datei fr den Synergy Server existiert nicht.5The executable for the synergy server does not exist. MainWindownDie Anwendung<br><br>%1<br><br> konnte nicht gestartet werden, obwohl sie vorhanden ist. Bitte berprfen sie, ob sie die bentigten Berechtigungen zur Ausfhrung der Anwendung haben,The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowDie temporre Konfigurationsdatei konnte nicht geschrieben werden. Sie wird jedoch fr den Start von Synergy bentigt.NThe temporary configuration file required to start synergy can not be written. MainWindowUnbekanntUnknown MainWindowSie haben keine gltige Konfigurationsdatei angegeben. Wollen sie jetzt nach dieser Datei suchen?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow &ber Synergy...&About Synergy...MainWindowBase&Anwenden&ApplyMainWindowBase&Durchsuchen... &Browse...MainWindowBase*&Konfigurationsdatei:&Configuration file:MainWindowBase0Server &konfigurieren...&Configure Server...MainWindowBase&Verstecken&HideMainWindowBase&Beenden&QuitMainWindowBaseServer IP: &Server IP:MainWindowBase&Zeigen&ShowMainWindowBase &Start&StartMainWindowBase2Interaktiv konfigurieren:Configure interactively:MainWindowBase0Einstellungen bearbeiten Edit settingsMainWindowBaseVersteckenHideMainWindowBaseIP Adressen: IP addresses:MainWindowBaseLogLogMainWindowBaseBeendenQuitMainWindowBase FertigReadyMainWindowBase StartRunMainWindowBase&Assistent ausfhren Run WizardMainWindowBase S&tatus anzeigen S&how StatusMainWindowBase S&toppS&topMainWindowBaseDConfiguration speichern &unter ...Save configuration &as...MainWindowBase~Speichere die interaktiv erstellte Konfiguration in eine Datei.@Save the interactively generated server configuration to a file.MainWindowBaseAnzeigename: Screen name:MainWindowBaseEinstellungenSettingsMainWindowBaseAnzeigenShowMainWindowBaseStopStopMainWindowBaseSynergySynergyMainWindowBaseDVerwende bestehende Konfiguration:Use existing configuration:MainWindowBaseUnbenanntUnnamedNewScreenWidget$Synergy einrichten Setup SynergyPluginWizardPagehSynergy Konfigurationen (*.conf);;Alle Dateien (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectfSynergy Konfigurationen (*.sgc);;Alle Dateien (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectbInfobereich ist nicht verfgbar. Beende Programm.%System tray is unavailable, quitting.QObject0Der Anzeigename ist leerScreen name is emptyScreenSettingsDialog>Der Anzeigename passt zum AliasScreen name matches aliasScreenSettingsDialogDer Bildschirmname darf nicht leer sein. Bitte trage einen Namen ein oder schliee das Fenster.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogDer Anzeigename kann nicht derselbe sein wie der Alias. Bitte entfernen sie den Alias oder ndern sie den Anzeigenamen.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog&Hinzufgen&AddScreenSettingsDialogBase &Strg:&Ctrl:ScreenSettingsDialogBase"&Tote" Ecken &Dead cornersScreenSettingsDialogBase&Korrekturen&FixesScreenSettingsDialogBase&Zusatztasten&Modifier keysScreenSettingsDialogBase&Entfernen&RemoveScreenSettingsDialogBaseUm&schalt:&Shift:ScreenSettingsDialogBaseA&liaseA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseUnten-links Bottom-leftScreenSettingsDialogBaseUnten-rechts Bottom-rightScreenSettingsDialogBase&Gre: Corner Si&ze:ScreenSettingsDialogBaseStrgCtrlScreenSettingsDialogBase8Korrektur fr FeststelltasteFix CAPS LOCK keyScreenSettingsDialogBase,Korrektur fr Num LockFix NUM LOCK keyScreenSettingsDialogBase2Korrektur fr Scroll LockFix SCROLL LOCK keyScreenSettingsDialogBase@Korrektur fr XTest mit XineramaFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBase KeineNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBaseAnzeige&name: Screen &name:ScreenSettingsDialogBase(AnzeigeeinstellungenScreen SettingsScreenSettingsDialogBaseUmschaltShiftScreenSettingsDialogBaseWindowsSuperScreenSettingsDialogBaseOben-linksTop-leftScreenSettingsDialogBaseOben-rechts Top-rightScreenSettingsDialogBase2<center>Anzeige: <b>%1</b></center><br>Klicken Sie doppelt um die Einstellungen zu ndern<br>Ziehen Sie die Anzeige in den Papierkorb um sie zu entferneno
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel&Unten-links &Bottom-leftServerConfigDialogBaseJPrfe auf Meldungen vom &Client aller&Check clients everyServerConfigDialogBase"&Tote" Ecken &Dead cornersServerConfigDialogBase&Bearbeiten&EditServerConfigDialogBase&Hotkeys&HotkeysServerConfigDialogBase&Neu&NewServerConfigDialogBase&Optionen&OptionsServerConfigDialogBase&Entfernen&RemoveServerConfigDialogBaseWech&sel&SwitchServerConfigDialogBase&BefehleA&ctionsServerConfigDialogBase:Erwiterte ServereinstellungenAdvanced server settingsServerConfigDialogBaseUnten-rec&hts Bottom-ri&ghtServerConfigDialogBaseKonfigurieren Sie die Anordnung Ihrer Synergy Server Konfiguration.:Configure the layout of your synergy server configuration.ServerConfigDialogBase&Gre: Cor&ner Size:ServerConfigDialogBasexAuf Windows Servern &Fenster im Vordergrund nicht aktivieren0Don't take &foreground window on Windows serversServerConfigDialogBaseZiehen Sie eine Anzeige vom Raster in den Papierkorb um sie zu entfernen.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaseZiehen Sie neue Anzeigen auf das Raster oder verschieben sie existierende. Ziehen Sie eine Anzeige in den Papierkorb um sie zu entfernen. Klicken sie doppelt auf eine Anzeige um die Einstellungen zu bearbeiten.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBaseZiehen diese Symbol auf das Raster um eine neue Anzeige hinzuzufgen.1Drag this button to the grid to add a new screen.ServerConfigDialogBasen&dernE&ditServerConfigDialogBaseHotkeysHotkeysServerConfigDialogBaseNe&uNe&wServerConfigDialogBase&EntfernenRe&moveServerConfigDialogBaseDBildschirmschoner s&ynchronisierenS&ynchronize screen saversServerConfigDialogBase2Anzeigen und VerbindungenScreens and linksServerConfigDialogBase(Server KonfigurationServer ConfigurationServerConfigDialogBase.Wechsel n&ach WartezeitSwitch &after waitingServerConfigDialogBasefWechsel nach doppel&ter Randberhrung innerhalb vonSwitch on double &tap withinServerConfigDialogBaseO&ben-links To&p-leftServerConfigDialogBaseOben-rec&hts Top-rig&htServerConfigDialogBaseBVe&rwende relative MausbewegungenUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseZSind Sie sicher das Sie Synergy Erweiterte Benutzerrechte einrumen wollen? Das erlaubt Synergy mit Prozessen die hhere Rechte haben und dem UAC-Dialog zu interagieren, kann aber bei normalen Prozessen Probleme verursachen. Erweiterte Rechte an Synergy bitte nur vergeben wenn es unbedingt ntig ist.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialog"Synergy BefrdernElevate SynergySettingsDialog0Speicherort des LogfilesSave log file to...SettingsDialogSchn&ittstelle &Interface:SettingsDialogBaseSprache: &Language:SettingsDialogBase&Umfang:&Logging level:SettingsDialogBase&Sonstiges&MiscellaneousSettingsDialogBaseDurchsuchen... Browse...SettingsDialogBase DebugDebugSettingsDialogBase Debug1Debug1SettingsDialogBase Debug2Debug2SettingsDialogBase FehlerErrorSettingsDialogBaseInfoInfoSettingsDialogBaseIn Datei: Log to file:SettingsDialogBaseProtokollierungLoggingSettingsDialogBaseHinweisNoteSettingsDialogBase P&ort:P&ort:SettingsDialogBase&Anzeigename: Sc&reen name:SettingsDialogBaseEinstellungenSettingsSettingsDialogBaseWarnungWarningSettingsDialogBaserBitte geben Sie Ihre E-Mail Adresse und Ihr Passwort ein.-Please enter your email address and password. SetupWizardBBitte whlen Sie eine option aus.Please select an option. SetupWizard$Synergy einrichten Setup Synergy SetupWizard&Server oder Client?Server or Client?SetupWizardBase$Synergy einrichten Setup SynergySetupWizardBase^Mit Synergy knnen Sie einfach Ihre Tastatur und Maus an mehreren Computern auf Ihrem Schreibtisch nutzen, und es ist Frei und Open Source. Bewegen Sie einfach ihre Maus ber den Rand des Bildschirms eines Computers auf den Bildschirm eines anderen. Sie knnen sogar den Inhalt ihrer Zwischenablage an alle Computer verteilen. Alles was Sie brauchen ist ein Netzwerk-Anschluss. Synergy funktioniert auf Windows, Mac OS X und Linux.ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBasePDanke, dass du Synergy installiert hast!Thanks for installing Synergy!SetupWizardBaseWillkommenWelcomeSetupWizardBaseUnbekanntUnknownVersionCheckerhLogin fehlgeschlagen, ein Fehler ist aufgetreten. %1$Login failed, an error occurred. %1 WebClientLogin fehlgeschlagen, ein Fehler ist aufgetreten. Serverantwort: %16Login failed, an error occurred. Server response: %1 WebClientvLogin fehlgeschlagen, falsche E-Mail Adresse oder Passwort.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_de.ts000066400000000000000000001726741305627404700214220ustar00rootroot00000000000000 AboutDialogBase About Synergy Über Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Unbekannt Version: Version: &Ok &Ok ActionDialogBase Configure Action Aktion konfigurieren Choose the action to perform Wähle eine Aktion, die ausgeführt werden soll Press a hotkey Hotkey drücken Release a hotkey Hotkey loslassen Press and release a hotkey Hotkey drücken und loslassen only on these screens Nur auf diesen Bildschirmen Switch to screen Zu Anzeige Wechseln Switch in direction In Richtung wechseln left links right rechts up hoch down runter Lock cursor to screen Cursor auf Anzeige beschränken toggle umschalten on ein off aus This action is performed when Diese Aktion wird ausgeführt, wenn the hotkey is pressed wenn der Hotkey gedrückt wird the hotkey is released wenn der Hotkey losgelassen wird AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Hotkey Enter the specification for the hotkey: Gib die Definition für den Hotkey ein: MainWindow &Start &Start &File &Datei &Edit &Bearbeiten &Window &Fenster &Help &Hilfe <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Ihre Synergy Version ist veraltet. Version <b>%1</b> ist jetzt zum <a href="%2">Download</a> verfügbar.</p> Program can not be started Das Programm konnte nicht gestartet werden The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Die Anwendung<br><br>%1<br><br> konnte nicht gestartet werden, obwohl sie vorhanden ist. Bitte überprüfen sie, ob sie die benötigten Berechtigungen zur Ausführung der Anwendung haben, Synergy client not found Der Synergy Client wurde nicht gefunden The executable for the synergy client does not exist. Die ausführbare Datei für den Synergy Client existiert nicht. Hostname is empty Der Hostname is leer Please fill in a hostname for the synergy client to connect to. Bitte tragen Sie einen Hostnamen ein, zu dem sich der Synergy-Client verbinden soll. Cannot write configuration file Konfigurationsdatei konnte nicht geschrieben werden The temporary configuration file required to start synergy can not be written. Die temporäre Konfigurationsdatei konnte nicht geschrieben werden. Sie wird jedoch für den Start von Synergy benötigt. Configuration filename invalid Der Dateiname der Konfigurationsdatei ist ungültig. You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Sie haben keine gültige Konfigurationsdatei angegeben. Wollen sie jetzt nach dieser Datei suchen? Synergy server not found Der Synergy Server wurde nicht gefunden. The executable for the synergy server does not exist. Die ausführbare Datei für den Synergy Server existiert nicht. Synergy terminated with an error Synergy wurde mit einem Fehler beendet. Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy wurde unerwartet mit Abbruchcode %1 beendet. <br><br> Weitere Informationen können dem Log entnommen werden. &Stop &Stopp Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy wird gestartet. Synergy is running. Synergy läuft. Synergy is not running. Synergy wird nicht ausgeführt. Unknown Unbekannt Synergy Synergy Browse for a synergys config file Nach einer Konfigurationsdatei für Synergy suchen. Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Konfiguration speichern unter ... Save failed Speichern fehlgeschlagen Could not save configuration to file. Konfiguration konnte nicht in Datei gespeichert werden MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Anzeigename: &Server IP: Server IP: &Start &Start Use existing configuration: Verwende bestehende Konfiguration: &Configuration file: &Konfigurationsdatei: &Browse... &Durchsuchen... Configure interactively: Interaktiv konfigurieren: &Configure Server... Server &konfigurieren... Ready Fertig Log Log &Apply &Anwenden IP addresses: IP Adressen: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Über Synergy... &Quit &Beenden Quit Beenden Run Start S&top S&topp Stop Stop S&how Status S&tatus anzeigen &Hide &Verstecken Hide Verstecken &Show &Zeigen Show Anzeigen Save configuration &as... Configuration speichern &unter ... Save the interactively generated server configuration to a file. Speichere die interaktiv erstellte Konfiguration in eine Datei. Settings Einstellungen Edit settings Einstellungen bearbeiten Run Wizard Assistent ausführen NewScreenWidget Unnamed Unbenannt PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Synergy einrichten Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Konfigurationen (*.sgc);;Alle Dateien (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy Konfigurationen (*.conf);;Alle Dateien (*.*) System tray is unavailable, quitting. Infobereich ist nicht verfügbar. Beende Programm. ScreenSettingsDialog Screen name is empty Der Anzeigename ist leer The screen name cannot be empty. Please either fill in a name or cancel the dialog. Der Bildschirmname darf nicht leer sein. Bitte trage einen Namen ein oder schließe das Fenster. Screen name matches alias Der Anzeigename passt zum Alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Der Anzeigename kann nicht derselbe sein wie der Alias. Bitte entfernen sie den Alias oder ändern sie den Anzeigenamen. ScreenSettingsDialogBase Screen Settings Anzeigeeinstellungen Screen &name: Anzeige&name: A&liases A&liase &Add &Hinzufügen &Remove &Entfernen &Modifier keys &Zusatztasten &Shift: Um&schalt: Shift Umschalt Ctrl Strg Alt Alt Meta Meta Super Windows None Keine &Ctrl: &Strg: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners "&Tote" Ecken Top-left Oben-links Top-right Oben-rechts Bottom-left Unten-links Bottom-right Unten-rechts Corner Si&ze: &Größe: &Fixes &Korrekturen Fix CAPS LOCK key Korrektur für Feststelltaste Fix NUM LOCK key Korrektur für Num Lock Fix SCROLL LOCK key Korrektur für Scroll Lock Fix XTest for Xinerama Korrektur für XTest mit Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Anzeige: <b>%1</b></center><br>Klicken Sie doppelt um die Einstellungen zu ändern<br>Ziehen Sie die Anzeige in den Papierkorb um sie zu entfernen ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Server Konfiguration Screens and links Anzeigen und Verbindungen Drag a screen from the grid to the trashcan to remove it. Ziehen Sie eine Anzeige vom Raster in den Papierkorb um sie zu entfernen. Configure the layout of your synergy server configuration. Konfigurieren Sie die Anordnung Ihrer Synergy Server Konfiguration. Drag this button to the grid to add a new screen. Ziehen diese Symbol auf das Raster um eine neue Anzeige hinzuzufügen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Ziehen Sie neue Anzeigen auf das Raster oder verschieben sie existierende. Ziehen Sie eine Anzeige in den Papierkorb um sie zu entfernen. Klicken sie doppelt auf eine Anzeige um die Einstellungen zu bearbeiten. Hotkeys Hotkeys &Hotkeys &Hotkeys &New &Neu &Edit &Bearbeiten &Remove &Entfernen A&ctions &Befehle Ne&w Ne&u E&dit Än&dern Re&move &Entfernen Advanced server settings Erwiterte Servereinstellungen &Switch Wech&sel Switch &after waiting Wechsel n&ach Wartezeit ms ms Switch on double &tap within Wechsel nach doppel&ter Randberührung innerhalb von &Options &Optionen &Check clients every Prüfe auf Meldungen vom &Client aller Use &relative mouse moves Ve&rwende relative Mausbewegungen S&ynchronize screen savers Bildschirmschoner s&ynchronisieren Don't take &foreground window on Windows servers Auf Windows Servern &Fenster im Vordergrund nicht aktivieren Ignore auto config clients &Dead corners "&Tote" Ecken To&p-left O&ben-links Top-rig&ht Oben-rec&hts &Bottom-left &Unten-links Bottom-ri&ght Unten-rec&hts Cor&ner Size: &Größe: SettingsDialog Save log file to... Speicherort des Logfiles Elevate Synergy Synergy Befördern Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Sind Sie sicher das Sie Synergy Erweiterte Benutzerrechte einräumen wollen? Das erlaubt Synergy mit Prozessen die höhere Rechte haben und dem UAC-Dialog zu interagieren, kann aber bei normalen Prozessen Probleme verursachen. Erweiterte Rechte an Synergy bitte nur vergeben wenn es unbedingt nötig ist. SettingsDialogBase Settings Einstellungen Sc&reen name: &Anzeigename: P&ort: P&ort: &Interface: Schn&ittstelle Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Protokollierung &Logging level: &Umfang: Log to file: In Datei: Browse... Durchsuchen... Error Fehler &Language: Sprache: &Miscellaneous &Sonstiges Warning Warnung Note Hinweis Info Info Debug Debug Debug1 Debug1 Debug2 Debug2 SetupWizard Setup Synergy Synergy einrichten Please select an option. Bitte wählen Sie eine option aus. Please enter your email address and password. Bitte geben Sie Ihre E-Mail Adresse und Ihr Passwort ein. SetupWizardBase Setup Synergy Synergy einrichten Welcome Willkommen Thanks for installing Synergy! Danke, dass du Synergy installiert hast! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Mit Synergy können Sie einfach Ihre Tastatur und Maus an mehreren Computern auf Ihrem Schreibtisch nutzen, und es ist Frei und Open Source. Bewegen Sie einfach ihre Maus über den Rand des Bildschirms eines Computers auf den Bildschirm eines anderen. Sie können sogar den Inhalt ihrer Zwischenablage an alle Computer verteilen. Alles was Sie brauchen ist ein Netzwerk-Anschluss. Synergy funktioniert auf Windows, Mac OS X und Linux. Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Server oder Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Unbekannt WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login fehlgeschlagen, falsche E-Mail Adresse oder Passwort. Login failed, an error occurred. %1 Login fehlgeschlagen, ein Fehler ist aufgetreten. %1 Login failed, an error occurred. Server response: %1 Login fehlgeschlagen, ein Fehler ist aufgetreten. Serverantwort: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_es.qm000066400000000000000000000560701305627404700214170ustar00rootroot00000000000000;#}S ku>Y(Z  = nbj#4q3vN=ZUTEv._& e@"w9*+s x;H}H38O $6O M:O M]J||) VE G1UN.Yu:Jl_ } $*Bl5qIIW <:+ :5 x G$ZGJ0"QJ-izJ@d-Xl 1[攄 J"M(M:S'+( n4.d2@Ty/ L#F{7  !h`z>UJH 3x=Tk@d5ycS %@~ =C+}F?npCC8.%L I_ JzK* k#:V v~>1 A -5 PnA d& ~5@ ~qTb ք~ ȹ ȹ#G ȹV aF |1 F, F7c Z,c 7 KG  @{ RV RVt RVS| RO T# V4p  |*G` c7 s" sK cA F- ҪF ^ /, 4pB[ d0+ i! r- zk; PK ¦eS= x48 ]^^L1\R=7> 9bunCy~L ' rx/u7/kC?Ek6.9>).iVG&Ok&OkAboutDialogBase"Acerca de Synergy About SynergyAboutDialogBaseDesconocidoUnknownAboutDialogBaseVersinVersion:AboutDialogBase4Elige la accin a realizarChoose the action to performActionDialogBase"Configurar AccinConfigure ActionActionDialogBase6Bloquear cursor en pantallaLock cursor to screenActionDialogBaseHPresiona una tecla de acceso directoPress a hotkeyActionDialogBaseJAl pulsar y liberar el acceso directoPress and release a hotkeyActionDialogBaseNAl levantar liberar el accedo directoRelease a hotkeyActionDialogBase"Cambiar direccinSwitch in directionActionDialogBase$Cambiar a pantallaSwitch to screenActionDialogBase:Esta accin se realiza cuandoThis action is performed whenActionDialogBase abajodownActionDialogBaseizquierdaleftActionDialogBasedesactivadooffActionDialogBaseactivadoonActionDialogBase.slo en estas pantallasonly on these screensActionDialogBasederecharightActionDialogBasePla tecla de acceso directo es presionadathe hotkey is pressedActionDialogBaseJla tecla de acceso directo es soltadathe hotkey is releasedActionDialogBasealternartoggleActionDialogBase arribaupActionDialogBasetIngresa la especificacin para la tecla de acceso directo:'Enter the specification for the hotkey:HotkeyDialogBase.Tecla de acceso directoHotkeyHotkeyDialogBase&Edicin&Edit MainWindow&Archivo&File MainWindow &Ayuda&Help MainWindow&Iniciar&Start MainWindow&Detener&Stop MainWindow&Ventana&Window MainWindow<p>T versin de Synergy es antigua. La versin <b>%1</b> esta ahora disponible para <a href="%2">descargar</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowTBuscar un archivo de configuracin Synergy!Browse for a synergys config file MainWindow`No se puede escribir el archivo de configuracinCannot write configuration file MainWindowVNombre de archivo de configuracin invlidoConfiguration filename invalid MainWindowdNo se pudo guardar la configuracin en el archivo.%Could not save configuration to file. MainWindow2Nombre de host est vacoHostname is empty MainWindowPor favor, ingresa un nombre de host al que se conectar el cliente Synergy.?Please fill in a hostname for the synergy client to connect to. MainWindow>El programa no se puede iniciarProgram can not be started MainWindow:Guardar configuracin como...Save configuration as... MainWindowNo se guard Save failed MainWindowSynergySynergy MainWindowBNo se encontr el cliente SynergySynergy client not found MainWindow<Synergy no se est ejecutando.Synergy is not running. MainWindow6Synergy se est ejecutando.Synergy is running. MainWindow.Synergy est iniciando.Synergy is starting. MainWindowDNo se encontr el servidor SynergySynergy server not found MainWindowSynergu termin inesperadamente con el cdigo de salida %1.<br><br>Por favor, vea el registro de eventos para detalles.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow8Synergy termin con un error Synergy terminated with an error MainWindow`El ejecutable para el cliente Synergy no existe.5The executable for the synergy client does not exist. MainWindowbEl ejecutable para el servidor Synergy no existe.5The executable for the synergy server does not exist. MainWindow>El ejecutable<br><br>%1<br><br>no se pudo iniciar exitsamente, aunque s existe. Por favor, revisa si tienes permisos suficientes para ejecutar este programa.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowEl archivo de configuracin temporal necesario para iniciar Synergy no puede ser escrito.NThe temporary configuration file required to start synergy can not be written. MainWindowDesconocidoUnknown MainWindowNo has ingresado un archivo de configuracin vlido para el servidor Synergy. Queres buscar el archivo de configuracin ahora?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow*&Acerca de Synergy...&About Synergy...MainWindowBaseAplicar&ApplyMainWindowBase&Buscar... &Browse...MainWindowBase&Configuracin:&Configuration file:MainWindowBase.&Configurar Servidor...&Configure Server...MainWindowBase&Ocultar&HideMainWindowBase &Salir&QuitMainWindowBase IP del servidor: &Server IP:MainWindowBase&Mostrar&ShowMainWindowBase&Iniciar&StartMainWindowBase8Configurar interactivamente:Configure interactively:MainWindowBaseEditar Opciones Edit settingsMainWindowBaseOcultarHideMainWindowBaseDirecciones IP: IP addresses:MainWindowBaseRegistroLogMainWindowBase SalirQuitMainWindowBase ListoReadyMainWindowBaseEjecutarRunMainWindowBase&Iniciar instalacin Run WizardMainWindowBase&Mostrar Estado S&how StatusMainWindowBaseDe&tenerS&topMainWindowBase<Gu&ardar configuracin como...Save configuration &as...MainWindowBaseGuardar la configuracin generada interactivamente en un archivo.@Save the interactively generated server configuration to a file.MainWindowBase&Nombre en pantalla: Screen name:MainWindowBaseOpcionesSettingsMainWindowBaseMostrarShowMainWindowBaseDetenerStopMainWindowBaseSynergySynergyMainWindowBase:Usar configuracin existente:Use existing configuration:MainWindowBaseSin nombreUnnamedNewScreenWidget$Configurar Synergy Setup SynergyPluginWizardPagetConfiguraciones Synergy (*.conf);;Todos los archivos (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectrConfiguraciones Synergy (*.sgc);;Todos los archivos (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectjEl rea de notificacin no esta disponible, cerrando.%System tray is unavailable, quitting.QObject:Nombre de pantalla est vacoScreen name is emptyScreenSettingsDialog\El nombre de la pantalla coincide con el aliasScreen name matches aliasScreenSettingsDialogEl nombre de la pantalla no puede estar vaci. Por favor introduce un nombre o cancela este dialogo.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogEl nombre de la pantalla no puede ser el mismo que un alias. Elimina el alias o cambia el nombre de pantalla por favor.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog&Agregar&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBase,Esquinas &Desactivadas &Dead cornersScreenSettingsDialogBase&Reparaciones&FixesScreenSettingsDialogBase"&Modificar teclas&Modifier keysScreenSettingsDialogBaseElimina&r&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBase &AliasA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseAbajo-Izquierda Bottom-leftScreenSettingsDialogBaseAbajo-Derecha Bottom-rightScreenSettingsDialogBase&&Tamao de Esquina: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBaseHReparar tecla CAPS LOCK (BLOQ MAYS)Fix CAPS LOCK keyScreenSettingsDialogBaseBReparar tecla NUM LOCK (BLOQ NUM)Fix NUM LOCK keyScreenSettingsDialogBaseLReparar tecla SCROLL LOCK (BLOQ DESPL)Fix SCROLL LOCK keyScreenSettingsDialogBase6Reparar XTest para XineramaFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseNingunoNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBase&&Nombre de Pantalla Screen &name:ScreenSettingsDialogBase(Opciones de PantallaScreen SettingsScreenSettingsDialogBaseMaysculasShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBase Arriba-IzquierdaTop-leftScreenSettingsDialogBaseArriba-Derecha Top-rightScreenSettingsDialogBase<center>Pantalla: <b>%1</b></center><br>Haz doble clic para editar opciones<br>Arrastra la pantalla a la papelera para borrarlao
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel&Bajo-Izquierda &Bottom-leftServerConfigDialogBase,Revisar &clientes cada&Check clients everyServerConfigDialogBase,Esquinas &Desactivadas &Dead cornersServerConfigDialogBase&Edicin&EditServerConfigDialogBase2&Teclas de acceso directo&HotkeysServerConfigDialogBase &Nueva&NewServerConfigDialogBaseOpciones&OptionsServerConfigDialogBaseElimina&r&RemoveServerConfigDialogBase&Cambiar&SwitchServerConfigDialogBase&AccionesA&ctionsServerConfigDialogBase<Opciones Avanzadas de ServidorAdvanced server settingsServerConfigDialogBase&Abajo-Derecha Bottom-ri&ghtServerConfigDialogBaseElige el diseo de rejilla para la configuracin de tu servidor Synergy.:Configure the layout of your synergy server configuration.ServerConfigDialogBase(&Tamao de Esqui&na: Cor&ner Size:ServerConfigDialogBaserNo tomar la ventana de primer plano en servidores Windows0Don't take &foreground window on Windows serversServerConfigDialogBase~Mueve una pantalla de la rejilla a la papelera para eliminarla.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaselArrastra nuevas pantallas hacia la rejilla o mueve las ya existentes. Mueve una pantalla a la papelera para eliminarla. Haz doble click sobre una pantalla para modificar sus ajustes.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasezMueve este botn a la rejilla para aadir una nueva pantalla.1Drag this button to the grid to add a new screen.ServerConfigDialogBase&EditarE&ditServerConfigDialogBase0Teclas de acceso directoHotkeysServerConfigDialogBase &NuevaNe&wServerConfigDialogBase&BorrarRe&moveServerConfigDialogBaseH&Sincronizar protectores de pantallaS&ynchronize screen saversServerConfigDialogBase&Pantallas y enlacesScreens and linksServerConfigDialogBase2Configuracin de ServidorServer ConfigurationServerConfigDialogBase&Cambiar &al esperarSwitch &after waitingServerConfigDialogBase,Cambiar doble toque enSwitch on double &tap withinServerConfigDialogBase"&Arriba-Izquierda To&p-leftServerConfigDialogBase &Arriba-Derec&ha Top-rig&htServerConfigDialogBaseJ&Sar movimientos &relativos del mouseUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseEsts seguro que quieres elevar a Synergy? Esto permitir que puedas interactuar con procesos elevados y el cuadro de dilogo de UAC, pero puede causar problemas con procesos no elevados. Eleva a Synergy solo si realmente lo necesitas.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialog Elevar a SynergyElevate SynergySettingsDialogBGuardar archivo de registro en...Save log file to...SettingsDialog&Interfaz: &Interface:SettingsDialogBaseIdioma: &Language:SettingsDialogBase&Nive&l de Registro:&Logging level:SettingsDialogBaseMiscelneos &MiscellaneousSettingsDialogBaseExaminar... Browse...SettingsDialogBaseDepuracinDebugSettingsDialogBaseDepuracin1Debug1SettingsDialogBaseDepuracin2Debug2SettingsDialogBase ErrorErrorSettingsDialogBaseInformacinInfoSettingsDialogBase8Guardar registro en archivo: Log to file:SettingsDialogBaseRegistroLoggingSettingsDialogBaseNotaNoteSettingsDialogBasePuert&o:P&ort:SettingsDialogBase*&Nomb&re de Pantalla: Sc&reen name:SettingsDialogBaseOpcionesSettingsSettingsDialogBaseAdvertenciaWarningSettingsDialogBaserIntroduce tu direccin de correo electrnico y contrasea-Please enter your email address and password. SetupWizard8Elige una opcin, por favor.Please select an option. SetupWizard$Configurar Synergy Setup Synergy SetupWizard(Servidor o Cliente?Server or Client?SetupWizardBase$Configurar Synergy Setup SynergySetupWizardBaseSynergy te permite compartir fcilmente tu mouse y teclado entre mltiples computadores en tu escritorio, es Gratis y es de Cdigo Abierto. Solo mueve tu mouse hacia los bordes de la pantalla de uno de los computadores hacia otro. Puedes incluso compartir tu portapapeles. Todo lo que necesitas es una conexin de red. Synergy es multiplataforma (funciona en Windows, Mac OS X y Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBase<Gracias por instalar Synergy!Thanks for installing Synergy!SetupWizardBaseBienvenidoWelcomeSetupWizardBaseDesconocidoUnknownVersionCheckerdInicio de sesin fallido, se encontr un error. %1$Login failed, an error occurred. %1 WebClientHa fallado el inicio de la sesin, ocurri un error. Respuesta del servidor: %16Login failed, an error occurred. Server response: %1 WebClienttInicio de sesin incorrecto, email o contrasea invlidos.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_es.ts000066400000000000000000001726651305627404700214410ustar00rootroot00000000000000 AboutDialogBase About Synergy Acerca de Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Desconocido Version: Versión &Ok &Ok ActionDialogBase Configure Action Configurar Acción Choose the action to perform Elige la acción a realizar Press a hotkey Presiona una tecla de acceso directo Release a hotkey Al levantar ó liberar el accedo directo Press and release a hotkey Al pulsar y liberar el acceso directo only on these screens sólo en estas pantallas Switch to screen Cambiar a pantalla Switch in direction Cambiar dirección left izquierda right derecha up arriba down abajo Lock cursor to screen Bloquear cursor en pantalla toggle alternar on activado off desactivado This action is performed when Esta acción se realiza cuando the hotkey is pressed la tecla de acceso directo es presionada the hotkey is released la tecla de acceso directo es soltada AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Tecla de acceso directo Enter the specification for the hotkey: Ingresa la especificación para la tecla de acceso directo: MainWindow &Start &Iniciar &File &Archivo &Edit &Edición &Window &Ventana &Help &Ayuda <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Tú versión de Synergy es antigua. La versión <b>%1</b> esta ahora disponible para <a href="%2">descargar</a>.</p> Program can not be started El programa no se puede iniciar The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. El ejecutable<br><br>%1<br><br>no se pudo iniciar exitósamente, aunque sí existe. Por favor, revisa si tienes permisos suficientes para ejecutar este programa. Synergy client not found No se encontró el cliente Synergy The executable for the synergy client does not exist. El ejecutable para el cliente Synergy no existe. Hostname is empty Nombre de host está vacío Please fill in a hostname for the synergy client to connect to. Por favor, ingresa un nombre de host al que se conectará el cliente Synergy. Cannot write configuration file No se puede escribir el archivo de configuración The temporary configuration file required to start synergy can not be written. El archivo de configuración temporal necesario para iniciar Synergy no puede ser escrito. Configuration filename invalid Nombre de archivo de configuración inválido You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? No has ingresado un archivo de configuración válido para el servidor Synergy. Queres buscar el archivo de configuración ahora? Synergy server not found No se encontró el servidor Synergy The executable for the synergy server does not exist. El ejecutable para el servidor Synergy no existe. Synergy terminated with an error Synergy terminó con un error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergu terminó inesperadamente con el código de salida %1.<br><br>Por favor, vea el registro de eventos para detalles. &Stop &Detener Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy está iniciando. Synergy is running. Synergy se está ejecutando. Synergy is not running. Synergy no se está ejecutando. Unknown Desconocido Synergy Synergy Browse for a synergys config file Buscar un archivo de configuración Synergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Guardar configuración como... Save failed No se guardó Could not save configuration to file. No se pudo guardar la configuración en el archivo. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Nombre en pantalla: &Server IP: IP del servidor: &Start &Iniciar Use existing configuration: Usar configuración existente: &Configuration file: &Configuración: &Browse... &Buscar... Configure interactively: Configurar interactivamente: &Configure Server... &Configurar Servidor... Ready Listo Log Registro &Apply Aplicar IP addresses: Direcciones IP: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Acerca de Synergy... &Quit &Salir Quit Salir Run Ejecutar S&top De&tener Stop Detener S&how Status &Mostrar Estado &Hide &Ocultar Hide Ocultar &Show &Mostrar Show Mostrar Save configuration &as... Gu&ardar configuración como... Save the interactively generated server configuration to a file. Guardar la configuración generada interactivamente en un archivo. Settings Opciones Edit settings Editar Opciones Run Wizard Iniciar instalación NewScreenWidget Unnamed Sin nombre PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Configurar Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Configuraciones Synergy (*.sgc);;Todos los archivos (*.*) Synergy Configurations (*.conf);;All files (*.*) Configuraciones Synergy (*.conf);;Todos los archivos (*.*) System tray is unavailable, quitting. El área de notificación no esta disponible, cerrando. ScreenSettingsDialog Screen name is empty Nombre de pantalla está vacío The screen name cannot be empty. Please either fill in a name or cancel the dialog. El nombre de la pantalla no puede estar vació. Por favor introduce un nombre o cancela este dialogo. Screen name matches alias El nombre de la pantalla coincide con el alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. El nombre de la pantalla no puede ser el mismo que un alias. Elimina el alias o cambia el nombre de pantalla por favor. ScreenSettingsDialogBase Screen Settings Opciones de Pantalla Screen &name: &Nombre de Pantalla A&liases &Alias &Add &Agregar &Remove Elimina&r &Modifier keys &Modificar teclas &Shift: &Shift: Shift Mayúsculas Ctrl Ctrl Alt Alt Meta Meta Super Super None Ninguno &Ctrl: &Ctrl: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners Esquinas &Desactivadas Top-left Arriba-Izquierda Top-right Arriba-Derecha Bottom-left Abajo-Izquierda Bottom-right Abajo-Derecha Corner Si&ze: &Tamaño de Esquina: &Fixes &Reparaciones Fix CAPS LOCK key Reparar tecla CAPS LOCK (BLOQ MAYÚS) Fix NUM LOCK key Reparar tecla NUM LOCK (BLOQ NUM) Fix SCROLL LOCK key Reparar tecla SCROLL LOCK (BLOQ DESPL) Fix XTest for Xinerama Reparar XTest para Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Pantalla: <b>%1</b></center><br>Haz doble clic para editar opciones<br>Arrastra la pantalla a la papelera para borrarla ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Configuración de Servidor Screens and links Pantallas y enlaces Drag a screen from the grid to the trashcan to remove it. Mueve una pantalla de la rejilla a la papelera para eliminarla. Configure the layout of your synergy server configuration. Elige el diseño de rejilla para la configuración de tu servidor Synergy. Drag this button to the grid to add a new screen. Mueve este botón a la rejilla para añadir una nueva pantalla. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Arrastra nuevas pantallas hacia la rejilla o mueve las ya existentes. Mueve una pantalla a la papelera para eliminarla. Haz doble click sobre una pantalla para modificar sus ajustes. Hotkeys Teclas de acceso directo &Hotkeys &Teclas de acceso directo &New &Nueva &Edit &Edición &Remove Elimina&r A&ctions &Acciones Ne&w &Nueva E&dit &Editar Re&move &Borrar Advanced server settings Opciones Avanzadas de Servidor &Switch &Cambiar Switch &after waiting Cambiar &al esperar ms ms Switch on double &tap within Cambiar doble toque en &Options Opciones &Check clients every Revisar &clientes cada Use &relative mouse moves &Sar movimientos &relativos del mouse S&ynchronize screen savers &Sincronizar protectores de pantalla Don't take &foreground window on Windows servers No tomar la ventana de primer plano en servidores Windows Ignore auto config clients &Dead corners Esquinas &Desactivadas To&p-left &Arriba-Izquierda Top-rig&ht &Arriba-Derec&ha &Bottom-left &Bajo-Izquierda Bottom-ri&ght &Abajo-Derecha Cor&ner Size: &Tamaño de Esqui&na: SettingsDialog Save log file to... Guardar archivo de registro en... Elevate Synergy Elevar a Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. ¿Estás seguro que quieres elevar a Synergy? Esto permitirá que puedas interactuar con procesos elevados y el cuadro de diálogo de UAC, pero puede causar problemas con procesos no elevados. Eleva a Synergy solo si realmente lo necesitas. SettingsDialogBase Settings Opciones Sc&reen name: &Nomb&re de Pantalla: P&ort: Puert&o: &Interface: &Interfaz: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Registro &Logging level: Nive&l de Registro: Log to file: Guardar registro en archivo: Browse... Examinar... Error Error &Language: Idioma: &Miscellaneous Misceláneos Warning Advertencia Note Nota Info Información Debug Depuración Debug1 Depuración1 Debug2 Depuración2 SetupWizard Setup Synergy Configurar Synergy Please select an option. Elige una opción, por favor. Please enter your email address and password. Introduce tu dirección de correo electrónico y contraseña SetupWizardBase Setup Synergy Configurar Synergy Welcome Bienvenido Thanks for installing Synergy! ¡Gracias por instalar Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy te permite compartir fácilmente tu mouse y teclado entre múltiples computadores en tu escritorio, es Gratis y es de Código Abierto. Solo mueve tu mouse hacia los bordes de la pantalla de uno de los computadores hacia otro. Puedes incluso compartir tu portapapeles. Todo lo que necesitas es una conexión de red. Synergy es multiplataforma (funciona en Windows, Mac OS X y Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? ¿Servidor o Cliente? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Desconocido WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Inicio de sesión incorrecto, email o contraseña inválidos. Login failed, an error occurred. %1 Inicio de sesión fallido, se encontró un error. %1 Login failed, an error occurred. Server response: %1 Ha fallado el inicio de la sesión, ocurrió un error. Respuesta del servidor: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_et-EE.qm000066400000000000000000000520231305627404700217010ustar00rootroot000000000000005)8}SMu>(Z ^= nbj 4d|.\vFZM6Ev.A_"_e9w9&Z&p ;H}H. O O EO FX]C6|$VE ,UN)Yu:Bl_ W} !"*<lR0BBM 5:&:0  @$ZAJ+"QJ-izC@d(l ,Y攄J(E:S#Q( n4.d-@Ty*XL#?{16.rz>JA 3n=Tk@d/ycKF%@~C'2}F9^nVC<`2! I_ JzC k#4x v~7 : -5 i Pn:u d" ~5: ~qLz ք~ ȹ ȹ ȹM a@ |, F' F1 Z' 2' KG @{ RVp RV RVK Ri T V4  |*@ c2e sD sD0 c;: F) ҪP ^ /( 4p; d+3 i! r+ zk PDk ¦eKo x43 ]^^E61\J=> 4(bun=y~D# r/7*kC8k1(.3m>)_iN)Ok&OkAboutDialogBaseSynergy'st About SynergyAboutDialogBaseTundmatuUnknownAboutDialogBaseVersioon:Version:AboutDialogBase,Vali teostatav tegevusChoose the action to performActionDialogBase*Tegevuse seadistamineConfigure ActionActionDialogBase0Lukusta kursor ekraanileLock cursor to screenActionDialogBase*Vajuta kiirklahv allaPress a hotkeyActionDialogBase@Vajuta kiirklahv alla ja vabastaPress and release a hotkeyActionDialogBase"Vabasta kiirklahvRelease a hotkeyActionDialogBaseLlitu suunasSwitch in directionActionDialogBase Llitu ekraanileSwitch to screenActionDialogBase6See toiming teostatakse kuiThis action is performed whenActionDialogBasealladownActionDialogBase vasakleftActionDialogBase vljaoffActionDialogBase sisseonActionDialogBase0ainult nendel ekraanidelonly on these screensActionDialogBase paremrightActionDialogBase6Kiirklahv on alla vajutatudthe hotkey is pressedActionDialogBase.kiirklahv on vabastatudthe hotkey is releasedActionDialogBase llitatoggleActionDialogBaselesupActionDialogBaseFSisesta kiirklahvi tpsemad seaded:'Enter the specification for the hotkey:HotkeyDialogBaseKiirklahvHotkeyHotkeyDialogBaseRedigeeri&Edit MainWindowFail&File MainWindowAbi&Help MainWindowKivita&Start MainWindow Peata&Stop MainWindowAken&Window MainWindow<p>Teie Synergy versioon on aegunud . Uus versioon <b>%1</b> on saadaval <a href="%2">allalaadimiseks</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindow2Vali synergy seadete fail!Browse for a synergys config file MainWindow>Ei saa kirjutada seadete faili.Cannot write configuration file MainWindow8Seadete faili nimi on viganeConfiguration filename invalid MainWindowNSeadete salvestamine faili ebannestus.%Could not save configuration to file. MainWindow,Tugijaama nimi on thiHostname is empty MainWindowPalun sisestage tugijaama nimi millega synergy klient peab henduma.?Please fill in a hostname for the synergy client to connect to. MainWindow6Rakendus ei suuda kivitudaProgram can not be started MainWindow,Salvesta seaded kui...Save configuration as... MainWindow0Salvestamine ebannestus Save failed MainWindowSynergySynergy MainWindow2Synergy klienti ei leitudSynergy client not found MainWindow"Synergy ei tta.Synergy is not running. MainWindowSynergy ttabSynergy is running. MainWindow"Synergy kivitub.Synergy is starting. MainWindow4Synergy serverit ei leitudSynergy server not found MainWindowSynergy katkestas ootamatul t veateatega %1.<br><br>Tpsema info saamiseks kontrollige vljundlogi.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow@Synergy katkestas t veateatega Synergy terminated with an error MainWindowPSynergy kliendi kivitusfaili ei leitud.5The executable for the synergy client does not exist. MainWindowPSynergy serveri kivitusfaili ei leitud.5The executable for the synergy server does not exist. MainWindow:Kivitusfaili<br><br>%1<br><br>ei nnestunud kivitada, vi pole seda olemas. Palun kontrollige, kas Teil on piisavalt iguseid selle toimingu teostamiseks..The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowSynergy kivitamiseks vajaliku ajutise seadete faili kirjutamine ebannestus.NThe temporary configuration file required to start synergy can not be written. MainWindowTundmatuUnknown MainWindowTe pole valinud korrektset seadete faili synergy serverile. Kas soovite valida seadete faili nd?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindowSynergy'st...&About Synergy...MainWindowBaseRakenda&ApplyMainWindowBaseVali &Browse...MainWindowBaseSeadete fail:&Configuration file:MainWindowBase.Serveri seadistamine...&Configure Server...MainWindowBase Peida&HideMainWindowBase Vlju&QuitMainWindowBaseServeri IP: &Server IP:MainWindowBase Nita&ShowMainWindowBaseKivita&StartMainWindowBase6Seadistage interaktiivselt:Configure interactively:MainWindowBase Seadete muutmine Edit settingsMainWindowBase PeidaHideMainWindowBaseIP aadressid: IP addresses:MainWindowBaseLogiLogMainWindowBase VljuQuitMainWindowBase ValmisReadyMainWindowBaseKivitaRunMainWindowBase Kivita nustaja Run WizardMainWindowBaseNita olekut S&how StatusMainWindowBase PeataS&topMainWindowBase,Salvesta seaded kui...Save configuration &as...MainWindowBasejSalvesta interakttivselt loodud serveri seaded faili.@Save the interactively generated server configuration to a file.MainWindowBaseEkraani nimi: Screen name:MainWindowBase SeadedSettingsMainWindowBase NitaShowMainWindowBase PeataStopMainWindowBaseSynergySynergyMainWindowBase>Kasuta olemasolevat seadistust:Use existing configuration:MainWindowBase NimetuUnnamedNewScreenWidget(Synergy seadistamine Setup SynergyPluginWizardPageTSynergy seaded (*.conf);;Kik failid (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectRSynergy seaded (*.sgc);;kik failid (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectLSsteemisalv pole kttesaadav, loobun.%System tray is unavailable, quitting.QObject(Ekraani nimi on thiScreen name is emptyScreenSettingsDialog:Ekraani nimi hildub aliasegaScreen name matches aliasScreenSettingsDialogEkraani nimi peab olema mratud. Palun mrake nimi vi katkestage dialoog.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogEkraani nimi peab olema erinev aliasest. Palun eemaldage alias vi muutke ekraani nime.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialogLisa&AddScreenSettingsDialogBase Ctrl:&Ctrl:ScreenSettingsDialogBaseSurnud nurgad &Dead cornersScreenSettingsDialogBaseParandused&FixesScreenSettingsDialogBaseMuuteklahvid&Modifier keysScreenSettingsDialogBaseEemalda&RemoveScreenSettingsDialogBase Shift:&Shift:ScreenSettingsDialogBaseAliasedA&liasesScreenSettingsDialogBaseAlt:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseAlumine vasak Bottom-leftScreenSettingsDialogBaseAlumine-parem Bottom-rightScreenSettingsDialogBaseNurga suurus: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase.Kinnita CAPS LOCK klahvFix CAPS LOCK keyScreenSettingsDialogBase,Kinnita NUM LOCK klahvFix NUM LOCK keyScreenSettingsDialogBase2Kinnita SCROLL LOCK klahvFix SCROLL LOCK keyScreenSettingsDialogBase0Kinnita XTest XineramaleFix XTest for XineramaScreenSettingsDialogBase Meta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBase PuudubNoneScreenSettingsDialogBase Super:S&uper:ScreenSettingsDialogBaseEkraani nimi: Screen &name:ScreenSettingsDialogBaseEkraani seadedScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBaselemine-vasakTop-leftScreenSettingsDialogBaselemine-parem Top-rightScreenSettingsDialogBase<center>Ekraan: <b>%1</b></center><br>Topeltklps seadete muutmiseks<br>Eemaldamiseks lohista ekraan prgikastio
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelAlumine-vasak &Bottom-leftServerConfigDialogBase6Kontrolli klienti peale iga&Check clients everyServerConfigDialogBaseSurnud nurgad &Dead cornersServerConfigDialogBaseRedigeeri&EditServerConfigDialogBaseKiirklahvid&HotkeysServerConfigDialogBaseUus&NewServerConfigDialogBaseValikud&OptionsServerConfigDialogBaseEemalda&RemoveServerConfigDialogBase Llitu&SwitchServerConfigDialogBaseToimingudA&ctionsServerConfigDialogBase.Tpsemad serveri seadedAdvanced server settingsServerConfigDialogBaseAlumine-parem Bottom-ri&ghtServerConfigDialogBaseVSeadista synergy serveri paigutuse seadeid.:Configure the layout of your synergy server configuration.ServerConfigDialogBaseNurga suurus Cor&ner Size:ServerConfigDialogBaseVra vta esiplaani akent Windows serverites0Don't take &foreground window on Windows serversServerConfigDialogBasejEemaldamiseks lohista ekraan joonestikult prgikasti.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase2Lohista uued ekraanid joonestikule vi liiguta olemasolevaid. Eemaldamiseks lohista ekraan prgikasti. Ekraani seadete muutmiseks tee sellel topeltklps.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasebEkraani lisamiseks lohista see nupp joonestikule.1Drag this button to the grid to add a new screen.ServerConfigDialogBase MuudaE&ditServerConfigDialogBaseKiirklahvidHotkeysServerConfigDialogBaseUusNe&wServerConfigDialogBaseEemaldaRe&moveServerConfigDialogBase2Snkrooni ekraanisstjadS&ynchronize screen saversServerConfigDialogBase$Ekraanid ja seosedScreens and linksServerConfigDialogBaseServeri seadedServer ConfigurationServerConfigDialogBase*Llitu peale ootamistSwitch &after waitingServerConfigDialogBaseBLlitu peale topeltkoputust ajagaSwitch on double &tap withinServerConfigDialogBaselemine vasak To&p-leftServerConfigDialogBaselemine-parem Top-rig&htServerConfigDialogBaseFKasuta relatiivseid hiire liikumisiUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseKas soovite kindlasti Synergy't lendada? See vimaldab Synergy'l toimetada lendatud protsessidega ja UAC dialoogiga, kuid vib tekitada probleeme lendamata protsessidega. lendage Synergy ainult kindlal vajadusel.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialog$Synergy lendamineElevate SynergySettingsDialog:Salvesta logifail asukohta...Save log file to...SettingsDialog Seade: &Interface:SettingsDialogBase Keel: &Language:SettingsDialogBaseLogimise tase:&Logging level:SettingsDialogBaseMitmesugust&MiscellaneousSettingsDialogBaseVali... Browse...SettingsDialogBase DebugDebugSettingsDialogBase Debug1Debug1SettingsDialogBase Debug2Debug2SettingsDialogBaseVigaErrorSettingsDialogBaseInfoInfoSettingsDialogBaseLogi faili: Log to file:SettingsDialogBaseLogimineLoggingSettingsDialogBase MrkusNoteSettingsDialogBase Port:P&ort:SettingsDialogBaseEkraani nimi: Sc&reen name:SettingsDialogBase SeadedSettingsSettingsDialogBaseHoiatusWarningSettingsDialogBaseBPalun sisestage oma uus salasna.-Please enter your email address and password. SetupWizard<Palun valida sobiv funktsioon.Please select an option. SetupWizard(Synergy seadistamine Setup Synergy SetupWizard$Server vi klient?Server or Client?SetupWizardBase(Synergy seadistamine Setup SynergySetupWizardBaseSynergy vimaldab lihtsalt jagada oma klaviatuuri ja hiirt mitme arvuti vahel, see on tasuta ja vabavaraline. Lihtsalt liiguta oma hiir le he arvuti ekraaniserva teise arvuti ekraanile. Vite isegi jagada kiki oma likepuhvreid. Vajad vaid vrgu hendust. Synergy't saab kasutada erinevates operatsioonissteemides (Windows, Mac OS X ja Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseFTname, et installeerisid Snergia!Thanks for installing Synergy!SetupWizardBaseTere tulemastWelcomeSetupWizardBaseTundmatuUnknownVersionCheckerJLogimine ebannestus, tekkis viga. %1$Login failed, an error occurred. %1 WebClienthLogimine ebannestus, tekkis viga. Server vastas: %16Login failed, an error occurred. Server response: %1 WebClienttLogimine ebannestus, vigane e-posti aadress vi salasna.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_et-EE.ts000066400000000000000000001703231305627404700217160ustar00rootroot00000000000000 AboutDialogBase About Synergy Synergy'st <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Tundmatu Version: Versioon: &Ok Ok ActionDialogBase Configure Action Tegevuse seadistamine Choose the action to perform Vali teostatav tegevus Press a hotkey Vajuta kiirklahv alla Release a hotkey Vabasta kiirklahv Press and release a hotkey Vajuta kiirklahv alla ja vabasta only on these screens ainult nendel ekraanidel Switch to screen Lülitu ekraanile Switch in direction Lülitu suunas left vasak right parem up üles down alla Lock cursor to screen Lukusta kursor ekraanile toggle lülita on sisse off välja This action is performed when See toiming teostatakse kui the hotkey is pressed Kiirklahv on alla vajutatud the hotkey is released kiirklahv on vabastatud AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Kiirklahv Enter the specification for the hotkey: Sisesta kiirklahvi täpsemad seaded: MainWindow &Start Käivita &File Fail &Edit Redigeeri &Window Aken &Help Abi <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Teie Synergy versioon on aegunud . Uus versioon <b>%1</b> on saadaval <a href="%2">allalaadimiseks</a>.</p> Program can not be started Rakendus ei suuda käivituda The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Käivitusfaili<br><br>%1<br><br>ei õnnestunud käivitada, või pole seda olemas. Palun kontrollige, kas Teil on piisavalt õiguseid selle toimingu teostamiseks.. Synergy client not found Synergy klienti ei leitud The executable for the synergy client does not exist. Synergy kliendi käivitusfaili ei leitud. Hostname is empty Tugijaama nimi on tühi Please fill in a hostname for the synergy client to connect to. Palun sisestage tugijaama nimi millega synergy klient peab ühenduma. Cannot write configuration file Ei saa kirjutada seadete faili. The temporary configuration file required to start synergy can not be written. Synergy käivitamiseks vajaliku ajutise seadete faili kirjutamine ebaõnnestus. Configuration filename invalid Seadete faili nimi on vigane You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Te pole valinud korrektset seadete faili synergy serverile. Kas soovite valida seadete faili nüüd? Synergy server not found Synergy serverit ei leitud The executable for the synergy server does not exist. Synergy serveri käivitusfaili ei leitud. Synergy terminated with an error Synergy katkestas töö veateatega Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy katkestas ootamatul töö veateatega %1.<br><br>Täpsema info saamiseks kontrollige väljundlogi. &Stop Peata Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy käivitub. Synergy is running. Synergy töötab Synergy is not running. Synergy ei tööta. Unknown Tundmatu Synergy Synergy Browse for a synergys config file Vali synergy seadete fail Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Salvesta seaded kui... Save failed Salvestamine ebaõnnestus Could not save configuration to file. Seadete salvestamine faili ebaõnnestus. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Ekraani nimi: &Server IP: Serveri IP: &Start Käivita Use existing configuration: Kasuta olemasolevat seadistust: &Configuration file: Seadete fail: &Browse... Vali Configure interactively: Seadistage interaktiivselt: &Configure Server... Serveri seadistamine... Ready Valmis Log Logi &Apply Rakenda IP addresses: IP aadressid: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Synergy'st... &Quit Välju Quit Välju Run Käivita S&top Peata Stop Peata S&how Status Näita olekut &Hide Peida Hide Peida &Show Näita Show Näita Save configuration &as... Salvesta seaded kui... Save the interactively generated server configuration to a file. Salvesta interakttivselt loodud serveri seaded faili. Settings Seaded Edit settings Seadete muutmine Run Wizard Käivita nõustaja NewScreenWidget Unnamed Nimetu PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Synergy seadistamine Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy seaded (*.sgc);;kõik failid (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy seaded (*.conf);;Kõik failid (*.*) System tray is unavailable, quitting. Süsteemisalv pole kättesaadav, loobun. ScreenSettingsDialog Screen name is empty Ekraani nimi on tühi The screen name cannot be empty. Please either fill in a name or cancel the dialog. Ekraani nimi peab olema määratud. Palun määrake nimi või katkestage dialoog. Screen name matches alias Ekraani nimi ühildub aliasega The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Ekraani nimi peab olema erinev aliasest. Palun eemaldage alias või muutke ekraani nime. ScreenSettingsDialogBase Screen Settings Ekraani seaded Screen &name: Ekraani nimi: A&liases Aliased &Add Lisa &Remove Eemalda &Modifier keys Muuteklahvid &Shift: Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Puudub &Ctrl: Ctrl: Al&t: Alt: M&eta: Meta: S&uper: Super: &Dead corners Surnud nurgad Top-left Ülemine-vasak Top-right Ülemine-parem Bottom-left Alumine vasak Bottom-right Alumine-parem Corner Si&ze: Nurga suurus: &Fixes Parandused Fix CAPS LOCK key Kinnita CAPS LOCK klahv Fix NUM LOCK key Kinnita NUM LOCK klahv Fix SCROLL LOCK key Kinnita SCROLL LOCK klahv Fix XTest for Xinerama Kinnita XTest Xineramale ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Ekraan: <b>%1</b></center><br>Topeltklõps seadete muutmiseks<br>Eemaldamiseks lohista ekraan prügikasti ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Serveri seaded Screens and links Ekraanid ja seosed Drag a screen from the grid to the trashcan to remove it. Eemaldamiseks lohista ekraan joonestikult prügikasti. Configure the layout of your synergy server configuration. Seadista synergy serveri paigutuse seadeid. Drag this button to the grid to add a new screen. Ekraani lisamiseks lohista see nupp joonestikule. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Lohista uued ekraanid joonestikule või liiguta olemasolevaid. Eemaldamiseks lohista ekraan prügikasti. Ekraani seadete muutmiseks tee sellel topeltklõps. Hotkeys Kiirklahvid &Hotkeys Kiirklahvid &New Uus &Edit Redigeeri &Remove Eemalda A&ctions Toimingud Ne&w Uus E&dit Muuda Re&move Eemalda Advanced server settings Täpsemad serveri seaded &Switch Lülitu Switch &after waiting Lülitu peale ootamist ms ms Switch on double &tap within Lülitu peale topeltkoputust ajaga &Options Valikud &Check clients every Kontrolli klienti peale iga Use &relative mouse moves Kasuta relatiivseid hiire liikumisi S&ynchronize screen savers Sünkrooni ekraanisäästjad Don't take &foreground window on Windows servers Ära võta esiplaani akent Windows serverites Ignore auto config clients &Dead corners Surnud nurgad To&p-left Ülemine vasak Top-rig&ht Ülemine-parem &Bottom-left Alumine-vasak Bottom-ri&ght Alumine-parem Cor&ner Size: Nurga suurus SettingsDialog Save log file to... Salvesta logifail asukohta... Elevate Synergy Synergy ülendamine Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Kas soovite kindlasti Synergy't ülendada? See võimaldab Synergy'l toimetada ülendatud protsessidega ja UAC dialoogiga, kuid võib tekitada probleeme ülendamata protsessidega. Ülendage Synergy ainult kindlal vajadusel. SettingsDialogBase Settings Seaded Sc&reen name: Ekraani nimi: P&ort: Port: &Interface: Seade: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Logimine &Logging level: Logimise tase: Log to file: Logi faili: Browse... Vali... Error Viga &Language: Keel: &Miscellaneous Mitmesugust Warning Hoiatus Note Märkus Info Info Debug Debug Debug1 Debug1 Debug2 Debug2 SetupWizard Setup Synergy Synergy seadistamine Please select an option. Palun valida sobiv funktsioon. Please enter your email address and password. Palun sisestage oma uus salasõna. SetupWizardBase Setup Synergy Synergy seadistamine Welcome Tere tulemast Thanks for installing Synergy! Täname, et installeerisid Sünergia! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy võimaldab lihtsalt jagada oma klaviatuuri ja hiirt mitme arvuti vahel, see on tasuta ja vabavaraline. Lihtsalt liiguta oma hiir üle ühe arvuti ekraaniserva teise arvuti ekraanile. Võite isegi jagada kõiki oma lõikepuhvreid. Vajad vaid võrgu ühendust. Synergy't saab kasutada erinevates operatsioonisüsteemides (Windows, Mac OS X ja Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Server või klient? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Tundmatu WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Logimine ebaõnnestus, vigane e-posti aadress või salasõna. Login failed, an error occurred. %1 Logimine ebaõnnestus, tekkis viga. %1 Login failed, an error occurred. Server response: %1 Logimine ebaõnnestus, tekkis viga. Server vastas: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_fi.qm000066400000000000000000000524301305627404700214020ustar00rootroot00000000000000JBLbCU` XY.7Z.sxx.>6-@}Su>I(Z = nbj 4/:vGZN0Ev._#Qe:w9,'>'6 ;H}H.O !O FO G]DX|%VE -UN*Yu:D l_ }} !*=%lh1C.Cg 6:'}:1x  A$ZB)J,"QJ;-izD@d)l -G攄|J(G#:S$O( n4.d.@Ty+:L#@{2zs>)JB_i 3=Tk@d0ycLVN%@~ #C(}F:nrC=j3" I_L JzE k#5` v~8 < -5 Pn; d# ~5;; ~qM` ք~ ȹ ȹ ȹN aA4 |- F(w F2 Z( 3 KG @{ RV~ RV RVL R T![ V4  |*A c3W s sER c 5bun>y~E$ rp/7+kC:k2.4W>Q*AiO'OK&OkAboutDialogBase"Tietoa Synergyst About SynergyAboutDialogBaseTuntematonUnknownAboutDialogBaseVersio:Version:AboutDialogBase:Mrit suoritettava toimintoChoose the action to performActionDialogBase Mrit toimintoConfigure ActionActionDialogBase0Lukitse kursori nytlleLock cursor to screenActionDialogBase2Paina pikanppin pohjaanPress a hotkeyActionDialogBase8Paina ja vapauta pikanppinPress and release a hotkeyActionDialogBase&Vapauta pikanppinRelease a hotkeyActionDialogBase VaihdaSwitch in directionActionDialogBaseVaihda nyttnSwitch to screenActionDialogBase Suorita toimintoThis action is performed whenActionDialogBasealasdownActionDialogBasevasemmalleleftActionDialogBasepois pltoffActionDialogBase plleonActionDialogBase*vain nill nytillonly on these screensActionDialogBaseoikeallerightActionDialogBase6kun pikanppint painetaanthe hotkey is pressedActionDialogBase6kun pikanppin vapautetaanthe hotkey is releasedActionDialogBase"kytke plle/poistoggleActionDialogBaseylsupActionDialogBase(Mrit pikanppin:'Enter the specification for the hotkey:HotkeyDialogBasePikanppinHotkeyHotkeyDialogBase&Muokkaa&Edit MainWindowTiedosto&File MainWindowOhje&Help MainWindow&Kynnist&Start MainWindow&Pysyt&Stop MainWindow Ikkuna&Window MainWindow<p>Synergy versiosi on vanhentunut. Versio <b>%1</b> on nyt saatavilla <a href="%2">ladattavaksi</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindow>Mrit Synergyn asetustiedosto!Browse for a synergys config file MainWindow>Asetustiedostoa ei voida luoda.Cannot write configuration file MainWindowTAsetustiedoston tiedostonimi virheellinen Configuration filename invalid MainWindowFEi voitu tallentaa asetustiedostoa.%Could not save configuration to file. MainWindow&Isntnimi on tyhjHostname is empty MainWindow^Tyt isntnimell johon Synergy voi yhdist.?Please fill in a hostname for the synergy client to connect to. MainWindow8Ohjelmaa ei voida kynnistProgram can not be started MainWindow:Tallenna asetukset nimell...Save configuration as... MainWindow*Tallennus eponnistui Save failed MainWindowSynergySynergy MainWindowBSynergyn asiakasohjelmaa ei lydySynergy client not found MainWindow2Synergy ei ole kynniss.Synergy is not running. MainWindow*Synergy on kynniss.Synergy is running. MainWindow&Synergy kynnistyy.Synergy is starting. MainWindow6Synergy palvelinta ei lydySynergy server not found MainWindowSynergy suljettiin odottamattomasti paluukoodilla %1.<br><br>Tarkista lokitiedosto saadaksesi listietoja.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowBSynergy suljettiin virheen vuoksi Synergy terminated with an error MainWindow^Ajotiedosto Synergyn asiakasohjelmalle puuttuu.5The executable for the synergy client does not exist. MainWindowRAjotiedosto Synergy palvelimelle puuttuu.5The executable for the synergy server does not exist. MainWindow"Ajotiedoston<br><br>%1<br><br>kynnistys ei onnistunut, vaikka se on olemassa. Tarkista onko sinulla riittvt kyttoikeudet ohjelman ajamiseen.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindow|Vliaikaista Synergyn vaatimaa asetustiedostoa ei voida luoda.NThe temporary configuration file required to start synergy can not be written. MainWindowTuntematonUnknown MainWindowEt ole mrittnyt kelvollista asetustiedostoa Synergy palvelimelle. Haluatko mritt asetustiedoston sijainnin nyt?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow"Tietoa Synergyst&About Synergy...MainWindowBase Kyt&ApplyMainWindowBaseSelaa... &Browse...MainWindowBaseAsetustiedosto:&Configuration file:MainWindowBase&Mrit palvelin...&Configure Server...MainWindowBasePiilota&HideMainWindowBase&Lopeta&QuitMainWindowBasePalvelimen IP: &Server IP:MainWindowBase Nyt&ShowMainWindowBase&Kynnist&StartMainWindowBase4Mrit interaktiivisesti:Configure interactively:MainWindowBase"Muokkaa asetuksia Edit settingsMainWindowBasePiilotaHideMainWindowBaseIP-osoitteet: IP addresses:MainWindowBaseLokiLogMainWindowBase LopetaQuitMainWindowBase ValmisReadyMainWindowBaseSuoritaRunMainWindowBase4Ohjattu asetusten mritys Run WizardMainWindowBaseNyt tila S&how StatusMainWindowBasePysytS&topMainWindowBase:Tallenna asetukset nimell...Save configuration &as...MainWindowBaseTallenna interaktiivisesti mritetty palvelinkokoonpano tiedostoon.@Save the interactively generated server configuration to a file.MainWindowBaseNytn nimi: Screen name:MainWindowBaseAsetuksetSettingsMainWindowBase NytShowMainWindowBasePysytStopMainWindowBaseSynergySynergyMainWindowBaseDKyt olemassa olevaa kokoonpanoa:Use existing configuration:MainWindowBaseNimetnUnnamedNewScreenWidgetMrit Synergy Setup SynergyPluginWizardPagelSynergy Configuration (*.conf);;Kaikki tiedostot (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectjSynergy Configuration (*.sgc);;Kaikki tiedostot (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectZIlmoitusalue ei ole kytettviss, suljetaan.%System tray is unavailable, quitting.QObject&Nytn nimi puuttuuScreen name is emptyScreenSettingsDialog:Nimimerkki on sala kuin aliasScreen name matches aliasScreenSettingsDialogzNimimerkki puuttuu. Ole hyv ja syt nimi tai sulje dialogi.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogNimimerkki ei voi olla sama kuin alias. Oleva hyv ja poista alias tai muuta nimimerkki.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog Lis&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBaseKuolleet kulmat &Dead cornersScreenSettingsDialogBaseKorjaukset&FixesScreenSettingsDialogBase Valintanppimet&Modifier keysScreenSettingsDialogBase Poista&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBaseAliaksetA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseAlavasen Bottom-leftScreenSettingsDialogBaseAlaoikea Bottom-rightScreenSettingsDialogBaseKulman koko: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase0Korjaa CAPS LOCK nppinFix CAPS LOCK keyScreenSettingsDialogBase.Korjaa NUM LOCK nppinFix NUM LOCK keyScreenSettingsDialogBase4Korjaa SCROLL LOCK nppinFix SCROLL LOCK keyScreenSettingsDialogBase0Korjaa XTest XineramalleFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseEi mitnNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBaseNytn nimi: Screen &name:ScreenSettingsDialogBase Nytn asetuksetScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBaseYlvasenTop-leftScreenSettingsDialogBaseYloikea Top-rightScreenSettingsDialogBase<center>Nytt: <b>%1</b></center><br>Kaksoisnapsauta muokataksesi asetuksia<br>Ved nytt roskakoriin poistaaksesi sen.o
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelAlavasen &Bottom-leftServerConfigDialogBase2Asiakkaiden tarkistusvli&Check clients everyServerConfigDialogBaseKuolleet kulmat &Dead cornersServerConfigDialogBase&Muokkaa&EditServerConfigDialogBasePikanppimet&HotkeysServerConfigDialogBase &Uusi&NewServerConfigDialogBase&Asetukset&OptionsServerConfigDialogBase Poista&RemoveServerConfigDialogBase Vaihda&SwitchServerConfigDialogBaseToiminnotA&ctionsServerConfigDialogBase0Palvelimen lisasetuksetAdvanced server settingsServerConfigDialogBaseAlaoikea Bottom-ri&ghtServerConfigDialogBaseTMrit Synergy-palvelimen nyttasetukset:Configure the layout of your synergy server configuration.ServerConfigDialogBaseKulman koko: Cor&ner Size:ServerConfigDialogBaserl siirr pllimmiseksi ikkunaksi Windows palvelimilla0Don't take &foreground window on Windows serversServerConfigDialogBasehVed nytt ruudukosta roskakoriin poistaaksesi sen.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaseFLis uusia nyttj ruudukkoon tai siirr olemassa olevia vetmll. Ved nytt roskakoriin poistaaksesi sen. Kaksoisnapsauta nytt muokataksesi sen asetuksia.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasejVed tm kuvake ruudukkoon listksesi uuden nytn.1Drag this button to the grid to add a new screen.ServerConfigDialogBaseMuokkaaE&ditServerConfigDialogBasePikanppimetHotkeysServerConfigDialogBaseUusiNe&wServerConfigDialogBase PoistaRe&moveServerConfigDialogBase2Synkronoi nytnsstjtS&ynchronize screen saversServerConfigDialogBase$Nytt ja linkitysScreens and linksServerConfigDialogBase(Palvelimen asetuksetServer ConfigurationServerConfigDialogBaseVaihtoviiveSwitch &after waitingServerConfigDialogBaseBVaihtoviive kaksoisnapautettaessaSwitch on double &tap withinServerConfigDialogBaseYlvasen To&p-leftServerConfigDialogBaseYloikea Top-rig&htServerConfigDialogBase:Suhteutetut kursorin liikkeetUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseOletko varma, ett haluat korottaa Synergyn? Tm mahdollistaa Synergyn kyttmisen korotetuissa prosesseissa ja UAC-dialogeissa, mutta voi aiheuttaa ongelma korottamattomissa prosesseissa. Korota Synergy vain jos se on vlttmtnt.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogKorota SynergyElevate SynergySettingsDialog@Lokitiedoston tallennuspaikka...Save log file to...SettingsDialogSovitin: &Interface:SettingsDialogBase Kieli: &Language:SettingsDialogBaseLokitaso&Logging level:SettingsDialogBaseSekalaiset&MiscellaneousSettingsDialogBaseSelaa... Browse...SettingsDialogBase DebugDebugSettingsDialogBase Debug1Debug1SettingsDialogBase Debug2Debug2SettingsDialogBase VirheErrorSettingsDialogBase TiedotInfoSettingsDialogBaseLokitiedosto Log to file:SettingsDialogBaseLokiLoggingSettingsDialogBaseHuomautusNoteSettingsDialogBasePortti:P&ort:SettingsDialogBaseNytn nimi: Sc&reen name:SettingsDialogBaseAsetuksetSettingsSettingsDialogBaseVaroitusWarningSettingsDialogBasejOle hyv ja syt shkpostiosoitteesi ja salasanasi.-Please enter your email address and password. SetupWizardTee valinta.Please select an option. SetupWizardMrit Synergy Setup Synergy SetupWizard*Palvelin vai Asiakas?Server or Client?SetupWizardBaseMrit Synergy Setup SynergySetupWizardBase|Synergyn avulla voit helposti jakaa hiiren ja nppimistsi usean tietokoneen vlill, ja se on ilmainen ja avointa lhdekoodia. Liikuta hiiresi vain nytn reunan yli toiselle koneelle. Voit jopa jakaa leikepytsi. Tarvitset vain internet yhteyden. Synergy on cross-platform ( toimii Windows, Mac OS X ja Linuxissa).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBase<Kiitos, ett asensit Synergyn!Thanks for installing Synergy!SetupWizardBaseTervetuloaWelcomeSetupWizardBaseTuntematonUnknownVersionCheckerXKirjautuinen eponnistui, tapahtui virhe. %1$Login failed, an error occurred. %1 WebClient|Kirjautuinen eponnistui, tapahtui virhe. Palvelimen vaste: %16Login failed, an error occurred. Server response: %1 WebClientxKirjautuminen eponnistui, shkposti tai salasana on vr.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_fi.ts000066400000000000000000001710251305627404700214150ustar00rootroot00000000000000 AboutDialogBase About Synergy Tietoa Synergystä <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Tuntematon Version: Versio: &Ok OK ActionDialogBase Configure Action Määritä toiminto Choose the action to perform Määritä suoritettava toiminto Press a hotkey Paina pikanäppäin pohjaan Release a hotkey Vapauta pikanäppäin Press and release a hotkey Paina ja vapauta pikanäppäin only on these screens vain näillä näytöillä Switch to screen Vaihda näyttöön Switch in direction Vaihda left vasemmalle right oikealle up ylös down alas Lock cursor to screen Lukitse kursori näytölle toggle kytke päälle/pois on päälle off pois päältä This action is performed when Suorita toiminto the hotkey is pressed kun pikanäppäintä painetaan the hotkey is released kun pikanäppäin vapautetaan AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Pikanäppäin Enter the specification for the hotkey: Määritä pikanäppäin: MainWindow &Start &Käynnistä &File Tiedosto &Edit &Muokkaa &Window Ikkuna &Help Ohje <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Synergy versiosi on vanhentunut. Versio <b>%1</b> on nyt saatavilla <a href="%2">ladattavaksi</a>.</p> Program can not be started Ohjelmaa ei voida käynnistää The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Ajotiedoston<br><br>%1<br><br>käynnistys ei onnistunut, vaikka se on olemassa. Tarkista onko sinulla riittävät käyttöoikeudet ohjelman ajamiseen. Synergy client not found Synergyn asiakasohjelmaa ei löydy The executable for the synergy client does not exist. Ajotiedosto Synergyn asiakasohjelmalle puuttuu. Hostname is empty Isäntänimi on tyhjä Please fill in a hostname for the synergy client to connect to. Täytä isäntänimellä johon Synergy voi yhdistää. Cannot write configuration file Asetustiedostoa ei voida luoda. The temporary configuration file required to start synergy can not be written. Väliaikaista Synergyn vaatimaa asetustiedostoa ei voida luoda. Configuration filename invalid Asetustiedoston tiedostonimi virheellinen You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Et ole määrittänyt kelvollista asetustiedostoa Synergy palvelimelle. Haluatko määrittää asetustiedoston sijainnin nyt? Synergy server not found Synergy palvelinta ei löydy The executable for the synergy server does not exist. Ajotiedosto Synergy palvelimelle puuttuu. Synergy terminated with an error Synergy suljettiin virheen vuoksi Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy suljettiin odottamattomasti paluukoodilla %1.<br><br>Tarkista lokitiedosto saadaksesi lisätietoja. &Stop &Pysäytä Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy käynnistyy. Synergy is running. Synergy on käynnissä. Synergy is not running. Synergy ei ole käynnissä. Unknown Tuntematon Synergy Synergy Browse for a synergys config file Määritä Synergyn asetustiedosto Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Tallenna asetukset nimellä... Save failed Tallennus epäonnistui Could not save configuration to file. Ei voitu tallentaa asetustiedostoa. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Näytön nimi: &Server IP: Palvelimen IP: &Start &Käynnistä Use existing configuration: Käytä olemassa olevaa kokoonpanoa: &Configuration file: Asetustiedosto: &Browse... Selaa... Configure interactively: Määritä interaktiivisesti: &Configure Server... Määritä palvelin... Ready Valmis Log Loki &Apply Käytä IP addresses: IP-osoitteet: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Tietoa Synergystä &Quit &Lopeta Quit Lopeta Run Suorita S&top Pysäytä Stop Pysäytä S&how Status Näytä tila &Hide Piilota Hide Piilota &Show Näytä Show Näytä Save configuration &as... Tallenna asetukset nimellä... Save the interactively generated server configuration to a file. Tallenna interaktiivisesti määritetty palvelinkokoonpano tiedostoon. Settings Asetukset Edit settings Muokkaa asetuksia Run Wizard Ohjattu asetusten määritys NewScreenWidget Unnamed Nimetön PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Määritä Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configuration (*.sgc);;Kaikki tiedostot (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy Configuration (*.conf);;Kaikki tiedostot (*.*) System tray is unavailable, quitting. Ilmoitusalue ei ole käytettävissä, suljetaan. ScreenSettingsDialog Screen name is empty Näytön nimi puuttuu The screen name cannot be empty. Please either fill in a name or cancel the dialog. Nimimerkki puuttuu. Ole hyvä ja syötä nimi tai sulje dialogi. Screen name matches alias Nimimerkki on sala kuin alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Nimimerkki ei voi olla sama kuin alias. Oleva hyvä ja poista alias tai muuta nimimerkki. ScreenSettingsDialogBase Screen Settings Näytön asetukset Screen &name: Näytön nimi: A&liases Aliakset &Add Lisää &Remove Poista &Modifier keys Valintanäppäimet &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Ei mitään &Ctrl: &Ctrl: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners Kuolleet kulmat Top-left Ylävasen Top-right Yläoikea Bottom-left Alavasen Bottom-right Alaoikea Corner Si&ze: Kulman koko: &Fixes Korjaukset Fix CAPS LOCK key Korjaa CAPS LOCK näppäin Fix NUM LOCK key Korjaa NUM LOCK näppäin Fix SCROLL LOCK key Korjaa SCROLL LOCK näppäin Fix XTest for Xinerama Korjaa XTest Xineramalle ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Näyttö: <b>%1</b></center><br>Kaksoisnapsauta muokataksesi asetuksia<br>Vedä näyttö roskakoriin poistaaksesi sen. ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Palvelimen asetukset Screens and links Näytöt ja linkitys Drag a screen from the grid to the trashcan to remove it. Vedä näyttö ruudukosta roskakoriin poistaaksesi sen. Configure the layout of your synergy server configuration. Määritä Synergy-palvelimen näyttöasetukset Drag this button to the grid to add a new screen. Vedä tämä kuvake ruudukkoon lisätäksesi uuden näytön. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Lisää uusia näyttöjä ruudukkoon tai siirrä olemassa olevia vetämällä. Vedä näyttö roskakoriin poistaaksesi sen. Kaksoisnapsauta näyttöä muokataksesi sen asetuksia. Hotkeys Pikanäppäimet &Hotkeys Pikanäppäimet &New &Uusi &Edit &Muokkaa &Remove Poista A&ctions Toiminnot Ne&w Uusi E&dit Muokkaa Re&move Poista Advanced server settings Palvelimen lisäasetukset &Switch Vaihda Switch &after waiting Vaihtoviive ms ms Switch on double &tap within Vaihtoviive kaksoisnapautettaessa &Options &Asetukset &Check clients every Asiakkaiden tarkistusväli Use &relative mouse moves Suhteutetut kursorin liikkeet S&ynchronize screen savers Synkronoi näytönsäästäjät Don't take &foreground window on Windows servers Älä siirrä päällimmäiseksi ikkunaksi Windows palvelimilla Ignore auto config clients &Dead corners Kuolleet kulmat To&p-left Ylävasen Top-rig&ht Yläoikea &Bottom-left Alavasen Bottom-ri&ght Alaoikea Cor&ner Size: Kulman koko: SettingsDialog Save log file to... Lokitiedoston tallennuspaikka... Elevate Synergy Korota Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Oletko varma, että haluat korottaa Synergyn? Tämä mahdollistaa Synergyn käyttämisen korotetuissa prosesseissa ja UAC-dialogeissa, mutta voi aiheuttaa ongelma korottamattomissa prosesseissa. Korota Synergy vain jos se on välttämätöntä. SettingsDialogBase Settings Asetukset Sc&reen name: Näytön nimi: P&ort: Portti: &Interface: Sovitin: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Loki &Logging level: Lokitaso Log to file: Lokitiedosto Browse... Selaa... Error Virhe &Language: Kieli: &Miscellaneous Sekalaiset Warning Varoitus Note Huomautus Info Tiedot Debug Debug Debug1 Debug1 Debug2 Debug2 SetupWizard Setup Synergy Määritä Synergy Please select an option. Tee valinta. Please enter your email address and password. Ole hyvä ja syötä sähköpostiosoitteesi ja salasanasi. SetupWizardBase Setup Synergy Määritä Synergy Welcome Tervetuloa Thanks for installing Synergy! Kiitos, että asensit Synergyn! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergyn avulla voit helposti jakaa hiiren ja näppäimistösi usean tietokoneen välillä, ja se on ilmainen ja avointa lähdekoodia. Liikuta hiiresi vain näytön reunan yli toiselle koneelle. Voit jopa jakaa leikepöytäsi. Tarvitset vain internet yhteyden. Synergy on cross-platform ( toimii Windows, Mac OS X ja Linuxissa). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Palvelin vai Asiakas? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Tuntematon WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Kirjautuminen epäonnistui, sähköposti tai salasana on väärä. Login failed, an error occurred. %1 Kirjautuinen epäonnistui, tapahtui virhe. %1 Login failed, an error occurred. Server response: %1 Kirjautuinen epäonnistui, tapahtui virhe. Palvelimen vaste: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_fr.qm000066400000000000000000000561221305627404700214150ustar00rootroot00000000000000Gz,JHLbIDU` XY25Z2mxx.F>:}S u>w(Z = nbj#4E3>vMZU|Ev._&e?w9*+?;H}H2O $ZO MO M]J>|(VE 1UN.`Yu:Il_ }} $*Bulz5%HI  ;:*:5  Gj$ZGJ0"QJ-izJ@d-0l 17攄 6J"g(MQ:S'-( n4.d2@Ty.L#FN{6"!z>}JHZ 3=Tk@d4ycS %!@~ C+}F?nxCB7%Z I_ JzJ k#9 v~= A" -5 # Pn@ d& ~5@_ ~qT ք~ ȹh ȹ#] ȹV( aF |1w F+ F7 Z,5 7M KG c @{ RV RV RVS R T$ V44  |*G" c7 s" sKB cA F-| Ҫd ^ /,} 4pB) d0 i! r- zk PK ¦eS x48M ]^^L~1\S=E> 9nbunCy~K' r/7/{kC>k6..8>-iVa&Ok&OkAboutDialogBase& propos de Synergy About SynergyAboutDialogBaseInconnuUnknownAboutDialogBaseVersion:Version:AboutDialogBase>Choisissez l'action effectuerChoose the action to performActionDialogBase&Configurer l'actionConfigure ActionActionDialogBase8Limiter le curseur l'cranLock cursor to screenActionDialogBase,Appuyez sur une touchePress a hotkeyActionDialogBase<Pressez et relchez une touchePress and release a hotkeyActionDialogBase&Relchez une toucheRelease a hotkeyActionDialogBase4Basculer dans la directionSwitch in directionActionDialogBase*Basculer vers l'cranSwitch to screenActionDialogBase>Cette action est excute quandThis action is performed whenActionDialogBasebasdownActionDialogBase gaucheleftActionDialogBaseinactifoffActionDialogBase activonActionDialogBase2uniquement sur ces cransonly on these screensActionDialogBase droiterightActionDialogBase0Le raccourci est utilisthe hotkey is pressedActionDialogBaseHLa touche de raccourci est relache.the hotkey is releasedActionDialogBaseactivertoggleActionDialogBasehautupActionDialogBaseHSaisir la touche de raccourci&nbsp;:'Enter the specification for the hotkey:HotkeyDialogBase"Raccourci clavierHotkeyHotkeyDialogBase&Editer&Edit MainWindow&Fichier&File MainWindow &Aide&Help MainWindow&Dmarrer&Start MainWindow &Stop&Stop MainWindow&Fentre&Window MainWindow<p>Votre version de Synergy est prime. La version <b>%1</b> est dsormais disponible au <a href="%2">tlchargement</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindow|Parcourir pour rechercher un fichier de configuration synergys!Browse for a synergys config file MainWindow`Impossible d'crire le fichier de configuration.Cannot write configuration file MainWindowbLe nom du fichier de configuration est incorrect.Configuration filename invalid MainWindowTImpossible de sauvegarder la configuration%Could not save configuration to file. MainWindow,Le nom d'hte est videHostname is empty MainWindowVeuillez renseigner un nom d'hte auquel le client Synergy doit se connecter?Please fill in a hostname for the synergy client to connect to. MainWindowBLe programme ne peut pas dmarrerProgram can not be started MainWindowHSauvegarder la configuration sous...Save configuration as... MainWindow>Erreur lors de l'enregistrement Save failed MainWindowSynergySynergy MainWindowFLe client Synergy n'est pas dtectSynergy client not found MainWindowPSynergy n'est pas en train de s'excuterSynergy is not running. MainWindow@Synergy est en cours d'excutionSynergy is running. MainWindow@Synergy est en train de dmarrerSynergy is starting. MainWindowLLe serveur Synergy n'a pas t dtectSynergy server not found MainWindowSynergy s'est termin de faon inattendue avec le code d'erreur %1.<br><br> Vous trouverez plus de dtails dans le fichier journal.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowNSynergy s'est arrt suite une erreur Synergy terminated with an error MainWindowVL excutable du client Synergy n'existe pas5The executable for the synergy client does not exist. MainWindowZL'excutable du serveur Synergy n'existe pas.5The executable for the synergy server does not exist. MainWindowHL'excutable<br><br>%1<br><br>n'a pas pu tre correctement lanc, bien qu'il existe. Veuillez vrifier si vos permissions sont suffisantes pour lancer ce programme.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowImpossible d'crire le fichier temporaire de configuration, ncessaire au lancement de synergy.NThe temporary configuration file required to start synergy can not be written. MainWindowInconnuUnknown MainWindowLe fichier de configuration du serveur synergy n'est pas correct. Voulez vous visualiser ce fichier ? You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow( &propos de Synergy&About Synergy...MainWindowBaseAppliquer&ApplyMainWindowBaseParcourir... &Browse...MainWindowBase8Le fichier de &configuration&Configuration file:MainWindowBase0Configurer le serveur...&Configure Server...MainWindowBaseCac&her&HideMainWindowBaseQuitter&QuitMainWindowBase&Serveur IP: &Server IP:MainWindowBase&Montrer&ShowMainWindowBase&Dmarrer&StartMainWindowBase:Configurer interactivement : Configure interactively:MainWindowBase*diter les paramtres Edit settingsMainWindowBase CacherHideMainWindowBaseAdresses IP: IP addresses:MainWindowBaseJournalLogMainWindowBaseQuitterQuitMainWindowBasePrtReadyMainWindowBaseExcuterRunMainWindowBase$Lancer l'Assistant Run WizardMainWindowBaseVoir l'tat S&how StatusMainWindowBase ArrtS&topMainWindowBaseJSauvegarder la configuration &sous...Save configuration &as...MainWindowBaseSauvegarder la configuration gnre du serveur dans un fichier.@Save the interactively generated server configuration to a file.MainWindowBaseNom de l'cran: Screen name:MainWindowBaseParamtresSettingsMainWindowBaseMontrerShowMainWindowBaseArrterStopMainWindowBaseSynergySynergyMainWindowBaseLUtiliser la configuration existante : Use existing configuration:MainWindowBaseSans nomUnnamedNewScreenWidget"Installer Synergy Setup SynergyPluginWizardPage`Synergy Configurations (*.conf);;All files (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectnConfiguration Synergy (*.sgc);; Tous les fichiers (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjecthLa barre des tches n'est pas disponible, fermeture.%System tray is unavailable, quitting.QObject4Le nom de l'cran est videScreen name is emptyScreenSettingsDialogBLe nom affich concorde l'aliasScreen name matches aliasScreenSettingsDialogLe nom de l'cran ne peut pas tre vide. Merci de complter le nom ou d'annuler la bote de dialogue.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogLe nom de l'cran ne peut pas tre le mme que l'alias. Merci de supprimer l'alias ou de changer le nom de l'cran.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog&Ajouter&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBaseCoins morts &Dead cornersScreenSettingsDialogBaseCorrectifs&FixesScreenSettingsDialogBase,Touches de combinaison&Modifier keysScreenSettingsDialogBase&Supprimer&RemoveScreenSettingsDialogBaseMaj&nbsp;:&Shift:ScreenSettingsDialogBase A&liasA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseBas-gauche Bottom-leftScreenSettingsDialogBaseBas-droit Bottom-rightScreenSettingsDialogBase&Taille des &coins : Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBasePCorrige la touche Verrouillage majusculeFix CAPS LOCK keyScreenSettingsDialogBasePCorrige la touche Verrouillage numriqueFix NUM LOCK keyScreenSettingsDialogBaseRCorrige la touche Verrouillage dfilementFix SCROLL LOCK keyScreenSettingsDialogBase6Corrige XTest pour XineramaFix XTest for XineramaScreenSettingsDialogBase &eta:M&eta:ScreenSettingsDialogBaseMtaMetaScreenSettingsDialogBase AucunNoneScreenSettingsDialogBase Super:S&uper:ScreenSettingsDialogBaseNom de l'cran Screen &name:ScreenSettingsDialogBase,Paramtres d'affichageScreen SettingsScreenSettingsDialogBaseMajShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBaseHaut-gaucheTop-leftScreenSettingsDialogBaseHaut-droit Top-rightScreenSettingsDialogBase<center>cran: <b>%1</b></center><br>Double cliquer pour modifier les rglages<br>Faire glisser vers la corbeille pour le supprimero
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel&Bas-gauche &Bottom-leftServerConfigDialogBase>Vrifier les clients toutes les&Check clients everyServerConfigDialogBaseCoins morts &Dead cornersServerConfigDialogBase&Editer&EditServerConfigDialogBase$Raccourcis clavier&HotkeysServerConfigDialogBase&Nouveau&NewServerConfigDialogBase&Options&OptionsServerConfigDialogBase&Supprimer&RemoveServerConfigDialogBaseBasculer&SwitchServerConfigDialogBaseA&ctionsA&ctionsServerConfigDialogBase8Configuration serveur avancAdvanced server settingsServerConfigDialogBaseBas-d&roit Bottom-ri&ghtServerConfigDialogBasepConfigurer l'organisation de votre configuration serveur:Configure the layout of your synergy server configuration.ServerConfigDialogBase&Taille des coi&ns : Cor&ner Size:ServerConfigDialogBaseNe pas prendre la fentre au premier plan sur les serveurs Windows.0Don't take &foreground window on Windows serversServerConfigDialogBaseFaire glisser un cran de la grille vers la corbeille pour le supprimer.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase|Faire glisser de nouveaux crans vers la grille ou dplacer ceux existant. Faire glisser un cran dans la corbeille pour le supprimer. Double cliquer sur un cran pour modifier ses rglages.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBaseFaire glisser ce bouton sur la grille pour ajouter un nouvel cran1Drag this button to the grid to add a new screen.ServerConfigDialogBaseE&diterE&ditServerConfigDialogBase$Raccourcis clavierHotkeysServerConfigDialogBaseNou&veauNe&wServerConfigDialogBaseSuppri&merRe&moveServerConfigDialogBaseDS&ynchroniser les crans de veilleS&ynchronize screen saversServerConfigDialogBasecrans et liensScreens and linksServerConfigDialogBase*Configuration ServeurServer ConfigurationServerConfigDialogBase*Changer d'cran aprsSwitch &after waitingServerConfigDialogBaseVChanger d'cran en double-cliquant dans lesSwitch on double &tap withinServerConfigDialogBaseHa&ut-gauche To&p-leftServerConfigDialogBaseHaut-&droit Top-rig&htServerConfigDialogBasePUtiliser des mouvements souris &relatifsUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBasetes-vous sr de vouloir lever Synergy&nbsp;? Ceci autorise Synergy interagir avec les processus levs et le dialogue UAC, mais peut poser des problmes avec les processus non-levs. N'levez Synergy que si cela est ncessaire.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialoglever SynergyElevate SynergySettingsDialogPEnregistrer le journal dans le fichier :Save log file to...SettingsDialogInterface : &Interface:SettingsDialogBase&Langage : &Language:SettingsDialogBase4Niveau de journalisation :&Logging level:SettingsDialogBase Divers&MiscellaneousSettingsDialogBaseParcourir Browse...SettingsDialogBase DebugDebugSettingsDialogBase Debug1Debug1SettingsDialogBase Debug2Debug2SettingsDialogBase ErreurErrorSettingsDialogBase InfosInfoSettingsDialogBaseZEnregistrer le journal dans le fichier&nbsp;: Log to file:SettingsDialogBaseJournalLoggingSettingsDialogBaseRemarqueNoteSettingsDialogBase&Port :P&ort:SettingsDialogBaseNom de l'c&ran Sc&reen name:SettingsDialogBaseParamtresSettingsSettingsDialogBaseAvertissementWarningSettingsDialogBasedMerci d'entrer votre e-mail et votre mot de passe.-Please enter your email address and password. SetupWizardLChoisissez une option s'il vous plait.Please select an option. SetupWizard"Installer Synergy Setup Synergy SetupWizard&Serveur ou client?Server or Client?SetupWizardBase"Installer Synergy Setup SynergySetupWizardBaseSynergy vous permet de partager facilement votre souris et votre clavier entre plusieurs ordinateurs. Il est libre et Open Source. Il suffit de dplacer la souris d'un ordinateur l'autre en passant par leurs bords, comme pour passer d'un cran l'autre en multi-cran. Vous pouvez mme partager les presse-papiers (copier-coller). Tout ce qu'il faut est une connexion rseau. Synergy est multi-plateforme (fonctionne sur Windows, Mac OS X et Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBase@Merci d'avoir install Synergy !Thanks for installing Synergy!SetupWizardBaseBienvenueWelcomeSetupWizardBaseInconnuUnknownVersionChecker`Connexion refuse, une erreur s'est produite. %1$Login failed, an error occurred. %1 WebClientConnexion refuse, une erreur s'est produite. Rponse du serveur : %16Login failed, an error occurred. Server response: %1 WebClientfConnexion refuse, e-mail ou mot de passe invalide.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_fr.ts000066400000000000000000001726601305627404700214340ustar00rootroot00000000000000 AboutDialogBase About Synergy À propos de Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Inconnu Version: Version: &Ok &Ok ActionDialogBase Configure Action Configurer l'action Choose the action to perform Choisissez l'action à effectuer Press a hotkey Appuyez sur une touche Release a hotkey Relâchez une touche Press and release a hotkey Pressez et relâchez une touche only on these screens uniquement sur ces écrans Switch to screen Basculer vers l'écran Switch in direction Basculer dans la direction left gauche right droite up haut down bas Lock cursor to screen Limiter le curseur à l'écran toggle activer on activé off inactif This action is performed when Cette action est exécutée quand the hotkey is pressed Le raccourci est utilisé the hotkey is released La touche de raccourci est relachée. AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Raccourci clavier Enter the specification for the hotkey: Saisir la touche de raccourci&nbsp;: MainWindow &Start &Démarrer &File &Fichier &Edit &Editer &Window &Fenêtre &Help &Aide <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Votre version de Synergy est périmée. La version <b>%1</b> est désormais disponible au <a href="%2">téléchargement</a>.</p> Program can not be started Le programme ne peut pas démarrer The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. L'exécutable<br><br>%1<br><br>n'a pas pu être correctement lancé, bien qu'il existe. Veuillez vérifier si vos permissions sont suffisantes pour lancer ce programme. Synergy client not found Le client Synergy n'est pas détecté The executable for the synergy client does not exist. L’exécutable du client Synergy n'existe pas Hostname is empty Le nom d'hôte est vide Please fill in a hostname for the synergy client to connect to. Veuillez renseigner un nom d'hôte auquel le client Synergy doit se connecter Cannot write configuration file Impossible d'écrire le fichier de configuration. The temporary configuration file required to start synergy can not be written. Impossible d'écrire le fichier temporaire de configuration, nécessaire au lancement de synergy. Configuration filename invalid Le nom du fichier de configuration est incorrect. You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Le fichier de configuration du serveur synergy n'est pas correct. Voulez vous visualiser ce fichier ? Synergy server not found Le serveur Synergy n'a pas été détecté The executable for the synergy server does not exist. L'exécutable du serveur Synergy n'existe pas. Synergy terminated with an error Synergy s'est arrêté suite à une erreur Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy s'est terminé de façon inattendue avec le code d'erreur %1.<br><br> Vous trouverez plus de détails dans le fichier journal. &Stop &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy est en train de démarrer Synergy is running. Synergy est en cours d'exécution Synergy is not running. Synergy n'est pas en train de s'exécuter Unknown Inconnu Synergy Synergy Browse for a synergys config file Parcourir pour rechercher un fichier de configuration synergys Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Sauvegarder la configuration sous... Save failed Erreur lors de l'enregistrement Could not save configuration to file. Impossible de sauvegarder la configuration MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Nom de l'écran: &Server IP: &Serveur IP: &Start &Démarrer Use existing configuration: Utiliser la configuration existante : &Configuration file: Le fichier de &configuration &Browse... Parcourir... Configure interactively: Configurer interactivement : &Configure Server... Configurer le serveur... Ready Prêt Log Journal &Apply Appliquer IP addresses: Adresses IP: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... À &propos de Synergy &Quit Quitter Quit Quitter Run Exécuter S&top Arrêt Stop Arrêter S&how Status Voir l'état &Hide Cac&her Hide Cacher &Show &Montrer Show Montrer Save configuration &as... Sauvegarder la configuration &sous... Save the interactively generated server configuration to a file. Sauvegarder la configuration générée du serveur dans un fichier. Settings Paramètres Edit settings Éditer les paramètres Run Wizard Lancer l'Assistant NewScreenWidget Unnamed Sans nom PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Installer Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Configuration Synergy (*.sgc);; Tous les fichiers (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. La barre des tâches n'est pas disponible, fermeture. ScreenSettingsDialog Screen name is empty Le nom de l'écran est vide The screen name cannot be empty. Please either fill in a name or cancel the dialog. Le nom de l'écran ne peut pas être vide. Merci de compléter le nom ou d'annuler la boîte de dialogue. Screen name matches alias Le nom affiché concorde à l'alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Le nom de l'écran ne peut pas être le même que l'alias. Merci de supprimer l'alias ou de changer le nom de l'écran. ScreenSettingsDialogBase Screen Settings Paramètres d'affichage Screen &name: Nom de l'écran A&liases A&lias &Add &Ajouter &Remove &Supprimer &Modifier keys Touches de combinaison &Shift: Maj&nbsp;: Shift Maj Ctrl Ctrl Alt Alt Meta Méta Super Super None Aucun &Ctrl: &Ctrl: Al&t: Al&t: M&eta: &eta: S&uper: Super: &Dead corners Coins morts Top-left Haut-gauche Top-right Haut-droit Bottom-left Bas-gauche Bottom-right Bas-droit Corner Si&ze: Taille des &coins : &Fixes Correctifs Fix CAPS LOCK key Corrige la touche Verrouillage majuscule Fix NUM LOCK key Corrige la touche Verrouillage numérique Fix SCROLL LOCK key Corrige la touche Verrouillage défilement Fix XTest for Xinerama Corrige XTest pour Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Écran: <b>%1</b></center><br>Double cliquer pour modifier les réglages<br>Faire glisser vers la corbeille pour le supprimer ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Configuration Serveur Screens and links Écrans et liens Drag a screen from the grid to the trashcan to remove it. Faire glisser un écran de la grille vers la corbeille pour le supprimer. Configure the layout of your synergy server configuration. Configurer l'organisation de votre configuration serveur Drag this button to the grid to add a new screen. Faire glisser ce bouton sur la grille pour ajouter un nouvel écran Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Faire glisser de nouveaux écrans vers la grille ou déplacer ceux existant. Faire glisser un écran dans la corbeille pour le supprimer. Double cliquer sur un écran pour modifier ses réglages. Hotkeys Raccourcis clavier &Hotkeys Raccourcis clavier &New &Nouveau &Edit &Editer &Remove &Supprimer A&ctions A&ctions Ne&w Nou&veau E&dit E&diter Re&move Suppri&mer Advanced server settings Configuration serveur avancé &Switch Basculer Switch &after waiting Changer d'écran après ms ms Switch on double &tap within Changer d'écran en double-cliquant dans les &Options &Options &Check clients every Vérifier les clients toutes les Use &relative mouse moves Utiliser des mouvements souris &relatifs S&ynchronize screen savers S&ynchroniser les écrans de veille Don't take &foreground window on Windows servers Ne pas prendre la fenêtre au premier plan sur les serveurs Windows. Ignore auto config clients &Dead corners Coins morts To&p-left Ha&ut-gauche Top-rig&ht Haut-&droit &Bottom-left &Bas-gauche Bottom-ri&ght Bas-d&roit Cor&ner Size: Taille des coi&ns : SettingsDialog Save log file to... Enregistrer le journal dans le fichier : Elevate Synergy Élever Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Êtes-vous sûr de vouloir élever Synergy&nbsp;? Ceci autorise Synergy à interagir avec les processus élevés et le dialogue UAC, mais peut poser des problèmes avec les processus non-élevés. N'élevez Synergy que si cela est nécessaire. SettingsDialogBase Settings Paramètres Sc&reen name: Nom de l'éc&ran P&ort: &Port : &Interface: Interface : Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Journal &Logging level: Niveau de journalisation : Log to file: Enregistrer le journal dans le fichier&nbsp;: Browse... Parcourir Error Erreur &Language: &Langage : &Miscellaneous Divers Warning Avertissement Note Remarque Info Infos Debug Debug Debug1 Debug1 Debug2 Debug2 SetupWizard Setup Synergy Installer Synergy Please select an option. Choisissez une option s'il vous plait. Please enter your email address and password. Merci d'entrer votre e-mail et votre mot de passe. SetupWizardBase Setup Synergy Installer Synergy Welcome Bienvenue Thanks for installing Synergy! Merci d'avoir installé Synergy ! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy vous permet de partager facilement votre souris et votre clavier entre plusieurs ordinateurs. Il est libre et Open Source. Il suffit de déplacer la souris d'un ordinateur à l'autre en passant par leurs bords, comme pour passer d'un écran à l'autre en multi-écran. Vous pouvez même partager les presse-papiers (copier-coller). Tout ce qu'il faut est une connexion réseau. Synergy est multi-plateforme (fonctionne sur Windows, Mac OS X et Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Serveur ou client ? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Inconnu WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Connexion refusée, e-mail ou mot de passe invalide. Login failed, an error occurred. %1 Connexion refusée, une erreur s'est produite. %1 Login failed, an error occurred. Server response: %1 Connexion refusée, une erreur s'est produite. Réponse du serveur : %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_gl.qm000066400000000000000000000065671305627404700214200ustar00rootroot00000000000000i &"Acerca de Synergy About SynergyAboutDialogBaseDescoecidoUnknownAboutDialogBaseVersin:Version:AboutDialogBase:Elixir a accin para realizarChoose the action to performActionDialogBase"Configurar accinConfigure ActionActionDialogBase abaixodownActionDialogBaseesquerdaleftActionDialogBasedereitarightActionDialogBase arribaupActionDialogBase&Ficheiro&File MainWindow<p>A sa versin de Synergy est desactualizada. A versin <b>%1</b> xa est dispoible para <a href="%2">descargar</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowXConfiguracin do nome de ficheiro non vlidaConfiguration filename invalid MainWindowErro ao gardar Save failed MainWindowSynergySynergy MainWindow<Cliente de Synergy non atopadoSynergy client not found MainWindow>Synergy non se est a executar.Synergy is not running. MainWindow4Synergy est a executarse.Synergy is running. MainWindow2Synergy est a iniciarse.Synergy is starting. MainWindow>Servidor de Synergy non atopadoSynergy server not found MainWindowDescoecidoUnknown MainWindow$&Acerca de Synergy&About Synergy...MainWindowBase&Explorar... &Browse...MainWindowBaseEditar axustes Edit settingsMainWindowBaseAgocharHideMainWindowBaseEnderezos IP: IP addresses:MainWindowBaseRexistroLogMainWindowBase$Executar asistente Run WizardMainWindowBaseAxustesSettingsMainWindowBaseSynergySynergyMainWindowBaseSen nomeUnnamedNewScreenWidget &Ctrl:&Ctrl:ScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBase&Idioma: &Language:SettingsDialogBaseInfoInfoSettingsDialogBaseAxustesSettingsSettingsDialogBaseBenvido/aWelcomeSetupWizardBaseDescoecidoUnknownVersionCheckerSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_gl.ts000066400000000000000000001613751305627404700214300ustar00rootroot00000000000000 AboutDialogBase About Synergy Acerca de Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Descoñecido Version: Versión: &Ok ActionDialogBase Configure Action Configurar acción Choose the action to perform Elixir a acción para realizar Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left esquerda right dereita up arriba down abaixo Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Ficheiro &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>A súa versión de Synergy está desactualizada. A versión <b>%1</b> xa está dispoñible para <a href="%2">descargar</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found Cliente de Synergy non atopado The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid Configuración do nome de ficheiro non válida You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found Servidor de Synergy non atopado The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy está a iniciarse. Synergy is running. Synergy está a executarse. Synergy is not running. Synergy non se está a executar. Unknown Descoñecido Synergy Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Erro ao gardar Could not save configuration to file. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... &Explorar... Configure interactively: &Configure Server... Ready Log Rexistro &Apply IP addresses: Enderezos IP: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Acerca de Synergy &Quit Quit Run S&top Stop S&how Status &Hide Hide Agochar &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Axustes Edit settings Editar axustes Run Wizard Executar asistente NewScreenWidget Unnamed Sen nome PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: &Ctrl: Al&t: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Axustes Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Idioma: &Miscellaneous Warning Note Info Info Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Benvido/a Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Descoñecido WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_grk.qm000066400000000000000000000110251305627404700215620ustar00rootroot00000000000000=*i&OkAboutDialogBase*   Synergy About SynergyAboutDialogBase:Version:AboutDialogBaseN     Choose the action to performActionDialogBase8   Configure ActionActionDialogBase4   Lock cursor to screenActionDialogBaseF    Press a hotkeyActionDialogBase\      Press and release a hotkeyActionDialogBaseF    Release a hotkeyActionDialogBase,  Switch in directionActionDialogBase"  Switch to screenActionDialogBaseD    This action is performed whenActionDialogBasedownActionDialogBaseleftActionDialogBase offActionDialogBase onActionDialogBase0    only on these screensActionDialogBase rightActionDialogBase:    the hotkey is pressedActionDialogBase8    the hotkey is releasedActionDialogBasetoggleActionDialogBaseupActionDialogBase4  'Enter the specification for the hotkey:HotkeyDialogBase HotkeyHotkeyDialogBase&Edit MainWindow &File MainWindow&Help MainWindow&Window MainWindowH     Program can not be started MainWindow*  Edit settingsMainWindowBase QuitMainWindowBase ReadyMainWindowBaseSettingsMainWindowBaseStopMainWindowBaseAltAltScreenSettingsDialogBase&EditServerConfigDialogBaseInfoSettingsDialogBaseSettingsSettingsDialogBase@ Synergy                   ,     .           .        clipboards.       .  Synergy     (  Windows, Mac OS X  Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBasesynergy-1.8.8-stable/src/gui/res/lang/gui_grk.ts000066400000000000000000001636311305627404700216060ustar00rootroot00000000000000 AboutDialogBase About Synergy Σχετικά με το Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: Έκδοση: &Ok ΟΚ ActionDialogBase Configure Action Διαμόρφωσε την ενέργεια αυτή Choose the action to perform Επιλέξτε την ενέργεια για να εκτελέστεί Press a hotkey Πιέστε ένα πλήκτρο άμεσης πρόσβασης Release a hotkey Άφηστε ένα πλήκτρο άμεσης πρόσβασης Press and release a hotkey Πιέστε και αφήστε ένα πλήκτρο άμεσης πρόσβασης only on these screens μόνο σε αυτές τις οθόνες Switch to screen Άλλαγή στην οθόνη Switch in direction Αλλαγή στην κατεύθυνση left αριστερά right δεξιά up πάνω down κάτω Lock cursor to screen Κλείδωμα δείκτη στην οθόνη toggle Εναλλαγή on άνοιξε off κλείσε This action is performed when Η δράση αυτή πραγματοποιείται όταν the hotkey is pressed Το άμεσο πλήκτρο έχει πατηθεί the hotkey is released Το άμεσο πλήκτρο έχει αφεθεί AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Άμεση πρόσβαση Enter the specification for the hotkey: Καθορισμός άμεσου πλήκτρου MainWindow &Start &File Αρχείο &Edit Επεξεργασία &Window Παράθυρο &Help Βοήθεια <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started Το πρόγραμμα δεν μπορεί να ξεκινήσει The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Έτοιμο Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Έξοδος Run S&top Stop Διακοπή S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Ιδιότητες Edit settings Επεξεργασία Ιδιοτήτων Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit Επεξεργασία &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Ιδιότητες Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Πληροφορίες Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Το Synergy σας αφήνει με εύκολο τρόπο να μοιράσετε το ποντίκι και το πληκτρολόγιο ανάμεσα σε πολλαπλούς υπολογιστές στο γραφείο σας, είναι Δωρεάν και Ανοιχτού Κώδικα. Απλά μετακινείστε το ποντίκι στην άκρη της μιας οθόνης στην άλλη. Μπορείτε να μοιράσετε ακόμα και όλα τα clipboards. Το μόνο που χρειάζεται μία σύνδεση δικτύου. Το Synergy λειτουργεί σε πολλαπλές πλατφόρμες (δουλεύει σε Windows, Mac OS X και Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_he.qm000066400000000000000000000324071305627404700214020ustar00rootroot00000000000000*,* *%\*0++`G#Gz J(gLb)U`Yx&}SBu>W(Z = nbjh4 &Tv,oEv._e$w9 ;H}HyO O +O ,$])VEYu:)xl_ 1} S*&l ((:: w$Z'J"QJm-iz*H@d攄(+( n4.d0{!86>' f>J()K 3=T k@d%}F$LnPC'"6 Jz* v~#? % -5A Pn%C d ~5$ ք~1 ȹ ȹ0 ȹ0= |\ F> F!} Zz ! KG @{ RV~ RV RV0 R 9 T V4X  c! s s* c% F ^` / 4p&s i! r3 zk P+ x4" ]^ ^+:=> " r> "i0v &&OkAboutDialogBase Synergy About SynergyAboutDialogBase UnknownAboutDialogBase :Version:AboutDialogBase   Choose the action to performActionDialogBase Configure ActionActionDialogBase*    Lock cursor to screenActionDialogBase$   Press a hotkeyActionDialogBase,   Press and release a hotkeyActionDialogBase  Release a hotkeyActionDialogBase Switch in directionActionDialogBase Switch to screenActionDialogBase$  This action is performed whenActionDialogBasedownActionDialogBaseleftActionDialogBase offActionDialogBaseonActionDialogBase  only on these screensActionDialogBaserightActionDialogBase the hotkey is pressedActionDialogBase  the hotkey is releasedActionDialogBase\toggleActionDialogBase upActionDialogBase6    :'Enter the specification for the hotkey:HotkeyDialogBase HotkeyHotkeyDialogBase &&Edit MainWindow &&File MainWindow &&Help MainWindow&Start MainWindow&Stop MainWindow &&Window MainWindow8    Synergy!Browse for a synergys config file MainWindow:     Cannot write configuration file MainWindow2    Configuration filename invalid MainWindow   Hostname is empty MainWindowT     Synergy  .?Please fill in a hostname for the synergy client to connect to. MainWindow0    Program can not be started MainWindow&  &...Save configuration as... MainWindow  Save failed MainWindowSynergySynergy MainWindow( Synergy  Synergy client not found MainWindowSynergy  Synergy is not running. MainWindowSynergy  Synergy is running. MainWindowSynergy Synergy is starting. MainWindow, -Synergy  .Synergy server not found MainWindowSynergy        %1.<br><br> ,    ().fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow.Synergy   . Synergy terminated with an error MainWindow@   Synergy  .5The executable for the synergy client does not exist. MainWindow>   Synergy  .5The executable for the synergy server does not exist. MainWindow:<br><br>%1<br><br>,    .       .The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindow     .       Synergy.NThe temporary configuration file required to start synergy can not be written. MainWindow Unknown MainWindow& &ApplyMainWindowBase ... &Browse...MainWindowBase &&QuitMainWindowBase&StartMainWindowBase  Edit settingsMainWindowBaseHideMainWindowBase$  (Log)LogMainWindowBase QuitMainWindowBaseRunMainWindowBase  Run WizardMainWindowBase & S&how StatusMainWindowBase &S&topMainWindowBase8   ...Save configuration &as...MainWindowBase@    .@Save the interactively generated server configuration to a file.MainWindowBase SettingsMainWindowBaseStopMainWindowBaseSynergySynergyMainWindowBase*  Use existing configuration:MainWindowBase  UnnamedNewScreenWidget Synergy Setup SynergyPluginWizardPage`   Synergy (*.conf);;All Files (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObject^   Synergy (*.sgc);;All Files (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObject2   , .%System tray is unavailable, quitting.QObject   Screen name is emptyScreenSettingsDialog &&AddScreenSettingsDialogBase &Ctrl&Ctrl:ScreenSettingsDialogBase&  &Dead cornersScreenSettingsDialogBase&&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBase &: A&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase- Bottom-leftScreenSettingsDialogBase- Bottom-rightScreenSettingsDialogBase& : Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseNoneScreenSettingsDialogBase : Screen &name:ScreenSettingsDialogBase Screen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase-Top-leftScreenSettingsDialogBase- Top-rightScreenSettingsDialogBase- &Bottom-leftServerConfigDialogBase$   &&Check clients everyServerConfigDialogBase&  &Dead cornersServerConfigDialogBase &&EditServerConfigDialogBase&&NewServerConfigDialogBase&&OptionsServerConfigDialogBase&&RemoveServerConfigDialogBase &&SwitchServerConfigDialogBase&A&ctionsServerConfigDialogBase&  &Advanced server settingsServerConfigDialogBase- Bottom-ri&ghtServerConfigDialogBase& : Cor&ner Size:ServerConfigDialogBaseB      .1Drag this button to the grid to add a new screen.ServerConfigDialogBase E&ditServerConfigDialogBaseNe&wServerConfigDialogBaseRe&moveServerConfigDialogBase  & S&ynchronize screen saversServerConfigDialogBase Screens and linksServerConfigDialogBase Server ConfigurationServerConfigDialogBase(  &  Switch &after waitingServerConfigDialogBase.  & Switch on double &tap withinServerConfigDialogBase- To&p-leftServerConfigDialogBase- Top-rig&htServerConfigDialogBase2   &Use &relative mouse movesServerConfigDialogBase msServerConfigDialogBase,&   (Log)&Logging level:SettingsDialogBase... Browse...SettingsDialogBase DebugDebugSettingsDialogBase Debug1Debug1SettingsDialogBase Debug2Debug2SettingsDialogBase ErrorSettingsDialogBaseInfoSettingsDialogBase :  Log to file:SettingsDialogBase"  (Log)LoggingSettingsDialogBaseNoteSettingsDialogBase &:P&ort:SettingsDialogBase& : Sc&reen name:SettingsDialogBase SettingsSettingsDialogBase  WarningSettingsDialogBase  .Please select an option. SetupWizard Synergy Setup Synergy SetupWizard  ?Server or Client?SetupWizardBase Synergy Setup SynergySetupWizardBaseSynergy           ,    .          .         .      .     ( -Windows, Mac OS X -Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBase UnknownVersionCheckerSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_he.ts000066400000000000000000001672461305627404700214250ustar00rootroot00000000000000 AboutDialogBase About Synergy אודות Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown לא ידוע Version: גירסא: &Ok &אישור ActionDialogBase Configure Action הגדר פעולה Choose the action to perform בחר פעולה לביצוע Press a hotkey לחיצה על מקש כלשהו Release a hotkey שחרור מקש כלשהו Press and release a hotkey לחיצה ושחרור מקש כלשהו only on these screens רק במסכים האלו Switch to screen עבור למסך Switch in direction החלף בכיוון left שמאל right ימין up למעלה down למטה Lock cursor to screen נעל את סמן העכבר במסך toggle הדלקה\כיבוי on דלוק off כיבוי This action is performed when הפעולה מבוצעת כאשר the hotkey is pressed המקש לחוץ the hotkey is released המקש אינו לחוץ AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey מקש קיצור Enter the specification for the hotkey: הכנס פירוט עבור מקש הקיצור: MainWindow &Start התחל &File &קובץ &Edit &עריכה &Window &חלון &Help ע&זרה <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started לא ניתן להפעיל את התוכנה The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. היישום:<br><br>%1<br><br>קיים, אך לא ניתן להפעילו. בדוק אם מוגדרות עבורך ההראשות המתאימות להפעלתו. Synergy client not found לקוח Synergy לא נמצא The executable for the synergy client does not exist. תוכנת הלקוח של Synergy לא קיימת. Hostname is empty לא צוין שם מחשב Please fill in a hostname for the synergy client to connect to. אנא ציין שם מחשב שלקוח Synergy יתחבר אליו. Cannot write configuration file לא ניתן לכתוב את קובץ ההגדרות The temporary configuration file required to start synergy can not be written. לא ניתן לכתוב לקובץ ההגדרות הזמני. הדבר הכרחי על מנת להפעיל את Synergy. Configuration filename invalid שם קובץ ההגדרות אינו חוקי You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found שרת ה-Synergy לא נמצא. The executable for the synergy server does not exist. תוכנת השרת של Synergy לא נמצאה. Synergy terminated with an error Synergy נסגרה עם שגיאה. Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy נסגרה באופן לא צפוי עם שגיאה מספר %1.<br><br>לפרטים נוספים, פנו לקובץ התיעוד (לוג). &Stop עצור Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy מאתחל Synergy is running. Synergy רץ ברקע Synergy is not running. Synergy לא רץ Unknown לא ידוע Synergy Synergy Browse for a synergys config file מציאת קובץ הגדרות של Synergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... שמור הגדרות &בשם... Save failed שמירה נכשלה Could not save configuration to file. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start התחל Use existing configuration: השתמש בהגדרות הקיימות &Configuration file: &Browse... חפש... Configure interactively: &Configure Server... Ready Log תיעוד פעילות (Log) &Apply &שמור שינויים IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit &יציאה Quit יציאה Run הפעל S&top ע&צור Stop עצור S&how Status הצג &מצב &Hide Hide הסתר &Show Show Save configuration &as... שמור הגדרות קונפיגורציה כ... Save the interactively generated server configuration to a file. שמור הגדרות השרת הנוכחיות לקובץ. Settings הגדרות Edit settings שנה הגדרות Run Wizard הפעל אשף NewScreenWidget Unnamed ללא שם PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy הגדרת Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) קבצי הגדרות של Synergy (*.sgc);;All Files (*.*) Synergy Configurations (*.conf);;All files (*.*) קבצי הגדרות של Synergy (*.conf);;All Files (*.*) System tray is unavailable, quitting. מגש המערכת לא זמין, יוצא. ScreenSettingsDialog Screen name is empty לא הוקלד שם מסך The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings הגדרות מסך Screen &name: שם מסך: A&liases שמות &נוספים: &Add &הוסף &Remove ה&סר &Modifier keys &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super None ללא &Ctrl: &Ctrl Al&t: Al&t: M&eta: M&eta: S&uper: &Dead corners &פינות מתות Top-left עליון-שמאל Top-right עליון-ימין Bottom-left שמאלית-תחתונה Bottom-right ימנית-תחתונה Corner Si&ze: &גודל הפינה: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration הגדרות שרת Screens and links מסכים וחיבורים Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. גרור את כפתור זה לרשת להוספת מסך. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &חדש &Edit &עריכה &Remove ה&סר A&ctions פ&עולות Ne&w חדש E&dit כריכה Re&move הסרה Advanced server settings הגדרות שרת &מתקדמות &Switch ה&חלפה Switch &after waiting החלף לאחר ה&מתנה של ms אלפיות שניה Switch on double &tap within החלף בלחיצה &כפולה בתוך &Options א&פשרויות &Check clients every בדוק את הלקוח &בכל Use &relative mouse moves השתמש בהזזות עכבר &יחסיות S&ynchronize screen savers סנכרן &שומרי מסך Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners &פינות מתות To&p-left שמאלית-עליונה Top-rig&ht ימנית-עליונה &Bottom-left שמאלית-תחתונה Bottom-ri&ght ימנית-תחתונה Cor&ner Size: &גודל הפינה: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings הגדרות Sc&reen name: &שם מסך: P&ort: &פורט: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging תיעוד פעולה (Log) &Logging level: &רמת תיעוד פעולה (Log) Log to file: תיעוד לקובץ: Browse... עיון... Error שגיאה &Language: &Miscellaneous Warning שים לב Note הערה Info מידע Debug Debug Debug1 Debug1 Debug2 Debug2 SetupWizard Setup Synergy הגדרת Synergy Please select an option. אנא בחר אופציה. Please enter your email address and password. SetupWizardBase Setup Synergy הגדרת Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy מאפשרת לשתף בקלות את העכבר והמקלדת בין מספר מחשבים על השולחן, וזה חופשית וקוד פתוח. רק להזיז את העכבר מקצה מסך אחד של המחשב לאחר. אתה יכול גם לשתף את כל לוחות כתיבה שלך. כל מה שצריך הוא חיבור לרשת. סינרגיה היא חוצה פלטפורמות (עובד ב-Windows, Mac OS X ו-Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? שרת או לקוח? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown לא ידוע WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_hi.qm000066400000000000000000000000271305627404700213770ustar00rootroot00000000000000 AboutDialogBase About Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: &Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left right up down Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_hr-HR.qm000066400000000000000000000500051305627404700217200ustar00rootroot000000000000003 }Su>y(Z = 3nbj 45+vDEv._"ke7w9^#$? ;H}H+tO O CO D>]AVE *UUN'HYu:A4l_ }} !"*:/l-@#@v 3:#:.6  >$Z?+J)"QJ{-izB@d&l )攄J(C( n4.d+)@Ty'L#={/L6>  z>OJ? 3<=Tk@d-v%C$}F7vnnC:z0X! I_ JzBK k#26 v~5 8 -5 m Pn8 d# ~58) ք~ ȹ ȹ ȹJ* a>> |) F$ F/ Z% / KG 9 @{ RVz RVb RVI R T V4  |*> c0 s> sB c9` F&h Ҫ ^ /%a 4p9 d( i! r5 zk! PB ¦eI x40 ]^^C1\I)=5> 1bun;- r/?7(kC6k..1'>G&iJc&U redu&OkAboutDialogBaseO Synergyu About SynergyAboutDialogBaseNepoznatoUnknownAboutDialogBaseIna ica:Version:AboutDialogBase:Odaberite radnju za izvoenjeChoose the action to performActionDialogBasePodesite radnjeConfigure ActionActionDialogBase:Zaklju aj pokaziva na zaslonLock cursor to screenActionDialogBase0Pritisnite tipku pre acaPress a hotkeyActionDialogBaseJPritisnite i oslobodite tipku pre acaPress and release a hotkeyActionDialogBase0Oslobodite tipku pre acaRelease a hotkeyActionDialogBase Prebaci u smjeruSwitch in directionActionDialogBase"Prebaci na zaslonSwitch to screenActionDialogBase2Ova radnja se izvodi kadaThis action is performed whenActionDialogBase doljedownActionDialogBase lijevoleftActionDialogBaseIsklju enooffActionDialogBaseUklju enoonActionDialogBase,samo na ovim zaslonimaonly on these screensActionDialogBase desnorightActionDialogBase6je tipka pre aca pritisnutathe hotkey is pressedActionDialogBase6je tipka pre aca osloboenathe hotkey is releasedActionDialogBase uklju i/isklju itoggleActionDialogBasegoreupActionDialogBase,Odredite tipku pre aca'Enter the specification for the hotkey:HotkeyDialogBaseTipka pre acaHotkeyHotkeyDialogBase &Uredi&Edit MainWindow&Datoteka&File MainWindow &Pomo&Help MainWindow&Pokreni&Start MainWindow&Zaustavi&Stop MainWindow&Prozor&Window MainWindowFOdaberite synergy datoteku postavki!Browse for a synergys config file MainWindowLNemogue ispisivanje datoteke postavkiCannot write configuration file MainWindow@Pogreaan naziv datoteke postavkiConfiguration filename invalid MainWindowNNemogue spremanje postavki u datoteku.%Could not save configuration to file. MainWindow0Naziv ra unala nedostajeHostname is empty MainWindowvUpiaite naziv ra unala synergy klijenta na koji se spajate.?Please fill in a hostname for the synergy client to connect to. MainWindow:Program ne mo~e biti pokrenutProgram can not be started MainWindow,Spremi postavke kao...Save configuration as... MainWindow&Neuspjelo spremanje Save failed MainWindowSynergySynergy MainWindow:Synergy klijent nije pronaenSynergy client not found MainWindow,Synergy nije pokrenut.Synergy is not running. MainWindow(Synergy je pokrenut.Synergy is running. MainWindow&Synergy se pokree.Synergy is starting. MainWindowBSynergy poslu~itelj nije pronaenSynergy server not found MainWindowSynergy je neo ekivano prestao sa radom, s izlaznim kodom of %1.<br><br>Pogledajte izlazni zapis za viae pojedinosti.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowNSynergy je prestao sa radom zbog greake Synergy terminated with an error MainWindowZIzvrana datoteka synergy klijenta ne postoji.5The executable for the synergy client does not exist. MainWindowbIzvrana datoteka synergy poslu~itelja ne postoji.5The executable for the synergy server does not exist. MainWindowIzvrana datoteka<br><br>%1<br><br>ne mo~e se pokrenuti, kao da ne postoji. Provjerite imate li potrebne dozvole za pokretanje ovog programa.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowPrivremena datoteka postavki potrebna za pokretanje synergya ne mo~e biti zapisana.NThe temporary configuration file required to start synergy can not be written. MainWindowNepoznatoUnknown MainWindowNiste odabrali valjanu datoteku postavki za synergy poslu~itelj. }elite li sada odabrati datoteku postavki?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow&O Synergyu...&About Synergy...MainWindowBase&Primijeni&ApplyMainWindowBase&Pregledaj... &Browse...MainWindowBase&&Datoteka postavki:&Configuration file:MainWindowBase0&Podesite poslu~itelj...&Configure Server...MainWindowBase&Sakrij&HideMainWindowBase&Zatvori&QuitMainWindowBase"&IP poslu~itelja: &Server IP:MainWindowBase&Prika~i&ShowMainWindowBase&Pokreni&StartMainWindowBase,Podesite interaktivno:Configure interactively:MainWindowBaseUredi postavke Edit settingsMainWindowBase SakrijHideMainWindowBaseIP adresa: IP addresses:MainWindowBase ZapisLogMainWindowBaseZatvoriQuitMainWindowBaseSpremanReadyMainWindowBasePokreniRunMainWindowBase Pokeni  arobnjak Run WizardMainWindowBaseP&rika~i status S&how StatusMainWindowBaseZ&austaviS&topMainWindowBase.Spremi postavke &kao...Save configuration &as...MainWindowBaseSpremi interaktivno generirane postavke poslu~itelja u datoteku...@Save the interactively generated server configuration to a file.MainWindowBaseNaziv zaslona: Screen name:MainWindowBasePostavkeSettingsMainWindowBasePrika~iShowMainWindowBaseZaustaviStopMainWindowBaseSynergySynergyMainWindowBase6Koristi postojee postavke:Use existing configuration:MainWindowBaseNeimenovanUnnamedNewScreenWidget Podesite Synergy Setup SynergyPluginWizardPageZSynergy postavke (*.conf);;Sve datoteke (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectXSynergy postavke (*.sgc);;Sve datoteke (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectTObavijesna ikona je nedostupna, otkazujem.%System tray is unavailable, quitting.QObject2Naziv zaslona nije upisanScreen name is emptyScreenSettingsDialog &Dodaj&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBase&Mrtvi kutovi &Dead cornersScreenSettingsDialogBase&Popraci&FixesScreenSettingsDialogBase &Promijeni tipke&Modifier keysScreenSettingsDialogBase&Ukloni&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBaseN&adimciA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseDolje-lijevo Bottom-leftScreenSettingsDialogBaseDolje-desno Bottom-rightScreenSettingsDialogBaseVeli ina ku&ta: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase.Popravi CAPS LOCK tipkuFix CAPS LOCK keyScreenSettingsDialogBase,Popravi NUM LOCK tipkuFix NUM LOCK keyScreenSettingsDialogBase2Popravi SCROLL LOCK tipkuFix SCROLL LOCK keyScreenSettingsDialogBase2Popravi XTest za XineramaFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseNijedanNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBaseNaziv &zaslona: Screen &name:ScreenSettingsDialogBase Postavke zaslonaScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBaseGore-lijevoTop-leftScreenSettingsDialogBaseGore-desno Top-rightScreenSettingsDialogBase$<center>Zaslon: <b>%1</b></center><br>Dvostruko kliknite za ureivanje postavki<br>Za uklanjanje zaslona dovucite ga do ikone smea i ispustite gao
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel&Dolje-lijevo &Bottom-leftServerConfigDialogBase0&Provjeri klijent svakih&Check clients everyServerConfigDialogBase&Mrtvi kutovi &Dead cornersServerConfigDialogBase &Uredi&EditServerConfigDialogBase&Tipke pre aca&HotkeysServerConfigDialogBase &Nova&NewServerConfigDialogBase&Mogunosti&OptionsServerConfigDialogBase&Ukloni&RemoveServerConfigDialogBase&Uklju i&SwitchServerConfigDialogBaseR&adnjeA&ctionsServerConfigDialogBase<Napredne postavke poslu~iteljaAdvanced server settingsServerConfigDialogBaseDolje-de&sno Bottom-ri&ghtServerConfigDialogBaseTPodesite izlaz vaaeg synergy poslu~itelja.:Configure the layout of your synergy server configuration.ServerConfigDialogBaseVel&i ina kuta: Cor&ner Size:ServerConfigDialogBasexNe uzimaj &prozor u prednjem planu na Windows poslu~iteljima0Don't take &foreground window on Windows serversServerConfigDialogBasejZa uklanjanje odvucite zaslon iz polja u ikonu smea.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaseZDovucite novi zaslon u odabrano polje ili premjestite iz trenutnog polja. Za brisanje zaslona odvucite ga u ikonu smea. Za ureivanje postavki dvostruko kliknite na zaslon.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasehPovucite ovu ikonu zaslona do odabranog polja ispod.1Drag this button to the grid to add a new screen.ServerConfigDialogBase U&rediE&ditServerConfigDialogBaseTipke pre acaHotkeysServerConfigDialogBase No&vaNe&wServerConfigDialogBaseUk&loniRe&moveServerConfigDialogBase.U&skladi  uvare zaslonaS&ynchronize screen saversServerConfigDialogBase&Zasloni i povezniceScreens and linksServerConfigDialogBase*Postavke poslu~iteljaServer ConfigurationServerConfigDialogBase,Uklju i &nakon  ekanjaSwitch &after waitingServerConfigDialogBase<Uklju i dvostrukim &dodirom zaSwitch on double &tap withinServerConfigDialogBaseGo&re-lijevo To&p-leftServerConfigDialogBaseGore-des&no Top-rig&htServerConfigDialogBase>Koristi &relativne pokrete miaaUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseSigurno ~elite dati UAC ovlasti Synergyu? To omoguuje Synergyu interakciju s ovlaatenim procesima i UAC dijalogom, ali mo~e uzrokovati probleme s neovlaatenim procesima. Dajte ovlasti Synergyu samo ako je stvarno potrebno.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialog(UAC ovlasti SynergyaElevate SynergySettingsDialog6Spremi datoteku zapisa u...Save log file to...SettingsDialog&Su elje: &Interface:SettingsDialogBase Jezik: &Language:SettingsDialogBase.&Razina prijavljivanja:&Logging level:SettingsDialogBaseOdaberi... Browse...SettingsDialogBase$Otklanjanje greakeDebugSettingsDialogBase&Otklanjanje greake1Debug1SettingsDialogBase&Otklanjanje greake2Debug2SettingsDialogBase GreakaErrorSettingsDialogBaseInfoInfoSettingsDialogBase&Prijava u datoteku: Log to file:SettingsDialogBasePrijavljivanjeLoggingSettingsDialogBaseNapomenaNoteSettingsDialogBase U&laz:P&ort:SettingsDialogBaseNa&ziv zaslona: Sc&reen name:SettingsDialogBasePostavkeSettingsSettingsDialogBaseUpozorenjeWarningSettingsDialogBase6Molim, odaberite mogunost.Please select an option. SetupWizard Podesite Synergy Setup Synergy SetupWizard0Poslu~itelj ili klijent?Server or Client?SetupWizardBase Podesite Synergy Setup SynergySetupWizardBaseSynergy vam omoguuje lagano dijeljenje vaag miaa i tipkovnice izmeu viae ra unala na vaaoj radnoj povraini. Synergy je besplatan i otvorenog kda. Jednostavno pomaknite vaa mia preko ruba zaslona jednog ra unala na zaslon drugog ra unala.  ak mo~ete dijeliti sve vaae meuspremnike. Sve ato trebate je Internet veza. Synergy je viae platformska aplikacija (radi na Windowsima, Mac OS X i Linuxu).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseDHvala ato ste instalirali Synergy!Thanks for installing Synergy!SetupWizardBaseDobrodoaliWelcomeSetupWizardBaseNepoznatoUnknownVersionCheckerSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_hr-HR.ts000066400000000000000000001705371305627404700217460ustar00rootroot00000000000000 AboutDialogBase About Synergy O Synergyu <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Nepoznato Version: Inačica: &Ok &U redu ActionDialogBase Configure Action Podesite radnje Choose the action to perform Odaberite radnju za izvođenje Press a hotkey Pritisnite tipku prečaca Release a hotkey Oslobodite tipku prečaca Press and release a hotkey Pritisnite i oslobodite tipku prečaca only on these screens samo na ovim zaslonima Switch to screen Prebaci na zaslon Switch in direction Prebaci u smjeru left lijevo right desno up gore down dolje Lock cursor to screen Zaključaj pokazivač na zaslon toggle uključi/isključi on Uključeno off Isključeno This action is performed when Ova radnja se izvodi kada the hotkey is pressed je tipka prečaca pritisnuta the hotkey is released je tipka prečaca oslobođena AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Tipka prečaca Enter the specification for the hotkey: Odredite tipku prečaca MainWindow &Start &Pokreni &File &Datoteka &Edit &Uredi &Window &Prozor &Help &Pomoć <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started Program ne može biti pokrenut The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Izvršna datoteka<br><br>%1<br><br>ne može se pokrenuti, kao da ne postoji. Provjerite imate li potrebne dozvole za pokretanje ovog programa. Synergy client not found Synergy klijent nije pronađen The executable for the synergy client does not exist. Izvršna datoteka synergy klijenta ne postoji. Hostname is empty Naziv računala nedostaje Please fill in a hostname for the synergy client to connect to. Upišite naziv računala synergy klijenta na koji se spajate. Cannot write configuration file Nemoguće ispisivanje datoteke postavki The temporary configuration file required to start synergy can not be written. Privremena datoteka postavki potrebna za pokretanje synergya ne može biti zapisana. Configuration filename invalid Pogrešan naziv datoteke postavki You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Niste odabrali valjanu datoteku postavki za synergy poslužitelj. Želite li sada odabrati datoteku postavki? Synergy server not found Synergy poslužitelj nije pronađen The executable for the synergy server does not exist. Izvršna datoteka synergy poslužitelja ne postoji. Synergy terminated with an error Synergy je prestao sa radom zbog greške Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy je neočekivano prestao sa radom, s izlaznim kodom of %1.<br><br>Pogledajte izlazni zapis za više pojedinosti. &Stop &Zaustavi Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy se pokreće. Synergy is running. Synergy je pokrenut. Synergy is not running. Synergy nije pokrenut. Unknown Nepoznato Synergy Synergy Browse for a synergys config file Odaberite synergy datoteku postavki Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Spremi postavke kao... Save failed Neuspjelo spremanje Could not save configuration to file. Nemoguće spremanje postavki u datoteku. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Naziv zaslona: &Server IP: &IP poslužitelja: &Start &Pokreni Use existing configuration: Koristi postojeće postavke: &Configuration file: &Datoteka postavki: &Browse... &Pregledaj... Configure interactively: Podesite interaktivno: &Configure Server... &Podesite poslužitelj... Ready Spreman Log Zapis &Apply &Primijeni IP addresses: IP adresa: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &O Synergyu... &Quit &Zatvori Quit Zatvori Run Pokreni S&top Z&austavi Stop Zaustavi S&how Status P&rikaži status &Hide &Sakrij Hide Sakrij &Show &Prikaži Show Prikaži Save configuration &as... Spremi postavke &kao... Save the interactively generated server configuration to a file. Spremi interaktivno generirane postavke poslužitelja u datoteku... Settings Postavke Edit settings Uredi postavke Run Wizard Pokeni čarobnjak NewScreenWidget Unnamed Neimenovan PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Podesite Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy postavke (*.sgc);;Sve datoteke (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy postavke (*.conf);;Sve datoteke (*.*) System tray is unavailable, quitting. Obavijesna ikona je nedostupna, otkazujem. ScreenSettingsDialog Screen name is empty Naziv zaslona nije upisan The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Postavke zaslona Screen &name: Naziv &zaslona: A&liases N&adimci &Add &Dodaj &Remove &Ukloni &Modifier keys &Promijeni tipke &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Nijedan &Ctrl: &Ctrl: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners &Mrtvi kutovi Top-left Gore-lijevo Top-right Gore-desno Bottom-left Dolje-lijevo Bottom-right Dolje-desno Corner Si&ze: Veličina ku&ta: &Fixes &Popraci Fix CAPS LOCK key Popravi CAPS LOCK tipku Fix NUM LOCK key Popravi NUM LOCK tipku Fix SCROLL LOCK key Popravi SCROLL LOCK tipku Fix XTest for Xinerama Popravi XTest za Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Zaslon: <b>%1</b></center><br>Dvostruko kliknite za uređivanje postavki<br>Za uklanjanje zaslona dovucite ga do ikone smeća i ispustite ga ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Postavke poslužitelja Screens and links Zasloni i poveznice Drag a screen from the grid to the trashcan to remove it. Za uklanjanje odvucite zaslon iz polja u ikonu smeća. Configure the layout of your synergy server configuration. Podesite izlaz vašeg synergy poslužitelja. Drag this button to the grid to add a new screen. Povucite ovu ikonu zaslona do odabranog polja ispod. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Dovucite novi zaslon u odabrano polje ili premjestite iz trenutnog polja. Za brisanje zaslona odvucite ga u ikonu smeća. Za uređivanje postavki dvostruko kliknite na zaslon. Hotkeys Tipke prečaca &Hotkeys &Tipke prečaca &New &Nova &Edit &Uredi &Remove &Ukloni A&ctions R&adnje Ne&w No&va E&dit U&redi Re&move Uk&loni Advanced server settings Napredne postavke poslužitelja &Switch &Uključi Switch &after waiting Uključi &nakon čekanja ms ms Switch on double &tap within Uključi dvostrukim &dodirom za &Options &Mogućnosti &Check clients every &Provjeri klijent svakih Use &relative mouse moves Koristi &relativne pokrete miša S&ynchronize screen savers U&skladi čuvare zaslona Don't take &foreground window on Windows servers Ne uzimaj &prozor u prednjem planu na Windows poslužiteljima Ignore auto config clients &Dead corners &Mrtvi kutovi To&p-left Go&re-lijevo Top-rig&ht Gore-des&no &Bottom-left &Dolje-lijevo Bottom-ri&ght Dolje-de&sno Cor&ner Size: Vel&ičina kuta: SettingsDialog Save log file to... Spremi datoteku zapisa u... Elevate Synergy UAC ovlasti Synergya Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Sigurno želite dati UAC ovlasti Synergyu? To omogućuje Synergyu interakciju s ovlaštenim procesima i UAC dijalogom, ali može uzrokovati probleme s neovlaštenim procesima. Dajte ovlasti Synergyu samo ako je stvarno potrebno. SettingsDialogBase Settings Postavke Sc&reen name: Na&ziv zaslona: P&ort: U&laz: &Interface: &Sučelje: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Prijavljivanje &Logging level: &Razina prijavljivanja: Log to file: Prijava u datoteku: Browse... Odaberi... Error Greška &Language: Jezik: &Miscellaneous Warning Upozorenje Note Napomena Info Info Debug Otklanjanje greške Debug1 Otklanjanje greške1 Debug2 Otklanjanje greške2 SetupWizard Setup Synergy Podesite Synergy Please select an option. Molim, odaberite mogućnost. Please enter your email address and password. SetupWizardBase Setup Synergy Podesite Synergy Welcome Dobrodošli Thanks for installing Synergy! Hvala što ste instalirali Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy vam omogućuje lagano dijeljenje vašg miša i tipkovnice između više računala na vašoj radnoj površini. Synergy je besplatan i otvorenog kôda. Jednostavno pomaknite vaš miš preko ruba zaslona jednog računala na zaslon drugog računala. Čak možete dijeliti sve vaše međuspremnike. Sve što trebate je Internet veza. Synergy je više platformska aplikacija (radi na Windowsima, Mac OS X i Linuxu). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Poslužitelj ili klijent? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Nepoznato WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_hu-HU.qm000066400000000000000000000442151305627404700217340ustar00rootroot000000000000000^}Sdu>(Z ,= nbj41)Kv=Ev. _ 4e4w9!]!N N;H}H)O O <O =}]:VE 'UN$Yu::l_ } *7<l*99 0:!:+S $Z8J&"QJ'-iz;M@d#l 'J攄(= ( n4.d(@Ty%S{,cV6>E 6z>J94 3=T k@d*^%C"/}F4wndC7-s I_ Jz; k#/] v~2 6 -5 Pn5 d ~556 ք~Q ȹ ȹ ȹC a86 |' F" F, Z" , KG @{ RV| RV RVB R% TP V4  |*8 c-0 s( s; c6w F$ ^ /# 4p6 d&* i! x r- zk# P< x4- ]^^ / r/7%kC3k+..6>$`iCK&Ok&OkAboutDialogBaseSynergy nvjegy About SynergyAboutDialogBaseIsmeretlenUnknownAboutDialogBaseVerzi:Version:AboutDialogBase.Vlasszon egy mqveletetChoose the action to performActionDialogBaseBelltsConfigure ActionActionDialogBase6Kurzor zrolsa a kpernyQnLock cursor to screenActionDialogBase<Nyomjon le egy gyorsbillentyqtPress a hotkeyActionDialogBaseZNyomja le, majd engedje fel a gyorsbillentyqtPress and release a hotkeyActionDialogBase:Engedje fel a gyorsbillentyqtRelease a hotkeyActionDialogBaseIrnyvltsSwitch in directionActionDialogBaseKpernyQvltsSwitch to screenActionDialogBase8Ez a mqvelet trtnik amikorThis action is performed whenActionDialogBaseledownActionDialogBaseballeftActionDialogBaseKIoffActionDialogBaseBEonActionDialogBase2csak ezeken a kpernyQknonly on these screensActionDialogBasejobbrightActionDialogBase(a gyorsgomb lenyomvathe hotkey is pressedActionDialogBase,a gyorsgomb felengedvethe hotkey is releasedActionDialogBase vlttoggleActionDialogBasefelupActionDialogBaseBAdjon meg lerst a gyorsgombhoz:'Enter the specification for the hotkey:HotkeyDialogBaseGyorsgombHotkeyHotkeyDialogBaseSzerkeszt&Edit MainWindowFjl&File MainWindowSg&Help MainWindow &Start&Start MainWindowStop&Stop MainWindow Ablak&Window MainWindowNA Synergy konfigurcis fjl kijellse!Browse for a synergys config file MainWindow@A konfigurcis fjl nem rhat.Cannot write configuration file MainWindowBKonfigurcis fjlnv rvnytelenConfiguration filename invalid MainWindowPA konfigurcis fjlt nem lehet menteni.%Could not save configuration to file. MainWindowA gpnv res.Hostname is empty MainWindowxKrjk adja meg a Synergy kliens gp nevt a csatlakozshoz.?Please fill in a hostname for the synergy client to connect to. MainWindow6A program nem tud elindulniProgram can not be started MainWindowBMentse msknt a konfigurcit...Save configuration as... MainWindow"Ments sikertelen Save failed MainWindowSynergySynergy MainWindow8Synergy kliens nem tallhatSynergy client not found MainWindow$A Synergy nem fut.Synergy is not running. MainWindowA Synergy futSynergy is running. MainWindow A Synergy indul.Synergy is starting. MainWindow8Synergy szerver nem elrhetQSynergy server not found MainWindowA Synergy a kvetkezQ hibakddal lpet ki: %1.<br><br>A rszletekrt tekintse meg a naplt.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowJA Synergy hibt jelzett, ezrt lellt Synergy terminated with an error MainWindowhA Synergy kliens futtathat llomnya nem tallhat.5The executable for the synergy client does not exist. MainWindowjA Synergy szerver futtathat llomnya nem tallhat.5The executable for the synergy server does not exist. MainWindow A vgrehajtand<br><br>%1<br><br>nem indul, esetleg nem ltezik. Krjk ellenQrizze, hogy rendelkezik-e a szksges engedlyekkel a futtatshoz.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowAz ideiglenes konfigurcis fjl, amely szksges a Synergy indtshoz, nem jtt ltre.NThe temporary configuration file required to start synergy can not be written. MainWindowIsmeretlenUnknown MainWindowNem adott meg rvnyes konfigurcis fjlnevet a synergy szerveren. Meg akarja keresni a konfigurcis fjlt most?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow$Synergy nvjegy...&About Synergy...MainWindowBaseAlkalmaz&ApplyMainWindowBaseTallzs... &Browse...MainWindowBase&Konfigurcis fjl:&Configuration file:MainWindowBase.Szerver konfigurci...&Configure Server...MainWindowBaseKilps&QuitMainWindowBase &Start&StartMainWindowBase0Interaktv konfigurci:Configure interactively:MainWindowBase,Belltsok mdostsa Edit settingsMainWindowBase NaplLogMainWindowBaseKilpsQuitMainWindowBaseKszReadyMainWindowBaseFut :-)RunMainWindowBase$Varzsl futtatsa Run WizardMainWindowBaseS&how Status S&how StatusMainWindowBase S&topS&topMainWindowBase,Konfig mentse mint...Save configuration &as...MainWindowBaseMentse az interaktvan ltrehozott szerver konfigurcit fjlba.@Save the interactively generated server configuration to a file.MainWindowBaseBelltsokSettingsMainWindowBaseStopStopMainWindowBaseSynergySynergyMainWindowBaseBA ltezQ konfigurci hasznlata:Use existing configuration:MainWindowBaseNvtelenUnnamedNewScreenWidget"Synergy bellts Setup SynergyPluginWizardPage`Synergy konfigurci (*.conf);;Minden fjl (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObject^Synergy konfigurci (*.sgc);;Minden fjl (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectJRendszer tlca nem elrhetQ, kilps.%System tray is unavailable, quitting.QObject"KpernyQnv res.Screen name is emptyScreenSettingsDialogHozzad&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBase&Dead corners &Dead cornersScreenSettingsDialogBase Rgzt&FixesScreenSettingsDialogBase&Mdost billentyqk&Modifier keysScreenSettingsDialogBaseEltvolt&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBaselnevekA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseBal-als Bottom-leftScreenSettingsDialogBaseJobb-als Bottom-rightScreenSettingsDialogBaseSarokmret: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase,Rgzti a CAPS LOCK-otFix CAPS LOCK keyScreenSettingsDialogBase*Rgzti a NUM LOCK-otFix NUM LOCK keyScreenSettingsDialogBase0Rgzti a SCROLL LOCK-otFix SCROLL LOCK keyScreenSettingsDialogBase,Fix XTest for XineramaFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseNoneNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBaseKpernyQnv: Screen &name:ScreenSettingsDialogBase(KpernyQ belltsokScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBaseBal-felsQTop-leftScreenSettingsDialogBaseJobb-felsQ Top-rightScreenSettingsDialogBase<center>KpernyQ: <b>%1</b></center><br>Dupla klikk a mdostshoz<br>Hzd a szemetesre a trlshezo
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelBal-als &Bottom-leftServerConfigDialogBase(Kliensek ellenQrzse&Check clients everyServerConfigDialogBase&Dead corners &Dead cornersServerConfigDialogBaseSzerkeszt&EditServerConfigDialogBaseGyorsgombok&HotkeysServerConfigDialogBasej&NewServerConfigDialogBaseBelltsok&OptionsServerConfigDialogBaseEltvolt&RemoveServerConfigDialogBase&Switch&SwitchServerConfigDialogBaseA&ctionsA&ctionsServerConfigDialogBase6Tovbbi szerver belltsokAdvanced server settingsServerConfigDialogBaseJobb-als Bottom-ri&ghtServerConfigDialogBasetConfigure the layout of your synergy server configuration.:Configure the layout of your synergy server configuration.ServerConfigDialogBaseSarok mret Cor&ner Size:ServerConfigDialogBase`Don't take &foreground window on Windows servers0Don't take &foreground window on Windows serversServerConfigDialogBasevHzd a kpernyQt a listbl a szemetesre, hogy eltvoltsd.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase>Hzza az j kpernyQket a listba vagy mozgassa a meglvQket. Hzza a kpernyQt a szemetesre, hogy trlQdjn. Dupla kattintssal szerkesztheti a belltsokat.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBaserHzd ezt a gombot a listba, hogy j kpernyQt adj hozz.1Drag this button to the grid to add a new screen.ServerConfigDialogBase E&ditE&ditServerConfigDialogBaseGyorsgombokHotkeysServerConfigDialogBaseNe&wNe&wServerConfigDialogBaseRe&moveRe&moveServerConfigDialogBase:KpernyQvdQk szinkronizlsaS&ynchronize screen saversServerConfigDialogBase0KpernyQk s kapcsolatokScreens and linksServerConfigDialogBase(Szerver konfigurciServer ConfigurationServerConfigDialogBase.Vlts a vrakozs utnSwitch &after waitingServerConfigDialogBase8Switch on double &tap withinSwitch on double &tap withinServerConfigDialogBaseBal-felsQ To&p-leftServerConfigDialogBaseJobb-felsQ Top-rig&htServerConfigDialogBase<Relatv egr mozgs hasznlataUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBase*Napl mentse mint...Save log file to...SettingsDialog&Interface: &Interface:SettingsDialogBase Naplzsi szint:&Logging level:SettingsDialogBaseTallzs... Browse...SettingsDialogBase DebugDebugSettingsDialogBase Debug1Debug1SettingsDialogBase Debug2Debug2SettingsDialogBaseHibaErrorSettingsDialogBaseInfInfoSettingsDialogBaseNapl fjlba: Log to file:SettingsDialogBaseNaplzsLoggingSettingsDialogBaseJegyzetNoteSettingsDialogBase P&ort:P&ort:SettingsDialogBaseKpernyQ neve: Sc&reen name:SettingsDialogBaseBelltsokSettingsSettingsDialogBaseFigyelmeztetsWarningSettingsDialogBase4Krem vlaszon egy opcit.Please select an option. SetupWizard"Synergy bellts Setup Synergy SetupWizard(Szerver vagy kliens?Server or Client?SetupWizardBase"Synergy bellts Setup SynergySetupWizardBaseA Synergy lehetQv teszi a billentyqzet s egr megosztst tbb szmtgp kztt s radsul Ingyenes s nylt forrskd. Csak mozgassa az egeret a kpernyQ szlre, hogy tkerljn a msik szmtgpe monitorra. A szmtgpek kztt a vglap is megosztsra kerl. Nincs msra szksge csak hlzati kapcsolatra a kt szmtgp kztt. A Synergy opercis rendszer fggetlen, gy hasznlhatja Windows, Mac OS X s Linux rendszerq szmtgppel.ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseIsmeretlenUnknownVersionCheckerSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_hu-HU.ts000066400000000000000000001677371305627404700217640ustar00rootroot00000000000000 AboutDialogBase About Synergy Synergy névjegy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Ismeretlen Version: Verzió: &Ok &Ok ActionDialogBase Configure Action Beállítás Choose the action to perform Válasszon egy műveletet Press a hotkey Nyomjon le egy gyorsbillentyűt Release a hotkey Engedje fel a gyorsbillentyűt Press and release a hotkey Nyomja le, majd engedje fel a gyorsbillentyűt only on these screens csak ezeken a képernyőkön Switch to screen Képernyőváltás Switch in direction Irányváltás left bal right jobb up fel down le Lock cursor to screen Kurzor zárolása a képernyőn toggle váltó on BE off KI This action is performed when Ez a művelet történik amikor the hotkey is pressed a gyorsgomb lenyomva the hotkey is released a gyorsgomb felengedve AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Gyorsgomb Enter the specification for the hotkey: Adjon meg leírást a gyorsgombhoz: MainWindow &Start &Start &File Fájl &Edit Szerkeszt &Window Ablak &Help Súgó <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started A program nem tud elindulni The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. A végrehajtandó<br><br>%1<br><br>nem indul, esetleg nem létezik. Kérjük ellenőrizze, hogy rendelkezik-e a szükséges engedélyekkel a futtatáshoz. Synergy client not found Synergy kliens nem található The executable for the synergy client does not exist. A Synergy kliens futtatható állománya nem található. Hostname is empty A gépnév üres. Please fill in a hostname for the synergy client to connect to. Kérjük adja meg a Synergy kliens gép nevét a csatlakozáshoz. Cannot write configuration file A konfigurációs fájl nem írható. The temporary configuration file required to start synergy can not be written. Az ideiglenes konfigurációs fájl, amely szükséges a Synergy indításához, nem jött létre. Configuration filename invalid Konfigurációs fájlnév érvénytelen You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Nem adott meg érvényes konfigurációs fájlnevet a synergy szerveren. Meg akarja keresni a konfigurációs fájlt most? Synergy server not found Synergy szerver nem elérhető The executable for the synergy server does not exist. A Synergy szerver futtatható állománya nem található. Synergy terminated with an error A Synergy hibát jelzett, ezért leállt Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. A Synergy a következő hibakóddal lépet ki: %1.<br><br>A részletekért tekintse meg a naplót. &Stop Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. A Synergy indul. Synergy is running. A Synergy fut Synergy is not running. A Synergy nem fut. Unknown Ismeretlen Synergy Synergy Browse for a synergys config file A Synergy konfigurációs fájl kijelölése Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Mentse másként a konfigurációt... Save failed Mentés sikertelen Could not save configuration to file. A konfigurációs fájlt nem lehet menteni. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start &Start Use existing configuration: A létező konfiguráció használata: &Configuration file: Konfigurációs fájl: &Browse... Tallózás... Configure interactively: Interaktív konfiguráció: &Configure Server... Szerver konfiguráció... Ready Kész Log Napló &Apply Alkalmaz IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Synergy névjegy... &Quit Kilépés Quit Kilépés Run Fut :-) S&top S&top Stop Stop S&how Status S&how Status &Hide Hide &Show Show Save configuration &as... Konfig mentése mint... Save the interactively generated server configuration to a file. Mentse az interaktívan létrehozott szerver konfigurációt fájlba. Settings Beállítások Edit settings Beállítások módosítása Run Wizard Varázsló futtatása NewScreenWidget Unnamed Névtelen PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Synergy beállítás Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy konfiguráció (*.sgc);;Minden fájl (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy konfiguráció (*.conf);;Minden fájl (*.*) System tray is unavailable, quitting. Rendszer tálca nem elérhető, kilépés. ScreenSettingsDialog Screen name is empty Képernyőnév üres. The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Képernyő beállítások Screen &name: Képernyőnév: A&liases Álnevek &Add Hozzáad &Remove Eltávolít &Modifier keys Módosító billentyűk &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None None &Ctrl: &Ctrl: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners &Dead corners Top-left Bal-felső Top-right Jobb-felső Bottom-left Bal-alsó Bottom-right Jobb-alsó Corner Si&ze: Sarokméret: &Fixes Rögzít Fix CAPS LOCK key Rögzíti a CAPS LOCK-ot Fix NUM LOCK key Rögzíti a NUM LOCK-ot Fix SCROLL LOCK key Rögzíti a SCROLL LOCK-ot Fix XTest for Xinerama Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Képernyő: <b>%1</b></center><br>Dupla klikk a módosításhoz<br>Húzd a szemetesre a törléshez ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Szerver konfiguráció Screens and links Képernyők és kapcsolatok Drag a screen from the grid to the trashcan to remove it. Húzd a képernyőt a listából a szemetesre, hogy eltávolítsd. Configure the layout of your synergy server configuration. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Húzd ezt a gombot a listába, hogy új képernyőt adj hozzá. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Húzza az új képernyőket a listába vagy mozgassa a meglévőket. Húzza a képernyőt a szemetesre, hogy törlődjön. Dupla kattintással szerkesztheti a beállításokat. Hotkeys Gyorsgombok &Hotkeys Gyorsgombok &New Új &Edit Szerkeszt &Remove Eltávolít A&ctions A&ctions Ne&w Ne&w E&dit E&dit Re&move Re&move Advanced server settings További szerver beállítások &Switch &Switch Switch &after waiting Váltás a várakozás után ms ms Switch on double &tap within Switch on double &tap within &Options Beállítások &Check clients every Kliensek ellenőrzése Use &relative mouse moves Relatív egér mozgás használata S&ynchronize screen savers Képernyővédők szinkronizálása Don't take &foreground window on Windows servers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners &Dead corners To&p-left Bal-felső Top-rig&ht Jobb-felső &Bottom-left Bal-alsó Bottom-ri&ght Jobb-alsó Cor&ner Size: Sarok méret SettingsDialog Save log file to... Napló mentése mint... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Beállítások Sc&reen name: Képernyő neve: P&ort: P&ort: &Interface: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Naplózás &Logging level: Naplózási szint: Log to file: Napló fájlba: Browse... Tallózás... Error Hiba &Language: &Miscellaneous Warning Figyelmeztetés Note Jegyzet Info Infó Debug Debug Debug1 Debug1 Debug2 Debug2 SetupWizard Setup Synergy Synergy beállítás Please select an option. Kérem válaszon egy opciót. Please enter your email address and password. SetupWizardBase Setup Synergy Synergy beállítás Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). A Synergy lehetővé teszi a billentyűzet és egér megosztását több számítógép között és ráadásul Ingyenes és nyílt forráskódú. Csak mozgassa az egeret a képernyő szélére, hogy átkerüljön a másik számítógépe monitorára. A számítógépek között a vágólap is megosztásra kerül. Nincs másra szüksége csak hálózati kapcsolatra a két számítógép között. A Synergy operációs rendszer független, így használhatja Windows, Mac OS X és Linux rendszerű számítógéppel. Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Szerver vagy kliens? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Ismeretlen WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_id.qm000066400000000000000000000111101305627404700213660ustar00rootroot00000000000000YiOke&OkAboutDialogBaseTentang Synergy About SynergyAboutDialogBaseTak dikenalUnknownAboutDialogBase Versi:Version:AboutDialogBase.Synergy tidak berjalan.Synergy is not running. MainWindow Memulai Synergy.Synergy is starting. MainWindowTak dikenalUnknown MainWindow&Sembunyi&HideMainWindowBaseUbah pengaturan Edit settingsMainWindowBaseSembunyiHideMainWindowBaseAlamat IP: IP addresses:MainWindowBaseLaporanLogMainWindowBaseSiapReadyMainWindowBaseJalankanRunMainWindowBase&Perlihatkan kondisi S&how StatusMainWindowBaseBerhentiS&topMainWindowBase:Simpan konfigurasi sebagai...Save configuration &as...MainWindowBasePengaturanSettingsMainWindowBaseBerhentiStopMainWindowBaseTanpa namaUnnamedNewScreenWidgetDSystem tidak memungkinkan, keluar.%System tray is unavailable, quitting.QObject"Nama layar kosongScreen name is emptyScreenSettingsDialogMasukan&AddScreenSettingsDialogBase Ctrl:&Ctrl:ScreenSettingsDialogBase Hapus&RemoveScreenSettingsDialogBaseNama lainA&liasesScreenSettingsDialogBaseAlt:Al&t:ScreenSettingsDialogBaseBawah-kiri Bottom-leftScreenSettingsDialogBaseBawah-kanan Bottom-rightScreenSettingsDialogBaseNama Layar: Screen &name:ScreenSettingsDialogBase Pengaturan LayarScreen SettingsScreenSettingsDialogBaseAtas-kiriTop-leftScreenSettingsDialogBaseAtas-kanan Top-rightScreenSettingsDialogBaseBaru&NewServerConfigDialogBase Hapus&RemoveServerConfigDialogBase4Pengaturan server lanjutanAdvanced server settingsServerConfigDialogBaseUbahE&ditServerConfigDialogBaseBaruNe&wServerConfigDialogBase HapusRe&moveServerConfigDialogBase$Konfigurasi serverServer ConfigurationServerConfigDialogBaseInformasiInfoSettingsDialogBasePengaturanSettingsSettingsDialogBasedSynergy akan mempermudah dalam membagi tetikus dan papan ketik diantara beberapa komputer yang berlainan, dan ini adalah software bebas dan bersumber terbuka. Hanya dengan menggeser tetikus ke pojok layar komputer maka akan berpindah ke layar komputer lainnya. Bahkan kamu dapat membagikan clipboard kamu. Yang kamu butuhkan hanya koneksi jaringan. Synerg adalah program yang dapat berjalan di beberapa Operating System yang berbeda. ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseTak dikenalUnknownVersionCheckersynergy-1.8.8-stable/src/gui/res/lang/gui_id.ts000066400000000000000000001616641305627404700214230ustar00rootroot00000000000000 AboutDialogBase About Synergy Tentang Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Tak dikenal Version: Versi: &Ok Oke ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left right up down Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Memulai Synergy. Synergy is running. Synergy is not running. Synergy tidak berjalan. Unknown Tak dikenal Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Siap Log Laporan &Apply IP addresses: Alamat IP: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run Jalankan S&top Berhenti Stop Berhenti S&how Status Perlihatkan kondisi &Hide &Sembunyi Hide Sembunyi &Show Show Save configuration &as... Simpan konfigurasi sebagai... Save the interactively generated server configuration to a file. Settings Pengaturan Edit settings Ubah pengaturan Run Wizard NewScreenWidget Unnamed Tanpa nama PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. System tidak memungkinkan, keluar. ScreenSettingsDialog Screen name is empty Nama layar kosong The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Pengaturan Layar Screen &name: Nama Layar: A&liases Nama lain &Add Masukan &Remove Hapus &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Ctrl: Al&t: Alt: M&eta: S&uper: &Dead corners Top-left Atas-kiri Top-right Atas-kanan Bottom-left Bawah-kiri Bottom-right Bawah-kanan Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Konfigurasi server Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New Baru &Edit &Remove Hapus A&ctions Ne&w Baru E&dit Ubah Re&move Hapus Advanced server settings Pengaturan server lanjutan &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Pengaturan Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Informasi Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy akan mempermudah dalam membagi tetikus dan papan ketik diantara beberapa komputer yang berlainan, dan ini adalah software bebas dan bersumber terbuka. Hanya dengan menggeser tetikus ke pojok layar komputer maka akan berpindah ke layar komputer lainnya. Bahkan kamu dapat membagikan clipboard kamu. Yang kamu butuhkan hanya koneksi jaringan. Synerg adalah program yang dapat berjalan di beberapa Operating System yang berbeda. Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Tak dikenal WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_is-IS.qm000066400000000000000000000000201305627404700217140ustar00rootroot00000000000000 AboutDialogBase About Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: &Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left right up down Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_it.qm000066400000000000000000000525371305627404700214300ustar00rootroot00000000000000^I(+[H4(SWuYu&G27*DW<,OG:VE,VEUg!`"+**1*%N*0z*+L+g+`G:Gz(JCwLbDU`XY-Z.xx.v>6A|}Su>(Z = nbj"4.vHZNEv.'_%e;w9&' j;H}H.O #JO GO H_]E VE -gUN*JYu:Dl_ } #*=lf0CC 7:&:1f B B$ZBJ,"QJS-izE@d(l ,攄@J!Y(H ( n4.d.O@Ty*L#A{2pL6> pz)>JC3 + 3=Tk@d0 %C'`}F:nvC>3x$X I_` JzE k#5p v~95 

5 bun>y~F r/7+'kC:_k1.4Y>a)iOOk&OkAboutDialogBase$Riguardo a Synergy About SynergyAboutDialogBaseSconosciutoUnknownAboutDialogBaseVersione:Version:AboutDialogBase6Scegli l'azione da compiereChoose the action to performActionDialogBase Configura azioneConfigure ActionActionDialogBase>Blocca il cursore sullo schermoLock cursor to screenActionDialogBase Premi una hotkeyPress a hotkeyActionDialogBase6Premi e rilascia una hotkeyPress and release a hotkeyActionDialogBase&Rilascia una hotkeyRelease a hotkeyActionDialogBase$Passa in direzioneSwitch in directionActionDialogBasePassa a schermoSwitch to screenActionDialogBaseNQuesta operazione viene eseguita quandoThis action is performed whenActionDialogBasegiu'downActionDialogBasesinistraleftActionDialogBasedisattivaoffActionDialogBase attivaonActionDialogBase,solo su questi schermionly on these screensActionDialogBase destrarightActionDialogBase.la hotkey viene premutathe hotkey is pressedActionDialogBase4la hotkey viene rilasciatathe hotkey is releasedActionDialogBasescambiatoggleActionDialogBasesuupActionDialogBaseDSpecifica la hotkey da utilizzare:'Enter the specification for the hotkey:HotkeyDialogBase HotkeyHotkeyHotkeyDialogBaseModifica&Edit MainWindowFile&File MainWindow Aiuto&Help MainWindow Avvia&Start MainWindow Ferma&Stop MainWindowFinestra&Window MainWindowSfoglia il contenuto del tuo computer per un file di configurazione di Synergy!Browse for a synergys config file MainWindowXNon posso scrivere il file di configurazioneCannot write configuration file MainWindowXIl nome file di configurazione non valido.Configuration filename invalid MainWindowrImpossibile salvare la configurazione attuale in un file.%Could not save configuration to file. MainWindow0Il nome macchina vuotoHostname is empty MainWindowSi prega di completare il nome macchina per permettere al client Synergy di connettercisi.?Please fill in a hostname for the synergy client to connect to. MainWindowHIl programma non puo' essere avviatoProgram can not be started MainWindowNSalva la configurazione attuale come...Save configuration as... MainWindow&Salvataggio fallito Save failed MainWindowSynergySynergy MainWindownLa componente client di Synergy non stata individuataSynergy client not found MainWindow4Synergy non in funzione.Synergy is not running. MainWindow,Synergy in funzione.Synergy is running. MainWindow0Synergy si sta avviando.Synergy is starting. MainWindowfLa componente server di Synergy non stata trovataSynergy server not found MainWindow Synergy si chiuso inaspettatamente con un codice di uscita di %1.<br><br> Sei pregato di visualizzare il log per maggiori dettagli.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowBSynergy si chiuso con un errore Synergy terminated with an error MainWindowbL'eseguibile per il client di Synergy non esiste.5The executable for the synergy client does not exist. MainWindow\L'eseguibile per il server Synergy non esiste.5The executable for the synergy server does not exist. MainWindowlL'eseguibile <br><br>%1<br><br>non puo' essere correttamente avviato, anche se esiste. Controlla di avere i permessi necessari ad eseguire il programma (Super User o Administrator?).The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowIl file temporaneo di configurazione necessario ad avviare Synergy non puo' essere scritto.NThe temporary configuration file required to start synergy can not be written. MainWindowSconosciutoUnknown MainWindowxNon hai specificato un nome di file di configurazione valido per la componente server di Synergy. Vuoi sfogliare il contenuto del tuo computer per il trovare il file di configurazione ora?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow*Riguardo a Synergy...&About Synergy...MainWindowBaseApplica&ApplyMainWindowBaseSfoglia... &Browse...MainWindowBase.File di configurazione:&Configuration file:MainWindowBase,Configura il Server...&Configure Server...MainWindowBaseNascondi&HideMainWindowBase Chiudi&QuitMainWindowBaseServer IP: &Server IP:MainWindowBase Mostra&ShowMainWindowBase Avvia&StartMainWindowBase6Configurazione interattiva:Configure interactively:MainWindowBase*Modifica impostazioni Edit settingsMainWindowBaseNascondiHideMainWindowBaseIndirizzi IP: IP addresses:MainWindowBase EventiLogMainWindowBase ChiudiQuitMainWindowBase ProntoReadyMainWindowBase EseguiRunMainWindowBase Esegui il Wizard Run WizardMainWindowBase Visualizza stato S&how StatusMainWindowBase FermaS&topMainWindowBase8Salva configurazione come...Save configuration &as...MainWindowBasetSalva la configurazione interattiva del server in un file.@Save the interactively generated server configuration to a file.MainWindowBaseNome schermo: Screen name:MainWindowBaseImpostazioniSettingsMainWindowBase MostraShowMainWindowBase FermaStopMainWindowBaseSynergySynergyMainWindowBaseLUtilizza una configurazione esistente:Use existing configuration:MainWindowBaseSenza nomeUnnamedNewScreenWidget"Configura Synergy Setup SynergyPluginWizardPagenConfigurazioni di Synergy (*.conf);;Tutti i files (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectlConfigurazioni di Synergy (*.sgc);;Tutti i files (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectL'icona nella barra di sistema non disponibile, sto chiudendo.%System tray is unavailable, quitting.QObject:Il nome dello schermo vuotoScreen name is emptyScreenSettingsDialogAggiungi&AddScreenSettingsDialogBase Ctrl:&Ctrl:ScreenSettingsDialogBaseAngoli morti &Dead cornersScreenSettingsDialogBasePunti fissi&FixesScreenSettingsDialogBaseTasti speciali&Modifier keysScreenSettingsDialogBaseRimuovi&RemoveScreenSettingsDialogBase Shift:&Shift:ScreenSettingsDialogBaseSoprannomiA&liasesScreenSettingsDialogBaseAlt:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase&In basso a sinistra Bottom-leftScreenSettingsDialogBase"In basso a destra Bottom-rightScreenSettingsDialogBase,Dimensione dell'angolo Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase2Blocca il tasto CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase0Blocca il tasto NUM LOCKFix NUM LOCK keyScreenSettingsDialogBase6Blocca il tasto SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase2Blocca XTest per XineramaFix XTest for XineramaScreenSettingsDialogBase Meta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseNessunoNoneScreenSettingsDialogBase Super:S&uper:ScreenSettingsDialogBase&Nome dello schermo: Screen &name:ScreenSettingsDialogBase4Impostazioni dello schermoScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBase$In alto a sinistraTop-leftScreenSettingsDialogBase In alto a destra Top-rightScreenSettingsDialogBase<center>Schermo: <b>%1</b></center><br>Doppio click per modificare le impostazioni<br>Trascina lo schermo nel cestino per rimuoverloo

Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel&In basso a sinistra &Bottom-leftServerConfigDialogBase0Controlla il client ogni&Check clients everyServerConfigDialogBaseAngoli morti &Dead cornersServerConfigDialogBaseModifica&EditServerConfigDialogBaseHotkeys&HotkeysServerConfigDialogBase Nuovo&NewServerConfigDialogBaseOpzioni&OptionsServerConfigDialogBaseRimuovi&RemoveServerConfigDialogBaseScambia&SwitchServerConfigDialogBaseOperazioniA&ctionsServerConfigDialogBaseDConfigurazioni avanzate del serverAdvanced server settingsServerConfigDialogBase"In basso a destra Bottom-ri&ghtServerConfigDialogBaseLConfigura il layout del server Synergy:Configure the layout of your synergy server configuration.ServerConfigDialogBase.Dimensione dell'angolo: Cor&ner Size:ServerConfigDialogBasevNon prendere la finestra in primo piano sui servers Windows0Don't take &foreground window on Windows serversServerConfigDialogBasexTrascina uno schermo dalla griglia al cestino per rimuoverlo9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaseXTrascina nuovi schermi sulla griglia o muovi quelli esistenti. Trascina uno schermo sul cestino per rimuoverlo. Doppio click su uno schermo per modificarne le impostazioni.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBaseTrascina questo pulsante sulla griglia per aggiungere un nuovo schermo.1Drag this button to the grid to add a new screen.ServerConfigDialogBaseModificaE&ditServerConfigDialogBaseHotkeysHotkeysServerConfigDialogBase NuovoNe&wServerConfigDialogBaseRimuoviRe&moveServerConfigDialogBase:Sincronizza gli screen saversS&ynchronize screen saversServerConfigDialogBase,Schermi e collegamentiScreens and linksServerConfigDialogBase2Configurazione del ServerServer ConfigurationServerConfigDialogBase<Scambia al termine dell'attesaSwitch &after waitingServerConfigDialogBase0Scambia con doppio toccoSwitch on double &tap withinServerConfigDialogBase$In alto a sinistra To&p-leftServerConfigDialogBase In alto a destra Top-rig&htServerConfigDialogBaseNUtilizza i movimenti del mouse relativiUse &relative mouse movesServerConfigDialogBasemillisecondimsServerConfigDialogBaseSei sicuro di voler elevare Synergy? Ci consentir a Synergy di interagire con molti processi e con il dialogo UAC,ma potrebbe casusare problemi con i processi non elevati.Eleva Synergy solo se ti serve davvero.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogEleva SynergyElevate SynergySettingsDialog.Salva il file di log...Save log file to...SettingsDialogInterfaccia: &Interface:SettingsDialogBase Lingua &Language:SettingsDialogBase>Livello di registrazione eventi&Logging level:SettingsDialogBaseSfoglia... Browse...SettingsDialogBase DebugDebugSettingsDialogBase Debug1Debug1SettingsDialogBase Debug2Debug2SettingsDialogBase ErroreErrorSettingsDialogBaseInformazioniInfoSettingsDialogBase<Registra gli eventi in un file Log to file:SettingsDialogBaseRegistro EventiLoggingSettingsDialogBaseNotaNoteSettingsDialogBase Porta:P&ort:SettingsDialogBase&Nome dello schermo: Sc&reen name:SettingsDialogBaseImpostazioniSettingsSettingsDialogBase AvvisoWarningSettingsDialogBase^Inserisci il tuo indirizzo email e la password.-Please enter your email address and password. SetupWizard<Pregasi selezionare un'opzionePlease select an option. SetupWizard"Configura Synergy Setup Synergy SetupWizard Server o Client?Server or Client?SetupWizardBase"Configura Synergy Setup SynergySetupWizardBasezSynergy ti permette facilmente di condividere il mouse e la tastiera tra piu' computers sulla tua scrivania, un software Libero e Gratuito. Ti basta muovere il mouse oltre i bordi dello schermo per passare da un computer ad un altro. Puoi anche condividere la bacheca degli appunti (Copia e Incolla). Tutto cio' che serve una connessione di rete (WiFi o LAN). Synergy multi-piattaforma (Funziona correttamente su Windows, Mac OS X e Linux)ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseFGrazie per aver installato Synergy!Thanks for installing Synergy!SetupWizardBase*Ti diamo il benvenutoWelcomeSetupWizardBaseSconosciutoUnknownVersionChecker`Login non riuscito, email o password non valida.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_it.ts000066400000000000000000001711561305627404700214400ustar00rootroot00000000000000 AboutDialogBase About Synergy Riguardo a Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Sconosciuto Version: Versione: &Ok Ok ActionDialogBase Configure Action Configura azione Choose the action to perform Scegli l'azione da compiere Press a hotkey Premi una hotkey Release a hotkey Rilascia una hotkey Press and release a hotkey Premi e rilascia una hotkey only on these screens solo su questi schermi Switch to screen Passa a schermo Switch in direction Passa in direzione left sinistra right destra up su down giu' Lock cursor to screen Blocca il cursore sullo schermo toggle scambia on attiva off disattiva This action is performed when Questa operazione viene eseguita quando the hotkey is pressed la hotkey viene premuta the hotkey is released la hotkey viene rilasciata AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Hotkey Enter the specification for the hotkey: Specifica la hotkey da utilizzare: MainWindow &Start Avvia &File File &Edit Modifica &Window Finestra &Help Aiuto <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started Il programma non puo' essere avviato The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. L'eseguibile <br><br>%1<br><br>non puo' essere correttamente avviato, anche se esiste. Controlla di avere i permessi necessari ad eseguire il programma (Super User o Administrator?). Synergy client not found La componente client di Synergy non è stata individuata The executable for the synergy client does not exist. L'eseguibile per il client di Synergy non esiste. Hostname is empty Il nome macchina è vuoto Please fill in a hostname for the synergy client to connect to. Si prega di completare il nome macchina per permettere al client Synergy di connettercisi. Cannot write configuration file Non posso scrivere il file di configurazione The temporary configuration file required to start synergy can not be written. Il file temporaneo di configurazione necessario ad avviare Synergy non puo' essere scritto. Configuration filename invalid Il nome file di configurazione non è valido. You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Non hai specificato un nome di file di configurazione valido per la componente server di Synergy. Vuoi sfogliare il contenuto del tuo computer per il trovare il file di configurazione ora? Synergy server not found La componente server di Synergy non è stata trovata The executable for the synergy server does not exist. L'eseguibile per il server Synergy non esiste. Synergy terminated with an error Synergy si è chiuso con un errore Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy si è chiuso inaspettatamente con un codice di uscita di %1.<br><br> Sei pregato di visualizzare il log per maggiori dettagli. &Stop Ferma Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy si sta avviando. Synergy is running. Synergy è in funzione. Synergy is not running. Synergy non è in funzione. Unknown Sconosciuto Synergy Synergy Browse for a synergys config file Sfoglia il contenuto del tuo computer per un file di configurazione di Synergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Salva la configurazione attuale come... Save failed Salvataggio fallito Could not save configuration to file. Impossibile salvare la configurazione attuale in un file. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Nome schermo: &Server IP: Server IP: &Start Avvia Use existing configuration: Utilizza una configurazione esistente: &Configuration file: File di configurazione: &Browse... Sfoglia... Configure interactively: Configurazione interattiva: &Configure Server... Configura il Server... Ready Pronto Log Eventi &Apply Applica IP addresses: Indirizzi IP: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Riguardo a Synergy... &Quit Chiudi Quit Chiudi Run Esegui S&top Ferma Stop Ferma S&how Status Visualizza stato &Hide Nascondi Hide Nascondi &Show Mostra Show Mostra Save configuration &as... Salva configurazione come... Save the interactively generated server configuration to a file. Salva la configurazione interattiva del server in un file. Settings Impostazioni Edit settings Modifica impostazioni Run Wizard Esegui il Wizard NewScreenWidget Unnamed Senza nome PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Configura Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Configurazioni di Synergy (*.sgc);;Tutti i files (*.*) Synergy Configurations (*.conf);;All files (*.*) Configurazioni di Synergy (*.conf);;Tutti i files (*.*) System tray is unavailable, quitting. L'icona nella barra di sistema non è disponibile, sto chiudendo. ScreenSettingsDialog Screen name is empty Il nome dello schermo è vuoto The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Impostazioni dello schermo Screen &name: Nome dello schermo: A&liases Soprannomi &Add Aggiungi &Remove Rimuovi &Modifier keys Tasti speciali &Shift: Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Nessuno &Ctrl: Ctrl: Al&t: Alt: M&eta: Meta: S&uper: Super: &Dead corners Angoli morti Top-left In alto a sinistra Top-right In alto a destra Bottom-left In basso a sinistra Bottom-right In basso a destra Corner Si&ze: Dimensione dell'angolo &Fixes Punti fissi Fix CAPS LOCK key Blocca il tasto CAPS LOCK Fix NUM LOCK key Blocca il tasto NUM LOCK Fix SCROLL LOCK key Blocca il tasto SCROLL LOCK Fix XTest for Xinerama Blocca XTest per Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Schermo: <b>%1</b></center><br>Doppio click per modificare le impostazioni<br>Trascina lo schermo nel cestino per rimuoverlo ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Configurazione del Server Screens and links Schermi e collegamenti Drag a screen from the grid to the trashcan to remove it. Trascina uno schermo dalla griglia al cestino per rimuoverlo Configure the layout of your synergy server configuration. Configura il layout del server Synergy Drag this button to the grid to add a new screen. Trascina questo pulsante sulla griglia per aggiungere un nuovo schermo. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Trascina nuovi schermi sulla griglia o muovi quelli esistenti. Trascina uno schermo sul cestino per rimuoverlo. Doppio click su uno schermo per modificarne le impostazioni. Hotkeys Hotkeys &Hotkeys Hotkeys &New Nuovo &Edit Modifica &Remove Rimuovi A&ctions Operazioni Ne&w Nuovo E&dit Modifica Re&move Rimuovi Advanced server settings Configurazioni avanzate del server &Switch Scambia Switch &after waiting Scambia al termine dell'attesa ms millisecondi Switch on double &tap within Scambia con doppio tocco &Options Opzioni &Check clients every Controlla il client ogni Use &relative mouse moves Utilizza i movimenti del mouse relativi S&ynchronize screen savers Sincronizza gli screen savers Don't take &foreground window on Windows servers Non prendere la finestra in primo piano sui servers Windows Ignore auto config clients &Dead corners Angoli morti To&p-left In alto a sinistra Top-rig&ht In alto a destra &Bottom-left In basso a sinistra Bottom-ri&ght In basso a destra Cor&ner Size: Dimensione dell'angolo: SettingsDialog Save log file to... Salva il file di log... Elevate Synergy Eleva Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Sei sicuro di voler elevare Synergy? Ciò consentirà a Synergy di interagire con molti processi e con il dialogo UAC,ma potrebbe casusare problemi con i processi non elevati.Eleva Synergy solo se ti serve davvero. SettingsDialogBase Settings Impostazioni Sc&reen name: Nome dello schermo: P&ort: Porta: &Interface: Interfaccia: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Registro Eventi &Logging level: Livello di registrazione eventi Log to file: Registra gli eventi in un file Browse... Sfoglia... Error Errore &Language: Lingua &Miscellaneous Warning Avviso Note Nota Info Informazioni Debug Debug Debug1 Debug1 Debug2 Debug2 SetupWizard Setup Synergy Configura Synergy Please select an option. Pregasi selezionare un'opzione Please enter your email address and password. Inserisci il tuo indirizzo email e la password. SetupWizardBase Setup Synergy Configura Synergy Welcome Ti diamo il benvenuto Thanks for installing Synergy! Grazie per aver installato Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy ti permette facilmente di condividere il mouse e la tastiera tra piu' computers sulla tua scrivania, è un software Libero e Gratuito. Ti basta muovere il mouse oltre i bordi dello schermo per passare da un computer ad un altro. Puoi anche condividere la bacheca degli appunti (Copia e Incolla). Tutto cio' che serve è una connessione di rete (WiFi o LAN). Synergy è multi-piattaforma (Funziona correttamente su Windows, Mac OS X e Linux) Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Server o Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Sconosciuto WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login non riuscito, email o password non valida. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_ja-JP.qm000066400000000000000000000417431305627404700217120ustar00rootroot00000000000000)&}S!u>(Z = nbjq4 $v8YZ=@Ev.S_Ye-dw9Zf ;H}H$RO O 7tO 8 ]5f|CVE#aUN Yu:5l_} @*/Kl%4H4 *::&>\ 3$$Z3Y J""QJ-iz5@dl "攄Ju(7:S( nk4.d$@Ty L#2L{'& Nz5>3J3 3=T k@d%yc<>%=C4}F-.n,C/( I_ Jz5 k#)f v~+ .V -5A Pn. d ~5- ~q< ք~ ȹ ȹ9 ȹ= a2 |# Fw F'c Z ' KG @{ y RVr RV RV< R ! T V4  |*2 c' s s6> c. F Ҫ ^ / 4p/ d! i!  r+ zkQ P6q ¦e; x4(g ]^ s^71\;[=> )"bun0y~6m r d/7!IkC,k&.(>  i>OK&OkAboutDialogBaseSynergy0k0d0D0f About SynergyAboutDialogBaseN fUnknownAboutDialogBase 00000:Version:AboutDialogBase[L0Y0RO\0xbChoose the action to performActionDialogBase RO\0ibConfigure ActionActionDialogBase00000u;b0kP[Lock cursor to screenActionDialogBase000000b0YPress a hotkeyActionDialogBase000000b0W0f0YPress and release a hotkeyActionDialogBase0000000YRelease a hotkeyActionDialogBaseR0f0H0eTSwitch in directionActionDialogBaseu;b0kR0f0HSwitch to screenActionDialogBase0S0nRO\0[L0Y0fB: This action is performed whenActionDialogBaseN downActionDialogBase]leftActionDialogBase00offActionDialogBase00onActionDialogBase0S000nu;b0`0Qonly on these screensActionDialogBaseSrightActionDialogBase000000b0W0_0h0Mthe hotkey is pressedActionDialogBase0000000W0_0h0Mthe hotkey is releasedActionDialogBaseR0f0HtoggleActionDialogBaseN upActionDialogBase(000000nc[el0QeR0W0f0O0`0U0D:'Enter the specification for the hotkey:HotkeyDialogBase 00000HotkeyHotkeyDialogBase}&Edit MainWindow0000&File MainWindow000&Help MainWindowY&Start MainWindowP\kb&Stop MainWindow 00000&Window MainWindow"Synergy0n-[00000Sqg!Browse for a synergys config file MainWindowib00000kf0M00~0[0Cannot write configuration file MainWindow"ib0000T 0Lkc0W0O0B00~0[00Configuration filename invalid MainWindow$-[000000kO[X0g0M0~0[00g0W0_%Could not save configuration to file. MainWindow000T 0LQeR0U00f0D0~0[0Hostname is empty MainWindow@Synergy0000000gc}0Y0000T 0QeR0W0f0O0`0U0D0?Please fill in a hostname for the synergy client to connect to. MainWindow000000Y0g0M0~0[0Program can not be started MainWindow-[0kT RM00d0Q0fO[XSave configuration as... MainWindowO[X0g0M0~0[00g0W0_ Save failed MainWindowSynergySynergy MainWindow*Synergy0000000L0d0K00~0[0Synergy client not found MainWindow"Synergy0oRO\0W0f0D0~0[00Synergy is not running. MainWindowSynergy0oRO\N-0g0Y0Synergy is running. MainWindowSynergy0YN-0g0Y0Synergy is starting. MainWindow&Synergy00000L0d0K00~0[0Synergy server not found MainWindowlSynergy0oNg0W0j0D}BN000%10g}BN0W0~0W0_0<br><br>s}00o000nQR0Sqg0W0f0O0`0U0D0fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow$Synergy0o0000g}BN0W0~0W0_ Synergy terminated with an error MainWindow8Synergy0000000n[L00000L[XW(0W0~0[005The executable for the synergy client does not exist. MainWindow4Synergy00000n[L00000L[XW(0W0~0[005The executable for the synergy server does not exist. MainWindow[L0000<br><br>%1<br><br>0o[XW(0W0~0Y0L0Y0g0M0~0[00g0W0_00S0n000000RO\0U0[0SAR0jj)P0L0B00K0i0F0Kx0W0f0O0`0U0D0The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowBSynergy0nY0k_ʼn0jNfBv0jib00000f0M00~0[00NThe temporary configuration file required to start synergy can not be written. MainWindowN fUnknown MainWindow`Synergy00000nkc0W0Dib00000f0M00g0D0~0[00N0ib000000W0~0Y0K?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindowSynergy0k0d0D0f...&About Synergy...MainWindowBaseiu(&ApplyMainWindowBaseSqg &Browse...MainWindowBase-[0000:&Configuration file:MainWindowBase00000-[&Configure Server...MainWindowBase0Y&HideMainWindowBase}BN&QuitMainWindowBase0000 IP: &Server IP:MainWindowBasehy:0Y0&ShowMainWindowBaseY&StartMainWindowBase000000000000g-[:Configure interactively:MainWindowBase -[0} Edit settingsMainWindowBase0YHideMainWindowBaseIP0000: IP addresses:MainWindowBase00LogMainWindowBase}BNQuitMainWindowBasenP[NReadyMainWindowBase[LRunMainWindowBase000000[L0Y0 Run WizardMainWindowBase raK0hy: S&how StatusMainWindowBaseP\kbS&topMainWindowBase-[0kT RM00d0Q0fO[XSave configuration &as...MainWindowBase:000000000000gub0W0_000Њ-[000000kO[X@Save the interactively generated server configuration to a file.MainWindowBase u;b0nT RM: Screen name:MainWindowBase-[SettingsMainWindowBasehy:0Y0ShowMainWindowBaseP\kbStopMainWindowBaseSynergySynergyMainWindowBasee[X0n-[0Ou(Use existing configuration:MainWindowBaseT RM0j0WUnnamedNewScreenWidgetSynergy0n000000 Setup SynergyPluginWizardPageBSynergy0nib(*.conf);;0Y0y0f0n0000(*.*)0Synergy Configurations (*.conf);;All files (*.*)QObject@Synergy0nib(*.sgc);;0Y0y0f0n0000(*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObject*0000000R)u(0g0M0~0[00}BN0W0~0Y0%System tray is unavailable, quitting.QObjectu;b0nT RM0Lzz0g0Y0Screen name is emptyScreenSettingsDialogu;b0nT RM0oR%T 0hNScreen name matches aliasScreenSettingsDialogZu;b0nT RM0zz0k0Y00S0h0o0g0M0~0[00T RM0QeR0Y00K000000000000W0f0O0`0U0D0SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialog\u;b0nT RM0R%T 0hT 0X0k0Y00S0h0oQge0~0[00R%T 0RJd0Y00Ku;b0nT RM0Y f0W0f0O0`0U0D0iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialogR&AddScreenSettingsDialogBase&undefinedCtrl:&Ctrl:ScreenSettingsDialogBase q!R0h0Y0 &Dead cornersScreenSettingsDialogBaseOkc&FixesScreenSettingsDialogBaseO00&Modifier keysScreenSettingsDialogBaseRJd&RemoveScreenSettingsDialogBase000&Shift:ScreenSettingsDialogBaseR%T A&liasesScreenSettingsDialogBase&undefinedl&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase]N  Bottom-leftScreenSettingsDialogBaseSN  Bottom-rightScreenSettingsDialogBase 0nY'0M0U Corner Si&ze:ScreenSettingsDialogBase 000000CtrlScreenSettingsDialogBaseCAPS000000V[Fix CAPS LOCK keyScreenSettingsDialogBaseNUM000000V[Fix NUM LOCK keyScreenSettingsDialogBaseSCROLL000000V[Fix SCROLL LOCK keyScreenSettingsDialogBase&XineramaT0Q0kXTest0OkcFix XTest for XineramaScreenSettingsDialogBase&undefined&eta:M&eta:ScreenSettingsDialogBase00MetaScreenSettingsDialogBase0j0WNoneScreenSettingsDialogBase &undefined&uper:S&uper:ScreenSettingsDialogBase u;b0nT RM Screen &name:ScreenSettingsDialogBase u;b0n-[Screen SettingsScreenSettingsDialogBase000ShiftScreenSettingsDialogBase0000SuperScreenSettingsDialogBase]N Top-leftScreenSettingsDialogBaseSN  Top-rightScreenSettingsDialogBase<center>u;b: <b>%1</b></center><br>00000000g-[0}<br>RJd0Y00h0M0ou;b000{0k00000W0~0Yo
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel]N  &Bottom-leftServerConfigDialogBase000000x;^&Check clients everyServerConfigDialogBase q!R0h0Y0 &Dead cornersServerConfigDialogBase}&EditServerConfigDialogBase 00000&HotkeysServerConfigDialogBasee&NewServerConfigDialogBase 00000&OptionsServerConfigDialogBaseRJd&RemoveServerConfigDialogBaseR0f0H&SwitchServerConfigDialogBase 00000A&ctionsServerConfigDialogBase00000ns}00j-[Advanced server settingsServerConfigDialogBaseSN  Bottom-ri&ghtServerConfigDialogBase000ib0nMn0-[0Y0:Configure the layout of your synergy server configuration.ServerConfigDialogBase 0nY'0M0U: Cor&ner Size:ServerConfigDialogBase2Windows0000g000000RMb0khy:0W0j0D0Don't take &foreground window on Windows serversServerConfigDialogBaseg,_S0k Synergy 0fh<0U0[0f000W0D0g0Y0K 0S00k00fh<0U00_00000 UAC dialog 0h0Synergy 0h0LN0D0kO\u(0W0B0F0S0h0L0g0M000F0k0j0S͗b0fh<0U00f0D0j0D00000h0n0gUOL0u0X00S0h00B0_0~0Y0x0K0k_ʼn0g0B00hR$e0g0M0X4T0k0n0 Synergy 0nfh<0L0c0f0O0`0U0D0Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogSynergy0nj)Pfh<Elevate SynergySettingsDialog0000000nO[XQHSave log file to...SettingsDialog00000000: &Interface:SettingsDialogBase &Language:SettingsDialogBase 00000:&Logging level:SettingsDialogBase0]0nN&MiscellaneousSettingsDialogBase Sqg... Browse...SettingsDialogBase 0000`X1DebugSettingsDialogBase0000`X11Debug1SettingsDialogBase0000`X12Debug2SettingsDialogBase000ErrorSettingsDialogBase`X1InfoSettingsDialogBase002QH0000: Log to file:SettingsDialogBase00LoggingSettingsDialogBasewNoteSettingsDialogBase000:P&ort:SettingsDialogBase00000T : Sc&reen name:SettingsDialogBase-[SettingsSettingsDialogBasefTJWarningSettingsDialogBase.00000000h000000QeR0W0f0O0`0U0D0-Please enter your email address and password. SetupWizard000000xb0W0f0O0`0U0D0Please select an option. SetupWizardSynergy0n000000 Setup Synergy SetupWizard00000~0_0o000000Server or Client?SetupWizardBaseSynergy0n000000 Setup SynergySetupWizardBaseSynergy0oep0n0000000n0000h000000|!SX0kQqg 0Y00S0h0L0g0M00000n00000000000000g0Y00B00000000nu;b0nz0k0000yR0Y00hR%0n0000000nu;b0ky00~0Y000000000Qqg 0Y00S0h00g0M0~0Y0_ʼn0j0n0o 000000c}0`0Q0g0Y0 Synergy0o000000000000gWindows, Mac OS X, LinuxN 0gRO\0W0~0Y0ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBase@Synergy00000000W0f0D0_0`0M00B00L0h0F0T0V0D0~0YThanks for installing Synergy!SetupWizardBase00F0S0]WelcomeSetupWizardBaseN fUnknownVersionChecker.0000Lvzu0W000000LY1eW0W0~0W0_0 %1$Login failed, an error occurred. %1 WebClient>0000Lvzu0W000000LY1eW0W0~0W0_0 0000n_{T %16Login failed, an error occurred. Server response: %1 WebClientB00000oY1eW0W0~0W0_000000000~0_0o000000Lq!R0g0Y0(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_ja-JP.ts000066400000000000000000001734161305627404700217260ustar00rootroot00000000000000 AboutDialogBase About Synergy Synergyについて <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown 不明 Version: バージョン: &Ok OK ActionDialogBase Configure Action 動作を構成 Choose the action to perform 実行する動作を選択 Press a hotkey ホットキーを押す Release a hotkey ホットキーを離す Press and release a hotkey ホットキーを押して離す only on these screens これらの画面だけ Switch to screen 画面に切り替え Switch in direction 切り替える方向 left right up down Lock cursor to screen カーソルを画面に限定 toggle 切り替え on オン off オフ This action is performed when この動作を実行する時: the hotkey is pressed ホットキーを押したとき the hotkey is released ホットキーを離したとき AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey ホットキー Enter the specification for the hotkey: ホットキーの指定方法を入力してください: MainWindow &Start 開始 &File ファイル &Edit 編集 &Window ウィンドウ &Help ヘルプ <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started プログラムを開始できません The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. 実行ファイル<br><br>%1<br><br>は存在しますが、開始できませんでした。このプログラムを動作させる十分な権限があるかどうか確認してください。 Synergy client not found Synergyクライアントが見つかりません The executable for the synergy client does not exist. Synergyクライアントの実行ファイルが存在しません。 Hostname is empty ホスト名が入力されていません Please fill in a hostname for the synergy client to connect to. Synergyクライアントで接続するホスト名を入力してください。 Cannot write configuration file 構成ファイルに書き込めません The temporary configuration file required to start synergy can not be written. Synergyの開始に必要な一時的な構成ファイルを書き込めません。 Configuration filename invalid 構成ファイル名が正しくありません。 You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergyサーバーの正しい構成ファイルを書き込んでいません。今、構成ファイルを閲覧しますか? Synergy server not found Synergyサーバーが見つかりません The executable for the synergy server does not exist. Synergyサーバーの実行ファイルが存在しません。 Synergy terminated with an error Synergyはエラーで終了しました Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergyは予期しない終了コード%1で終了しました。<br><br>詳細はログの出力を参照してください。 &Stop 停止 Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergyを開始中です。 Synergy is running. Synergyは動作中です。 Synergy is not running. Synergyは動作していません。 Unknown 不明 Synergy Synergy Browse for a synergys config file Synergyの設定ファイルを参照 Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... 設定に名前をつけて保存 Save failed 保存できませんでした Could not save configuration to file. 設定をファイルに保存できませんでした MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: 画面の名前: &Server IP: サーバー IP: &Start 開始 Use existing configuration: 既存の設定を使用 &Configuration file: 設定ファイル: &Browse... 参照 Configure interactively: インタラクティブモードで設定: &Configure Server... サーバーを設定 Ready 準備完了 Log ログ &Apply 適用 IP addresses: IPアドレス: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Synergyについて... &Quit 終了 Quit 終了 Run 実行 S&top 停止 Stop 停止 S&how Status 状態を表示 &Hide 隠す Hide 隠す &Show 表示する Show 表示する Save configuration &as... 設定に名前をつけて保存 Save the interactively generated server configuration to a file. インタラクティブモードで生成したサーバ設定をファイルに保存 Settings 設定 Edit settings 設定を編集 Run Wizard ウィザードを実行する NewScreenWidget Unnamed 名前なし PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Synergyのセットアップ Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergyの構成(*.sgc);;すべてのファイル(*.*) Synergy Configurations (*.conf);;All files (*.*) Synergyの構成(*.conf);;すべてのファイル(*.*) System tray is unavailable, quitting. タスクトレイを利用できません。終了します。 ScreenSettingsDialog Screen name is empty 画面の名前が空です。 The screen name cannot be empty. Please either fill in a name or cancel the dialog. 画面の名前を空にすることはできません。名前を入力するかダイアログをキャンセルしてください。 Screen name matches alias 画面の名前は別名と一致 The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. 画面の名前を別名と同じにすることは出来ません。別名を削除するか画面の名前を変更してください。 ScreenSettingsDialogBase Screen Settings 画面の設定 Screen &name: 画面の名前 A&liases 別名 &Add 追加 &Remove 削除 &Modifier keys 修飾キー &Shift: シフト Shift シフト Ctrl コントロール Alt Alt Meta メタ Super スーパー None なし &Ctrl: &undefinedCtrl: Al&t: &undefinedl&t: M&eta: &undefined&eta: S&uper: &undefined&uper: &Dead corners 無効とする角 Top-left 左上 Top-right 右上 Bottom-left 左下 Bottom-right 右下 Corner Si&ze: 角の大きさ &Fixes 修正 Fix CAPS LOCK key CAPSロックキーを固定 Fix NUM LOCK key NUMロックキーを固定 Fix SCROLL LOCK key SCROLLロックキーを固定 Fix XTest for Xinerama Xinerama向けにXTestを修正 ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>画面: <b>%1</b></center><br>ダブルクリックで設定を編集<br>削除するときは画面をゴミ箱にドラッグします ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration サーバーの構成 Screens and links 画面とリンク Drag a screen from the grid to the trashcan to remove it. 削除する時はグリッド内の画面をゴミ箱にドラッグしてください。 Configure the layout of your synergy server configuration. サーバ構成の配置を設定する Drag this button to the grid to add a new screen. 新規画面の追加はこのボタンをグリッド内にドラッグします。 Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. 新規画面をグリッド内にドラッグするか既存画面を移動してください。 画面をゴミ箱にドラッグすると削除します。 設定を編集する場合は画面上でダブルクリックしてください。 Hotkeys ホットキー &Hotkeys ホットキー &New 新規 &Edit 編集 &Remove 削除 A&ctions アクション Ne&w 新規 E&dit 編集 Re&move 削除 Advanced server settings サーバーの詳細な設定 &Switch 切り替え Switch &after waiting 次の時間の後切り替え ms ミリ秒 Switch on double &tap within 次の時間内のダブルタップで切り替え &Options オプション &Check clients every クライアント確認頻度 Use &relative mouse moves マウスの相対的な動きを使用 S&ynchronize screen savers スクリーンセーバーの同期 Don't take &foreground window on Windows servers Windowsサーバでウィンドウを前面に表示しない Ignore auto config clients &Dead corners 無効とする角 To&p-left 左上 Top-rig&ht 右上 &Bottom-left 左下 Bottom-ri&ght 右下 Cor&ner Size: 隅の大きさ: SettingsDialog Save log file to... ログファイルの保存先 Elevate Synergy Synergyの権限昇格 Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. 本当に Synergy を昇格させてよろしいですか? これにより昇格されたプロセスや UAC dialog と、Synergy とが互いに作用しあうことができるようになる反面、昇格されていないプロセスとの間で問題を生じることもあり得ます。確かに必要であると判断できる場合にのみ Synergy の昇格を行ってください。 SettingsDialogBase Settings 設定 Sc&reen name: スクリーン名: P&ort: ポート: &Interface: インターフェース: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging ログ &Logging level: ログレベル: Log to file: ログ記録先ファイル: Browse... 参照... Error エラー &Language: 言語 &Miscellaneous その他 Warning 警告 Note 通知 Info 情報 Debug デバッグ情報 Debug1 デバッグ情報1 Debug2 デバッグ情報2 SetupWizard Setup Synergy Synergyのセットアップ Please select an option. オプションを選択してください。 Please enter your email address and password. メールアドレスとパスワードを入力してください。 SetupWizardBase Setup Synergy Synergyのセットアップ Welcome ようこそ Thanks for installing Synergy! Synergyをインストールしていただき、ありがとうございます! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergyは複数のコンピュータ間のマウスとキーボードを簡単に共有することができるフリーのオープンソースソフトウェアです。あるコンピュータの画面の端にマウスを移動すると別のコンピュータの画面に移ります。クリップボードを共有することもできます。必要なのは ネットワーク接続だけです。 SynergyはクロスプラットフォームでWindows, Mac OS X, Linux上で動作します。 Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? サーバーまたはクライアント SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown 不明 WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. ログインは失敗しました。メールアドレスまたはパスワードが無効です。 Login failed, an error occurred. %1 エラーが発生し、ログインが失敗しました。 %1 Login failed, an error occurred. Server response: %1 エラーが発生し、ログインが失敗しました。 サーバの応答: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_ko.qm000066400000000000000000000437331305627404700214230ustar00rootroot00000000000000-N}S_u>(Z B= snbj4 A' v<ZA0Ev._e1"w9 aX ;H}H&O RO ;@O ;]92|VE %UN#.Yu:8l_ o} *3!l(8(8] .): :(  6$Z75/J$"QJ-iz9@d" l %W攄&J(;y:Su( n{4.d&@Ty#L#6{*: z>J7? 3=T >k@d(Byc@ %i@~C }F0n<C3j* I_ Jz9 k#,| v~/ 2 -5 Pn1 d ~51 ~q@ ք~ ȹ ȹ ȹA a6` |% F F*? Z!+ *} KGS @{  RV| RV RV? R T V4  |*6 c* s s: c2j F"b Ҫ ^ /!m 4p2 d$? i! r3 zki P:O ¦e? x4+G ]^^:1\?9=> ,.bun4y~: r/E7#kC0qk).+> ]"iA Ux(&O)&OkAboutDialogBaseSynergy X About SynergyAboutDialogBaseLLUnknownAboutDialogBase:Version:AboutDialogBaseՉ` ǑD X8ƔChoose the action to performActionDialogBase Ǒ $Configure ActionActionDialogBase| TtH Lock cursor to screenActionDialogBase͕Ф| t8ƔPress a hotkeyActionDialogBase͕Ф| <8ƔPress and release a hotkeyActionDialogBase͕Ф| <8ƔRelease a hotkeyActionDialogBaset )ե<\ XSwitch in directionActionDialogBaset Tt<\ XSwitch to screenActionDialogBaset Ǒt Չ L:This action is performed whenActionDialogBaseDdownActionDialogBase|ʽleftActionDialogBaseoffActionDialogBaseonActionDialogBaset Ttonly on these screensActionDialogBase$xʽrightActionDialogBase͕Ф 8µȲ.the hotkey is pressedActionDialogBase͕Ф DLµȲ.the hotkey is releasedActionDialogBaseѠtoggleActionDialogBaseupActionDialogBase"͕Ф\ $` Ф| t8Ɣ:'Enter the specification for the hotkey:HotkeyDialogBase͕ФHotkeyHotkeyDialogBase Ӹ(&E)&Edit MainWindow |(&F)&File MainWindow(&H)&Help MainWindow Ǒ(&S)&Start MainWindow (&S)&Stop MainWindow =(&W)&Window MainWindow<p>Ʃ x ܱ \ t DٲȲ. (<b>%1</b>)D <a href="%2">ƴ\</a> D  LjµȲ.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindow"synergys $ | !Browse for a synergys config file MainWindow$ |D  µȲ.Cannot write configuration file MainWindow&$ | tt ,t JµȲConfiguration filename invalid MainWindow,$ mD | ǥ`  µȲ.%Could not save configuration to file. MainWindow8¤Ҹt DŴLjµȲ.Hostname is empty MainWindow0t|tŸҸ ` 8¤ҸD Dž%t8Ɣ.?Please fill in a hostname for the synergy client to connect to. MainWindow \D Ǒ`  µȲProgram can not be started MainWindow"$D x t<\ ǥ...Save configuration as... MainWindowǥ (ՈµȲ Save failed MainWindowSynergySynergy MainWindow2Synergy t|tŸҸ| >D  µȲ.Synergy client not found MainWindow*Synergy Չ t JµȲ.Synergy is not running. MainWindow$Synergy Չ  DžȲ.Synergy is running. MainWindow$Synergy Չ  DžȲ.Synergy is starting. MainWindow*Synergy | >D  µȲSynergy server not found MainWindow~Synergy %1X Tܸ\ D <\ ȅ̴µȲ.<br><br>ǐ8\ m@ \ ͜%| UxX8ƔfSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow.Synergy $X\ xt ȅ̴µȲ Synergy terminated with an error MainWindow>Synergy t|tŸҸ Չ |t tǬX JµȲ.5The executable for the synergy client does not exist. MainWindow8Synergy  Չ |t tǬX JµȲ.5The executable for the synergy server does not exist. MainWindowՉ |<br><br>%1<br><br>t() tǬX 1<\ Չ ՈµȲ. t \D ՉФ0 \ ͩ\ \D Lj Uxt8Ɣ.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowTSynergy| lX0 t DƔ\ DŽ $ |D Ǒ1`  µȲ.NThe temporary configuration file required to start synergy can not be written. MainWindowLLUnknown MainWindowSynergy | ՉX0 \ $ |t \ Ǒ1Ŵ Lj JµȲ.  $ |D >D ܬµȮL?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow&Synergy X(&A)...&About Synergy...MainWindowBase Ʃ(&A)&ApplyMainWindowBase>D 0(&B)... &Browse...MainWindowBase$ |(&C):&Configuration file:MainWindowBase $(&C)&Configure Server...MainWindowBase(00&HideMainWindowBase ȅ(&Q)&QuitMainWindowBase  IP: &Server IP:MainWindowBaset0&ShowMainWindowBase Ǒ(&S)&StartMainWindowBase8ǑƩ $:Configure interactively:MainWindowBase $ Ӹ Edit settingsMainWindowBase(00HideMainWindowBase IP : IP addresses:MainWindowBase\LogMainWindowBaseȅQuitMainWindowBaseDReadyMainWindowBaseՉRunMainWindowBase ȼ Չ Run WizardMainWindowBase 0(&H) S&how StatusMainWindowBase (&T)S&topMainWindowBase*$D x t<\ ǥ(&A)...Save configuration &as...MainWindowBase68ǑƩ<\ 1  $D |\ ǥX0.@Save the interactively generated server configuration to a file.MainWindowBase Tt t: Screen name:MainWindowBase$SettingsMainWindowBaset0ShowMainWindowBaseStopMainWindowBaseSynergySynergyMainWindowBase0t $D Ʃ:Use existing configuration:MainWindowBasetLUnnamedNewScreenWidget ܱ $ Setup SynergyPluginWizardPageDSynergy $ | (*.conf);; | (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectBSynergy $ | (*.sgc);; | (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObject0¤\ Ҹt| Ʃ`  Ŵ ȅiȲ.%System tray is unavailable, quitting.QObject¤l tt DµȲScreen name is emptyScreenSettingsDialogĺ |XX Tt tScreen name matches aliasScreenSettingsDialogP¤l @ D̴X  µȲ. tD Dž%Xp T=D X8Ɣ.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialog\Tt t@ ĺ |`  µȲ. ĺD pXp Tt tD 8Ɣ.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog ͔(&A)&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBaseƩX J (&D) &Dead cornersScreenSettingsDialogBase (&F)&FixesScreenSettingsDialogBasep Ф(&M)&Modifier keysScreenSettingsDialogBase (&R)&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBase m(&L)A&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase X |ʽ Bottom-leftScreenSettingsDialogBase X $xʽ Bottom-rightScreenSettingsDialogBase l0(&Z) Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBaseCAPS LOCK Ф Fix CAPS LOCK keyScreenSettingsDialogBaseNUM LOCK Ф Fix NUM LOCK keyScreenSettingsDialogBase SCROLL LOCK Ф Fix SCROLL LOCK keyScreenSettingsDialogBase*Xinerama| \ XTest Fix XTest for XineramaScreenSettingsDialogBaseT(&M):M&eta:ScreenSettingsDialogBaseTMetaScreenSettingsDialogBaseLNoneScreenSettingsDialogBaseˆ|(&U):S&uper:ScreenSettingsDialogBaseTt t(&N): Screen &name:ScreenSettingsDialogBase Tt $Screen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBaseˆ|SuperScreenSettingsDialogBase |ʽTop-leftScreenSettingsDialogBase $xʽ Top-rightScreenSettingsDialogBase<center>Tt: <b>%1</b></center><br>$D ӸX$t Tt<br>X$t 4ѵ<\ ܷ X8Ɣo
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelX |ʽ(&B) &Bottom-leftServerConfigDialogBase( ܬȲ t|tŸҸ Ux(&C)&Check clients everyServerConfigDialogBaseƩX J (&D) &Dead cornersServerConfigDialogBase Ӹ(&E)&EditServerConfigDialogBase͕Ф(&H)&HotkeysServerConfigDialogBase 1(&N)&NewServerConfigDialogBase 5X(&O)&OptionsServerConfigDialogBase (&R)&RemoveServerConfigDialogBase X(&S)&SwitchServerConfigDialogBase Չ(&C)A&ctionsServerConfigDialogBase $Advanced server settingsServerConfigDialogBaseX $xʽ(&G) Bottom-ri&ghtServerConfigDialogBase6Synergy  l1 tDD $X8Ɣ.:Configure the layout of your synergy server configuration.ServerConfigDialogBase l0(&N): Cor&ner Size:ServerConfigDialogBaset|tŸҸ\ Xt X ¤ ) (̴Tt Ǒ t|tŸҸ\ Xt ̴Ttt p,  ̴Tt  \T t|tŸҸ X ̴TtD ))0Don't take &foreground window on Windows serversServerConfigDialogBase0X$t TtD 4ѵ<\ ܷ X8Ɣ.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaseȸ\ƴ TtD ͔X$t X TtD ǐ H<\ ܷ X8Ɣ. TtD X$t 4ѵ<\ ܷ X8Ɣ. Tt $D ӸX$t Tt X8Ɣ.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBaseFȸ\ƴ TtD ͔X$t t ҼD ǐ H<\ ܷ X8Ɣ.1Drag this button to the grid to add a new screen.ServerConfigDialogBase Ӹ(&D)E&ditServerConfigDialogBase͕ФHotkeysServerConfigDialogBase 1(&W)Ne&wServerConfigDialogBase (&M)Re&moveServerConfigDialogBase¤l8t ٮ0T(&Y)S&ynchronize screen saversServerConfigDialogBase Tt lScreens and linksServerConfigDialogBase  $Server ConfigurationServerConfigDialogBase0 X(&A)Switch &after waitingServerConfigDialogBase*ܬ H T <\ X(&T)Switch on double &tap withinServerConfigDialogBase |ʽ(&P) To&p-leftServerConfigDialogBase $xʽ(&H) Top-rig&htServerConfigDialogBase$x ư¤ t Ʃ(&R)Use &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseSynergyX \D ¹ XܬµȮL? tD ƩX t Synergy@ ¹  \8¤, UAC Tǐ@ 8ǑƩ `  Lj, ¹  J@ \8¤ 8 ݮ8  LjµȲ. Synergy \ ¹ @  DƔ\ ưй ƩX8Ɣ.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogSynergy ¹ Elevate SynergySettingsDialog\ | ǥX0...Save log file to...SettingsDialogx0Әt¤(&I): &Interface:SettingsDialogBaseŸŴ:(&l) &Language:SettingsDialogBase0] (&L):&Logging level:SettingsDialogBase0&MiscellaneousSettingsDialogBase>D0... Browse...SettingsDialogBaseDebugSettingsDialogBase1Debug1SettingsDialogBase2Debug2SettingsDialogBase$XErrorSettingsDialogBaseInfoSettingsDialogBase |\ ǥ: Log to file:SettingsDialogBase \ 0]LoggingSettingsDialogBaseLNoteSettingsDialogBaseҸ(&O):P&ort:SettingsDialogBaseTt t(&R): Sc&reen name:SettingsDialogBase$SettingsSettingsDialogBaseWarningSettingsDialogBase&tT|  T8| Dž%X8Ɣ.-Please enter your email address and password. SetupWizard5XD X8Ɣ.Please select an option. SetupWizard ܱ $ Setup Synergy SetupWizard  t|tŸҸ?Server or Client?SetupWizardBase ܱ $ Setup SynergySetupWizardBaseSynergy ư¤@ Фܹ| 0 } X Ʃ`  Lj t 4 $ ¤ \DžȲ. ư¤| \ʽ 0X Tt ]<\ .00 Xt x 0X Tt<\ t`  Lj AboutDialogBase About Synergy Synergy에 대하여 <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown 알수없음 Version: 버전: &Ok 확인(&O) ActionDialogBase Configure Action 동작 설정 Choose the action to perform 수행할 동작을 선택하세요 Press a hotkey 단축키를 누르세요 Release a hotkey 단축키를 놓으세요 Press and release a hotkey 단축키를 눌렀다 놓으세요 only on these screens 이 화면에서만 Switch to screen 이 화면으로 전환 Switch in direction 이 방향으로 전환 left 왼쪽 right 오른쪽 up down 아래 Lock cursor to screen 커서를 화면안에 고정 toggle 토글 on 켜짐 off 꺼짐 This action is performed when 이 동작이 수행 될 때: the hotkey is pressed 단축키가 눌렸습니다. the hotkey is released 단축키가 놓아졌습니다. AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey 단축키 Enter the specification for the hotkey: 단축키로 설정할 키를 누르세요: MainWindow &Start 시작(&S) &File 파일(&F) &Edit 편집(&E) &Window 창(&W) &Help 도움말(&H) <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>사용 중인 시너지는 최신 버전이 아닙니다. 새 버전(<b>%1</b>)을 <a href="%2">다운로드</a> 받을 수 있습니다.</p> Program can not be started 프로그램을 시작할 수 없습니다 The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. 실행파일<br><br>%1<br><br>이(가) 존재하지만 성공적으로 실행되지 못했습니다. 이 프로그램을 실행시키기 위한 충분한 권한을 가지고 있는지 확인해주세요. Synergy client not found Synergy 클라이언트를 찾을 수 없습니다. The executable for the synergy client does not exist. Synergy 클라이언트 실행 파일이 존재하지 않습니다. Hostname is empty 호스트명이 비어있습니다. Please fill in a hostname for the synergy client to connect to. 클라이언트가 접속할 호스트명을 입력해주세요. Cannot write configuration file 설정파일을 쓸 수 없습니다. The temporary configuration file required to start synergy can not be written. Synergy를 구동하기 위해 필요한 임시 설정 파일을 작성할 수 없습니다. Configuration filename invalid 설정 파일 이름이 올바르지 않습니다 You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy 서버를 실행하기 위한 설정 파일이 제대로 작성되어 있지 않습니다. 지금 설정 파일을 찾아 보시겠습니까? Synergy server not found Synergy 서버를 찾을 수 없습니다 The executable for the synergy server does not exist. Synergy 서버 실행 파일이 존재하지 않습니다. Synergy terminated with an error Synergy가 오류로 인해 종료되었습니다 Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy가 %1의 코드로 비 정상적으로 종료되었습니다.<br><br>자세한 사항은 로그 출력결과를 확인하세요 &Stop 중지(&S) Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy가 실행 중 입니다. Synergy is running. Synergy가 실행 중 입니다. Synergy is not running. Synergy가 실행 중이지 않습니다. Unknown 알수없음 Synergy Synergy Browse for a synergys config file synergys 설정 파일 탐색 Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... 설정을 다른 이름으로 저장... Save failed 저장에 실패했습니다 Could not save configuration to file. 설정 사항을 파일에 저장할 수 없습니다. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: 화면 이름: &Server IP: 서버 IP: &Start 시작(&S) Use existing configuration: 기존 설정을 사용: &Configuration file: 설정 파일(&C): &Browse... 찾아 보기(&B)... Configure interactively: 상호작용 설정: &Configure Server... 서버 설정(&C) Ready 준비 Log 로그 &Apply 적용(&A) IP addresses: IP 주소: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Synergy에 관하여(&A)... &Quit 종료(&Q) Quit 종료 Run 실행 S&top 중지(&T) Stop 중지 S&how Status 상태 보기(&H) &Hide 숨기기 Hide 숨기기 &Show 보이기 Show 보이기 Save configuration &as... 설정을 다른 이름으로 저장(&A)... Save the interactively generated server configuration to a file. 상호작용으로 생성된 서버 설정을 파일로 저장하기. Settings 설정 Edit settings 설정 편집 Run Wizard 마법사 실행 NewScreenWidget Unnamed 이름없음 PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy 시너지 설정 Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy 설정파일 (*.sgc);;모든 파일 (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy 설정파일 (*.conf);;모든 파일 (*.*) System tray is unavailable, quitting. 시스템 트레이를 사용할 수 없어 종료합니다. ScreenSettingsDialog Screen name is empty 스크린 이름이 비었습니다 The screen name cannot be empty. Please either fill in a name or cancel the dialog. 스크린 명은 비워둘 수 없습니다. 이름을 입력하거나 대화창을 취소하세요. Screen name matches alias 별명과 일치하는 화면 이름 The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. 화면 이름은 별명과 동일할 수 없습니다. 별명을 제거하거나 화면 이름을 바꿔주세요. ScreenSettingsDialogBase Screen Settings 화면 설정 Screen &name: 화면 이름(&N): A&liases 별칭(&L) &Add 추가(&A) &Remove 삭제(&R) &Modifier keys 보조 키(&M) &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta 메타 Super 슈퍼 None 없음 &Ctrl: &Ctrl: Al&t: Al&t: M&eta: 메타(&M): S&uper: 슈퍼(&U): &Dead corners 사용하지 않는 모서리(&D) Top-left 상단 왼쪽 Top-right 상단 오른쪽 Bottom-left 하단 왼쪽 Bottom-right 하단 오른쪽 Corner Si&ze: 모서리 크기(&Z) &Fixes 고정(&F) Fix CAPS LOCK key CAPS LOCK 키 고정 Fix NUM LOCK key NUM LOCK 키 고정 Fix SCROLL LOCK key SCROLL LOCK 키 고정 Fix XTest for Xinerama Xinerama를 위한 XTest 고정 ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>화면: <b>%1</b></center><br>설정을 편집하려면 더블클릭<br>삭제하려면 휴지통으로 드래그 하세요 ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration 서버 설정 Screens and links 화면과 링크 Drag a screen from the grid to the trashcan to remove it. 삭제하려면 화면을 휴지통으로 드래그 하세요. Configure the layout of your synergy server configuration. Synergy 서버 구성과 레이아웃을 설정하세요. Drag this button to the grid to add a new screen. 새로운 화면을 추가하려면 이 버튼을 격자 안으로 드래그 하세요. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. 새로운 화면을 추가하려면 상단의 화면을 격자 안으로 드래그 하세요. 화면을 삭제하려면 휴지통으로 드래그 하세요. 화면 설정을 편집하려면 더블클릭 하세요. Hotkeys 단축키 &Hotkeys 단축키(&H) &New 생성(&N) &Edit 편집(&E) &Remove 삭제(&R) A&ctions 행동(&C) Ne&w 생성(&W) E&dit 편집(&D) Re&move 삭제(&M) Advanced server settings 고급 설정 &Switch 전환(&S) Switch &after waiting 대기 후 전환(&A) ms ms Switch on double &tap within 지정시간 안에 더블 탭으로 전환(&T) &Options 옵션(&O) &Check clients every 지정 시간마다 클라이언트 확인(&C) Use &relative mouse moves 상대적인 마우스 이동 사용(&R) S&ynchronize screen savers 스크린세이버 동기화(&Y) Don't take &foreground window on Windows servers 클라이언트로 전환시해도 서버의 포커스 방지 (전체화면 작업중 클라이언트로 전환해도 전체화면이 유지되며, 서버에서 전체화면 중 최소화 후 클라이언트 전환시 전체화면을 방지) Ignore auto config clients &Dead corners 사용하지 않는 모서리(&D) To&p-left 상단 왼쪽(&P) Top-rig&ht 상단 오른쪽(&H) &Bottom-left 하단 왼쪽(&B) Bottom-ri&ght 하단 오른쪽(&G) Cor&ner Size: 모서리 크기(&N): SettingsDialog Save log file to... 로그 파일 저장하기... Elevate Synergy Synergy 승급 Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Synergy의 권한을 승급 하시겠습니까? 이것을 허용하게 되면 Synergy와 승급된 프로세스, UAC 대화상자와 상호작용 할 수 있지만, 승급되지 않은 프로세스들과 문제가 생길 수 있습니다. Synergy 권한 승급은 반드시 필요한 경우에만 사용하세요. SettingsDialogBase Settings 설정 Sc&reen name: 화면 이름(&R): P&ort: 포트(&O): &Interface: 인터페이스(&I): Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging 로그 기록 &Logging level: 기록 수준(&L): Log to file: 파일로 저장: Browse... 찾아보기... Error 오류 &Language: 언어:(&l) &Miscellaneous 기타 Warning 경고 Note 알림 Info 정보 Debug 디버그 Debug1 디버그1 Debug2 디버그2 SetupWizard Setup Synergy 시너지 설정 Please select an option. 옵션을 선택하세요. Please enter your email address and password. 이메일 주소 및 암호를 입력하세요. SetupWizardBase Setup Synergy 시너지 설정 Welcome 환영합니다. Thanks for installing Synergy! 시너지를 설치하여 주셔서 감사합니다. Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy는 마우스와 키보드를 여러 컴퓨터에 쉽게 공유하여 사용할 수 있게 해주는 무료 오픈 소스 프로그램입니다. 마우스를 한쪽 컴퓨터의 화면 끝으로 옮기기만 하면 다른 컴퓨터의 화면으로 이동할 수 있으며 클립보드의 내용까지도 공유할 수 있습니다. 필요한 것은 단지 네트워크 연결 뿐이며 Synergy는 여러 플랫폼(Windows와 Mac OS X, Linux)에서 사용할 수 있습니다. Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? 서버 또는 클라이언트? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown 알수없음 WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. 로그인에 실패했습니다. 전자메일 또는 암호가 잘못되었습니다. Login failed, an error occurred. %1 로그인에 실패했습니다. 오류가 발생했습니다. %1 Login failed, an error occurred. Server response: %1 로그인에 실패했습니다. 오류가 발생했습니다. 서버 응답은 다음과 같습니다: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_lt.qm000066400000000000000000000042641305627404700214250ustar00rootroot00000000000000 AboutDialogBase About Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: &Ok Gerai ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left kairė right dešinė up viršus down apačia Lock cursor to screen toggle on ijungta off Išiungta This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start Pradėti &File &Edit &Window &Help Pagalba <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Stabdyti Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: Serverio IP: &Start Pradėti Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: IP adresas: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Rodyti Show Rodyti Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error Klaida &Language: &Miscellaneous Warning Įspėjimas Note Info Informacija Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy leis jums dalintis jūsų pelė ir klaviatūra tarp kompiuterių ir tai nieko nekainuoja ir tai Open Source. Tiesiog perkelkite pelę iš vieno kompiuterio ekrano krašto į kitą. Netgi galite dalintis Clipbourdų. Viskas ko jums reikia, yra tinklo sujungimas. Synergy yra cross-platform dirba ant Windows, Mac OS X ir Linux. Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_lv.qm000066400000000000000000000023221305627404700214200ustar00rootroot00000000000000 AboutDialogBase About Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: &Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left right up down Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Informācija Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy ļauj tev viegli izmantot savu peli un klaviatūru vairākos datoros vienlaicīgi, un tā ir bezmakas un atvērtā koda programma. Vienkārši virzi kursoru no viena datora ekrāna malas uz cita datora ekrānu. Arī starpliktuve var būt kopīga. Vienīgais, kas tev nepieciešams, ir tīkla savienojums. Synergy darbojas uz dažādām operētājsistēmām – Windows, OS X un Linux. Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_mr.qm000066400000000000000000000070651305627404700214260ustar00rootroot00000000000000Choose the action to performActionDialogBase0  0 M 8 0 * ! & M / > 6 @ , & M '  0 > Lock cursor to screenActionDialogBase 9 I   @ & > , >Press a hotkeyActionDialogBase 9 I   @ & > , B ( 8 K ! >Press and release a hotkeyActionDialogBase 9 I   @ 8 K < ! >Release a hotkeyActionDialogBase & ? 6 G 2 > 5 3 >Switch in directionActionDialogBase * ! & M / >  ! G 5 3 >Switch to screenActionDialogBase0 9 @  C $ @  G 2 @  > $ G  G 5 M 9 >This action is performed whenActionDialogBase  > 2 @downActionDialogBase ! > 5 GleftActionDialogBase ,  &offActionDialogBase  > 2 BonActionDialogBase$  G 5 3 / > * ! & M / >  5 0 only on these screensActionDialogBase  5 GrightActionDialogBase( 9 I   @ & > , 2 @  G 2 @  9 Gthe hotkey is pressedActionDialogBase, 9 I   @ 8 K ! # M / > $  2 @  9 Gthe hotkey is releasedActionDialogBase  I  2toggleActionDialogBase 5 0upActionDialogBase( 9 I   @  G $ * 6 @ 2 * A 0 5 >:'Enter the specification for the hotkey:HotkeyDialogBase 9 I   @HotkeyHotkeyDialogBase& , & 2&Edit MainWindow & + >  2&File MainWindow& . & $&Help MainWindow &  ? !  @&Window MainWindow:  > 0 M /  M 0 . 8 A 0 B 9 K 6  2 > ( > 9 @.Program can not be started MainWindow& , & 2&EditServerConfigDialogBase & - > 7 >: &Language:SettingsDialogBase . > 9 ? $ @InfoSettingsDialogBaseV 8 ? ( 0 M  @ 8 9 $ A . M 9 @ $ A .  >  @ , K 0 M !  # ? . > 8  ( G  8   #  >  8 . 5 G $ 5 > * 0 B 6  $ >.   > * ! & M / >  M / >  ! G $ B ( . > 8 & A 8 1 M / > * ! & M / > 5 0 ( G 6  $ >, 8 > . >    M 2 ? * , K 0 M ! 5 > 0 B 6  $ >.  5 6 M /  $ >  9 G $ @  G 5 3   > ( G  5 0 M   ( G  M 6 (  @. 8 ? ( 0 M  @ . K + $  9 G, . A  M $ 8 M 0 K $  9 G  # ?  ( G  * M 0 # > 2 M / >  5 0  > 2 B 6  $ G. ( 5 ?  ! K , . E  -  8   M 8  # ? 2 ? (  M 8)ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseJ 8 ? ( 0 M  @  ( M 8 M  I 2  G 2 M / > , & M & 2 ' ( M / 5 > &.Thanks for installing Synergy!SetupWizardBase 8 M 5 >  $ . MWelcomeSetupWizardBasesynergy-1.8.8-stable/src/gui/res/lang/gui_mr.ts000066400000000000000000001635111305627404700214360ustar00rootroot00000000000000 AboutDialogBase About Synergy सिनर्जी बद्दल <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: आवृत्ती: &Ok &ठीक ActionDialogBase Configure Action Choose the action to perform कृती निवडा Press a hotkey हॉटकी दाबा Release a hotkey हॉटकी सो़डा Press and release a hotkey हॉटकी दाबून सोडा only on these screens केवळ या पडद्यांवरच Switch to screen पडद्याकडे वळा Switch in direction दिशेला वळा left डावे right उजवे up वर down खाली Lock cursor to screen कर्सर पडद्याशी बद्ध करा toggle टॉगल on चालू off बंद This action is performed when ही कृती केली जाते जेव्हा the hotkey is pressed हॉटकी दाबली गेली आहे the hotkey is released हॉटकी सोडण्यात आली आहे AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey हॉटकी Enter the specification for the hotkey: हॉटकीचे तपशील पुरवा: MainWindow &Start &File &फाईल &Edit &बदल &Window &खिडकी &Help &मदत <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started कार्यक्रम सुरू होऊ शकला नाही. The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &बदल &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &भाषा: &Miscellaneous Warning Note Info माहिती Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome स्वागतम् Thanks for installing Synergy! सिनर्जी इन्स्टॉल केल्याबद्दल धन्यवाद. Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). सिनर्जी सह तुम्ही तुमचा कीबोर्ड आणि माऊस अनेक संगणकांसमवेत वापरू शकता. एका पडद्याच्या कडेतून माऊस दुसऱ्या पडद्यावर नेऊ शकता, सामाईक क्लिपबोर्ड वारू शकता. आवश्यकता आहे ती केवळ एका नेटवर्क कनेक्शनची. सिनर्जी मोफत आहे, मुक्त स्रोत आहे आणि अनेक प्रणाल्यांवर चालू शकते. (विंडोज, मॅक ओ-एस एक्स आणि लिनक्स) Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_nl-NL.qm000066400000000000000000000537151305627404700217330ustar00rootroot00000000000000*30*%t*0*++g`+` G;Gz*JELbEU`DXVY/sZ/xx.>7~}Su>/(Z = nbj!4^30vJZPEv.w_$]e<w9h()-Z;H}H04O "O IO I]F|'VE c/UN,*Yu:F+l_ } "*?ld2qERE 8y:(:2  D $ZDEJ-"QJa-izF@d+ l .{攄J (Ik:S%m( n4.d/@Ty,L#B{3Hz>AJD 3,=Tk@d2&ycOv%@~ kC)l}F<\nbC?j5# I_ JzG0 k#6 v~: = -5 Pn= d% ~5=) ~qP$ ք~ ȹ ȹ! ȹQ aCX |. F) F49 Z* 4 KG 5 @{ RVv RVV RVOJ RE T"g V4  |*C c4 s! sG| c>R F+V Ҫ ^ /*Q 4p> d-Y i! p r- zk PG ¦eO x45 ]^^H1\N=%> 6bun@#y~H % r6/K7,kC;k3r.5>+iQ&Ok&OkAboutDialogBaseOver Synergy About SynergyAboutDialogBaseOnbekendUnknownAboutDialogBaseVersie:Version:AboutDialogBase6Kies de uit te voeren actieChoose the action to performActionDialogBase"Configureer ActieConfigure ActionActionDialogBase2Vergrendel muis op schermLock cursor to screenActionDialogBase*Druk op een sneltoetsPress a hotkeyActionDialogBaseBDruk op een sneltoets en laat losPress and release a hotkeyActionDialogBase,Laat een sneltoets losRelease a hotkeyActionDialogBaseBVerander in een bepaalde richtingSwitch in directionActionDialogBase Naar scherm gaanSwitch to screenActionDialogBaseFDeze actie wordt uitgevoerd wanneerThis action is performed whenActionDialogBase omlaagdownActionDialogBase linksleftActionDialogBaseuitoffActionDialogBaseaanonActionDialogBase.alleen op deze schermenonly on these screensActionDialogBase rechtsrightActionDialogBase2de sneltoets is ingedruktthe hotkey is pressedActionDialogBase4de sneltoets is losgelatenthe hotkey is releasedActionDialogBase wisseltoggleActionDialogBase omhoogupActionDialogBaseTVoer de specificatie voor de sneltoets in:'Enter the specification for the hotkey:HotkeyDialogBaseSneltoetsHotkeyHotkeyDialogBase&Bewerken&Edit MainWindow&Bestand&File MainWindow &Help&Help MainWindow &Start&Start MainWindow &Stop&Stop MainWindow&Venster&Window MainWindow<p> Uw versie van Synergy is verouderd. Versie <b>%1</b> is nu beschikbaar om te <a href="%2">downloaden</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowHOpen een Synergy configuratiebestand!Browse for a synergys config file MainWindowJKan configuratiebestand niet aanmakenCannot write configuration file MainWindow^De bestandsnaam van de configuratie is ongeldigConfiguration filename invalid MainWindowVKon configuratie niet opslaan naar bestand.%Could not save configuration to file. MainWindow Hostnaam is leegHostname is empty MainWindowVul a.u.b. een hostnaam in voor de Synergy client om mee te verbinden.?Please fill in a hostname for the synergy client to connect to. MainWindowJHet programma kan niet worden gestartProgram can not be started MainWindow4Sla configuratie op als...Save configuration as... MainWindow$Opslaan is mislukt Save failed MainWindowSynergySynergy MainWindowDDe Synergy client is niet gevondenSynergy client not found MainWindow.Synergy is niet actief.Synergy is not running. MainWindow$Synergy is actief.Synergy is running. MainWindow,Synergy wordt gestart.Synergy is starting. MainWindow>Synergy server is niet gevondenSynergy server not found MainWindowSynergy werd onverwachts afgesloten met de volgende exit code: %1.<br><br>. Raadpleeg de log voor meer details.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowJSynergy werd afgesloten met een error Synergy terminated with an error MainWindowdDe executable voor de Synergy client bestaat niet.5The executable for the synergy client does not exist. MainWindowdDe executable voor de Synergy client bestaat niet.5The executable for the synergy server does not exist. MainWindowTDe uitvoering van <br><br>%1<br><br>kon niet succesvol worden uitgevoerd, hoewel het bestaat. Verifieer eerst of u de nodige rechten heeft om het programma uit te voeren.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowHet tijdelijke configuratiebestand om Synergy te starten kan niet geschreven worden.NThe temporary configuration file required to start synergy can not be written. MainWindowOnbekendUnknown MainWindowU heeft een ongeldig configuratiebestand ingegeven voor de Synergy server. Wilt u nu een configuratiebestand opgeven?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow &Over Synergy...&About Synergy...MainWindowBaseToep&assen&ApplyMainWindowBase&Bladeren... &Browse...MainWindowBase*&Configuratiebestand:&Configuration file:MainWindowBase,&Configureer Server...&Configure Server...MainWindowBase&Verberg&HideMainWindowBase&Sluiten&QuitMainWindowBaseServer IP: &Server IP:MainWindowBase &Toon&ShowMainWindowBase &Start&StartMainWindowBase*Configureer grafisch:Configure interactively:MainWindowBase&Wijzig instellingen Edit settingsMainWindowBaseVerbergHideMainWindowBaseIP adres: IP addresses:MainWindowBaseLogLogMainWindowBase SluitQuitMainWindowBase KlaarReadyMainWindowBase StartRunMainWindowBaseStart Wizard Run WizardMainWindowBaseT&oon Status S&how StatusMainWindowBase S&topS&topMainWindowBase8Configuratie opslaan &als...Save configuration &as...MainWindowBaseSla de grafisch gemaakte serverconfiguratie naar een bestand op.@Save the interactively generated server configuration to a file.MainWindowBaseSchermnaam: Screen name:MainWindowBaseInstellingenSettingsMainWindowBaseToonShowMainWindowBaseStopStopMainWindowBaseSynergySynergyMainWindowBase>Gebruik bestaande configuratie:Use existing configuration:MainWindowBaseNaamloosUnnamedNewScreenWidget(Synergy configureren Setup SynergyPluginWizardPagefSynergy configuratie (*.conf);;Alle bestanden (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectdSynergy Configuratie (*.sgc);;Alle bestanden (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectnTaakbalk is niet beschikbaar, Synergy wordt afgesloten.%System tray is unavailable, quitting.QObject$Schermnaam is leegScreen name is emptyScreenSettingsDialogBSchermnaam komt overeen met aliasScreen name matches aliasScreenSettingsDialogDe schermnaam kan niet leeg zijn. Geef een naam in of annuleer het venster.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogDe schermnaam kan niet hetzelfde zijn als een alias. Verwijder of de alias of verander de schermnaam.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog &Nieuw&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBase&Dode hoeken &Dead cornersScreenSettingsDialogBase &Fixes&FixesScreenSettingsDialogBase&Prefixtoetsen&Modifier keysScreenSettingsDialogBase&Verwijderen&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBaseA&liassenA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseLinksonder Bottom-leftScreenSettingsDialogBaseRechtsonder Bottom-rightScreenSettingsDialogBase&Grootte: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase&Fix CAPS LOCK toetsFix CAPS LOCK keyScreenSettingsDialogBase$Fix NUM LOCK toetsFix NUM LOCK keyScreenSettingsDialogBase*Fix SCROLL LOCK toetsFix SCROLL LOCK keyScreenSettingsDialogBase.Fix XTest voor XineramaFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseGeenNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBaseScherm &naam: Screen &name:ScreenSettingsDialogBase&Scherm InstellingenScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBaseLinksbovenTop-leftScreenSettingsDialogBaseRechtsboven Top-rightScreenSettingsDialogBase<center>Scherm: <b>%1</b></center><br>Dubbelklik om instellingen te wijzigen<br>Sleep een scherm naar de prullenbak om het te verwijdereno
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelLinksonder &Bottom-leftServerConfigDialogBase0&Controleer clients elke&Check clients everyServerConfigDialogBase&Dode hoeken &Dead cornersServerConfigDialogBase&Bewerken&EditServerConfigDialogBase&Sneltoetsen&HotkeysServerConfigDialogBase &Nieuw&NewServerConfigDialogBase&Opties&OptionsServerConfigDialogBase&Verwijderen&RemoveServerConfigDialogBase Wissel&SwitchServerConfigDialogBaseA&ctiesA&ctionsServerConfigDialogBase@Geavanceerde server instellingenAdvanced server settingsServerConfigDialogBaseRechtsonder Bottom-ri&ghtServerConfigDialogBasedConfigureer de layout voor de server configuratie.:Configure the layout of your synergy server configuration.ServerConfigDialogBaseHoek Grootte: Cor&ner Size:ServerConfigDialogBaseXWordt geen actief venster op Windows Servers0Don't take &foreground window on Windows serversServerConfigDialogBasetSleep een scherm naar de prullenbak om het te verwijderen.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase|Sleep nieuwe schermen naar het raster of verplaats bestaande schermen. Sleep een scherm naar de prullenbak om het te verwijderen. Dubbelklik op een scherm om zijn instellingen aan te passen.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBaseSleep dit icoon naar het raster om een nieuw scherm toe te voegen.1Drag this button to the grid to add a new screen.ServerConfigDialogBaseAanpa&ssenE&ditServerConfigDialogBaseSneltoetsenHotkeysServerConfigDialogBase Nieu&wNe&wServerConfigDialogBaseVerwijderenRe&moveServerConfigDialogBase@S&ynchronizeer schermbeveiligingS&ynchronize screen saversServerConfigDialogBase"Schermen en linksScreens and linksServerConfigDialogBase&Server configuratieServer ConfigurationServerConfigDialogBase&Verander na wachtenSwitch &after waitingServerConfigDialogBase>Verander na een dubbele klik inSwitch on double &tap withinServerConfigDialogBaseLinksboven To&p-leftServerConfigDialogBaseRechtsboven Top-rig&htServerConfigDialogBaseDGebruik &relatieve muis bewegingenUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseWeet je zeker dat je Synergy's privileges wil verhogen? Dit staat interactie toe met verhoogde processen en het UAC venster, maar kan problemen veroorzaken met niet-verhoogde processen. Verhoog Synergy alleen als het noodzakelijk is.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialog8Verhoog Synergy's PrivilegesElevate SynergySettingsDialog4Schrijf logbestand naar...Save log file to...SettingsDialog&Interface: &Interface:SettingsDialogBase Taal: &Language:SettingsDialogBaseLog niveau:&Logging level:SettingsDialogBaseOverige&MiscellaneousSettingsDialogBase&Bladeren... Browse...SettingsDialogBase DebugDebugSettingsDialogBase Debug1Debug1SettingsDialogBase Debug2Debug2SettingsDialogBaseFoutErrorSettingsDialogBaseInfoInfoSettingsDialogBase"Log naar bestand: Log to file:SettingsDialogBase LoggenLoggingSettingsDialogBaseOpmerkingNoteSettingsDialogBase Poort:P&ort:SettingsDialogBaseScherm naam: Sc&reen name:SettingsDialogBaseInstellingenSettingsSettingsDialogBaseWaarschuwingWarningSettingsDialogBaseHVul uw e-mailadres en wachtwoord in.-Please enter your email address and password. SetupWizard@Selecteer alstublieft een optie.Please select an option. SetupWizard(Synergy configureren Setup Synergy SetupWizard"Server of Client?Server or Client?SetupWizardBase(Synergy configureren Setup SynergySetupWizardBaseMet Synergy kunt u eenvoudig uw muis en toetsenbord delen tussen meerdere computers op uw bureau. Bovendien is het gratis en Open Source. Beweeg uw muis over de rand van het scherm van de ene computer naar de andere. U kunt zelfs al uw klemborden delen. Het enige wat u nodig hebt is een netwerkverbinding. Synergy is cross-platform (werkt op Windows, Mac OS X en Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseRBedankt voor het installeren van Synergy!Thanks for installing Synergy!SetupWizardBase WelkomWelcomeSetupWizardBaseOnbekendUnknownVersionChecker^Inloggen mislukt, er is een fout opgetreden. %1$Login failed, an error occurred. %1 WebClientzInloggen mislukt, er is een fout opgetreden. Foutmelding: %16Login failed, an error occurred. Server response: %1 WebClientrInloggen mislukt, ongeldige gebruikersnaam of wachtwoord.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_nl-NL.ts000066400000000000000000001714041305627404700217400ustar00rootroot00000000000000 AboutDialogBase About Synergy Over Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Onbekend Version: Versie: &Ok &Ok ActionDialogBase Configure Action Configureer Actie Choose the action to perform Kies de uit te voeren actie Press a hotkey Druk op een sneltoets Release a hotkey Laat een sneltoets los Press and release a hotkey Druk op een sneltoets en laat los only on these screens alleen op deze schermen Switch to screen Naar scherm gaan Switch in direction Verander in een bepaalde richting left links right rechts up omhoog down omlaag Lock cursor to screen Vergrendel muis op scherm toggle wissel on aan off uit This action is performed when Deze actie wordt uitgevoerd wanneer the hotkey is pressed de sneltoets is ingedrukt the hotkey is released de sneltoets is losgelaten AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Sneltoets Enter the specification for the hotkey: Voer de specificatie voor de sneltoets in: MainWindow &Start &Start &File &Bestand &Edit &Bewerken &Window &Venster &Help &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p> Uw versie van Synergy is verouderd. Versie <b>%1</b> is nu beschikbaar om te <a href="%2">downloaden</a>.</p> Program can not be started Het programma kan niet worden gestart The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. De uitvoering van <br><br>%1<br><br>kon niet succesvol worden uitgevoerd, hoewel het bestaat. Verifieer eerst of u de nodige rechten heeft om het programma uit te voeren. Synergy client not found De Synergy client is niet gevonden The executable for the synergy client does not exist. De executable voor de Synergy client bestaat niet. Hostname is empty Hostnaam is leeg Please fill in a hostname for the synergy client to connect to. Vul a.u.b. een hostnaam in voor de Synergy client om mee te verbinden. Cannot write configuration file Kan configuratiebestand niet aanmaken The temporary configuration file required to start synergy can not be written. Het tijdelijke configuratiebestand om Synergy te starten kan niet geschreven worden. Configuration filename invalid De bestandsnaam van de configuratie is ongeldig You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? U heeft een ongeldig configuratiebestand ingegeven voor de Synergy server. Wilt u nu een configuratiebestand opgeven? Synergy server not found Synergy server is niet gevonden The executable for the synergy server does not exist. De executable voor de Synergy client bestaat niet. Synergy terminated with an error Synergy werd afgesloten met een error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy werd onverwachts afgesloten met de volgende exit code: %1.<br><br>. Raadpleeg de log voor meer details. &Stop &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy wordt gestart. Synergy is running. Synergy is actief. Synergy is not running. Synergy is niet actief. Unknown Onbekend Synergy Synergy Browse for a synergys config file Open een Synergy configuratiebestand Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Sla configuratie op als... Save failed Opslaan is mislukt Could not save configuration to file. Kon configuratie niet opslaan naar bestand. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Schermnaam: &Server IP: Server IP: &Start &Start Use existing configuration: Gebruik bestaande configuratie: &Configuration file: &Configuratiebestand: &Browse... &Bladeren... Configure interactively: Configureer grafisch: &Configure Server... &Configureer Server... Ready Klaar Log Log &Apply Toep&assen IP addresses: IP adres: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Over Synergy... &Quit &Sluiten Quit Sluit Run Start S&top S&top Stop Stop S&how Status T&oon Status &Hide &Verberg Hide Verberg &Show &Toon Show Toon Save configuration &as... Configuratie opslaan &als... Save the interactively generated server configuration to a file. Sla de grafisch gemaakte serverconfiguratie naar een bestand op. Settings Instellingen Edit settings Wijzig instellingen Run Wizard Start Wizard NewScreenWidget Unnamed Naamloos PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Synergy configureren Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configuratie (*.sgc);;Alle bestanden (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy configuratie (*.conf);;Alle bestanden (*.*) System tray is unavailable, quitting. Taakbalk is niet beschikbaar, Synergy wordt afgesloten. ScreenSettingsDialog Screen name is empty Schermnaam is leeg The screen name cannot be empty. Please either fill in a name or cancel the dialog. De schermnaam kan niet leeg zijn. Geef een naam in of annuleer het venster. Screen name matches alias Schermnaam komt overeen met alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. De schermnaam kan niet hetzelfde zijn als een alias. Verwijder of de alias of verander de schermnaam. ScreenSettingsDialogBase Screen Settings Scherm Instellingen Screen &name: Scherm &naam: A&liases A&liassen &Add &Nieuw &Remove &Verwijderen &Modifier keys &Prefixtoetsen &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Geen &Ctrl: &Ctrl: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners &Dode hoeken Top-left Linksboven Top-right Rechtsboven Bottom-left Linksonder Bottom-right Rechtsonder Corner Si&ze: &Grootte: &Fixes &Fixes Fix CAPS LOCK key Fix CAPS LOCK toets Fix NUM LOCK key Fix NUM LOCK toets Fix SCROLL LOCK key Fix SCROLL LOCK toets Fix XTest for Xinerama Fix XTest voor Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Scherm: <b>%1</b></center><br>Dubbelklik om instellingen te wijzigen<br>Sleep een scherm naar de prullenbak om het te verwijderen ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Server configuratie Screens and links Schermen en links Drag a screen from the grid to the trashcan to remove it. Sleep een scherm naar de prullenbak om het te verwijderen. Configure the layout of your synergy server configuration. Configureer de layout voor de server configuratie. Drag this button to the grid to add a new screen. Sleep dit icoon naar het raster om een nieuw scherm toe te voegen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Sleep nieuwe schermen naar het raster of verplaats bestaande schermen. Sleep een scherm naar de prullenbak om het te verwijderen. Dubbelklik op een scherm om zijn instellingen aan te passen. Hotkeys Sneltoetsen &Hotkeys &Sneltoetsen &New &Nieuw &Edit &Bewerken &Remove &Verwijderen A&ctions A&cties Ne&w Nieu&w E&dit Aanpa&ssen Re&move Verwijderen Advanced server settings Geavanceerde server instellingen &Switch Wissel Switch &after waiting Verander na wachten ms ms Switch on double &tap within Verander na een dubbele klik in &Options &Opties &Check clients every &Controleer clients elke Use &relative mouse moves Gebruik &relatieve muis bewegingen S&ynchronize screen savers S&ynchronizeer schermbeveiliging Don't take &foreground window on Windows servers Wordt geen actief venster op Windows Servers Ignore auto config clients &Dead corners &Dode hoeken To&p-left Linksboven Top-rig&ht Rechtsboven &Bottom-left Linksonder Bottom-ri&ght Rechtsonder Cor&ner Size: Hoek Grootte: SettingsDialog Save log file to... Schrijf logbestand naar... Elevate Synergy Verhoog Synergy's Privileges Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Weet je zeker dat je Synergy's privileges wil verhogen? Dit staat interactie toe met verhoogde processen en het UAC venster, maar kan problemen veroorzaken met niet-verhoogde processen. Verhoog Synergy alleen als het noodzakelijk is. SettingsDialogBase Settings Instellingen Sc&reen name: Scherm naam: P&ort: Poort: &Interface: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Loggen &Logging level: Log niveau: Log to file: Log naar bestand: Browse... &Bladeren... Error Fout &Language: Taal: &Miscellaneous Overige Warning Waarschuwing Note Opmerking Info Info Debug Debug Debug1 Debug1 Debug2 Debug2 SetupWizard Setup Synergy Synergy configureren Please select an option. Selecteer alstublieft een optie. Please enter your email address and password. Vul uw e-mailadres en wachtwoord in. SetupWizardBase Setup Synergy Synergy configureren Welcome Welkom Thanks for installing Synergy! Bedankt voor het installeren van Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Met Synergy kunt u eenvoudig uw muis en toetsenbord delen tussen meerdere computers op uw bureau. Bovendien is het gratis en Open Source. Beweeg uw muis over de rand van het scherm van de ene computer naar de andere. U kunt zelfs al uw klemborden delen. Het enige wat u nodig hebt is een netwerkverbinding. Synergy is cross-platform (werkt op Windows, Mac OS X en Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Server of Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Onbekend WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Inloggen mislukt, ongeldige gebruikersnaam of wachtwoord. Login failed, an error occurred. %1 Inloggen mislukt, er is een fout opgetreden. %1 Login failed, an error occurred. Server response: %1 Inloggen mislukt, er is een fout opgetreden. Foutmelding: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_no.qm000066400000000000000000000523241305627404700214220ustar00rootroot000000000000005$}Su>s(Z >= nbj4&l.JvGyZNEv._!e:Nw9X&&FV p;H}H-O \O FvO G$]C|$VE ,UN)Yu:Cl_ C} *<l>05BB 6i:&S:0  Ap$ZAwJ+z"QJ-izDY@d(~l ,-攄J(F:S"( n4.d-@Ty*2L#@{1Bz>_JB@w 3=Tk@d/ycLD %@~C&}F:nRC=.2!R I_ JzD k#4 v~8 ; -5 A Pn;+ d" ~5: ~qM> ք~ ȹ ȹu ȹN a@ |,o F'E F2 Z' 2C KG @{ RVr RV RVLt R+ T  V4  |*A& c2} s sD c; F( Ҫ ^ /' 4p< d+ i! r- zk PE! ¦eL7 x43E ]^^F1\K=> 4xbun=y~E_#g r/7*kC9k18.3>)7iN&Ok&OkAboutDialogBaseOm Synergy About SynergyAboutDialogBase UkjentUnknownAboutDialogBaseVersjon:Version:AboutDialogBase,Velg handling utfreChoose the action to performActionDialogBase*Konfigurer handlingenConfigure ActionActionDialogBase(Ls peker til skjermLock cursor to screenActionDialogBase&Trykk en hurtigtastPress a hotkeyActionDialogBase8Trykk og slipp en hurtigtastPress and release a hotkeyActionDialogBase&Slipp en hurtigtastRelease a hotkeyActionDialogBaseBytt i retningSwitch in directionActionDialogBaseBytt til skjermSwitch to screenActionDialogBase@Denne handlingen blir utfrt nrThis action is performed whenActionDialogBaseneddownActionDialogBasevenstreleftActionDialogBaseavoffActionDialogBaseponActionDialogBase,kun p disse skjermeneonly on these screensActionDialogBase hyrerightActionDialogBase(hurtigtasten trykkesthe hotkey is pressedActionDialogBase(hurtigtasten slippesthe hotkey is releasedActionDialogBase veksletoggleActionDialogBaseoppupActionDialogBaseDAngi spesifikasjon for hurtigtast:'Enter the specification for the hotkey:HotkeyDialogBaseHurtigtastHotkeyHotkeyDialogBase&Rediger&Edit MainWindow&Fil&File MainWindow &Hjelp&Help MainWindow &Start&Start MainWindow &Stopp&Stop MainWindow &Vindu&Window MainWindow<p>Din Synergy-versjon er utdatert. Versjon <b>%1</b> er n tilgjengelig for <a href="%2">nedlasting</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowBVelg en oppsettsfil for synergys.!Browse for a synergys config file MainWindowBKan ikke skrive konfigurasjonsfilCannot write configuration file MainWindow<Konfigurasjons-filnavn ugyldigConfiguration filename invalid MainWindow>Kunne ikke lagre oppsettsfilen.%Could not save configuration to file. MainWindow"Vertsnavn er tomtHostname is empty MainWindowVennligst fyll inn et vertsnavn for Synergy-klienten koble til.?Please fill in a hostname for the synergy client to connect to. MainWindow4Programmet kan ikke starteProgram can not be started MainWindow.Lagre oppsettet som ...Save configuration as... MainWindow Kunne ikke lagre Save failed MainWindowSynergySynergy MainWindow4Finner ikke Synergy klientSynergy client not found MainWindow&Synergy kjrer ikkeSynergy is not running. MainWindowSynergy kjrerSynergy is running. MainWindowSynergy starterSynergy is starting. MainWindow4Finner ikke Synergy serverSynergy server not found MainWindowSynergy stoppet uventet med kode %1.<br><br>Se i loggen for detaljer.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow6Synergy stoppet med en feil Synergy terminated with an error MainWindowZProgramfilen for Synergy-klienten finnes ikke5The executable for the synergy client does not exist. MainWindow\Programfilen for synergy-tjeneren finnes ikke.5The executable for the synergy server does not exist. MainWindow.Programfilen <br><br>%1<br><br> kunne ikke startes riktig, selv om den finnes. Sjekk at du har tilstrekkelige rettigheter til kjre dette programmet.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowDen midlertidige oppsettsfilen, som er ndvendig for starte Synergy, kan ikke opprettes.NThe temporary configuration file required to start synergy can not be written. MainWindow UkjentUnknown MainWindowDu har ikke lagt inn en gyldig oppsettsfil for synergy-tjeneren. Vil du velge oppsettsfilen n?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow&Om Synergy&About Synergy...MainWindowBase &Bruk&ApplyMainWindowBase&Velg... &Browse...MainWindowBase&Oppsettsfil:&Configuration file:MainWindowBase&&Sett opp tjener...&Configure Server...MainWindowBase &Skjul&HideMainWindowBase&Avslutt&QuitMainWindowBase&Tjener-IP: &Server IP:MainWindowBase&Vis&ShowMainWindowBase &Start&StartMainWindowBase*Sett opp interaktivt:Configure interactively:MainWindowBase&Endre innstillinger Edit settingsMainWindowBase SkjulHideMainWindowBaseIP-adresser: IP addresses:MainWindowBaseLoggLogMainWindowBaseAvsluttQuitMainWindowBaseKlarReadyMainWindowBaseKjrRunMainWindowBaseKjr Veiledning Run WizardMainWindowBase&Vis Status S&how StatusMainWindowBase S&toppS&topMainWindowBase0L&agre oppsettet som ...Save configuration &as...MainWindowBasezLagre det interaktivt opprettede tjener-oppsettet til en fil.@Save the interactively generated server configuration to a file.MainWindowBaseSkjermnavn: Screen name:MainWindowBaseInnstillingerSettingsMainWindowBaseVisShowMainWindowBase StoppStopMainWindowBaseSynergySynergyMainWindowBase4Bruk eksisterende oppsett:Use existing configuration:MainWindowBaseUten navnUnnamedNewScreenWidget$Konfigurer Synergy Setup SynergyPluginWizardPageTSynergy-oppsett (*.conf);;Alle filer (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectRSynergy-oppsett (*.sgc);;Alle filer (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObject`Systemstatusfeltet er utilgjengelig - avslutter.%System tray is unavailable, quitting.QObject(Skjermnavnet er tomtScreen name is emptyScreenSettingsDialog0Skjermnavn er likt aliasScreen name matches aliasScreenSettingsDialogSkjermnavnet kan ikke st tomt. Vennligst fyll inn et navn eller lukk dialogen.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogSkjermnavnet kan ikke vre likt som et alias. Vennligst fjern aliaset eller endre skjermnavnet.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog&Legg til&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBase&Dde hjrner &Dead cornersScreenSettingsDialogBase&Rettelser&FixesScreenSettingsDialogBase&Spesialtaster&Modifier keysScreenSettingsDialogBase &Fjern&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBaseA&liaserA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase&Nederst til venstre Bottom-leftScreenSettingsDialogBase"Nederst til hyre Bottom-rightScreenSettingsDialogBase Hj&rnestrrelse Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase*Fiksr CAPS LOCK tastFix CAPS LOCK keyScreenSettingsDialogBase(Fiksr NUM LOCK tastFix NUM LOCK keyScreenSettingsDialogBase.Fiksr SCROLL LOCK tastFix SCROLL LOCK keyScreenSettingsDialogBase2Fiksr XTest for XineramaFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBase IngenNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBaseSkjerm&navn: Screen &name:ScreenSettingsDialogBase&SkjerminnstillingerScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBase$verst til venstreTop-leftScreenSettingsDialogBase verst til hyre Top-rightScreenSettingsDialogBase<center>Skjerm: <b>%1</b></center><br>Dobbeltklikk for endre innstillinger<br>Dra skjermen til sppelbtta for fjerne deno
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel&Nederst til venstre &Bottom-leftServerConfigDialogBase2Kontroller klienter hvert&Check clients everyServerConfigDialogBase&Dde hjrner &Dead cornersServerConfigDialogBase&Rediger&EditServerConfigDialogBase&Hurtigtaster&HotkeysServerConfigDialogBase&Ny&NewServerConfigDialogBaseAlternativer&OptionsServerConfigDialogBase &Fjern&RemoveServerConfigDialogBaseBytt&SwitchServerConfigDialogBase&HandlingerA&ctionsServerConfigDialogBase<Avanserte tjener-innstillingerAdvanced server settingsServerConfigDialogBase"Nederst til hyre Bottom-ri&ghtServerConfigDialogBasetKonfigurer oppsettet for din Synergy tjener-konfigurasjon.:Configure the layout of your synergy server configuration.ServerConfigDialogBase Hjrnestrrelse: Cor&ner Size:ServerConfigDialogBase`Ikke overta som forgrunnsvindu p Windowstjenere0Don't take &foreground window on Windows serversServerConfigDialogBasezDra en skjerm fra oppsettet til sppelbtta for fjerne den.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaseVDra nye skjermer til oppsettet eller flytt rundt p de eksisterende. Dra en skjerm til sppelbtta for fjerne den. Dobbeltklikk en skjerm for endre dens innstillinger.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasezDra denne knappen til oppsettet for legge til en ny skjerm.1Drag this button to the grid to add a new screen.ServerConfigDialogBase En&dreE&ditServerConfigDialogBaseHurtigtasterHotkeysServerConfigDialogBaseN&yNe&wServerConfigDialogBase &FjernRe&moveServerConfigDialogBase2Synkroniser skjermsparereS&ynchronize screen saversServerConfigDialogBase*Skjermer og koblingerScreens and linksServerConfigDialogBase(Tjener-konfigurasjonServer ConfigurationServerConfigDialogBase,Bytt etter ha ventetSwitch &after waitingServerConfigDialogBase<Bytt ved dobbel berring innenSwitch on double &tap withinServerConfigDialogBase$verst til venstre To&p-leftServerConfigDialogBase verst til hyre Top-rig&htServerConfigDialogBase8Bruk relative musebevegelserUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseEr du sikker p at du vil gi Synergy forhyede rettigheter? Dette tillater Synergy kommunisere med forhyede prosesser og UAC dialoger. Dette kan fre til problemer med normale prosesser. Bruk dette kun om du m.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogHev SynergyElevate SynergySettingsDialog(Lagre loggfil til...Save log file to...SettingsDialogGrensesnitt: &Interface:SettingsDialogBase Sprk: &Language:SettingsDialogBaseLoggingniv:&Logging level:SettingsDialogBase&Diverse&MiscellaneousSettingsDialogBaseVelg... Browse...SettingsDialogBaseFeilskDebugSettingsDialogBaseFeilsk1Debug1SettingsDialogBaseFeilsk2Debug2SettingsDialogBaseFeilErrorSettingsDialogBaseInfoInfoSettingsDialogBaseLogg til fil Log to file:SettingsDialogBaseLoggingLoggingSettingsDialogBaseMerknadNoteSettingsDialogBase Port:P&ort:SettingsDialogBaseSkjermnavn Sc&reen name:SettingsDialogBaseInnstillingerSettingsSettingsDialogBaseAdvarselWarningSettingsDialogBaseXVennligst fyll inn e-postadresse og passord.-Please enter your email address and password. SetupWizard:Vennligst velg et alternativ.Please select an option. SetupWizard$Konfigurer Synergy Setup Synergy SetupWizard(Tjener eller Klient?Server or Client?SetupWizardBase$Konfigurer Synergy Setup SynergySetupWizardBaseSynergy kan du enkelt dele dine mus og tastatur mellom flere datamaskiner p skrivebordet, og det er gratis og Open Source. Bare flytte musen utenfor kanten av en datamaskin skjerm til en annen. Du kan ogs dele alle dine oppslagstavler. Alt du trenger er en nettverksforbindelse. Synergy er cross-platform (fungerer p Windows, Mac OS X og Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseFTakk for at du installerte Synergy!Thanks for installing Synergy!SetupWizardBaseVelkommenWelcomeSetupWizardBase UkjentUnknownVersionCheckerRInnlogging mislykket, en feil oppsto. %1$Login failed, an error occurred. %1 WebClientrInnlogging mislykket, en feil oppsto. Svar fra tjener: %16Login failed, an error occurred. Server response: %1 WebClient`Innlogging feilet, ugyldig e-post eller passord.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_no.ts000066400000000000000000001706741305627404700214440ustar00rootroot00000000000000 AboutDialogBase About Synergy Om Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Ukjent Version: Versjon: &Ok &Ok ActionDialogBase Configure Action Konfigurer handlingen Choose the action to perform Velg handling å utføre Press a hotkey Trykk en hurtigtast Release a hotkey Slipp en hurtigtast Press and release a hotkey Trykk og slipp en hurtigtast only on these screens kun på disse skjermene Switch to screen Bytt til skjerm Switch in direction Bytt i retning left venstre right høyre up opp down ned Lock cursor to screen Lås peker til skjerm toggle veksle on off av This action is performed when Denne handlingen blir utført når the hotkey is pressed hurtigtasten trykkes the hotkey is released hurtigtasten slippes AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Hurtigtast Enter the specification for the hotkey: Angi spesifikasjon for hurtigtast: MainWindow &Start &Start &File &Fil &Edit &Rediger &Window &Vindu &Help &Hjelp <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Din Synergy-versjon er utdatert. Versjon <b>%1</b> er nå tilgjengelig for <a href="%2">nedlasting</a>.</p> Program can not be started Programmet kan ikke starte The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Programfilen <br><br>%1<br><br> kunne ikke startes riktig, selv om den finnes. Sjekk at du har tilstrekkelige rettigheter til å kjøre dette programmet. Synergy client not found Finner ikke Synergy klient The executable for the synergy client does not exist. Programfilen for Synergy-klienten finnes ikke Hostname is empty Vertsnavn er tomt Please fill in a hostname for the synergy client to connect to. Vennligst fyll inn et vertsnavn for Synergy-klienten å koble til. Cannot write configuration file Kan ikke skrive konfigurasjonsfil The temporary configuration file required to start synergy can not be written. Den midlertidige oppsettsfilen, som er nødvendig for å starte Synergy, kan ikke opprettes. Configuration filename invalid Konfigurasjons-filnavn ugyldig You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Du har ikke lagt inn en gyldig oppsettsfil for synergy-tjeneren. Vil du velge oppsettsfilen nå? Synergy server not found Finner ikke Synergy server The executable for the synergy server does not exist. Programfilen for synergy-tjeneren finnes ikke. Synergy terminated with an error Synergy stoppet med en feil Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy stoppet uventet med kode %1.<br><br>Se i loggen for detaljer. &Stop &Stopp Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy starter Synergy is running. Synergy kjører Synergy is not running. Synergy kjører ikke Unknown Ukjent Synergy Synergy Browse for a synergys config file Velg en oppsettsfil for synergys. Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Lagre oppsettet som ... Save failed Kunne ikke lagre Could not save configuration to file. Kunne ikke lagre oppsettsfilen. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Skjermnavn: &Server IP: &Tjener-IP: &Start &Start Use existing configuration: Bruk eksisterende oppsett: &Configuration file: &Oppsettsfil: &Browse... &Velg... Configure interactively: Sett opp interaktivt: &Configure Server... &Sett opp tjener... Ready Klar Log Logg &Apply &Bruk IP addresses: IP-adresser: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Om Synergy &Quit &Avslutt Quit Avslutt Run Kjør S&top S&topp Stop Stopp S&how Status &Vis Status &Hide &Skjul Hide Skjul &Show &Vis Show Vis Save configuration &as... L&agre oppsettet som ... Save the interactively generated server configuration to a file. Lagre det interaktivt opprettede tjener-oppsettet til en fil. Settings Innstillinger Edit settings Endre innstillinger Run Wizard Kjør Veiledning NewScreenWidget Unnamed Uten navn PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Konfigurer Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy-oppsett (*.sgc);;Alle filer (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy-oppsett (*.conf);;Alle filer (*.*) System tray is unavailable, quitting. Systemstatusfeltet er utilgjengelig - avslutter. ScreenSettingsDialog Screen name is empty Skjermnavnet er tomt The screen name cannot be empty. Please either fill in a name or cancel the dialog. Skjermnavnet kan ikke stå tomt. Vennligst fyll inn et navn eller lukk dialogen. Screen name matches alias Skjermnavn er likt alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Skjermnavnet kan ikke være likt som et alias. Vennligst fjern aliaset eller endre skjermnavnet. ScreenSettingsDialogBase Screen Settings Skjerminnstillinger Screen &name: Skjerm&navn: A&liases A&liaser &Add &Legg til &Remove &Fjern &Modifier keys &Spesialtaster &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Ingen &Ctrl: &Ctrl: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners &Døde hjørner Top-left Øverst til venstre Top-right Øverst til høyre Bottom-left Nederst til venstre Bottom-right Nederst til høyre Corner Si&ze: Hj&ørnestørrelse &Fixes &Rettelser Fix CAPS LOCK key Fiksér CAPS LOCK tast Fix NUM LOCK key Fiksér NUM LOCK tast Fix SCROLL LOCK key Fiksér SCROLL LOCK tast Fix XTest for Xinerama Fiksér XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Skjerm: <b>%1</b></center><br>Dobbeltklikk for å endre innstillinger<br>Dra skjermen til søppelbøtta for å fjerne den ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Tjener-konfigurasjon Screens and links Skjermer og koblinger Drag a screen from the grid to the trashcan to remove it. Dra en skjerm fra oppsettet til søppelbøtta for å fjerne den. Configure the layout of your synergy server configuration. Konfigurer oppsettet for din Synergy tjener-konfigurasjon. Drag this button to the grid to add a new screen. Dra denne knappen til oppsettet for å legge til en ny skjerm. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Dra nye skjermer til oppsettet eller flytt rundt på de eksisterende. Dra en skjerm til søppelbøtta for å fjerne den. Dobbeltklikk en skjerm for å endre dens innstillinger. Hotkeys Hurtigtaster &Hotkeys &Hurtigtaster &New &Ny &Edit &Rediger &Remove &Fjern A&ctions &Handlinger Ne&w N&y E&dit En&dre Re&move &Fjern Advanced server settings Avanserte tjener-innstillinger &Switch Bytt Switch &after waiting Bytt etter å ha ventet ms ms Switch on double &tap within Bytt ved dobbel berøring innen &Options Alternativer &Check clients every Kontroller klienter hvert Use &relative mouse moves Bruk relative musebevegelser S&ynchronize screen savers Synkroniser skjermsparere Don't take &foreground window on Windows servers Ikke overta som forgrunnsvindu på Windowstjenere Ignore auto config clients &Dead corners &Døde hjørner To&p-left Øverst til venstre Top-rig&ht Øverst til høyre &Bottom-left Nederst til venstre Bottom-ri&ght Nederst til høyre Cor&ner Size: Hjørnestørrelse: SettingsDialog Save log file to... Lagre loggfil til... Elevate Synergy Hev Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Er du sikker på at du vil gi Synergy forhøyede rettigheter? Dette tillater Synergy å kommunisere med forhøyede prosesser og UAC dialoger. Dette kan føre til problemer med normale prosesser. Bruk dette kun om du må. SettingsDialogBase Settings Innstillinger Sc&reen name: Skjermnavn P&ort: Port: &Interface: Grensesnitt: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Logging &Logging level: Loggingnivå: Log to file: Logg til fil Browse... Velg... Error Feil &Language: Språk: &Miscellaneous &Diverse Warning Advarsel Note Merknad Info Info Debug Feilsøk Debug1 Feilsøk1 Debug2 Feilsøk2 SetupWizard Setup Synergy Konfigurer Synergy Please select an option. Vennligst velg et alternativ. Please enter your email address and password. Vennligst fyll inn e-postadresse og passord. SetupWizardBase Setup Synergy Konfigurer Synergy Welcome Velkommen Thanks for installing Synergy! Takk for at du installerte Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy kan du enkelt dele dine mus og tastatur mellom flere datamaskiner på skrivebordet, og det er gratis og Open Source. Bare flytte musen utenfor kanten av en datamaskin skjerm til en annen. Du kan også dele alle dine oppslagstavler. Alt du trenger er en nettverksforbindelse. Synergy er cross-platform (fungerer på Windows, Mac OS X og Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Tjener eller Klient? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Ukjent WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Innlogging feilet, ugyldig e-post eller passord. Login failed, an error occurred. %1 Innlogging mislykket, en feil oppsto. %1 Login failed, an error occurred. Server response: %1 Innlogging mislykket, en feil oppsto. Svar fra tjener: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_pes-IR.qm000066400000000000000000000020561305627404700221020ustar00rootroot00000000000000:+mYx 3\ Tm  s sOiH1'3*:Version:AboutDialogBase ~'FdownActionDialogBase~leftActionDialogBase .'EH4offActionDialogBase1H4FonActionDialogBase1'3*rightActionDialogBase('D'upActionDialogBaseH1'4 *F8E'* Edit settingsMainWindowBase.1H,QuitMainWindowBase',1'RunMainWindowBase*F8E'*SettingsMainWindowBase*HBAStopMainWindowBase ( F'EUnnamedNewScreenWidgetAltAltScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase*F8E'*SettingsSettingsDialogBasesynergy-1.8.8-stable/src/gui/res/lang/gui_pes-IR.ts000066400000000000000000001604011305627404700221120ustar00rootroot00000000000000 AboutDialogBase About Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: ویراست: &Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left چپ right راست up بالا down پایین Lock cursor to screen toggle on روشن off خاموش This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit خروج Run اجرا S&top Stop توقف S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings تنظیمات Edit settings ویرایش تنظیمات Run Wizard NewScreenWidget Unnamed بی نام PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings تنظیمات Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_pl-PL.qm000066400000000000000000000537011305627404700217320ustar00rootroot000000000000007MB}Su>(Z = 9nbj!404vIZPEv._$e;w9(($ ;H}H/O "ZO HO I]FL|&VE .UN+Yu:El_ a} "*>qlN2 EEM 8:(W:2  C$ZCJ-"QJ7-izF@d*l .3攄TJ w(I':S%( n4.d/@Ty,,L#B{3zW>JD?G 3=Tk@d1ycO|"T%@~ +C(}F;nZC>4#h I_( JzF k#6 v~: =. -5 Q Pn< d$ ~5) d- i! r- zk PG ¦eO x45' ]^3^Hr1\N=9> 6"bun?my~G% r/7,kC;k3.5u>[+!iQ&Ok&OkAboutDialogBaseO Synergy About SynergyAboutDialogBaseNieznaneUnknownAboutDialogBaseWersja:Version:AboutDialogBase4Wybierz akcj do wykonaniaChoose the action to performActionDialogBase Konfiguruj akcjeConfigure ActionActionDialogBasePZablokuj kursor myszki dla danego ekranuLock cursor to screenActionDialogBaseWci[nij klawiszPress a hotkeyActionDialogBase2Wci[nij i zwolnij klawiszPress and release a hotkeyActionDialogBaseZwolnij klawiszRelease a hotkeyActionDialogBase&PrzeBcz w kierunkuSwitch in directionActionDialogBase"Przejdz do ekranuSwitch to screenActionDialogBase8Ta akcja jest wykonywana gdyThis action is performed whenActionDialogBase w dBdownActionDialogBase w lewoleftActionDialogBasewyB.offActionDialogBasewB.onActionDialogBase,tylko na tych ekranachonly on these screensActionDialogBasew praworightActionDialogBase:klawisz skrtu jest wci[nitythe hotkey is pressedActionDialogBase:klawisz skrtu jest zwolnionythe hotkey is releasedActionDialogBaseprzeBcztoggleActionDialogBase w grupActionDialogBaseLWprowadz opis dla skrtu klawiszowego:'Enter the specification for the hotkey:HotkeyDialogBaseKlawisz skrtuHotkeyHotkeyDialogBase Edytuj&Edit MainWindowPlik&File MainWindow &Pomoc&Help MainWindow Start&Start MainWindowStop&Stop MainWindowOkno&Window MainWindow<p>Dostpna jest wersja %1, <a href="%2">odwiedz stron internetow</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowBWska| plik konfiguracyjny synergy!Browse for a synergys config file MainWindowPNie mo|na zapisa pliku konfiguracyjnegoCannot write configuration file MainWindowPNiewBa[ciwa nazwa pliku konfiguracyjnegoConfiguration filename invalid MainWindowPNie mo|na zapisa konfiguracji do pliku.%Could not save configuration to file. MainWindow:Pole "Nazwa hosta" jest pusteHostname is empty MainWindow~WypeBnij nazw hosta do ktrej ma si podBczy klient synergy.?Please fill in a hostname for the synergy client to connect to. MainWindow8Nie mo|na uruchomi programuProgram can not be started MainWindow6Zachowaj konfiguracj jako &Save configuration as... MainWindowBBd zapisu Save failed MainWindowSynergySynergy MainWindowJKlient Synergy nie zostaB odnalezionySynergy client not found MainWindow0Synergy nie uruchomione.Synergy is not running. MainWindow(Synergy uruchomione.Synergy is running. MainWindow2Synergy jest uruchamiane.Synergy is starting. MainWindow<Nie znaleziono serwera SynergySynergy server not found MainWindowSynergy zakoDczyB dziaBanie w sposb nieoczekiwany, kod wyj[cia %1 (exit code). <br><br>Wicej szczegBw w pliku logw wyj[ciowych.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowFSynergy zostaBo zatrzymane z bBdem Synergy terminated with an error MainWindowZPlik wykonywalny klienta synergy nie istnieje5The executable for the synergy client does not exist. MainWindowZPlik wykonywalny serwera synergy nie istnieje5The executable for the synergy server does not exist. MainWindowtPlik wykonawczy<br><br>%1<br><br>nie zostaB poprawnie uruchomiony, mimo, |e istnieje. Prosz sprawdzi czy dane konto posiada odpowiednie uprawnienia do uruchomienia wskazanej aplikacji.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowNie mo|na zapisa tymczasowego pliku konfiguracyjnego wymaganego do uruchomienia synergy.NThe temporary configuration file required to start synergy can not be written. MainWindowNieznaneUnknown MainWindowNie podaBe[ poprawnego pliku konfiguracji potrzebnego do uruchomienia serwera synergy. Czy chcesz wskaza ten plik teraz?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindowO Synergy...&About Synergy...MainWindowBase&Zastosuj&ApplyMainWindowBaseWyszukaj... &Browse...MainWindowBase*&Plik konfiguracyjny:&Configuration file:MainWindowBase(Konfiguruj Serwer...&Configure Server...MainWindowBase &Ukryj&HideMainWindowBaseZakoDcz&QuitMainWindowBaseIP &serwera &Server IP:MainWindowBase &Poka|&ShowMainWindowBase Start&StartMainWindowBase2Konfiguruj interaktywnie:Configure interactively:MainWindowBase"Edytuj ustawienia Edit settingsMainWindowBase UkryjHideMainWindowBaseAdresy IP: IP addresses:MainWindowBaseLogLogMainWindowBaseZakoDczQuitMainWindowBase GotoweReadyMainWindowBaseUruchomRunMainWindowBase Uruchom Kreatora Run WizardMainWindowBasePoka| status S&how StatusMainWindowBaseZatrzymajS&topMainWindowBase6Zapisz konfiguracj jako...Save configuration &as...MainWindowBaseZapisz interaktywnie wygenerowan konfiguracj serwera do pliku.@Save the interactively generated server configuration to a file.MainWindowBaseNazwa ekranu: Screen name:MainWindowBaseUstawieniaSettingsMainWindowBase Poka|ShowMainWindowBaseZatrzymajStopMainWindowBaseSynergySynergyMainWindowBase<U|yj istniejcej konfiguracji:Use existing configuration:MainWindowBaseNienazwanyUnnamedNewScreenWidget(Konfiguracja Synergy Setup SynergyPluginWizardPagehKonfiguracje Synergy (*.conf);;Wszystkie pliki (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectfKonfiguracje Synergy (*.sgc);;Wszystkie pliki (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectNTacka systemowa niedostpna, zamykanie &%System tray is unavailable, quitting.QObject.Nazwa ekranu jest pustaScreen name is emptyScreenSettingsDialog>Nazwa ekranu odpowiada aliasowiScreen name matches aliasScreenSettingsDialogNazwa ekranu nie mo|e by pusta. Wprowadz nazw lub anuluj to okno dialogowe.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogNazwa ekranu nie mo|e by taka sama jak alias. UsuD alias lub zmieD nazw ekranu.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog Dodaj&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBase&Naro|niki nieczynne &Dead cornersScreenSettingsDialogBasePoprawki&FixesScreenSettingsDialogBase,Klawisze &modyfikujce&Modifier keysScreenSettingsDialogBaseUsuD&RemoveScreenSettingsDialogBase Shift&Shift:ScreenSettingsDialogBase AliasyA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseLewy-dB Bottom-leftScreenSettingsDialogBasePrawy-dB Bottom-rightScreenSettingsDialogBase(Wielko[ naro|nikw: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase2Napraw przycisk CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase0Napraw przycisk NUM LOCKFix NUM LOCK keyScreenSettingsDialogBase6Napraw przycisk SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase.Napraw XTest w XineramaFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBase {adenNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBaseNazwa ekranu: Screen &name:ScreenSettingsDialogBase"Ustawienia ekranuScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBaseLewy-grnyTop-leftScreenSettingsDialogBasePrawy-grny Top-rightScreenSettingsDialogBase<center>Ekran: <b>%1</b></center><br>Kliknij dwukrotnie, aby edytowa ustawienia<br>Przecignij ekran do kosza, aby go usuno
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelDolny-lewy &Bottom-leftServerConfigDialogBase4&Sprawdz klientw co ka|de&Check clients everyServerConfigDialogBase&Naro|niki nieczynne &Dead cornersServerConfigDialogBase Edytuj&EditServerConfigDialogBase$&Skrty klawiszowe&HotkeysServerConfigDialogBase &Nowy&NewServerConfigDialogBase &Opcje&OptionsServerConfigDialogBaseUsuD&RemoveServerConfigDialogBase&PrzeBcz&SwitchServerConfigDialogBase A&kcjeA&ctionsServerConfigDialogBase>Zaawansowane ustawienia serweraAdvanced server settingsServerConfigDialogBaseDolny-prawy Bottom-ri&ghtServerConfigDialogBaseHKonfiguracja ukBadu serwera synergy.:Configure the layout of your synergy server configuration.ServerConfigDialogBase&Wielko[ naro|nika: Cor&ner Size:ServerConfigDialogBaserNie zmieniaj statusu okna na &wierzch w systemie Windows.0Don't take &foreground window on Windows serversServerConfigDialogBasefPrzecignij ekran zsiatki do kosza, aby go usun.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase<Przecignij nowe ekrany na siatk lub przeno[ istniejce. Przecignij ekran do kosza, aby go usun. Kliknij dwukrotnie wekran, aby edytowa jego ustawienia.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasel{eby doda nowy ekran, przesuD ten przycisk na siatk.1Drag this button to the grid to add a new screen.ServerConfigDialogBaseE&dytujE&ditServerConfigDialogBase"Skrty klawiszoweHotkeysServerConfigDialogBase No&wyNe&wServerConfigDialogBase U&suDRe&moveServerConfigDialogBase>S&ynchronizuj wygaszacze ekranuS&ynchronize screen saversServerConfigDialogBase&Ekrany ipoBczeniaScreens and linksServerConfigDialogBase(Konfiguracja serweraServer ConfigurationServerConfigDialogBase.PrzeBcz &po odczekaniuSwitch &after waitingServerConfigDialogBaseFPrzeBcz po &podwjnym stukniciu wSwitch on double &tap withinServerConfigDialogBaseGrny-lewy To&p-leftServerConfigDialogBaseGrny-prawy Top-rig&htServerConfigDialogBase<U|yj &wzgldnych ruchw myszkiUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseNCzy jeste[ pewien, |eby podnie[ uprawnienia Synergy? Pozwoli to Synergy wspBpracowa z innymi aplikacjami o podniesionych uprawnieniach oraz systemem UAC, ale mo|e stwarza problemy z aplikacjami bez podniesionych uprawnieD. Podno[ uprawnienia tylko w sytuacji, gdy naprawd tego potrzebujesz.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialog6Zwiksz uprawnienia SynergyElevate SynergySettingsDialog"Zapisz logi do...Save log file to...SettingsDialogInterfejs: &Interface:SettingsDialogBase Jzyk &Language:SettingsDialogBase"Poziom logowania:&Logging level:SettingsDialogBase&R|no[ci&MiscellaneousSettingsDialogBasePrzegldaj... Browse...SettingsDialogBase DebugDebugSettingsDialogBase Debug1Debug1SettingsDialogBase Debug2Debug2SettingsDialogBaseBBdErrorSettingsDialogBaseInfoInfoSettingsDialogBase,Zapisuj logi do pliku: Log to file:SettingsDialogBaseLogowanieLoggingSettingsDialogBase UwagaNoteSettingsDialogBase Port:P&ort:SettingsDialogBaseNazwa ekranu: Sc&reen name:SettingsDialogBaseUstawieniaSettingsSettingsDialogBaseOstrze|enieWarningSettingsDialogBaseXProsz wprowadzi swj adres e-mail i hasBo.-Please enter your email address and password. SetupWizard(Prosz wybra opcj,Please select an option. SetupWizard(Konfiguracja Synergy Setup Synergy SetupWizard$Klient czy Serwer?Server or Client?SetupWizardBase(Konfiguracja Synergy Setup SynergySetupWizardBase(Synergy pozwala w Batwy sposb dzieli si myszk i klawiatur pomidzy wieloma komputerami na Twoim biurku, jest darmowe i Open Source. Wystarczy przesun kursor myszy poza krawdz jednego monitora aby przej[ na monitor innego komputera. Mo|esz nawet dzieli wszystkie swoje schowki. Potrzebujesz do tego tylko poBczenia z sieci. Synergy jest wieloplatformowe (dziaBa na Windows, Mac OS X i Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseJDzikujemy za zainstalowanie Synergy!Thanks for installing Synergy!SetupWizardBase Witaj!WelcomeSetupWizardBaseNieznaneUnknownVersionChecker\Logowanie nie powiodBo si, wystpiB bBd. %1$Login failed, an error occurred. %1 WebClientLogowanie nie powiodBo si, wystpiB bBd. Odpowiedz serwera: %16Login failed, an error occurred. Server response: %1 WebClienthLogowanie nie powiodBo si - bBdny email lub hasBo.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_pl-PL.ts000066400000000000000000001716151305627404700217500ustar00rootroot00000000000000 AboutDialogBase About Synergy O Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Nieznane Version: Wersja: &Ok &Ok ActionDialogBase Configure Action Konfiguruj akcje Choose the action to perform Wybierz akcję do wykonania Press a hotkey Wciśnij klawisz Release a hotkey Zwolnij klawisz Press and release a hotkey Wciśnij i zwolnij klawisz only on these screens tylko na tych ekranach Switch to screen Przejdź do ekranu Switch in direction Przełącz w kierunku left w lewo right w prawo up w górę down w dół Lock cursor to screen Zablokuj kursor myszki dla danego ekranu toggle przełącz on wł. off wył. This action is performed when Ta akcja jest wykonywana gdy the hotkey is pressed klawisz skrótu jest wciśnięty the hotkey is released klawisz skrótu jest zwolniony AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Klawisz skrótu Enter the specification for the hotkey: Wprowadź opis dla skrótu klawiszowego: MainWindow &Start Start &File Plik &Edit Edytuj &Window Okno &Help &Pomoc <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Dostępna jest wersja %1, <a href="%2">odwiedź stronę internetową</a>.</p> Program can not be started Nie można uruchomić programu The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Plik wykonawczy<br><br>%1<br><br>nie został poprawnie uruchomiony, mimo, że istnieje. Proszę sprawdzić czy dane konto posiada odpowiednie uprawnienia do uruchomienia wskazanej aplikacji. Synergy client not found Klient Synergy nie został odnaleziony The executable for the synergy client does not exist. Plik wykonywalny klienta synergy nie istnieje Hostname is empty Pole "Nazwa hosta" jest puste Please fill in a hostname for the synergy client to connect to. Wypełnij nazwę hosta do której ma się podłączyć klient synergy. Cannot write configuration file Nie można zapisać pliku konfiguracyjnego The temporary configuration file required to start synergy can not be written. Nie można zapisać tymczasowego pliku konfiguracyjnego wymaganego do uruchomienia synergy. Configuration filename invalid Niewłaściwa nazwa pliku konfiguracyjnego You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Nie podałeś poprawnego pliku konfiguracji potrzebnego do uruchomienia serwera synergy. Czy chcesz wskazać ten plik teraz? Synergy server not found Nie znaleziono serwera Synergy The executable for the synergy server does not exist. Plik wykonywalny serwera synergy nie istnieje Synergy terminated with an error Synergy zostało zatrzymane z błędem Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy zakończył działanie w sposób nieoczekiwany, kod wyjścia %1 (exit code). <br><br>Więcej szczegółów w pliku logów wyjściowych. &Stop Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy jest uruchamiane. Synergy is running. Synergy uruchomione. Synergy is not running. Synergy nie uruchomione. Unknown Nieznane Synergy Synergy Browse for a synergys config file Wskaż plik konfiguracyjny synergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Zachowaj konfigurację jako… Save failed Błąd zapisu Could not save configuration to file. Nie można zapisać konfiguracji do pliku. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Nazwa ekranu: &Server IP: IP &serwera &Start Start Use existing configuration: Użyj istniejącej konfiguracji: &Configuration file: &Plik konfiguracyjny: &Browse... Wyszukaj... Configure interactively: Konfiguruj interaktywnie: &Configure Server... Konfiguruj Serwer... Ready Gotowe Log Log &Apply &Zastosuj IP addresses: Adresy IP: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... O Synergy... &Quit Zakończ Quit Zakończ Run Uruchom S&top Zatrzymaj Stop Zatrzymaj S&how Status Pokaż status &Hide &Ukryj Hide Ukryj &Show &Pokaż Show Pokaż Save configuration &as... Zapisz konfigurację jako... Save the interactively generated server configuration to a file. Zapisz interaktywnie wygenerowaną konfigurację serwera do pliku. Settings Ustawienia Edit settings Edytuj ustawienia Run Wizard Uruchom Kreatora NewScreenWidget Unnamed Nienazwany PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Konfiguracja Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Konfiguracje Synergy (*.sgc);;Wszystkie pliki (*.*) Synergy Configurations (*.conf);;All files (*.*) Konfiguracje Synergy (*.conf);;Wszystkie pliki (*.*) System tray is unavailable, quitting. Tacka systemowa niedostępna, zamykanie… ScreenSettingsDialog Screen name is empty Nazwa ekranu jest pusta The screen name cannot be empty. Please either fill in a name or cancel the dialog. Nazwa ekranu nie może być pusta. Wprowadź nazwę lub anuluj to okno dialogowe. Screen name matches alias Nazwa ekranu odpowiada aliasowi The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Nazwa ekranu nie może być taka sama jak alias. Usuń alias lub zmień nazwę ekranu. ScreenSettingsDialogBase Screen Settings Ustawienia ekranu Screen &name: Nazwa ekranu: A&liases Aliasy &Add Dodaj &Remove Usuń &Modifier keys Klawisze &modyfikujące &Shift: Shift Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Żaden &Ctrl: &Ctrl: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners Narożniki nieczynne Top-left Lewy-górny Top-right Prawy-górny Bottom-left Lewy-dół Bottom-right Prawy-dół Corner Si&ze: Wielkość narożników: &Fixes Poprawki Fix CAPS LOCK key Napraw przycisk CAPS LOCK Fix NUM LOCK key Napraw przycisk NUM LOCK Fix SCROLL LOCK key Napraw przycisk SCROLL LOCK Fix XTest for Xinerama Napraw XTest w Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Ekran: <b>%1</b></center><br>Kliknij dwukrotnie, aby edytować ustawienia<br>Przeciągnij ekran do kosza, aby go usunąć ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Konfiguracja serwera Screens and links Ekrany i połączenia Drag a screen from the grid to the trashcan to remove it. Przeciągnij ekran z siatki do kosza, aby go usunąć. Configure the layout of your synergy server configuration. Konfiguracja układu serwera synergy. Drag this button to the grid to add a new screen. Żeby dodać nowy ekran, przesuń ten przycisk na siatkę. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Przeciągnij nowe ekrany na siatkę lub przenoś istniejące. Przeciągnij ekran do kosza, aby go usunąć. Kliknij dwukrotnie w ekran, aby edytować jego ustawienia. Hotkeys Skróty klawiszowe &Hotkeys &Skróty klawiszowe &New &Nowy &Edit Edytuj &Remove Usuń A&ctions A&kcje Ne&w No&wy E&dit E&dytuj Re&move U&suń Advanced server settings Zaawansowane ustawienia serwera &Switch &Przełącz Switch &after waiting Przełącz &po odczekaniu ms ms Switch on double &tap within Przełącz po &podwójnym stuknięciu w &Options &Opcje &Check clients every &Sprawdź klientów co każde Use &relative mouse moves Użyj &względnych ruchów myszki S&ynchronize screen savers S&ynchronizuj wygaszacze ekranu Don't take &foreground window on Windows servers Nie zmieniaj statusu okna na &wierzch w systemie Windows. Ignore auto config clients &Dead corners Narożniki nieczynne To&p-left Górny-lewy Top-rig&ht Górny-prawy &Bottom-left Dolny-lewy Bottom-ri&ght Dolny-prawy Cor&ner Size: Wielkość narożnika: SettingsDialog Save log file to... Zapisz logi do... Elevate Synergy Zwiększ uprawnienia Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Czy jesteś pewien, żeby podnieść uprawnienia Synergy? Pozwoli to Synergy współpracować z innymi aplikacjami o podniesionych uprawnieniach oraz systemem UAC, ale może stwarzać problemy z aplikacjami bez podniesionych uprawnień. Podnoś uprawnienia tylko w sytuacji, gdy naprawdę tego potrzebujesz. SettingsDialogBase Settings Ustawienia Sc&reen name: Nazwa ekranu: P&ort: Port: &Interface: Interfejs: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Logowanie &Logging level: Poziom logowania: Log to file: Zapisuj logi do pliku: Browse... Przeglądaj... Error Błąd &Language: Język &Miscellaneous &Różności Warning Ostrzeżenie Note Uwaga Info Info Debug Debug Debug1 Debug1 Debug2 Debug2 SetupWizard Setup Synergy Konfiguracja Synergy Please select an option. Proszę wybrać opcję, Please enter your email address and password. Proszę wprowadzić swój adres e-mail i hasło. SetupWizardBase Setup Synergy Konfiguracja Synergy Welcome Witaj! Thanks for installing Synergy! Dziękujemy za zainstalowanie Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy pozwala w łatwy sposób dzielić się myszką i klawiaturą pomiędzy wieloma komputerami na Twoim biurku, jest darmowe i Open Source. Wystarczy przesunąć kursor myszy poza krawędź jednego monitora aby przejść na monitor innego komputera. Możesz nawet dzielić wszystkie swoje schowki. Potrzebujesz do tego tylko połączenia z siecią. Synergy jest wieloplatformowe (działa na Windows, Mac OS X i Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Klient czy Serwer? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Nieznane WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Logowanie nie powiodło się - błędny email lub hasło. Login failed, an error occurred. %1 Logowanie nie powiodło się, wystąpił błąd. %1 Login failed, an error occurred. Server response: %1 Logowanie nie powiodło się, wystąpił błąd. Odpowiedź serwera: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_pt-BR.qm000066400000000000000000000536531305627404700217400ustar00rootroot000000000000007Yt}S u>1(Z 8= nbj"4~#0vIZPEv.w_$e;w9L'(Op~;H}H/O "O HO I]F0VE w.UN+xYu:El_ } #L*>ol|1EE= 8:( :2n  C$ZCJ-@"QJ_-izF@d*0l -攄J (I/:S%( n4.d/g@Ty+L#Bt{3xdz>JD 3=Tk@d1ycO%@~ gC(}F;ntC>4r$ I_~ JzF k#6 v~: =4 -5 Pn< d%n ~5 d, i! r+ zk PG ¦eO+ x44 ]^^Hj1\N=+> 66bun?{y~G&u rH/+7,OkC;)k2.5S>!*iQOk&OkAboutDialogBaseSobre o Synergy About SynergyAboutDialogBaseDesconhecidoUnknownAboutDialogBaseVerso:Version:AboutDialogBase<Escolha a ao a ser executadaChoose the action to performActionDialogBaseConfigurar AoConfigure ActionActionDialogBase*Travar cursor na telaLock cursor to screenActionDialogBase6Pressione a tecla de atalhoPress a hotkeyActionDialogBaseFPressione e solte a tecla de atalhoPress and release a hotkeyActionDialogBase.Solte a tecla de atalhoRelease a hotkeyActionDialogBaseMude de direoSwitch in directionActionDialogBaseMude para telaSwitch to screenActionDialogBase8Essa ao executada quandoThis action is performed whenActionDialogBase abaixodownActionDialogBaseesquerdaleftActionDialogBasedesligaroffActionDialogBase ligaronActionDialogBase(somente nessas telasonly on these screensActionDialogBasedireitarightActionDialogBase>a tecla de atalho pressionadathe hotkey is pressedActionDialogBase2a tecla de atalho soltathe hotkey is releasedActionDialogBasealternartoggleActionDialogBase acimaupActionDialogBaseREntre com a descrio da tecla de atalho:'Enter the specification for the hotkey:HotkeyDialogBaseTecla de atalhoHotkeyHotkeyDialogBase Editar&Edit MainWindowArquivo&File MainWindow Ajuda&Help MainWindow Incio&Start MainWindow Parar&Stop MainWindow Janela&Window MainWindow<p>A sua verso do Synergy est desatualizada. Verso <b>%1</b> est disponvel para <a href="%2">download</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindow\Selecionar um arquivo de configurao synergys!Browse for a synergys config file MainWindowNNo foi possvel gravar as configuraoCannot write configuration file MainWindowPNome do arquivo de configurao invlidoConfiguration filename invalid MainWindowdNo foi possvel salvar a configurao no arquivo.%Could not save configuration to file. MainWindow"Nome do servidor:Hostname is empty MainWindowPor favor, preencha um nome do servidor para o cliente Synergy se conectar.?Please fill in a hostname for the synergy client to connect to. MainWindow<Programa no pode ser iniciadoProgram can not be started MainWindow:Gravar a configurao como...Save configuration as... MainWindowGravao falhou Save failed MainWindowSynergySynergy MainWindowFCliente Synergy no foi encontrado.Synergy client not found MainWindow2Synergy no esta rodando.Synergy is not running. MainWindow*Synergy esta rodando.Synergy is running. MainWindow*Synergy foi iniciado.Synergy is starting. MainWindowLServidor do Synergy no foi encontradoSynergy server not found MainWindowSynergy fechou inesperadamente retornando o cdigo %1.<br><br>Por favor veja o log para detalhes.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow8Synergy terminou com um erro Synergy terminated with an error MainWindowdO executvel para o cliente do synergy no existe.5The executable for the synergy client does not exist. MainWindowfO executvel para o servidor do synergy no existe.5The executable for the synergy server does not exist. MainWindow(O executvel <br><br>%1<br><br>no pde ser iniciado com xito. Por favor, verifique se voc tem permisses suficientes para executar este programa.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowO arquivo temporrio de configurao, necessrio para iniciar o Synergy, no pode ser gravado.NThe temporary configuration file required to start synergy can not be written. MainWindowDesconhecidoUnknown MainWindowVoc no preencheu um arquivo de configurao vlido para o servidor do Synergy. Voc quer procur-lo agora?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow$Sobre o Synergy...&About Synergy...MainWindowBaseAplicar&ApplyMainWindowBaseNavegar... &Browse...MainWindowBase0Arquivo de configurao:&Configuration file:MainWindowBase&Configurar servidor&Configure Server...MainWindowBase&Ocultar&HideMainWindowBaseSair&QuitMainWindowBaseIP do servidor &Server IP:MainWindowBase&Exibir&ShowMainWindowBase Incio&StartMainWindowBase6Configurar interativamente:Configure interactively:MainWindowBase(Editar configuraes Edit settingsMainWindowBaseOcultarHideMainWindowBaseEndereo ip: IP addresses:MainWindowBaseRegistroLogMainWindowBaseSairQuitMainWindowBase ProntoReadyMainWindowBase RodarRunMainWindowBase*Executar o assistente Run WizardMainWindowBaseMostrar Status S&how StatusMainWindowBase PararS&topMainWindowBase:Gravar a configurao como...Save configuration &as...MainWindowBaseSalvar a configurao do servidor gerada dinamicamente para um arquivo.@Save the interactively generated server configuration to a file.MainWindowBaseNome da tela: Screen name:MainWindowBaseConfiguraesSettingsMainWindowBase ExibirShowMainWindowBase PararStopMainWindowBaseSynergySynergyMainWindowBasedUsar a configurao existente:Use a configurao eUse existing configuration:MainWindowBaseSem nomeUnnamedNewScreenWidget$Configurar Synergy Setup SynergyPluginWizardPagetConfiguraes do Synergy (*.conf);;Todos os arquivos (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectrConfiguraes do Synergy (*.sgc);;Todos os arquivos (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectdA rea de notificao no est disponvel, saindo.%System tray is unavailable, quitting.QObject<O nome de exibio est vazio.Screen name is emptyScreenSettingsDialogLNome de exibio corresponde o apelidoScreen name matches aliasScreenSettingsDialogO nome de exibio no pode ser vazio. Por favor preencha o nome ou cancele.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogAdicionar&AddScreenSettingsDialogBase Ctrl:&Ctrl:ScreenSettingsDialogBase Cantos &Dead cornersScreenSettingsDialogBaseCorrees&FixesScreenSettingsDialogBase(Teclas modificadoras&Modifier keysScreenSettingsDialogBaseRemover&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBaseApelidosA&liasesScreenSettingsDialogBaseAlt:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase"Inferior-esquerdo Bottom-leftScreenSettingsDialogBase Inferior-direito Bottom-rightScreenSettingsDialogBase"Tamanho do Canto: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase.Trava a tecla CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase.Trava a tecla CAPS LOCKFix NUM LOCK keyScreenSettingsDialogBase2Trava a tecla SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase<Corrigir XTest para o XineramaFix XTest for XineramaScreenSettingsDialogBase Meta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseNenhumaNoneScreenSettingsDialogBase Super:S&uper:ScreenSettingsDialogBaseNome da tela: Screen &name:ScreenSettingsDialogBase*Configuraes da telaScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBase"Superior-esquerdoTop-leftScreenSettingsDialogBase Superior-direito Top-rightScreenSettingsDialogBase<center>Tela: <b>%1</b></center><br>Clique duplo para editar configuraes<br>Arraste a tela para a lixeira para remove-la.o
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel"Inferior-esquerdo &Bottom-leftServerConfigDialogBase8Verificar os clientes a cada&Check clients everyServerConfigDialogBase Cantos &Dead cornersServerConfigDialogBase Editar&EditServerConfigDialogBase Teclas de Atalho&HotkeysServerConfigDialogBaseNovo&NewServerConfigDialogBase Opes&OptionsServerConfigDialogBaseRemover&RemoveServerConfigDialogBase Trocar&SwitchServerConfigDialogBase AesA&ctionsServerConfigDialogBaseFConfiguraes avanadas de servidorAdvanced server settingsServerConfigDialogBase Inferior-direito Bottom-ri&ghtServerConfigDialogBase~Configure a disposio na sua configurao do servidor synergy.:Configure the layout of your synergy server configuration.ServerConfigDialogBase"Tamanho do Canto: Cor&ner Size:ServerConfigDialogBasenNo tome janela de primeiro plano em servidores Windows0Don't take &foreground window on Windows serversServerConfigDialogBase^Arraste uma tela para a lixeira para remove-la.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase>Arrste novas telas para o grid ou mova as existentes. Arraste uma tela para a lixeira para remove-la. Clique duplo numa tela para editar as suas configuraes.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasexArraste este boto para o grid para adicionar uma nova tela.1Drag this button to the grid to add a new screen.ServerConfigDialogBase EditarE&ditServerConfigDialogBase Teclas de AtalhoHotkeysServerConfigDialogBaseNovoNe&wServerConfigDialogBaseRemoverRe&moveServerConfigDialogBase8Sincronize protees de telaS&ynchronize screen saversServerConfigDialogBaseTelas e linksScreens and linksServerConfigDialogBase0Configurao do servidorServer ConfigurationServerConfigDialogBase(Trocar aps aguardarSwitch &after waitingServerConfigDialogBase6Ligar em toque duplo dentroSwitch on double &tap withinServerConfigDialogBase"Superior-esquerdo To&p-leftServerConfigDialogBase Superior-direito Top-rig&htServerConfigDialogBaseBUsar movimentos relativo do mouseUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseVoc quer elevar os privilegios de execuo do Synergy? Isso permite ao Synergy interagir com processos privilegiados e com o UAC, mas pode causar problemas com processos sem privilgios. Eleve os privilgios de execuo somente se voc realmente precisar.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogRElevar privilgios de execuo do SynergyElevate SynergySettingsDialog:Salvar o arquivo de log em...Save log file to...SettingsDialogInterface &Interface:SettingsDialogBase&Idioma: &Language:SettingsDialogBaseNvel do log:&Logging level:SettingsDialogBaseDiversos&MiscellaneousSettingsDialogBaseNavegar... Browse...SettingsDialogBaseDepurarDebugSettingsDialogBaseDepurar1Debug1SettingsDialogBaseDepurar2Debug2SettingsDialogBaseErroErrorSettingsDialogBaseInfoInfoSettingsDialogBaseSalvar log em: Log to file:SettingsDialogBaseRegistrandoLoggingSettingsDialogBaseNotaNoteSettingsDialogBase Porta:P&ort:SettingsDialogBase"Nome de Exibio: Sc&reen name:SettingsDialogBaseConfiguraesSettingsSettingsDialogBase AvisoWarningSettingsDialogBasefPor favor informe o seu endereo de e-mail e senha.-Please enter your email address and password. SetupWizard<Por favor, selecione uma opoPlease select an option. SetupWizard$Configurar Synergy Setup Synergy SetupWizard(Servidor ou Cliente?Server or Client?SetupWizardBase$Configurar Synergy Setup SynergySetupWizardBaseJSynergy permite que voc compartilhe seu mouse e teclado facilmente entre vrios computadores na sua rea de trabalho, alm de ser gratuito e de cdigo aberto. Basta mover o mouse para fora da borda da tela de um computador para outro. Voc pode at mesmo compartilhar todas as suas reas de transferncia. Tudo que voc precisa de uma conexo de rede. Synergy multiplataforma (funciona em Windows, Mac OS X e Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBase@Obrigado por instalar o Synergy!Thanks for installing Synergy!SetupWizardBaseBem-vindoWelcomeSetupWizardBaseDesconhecidoUnknownVersionCheckerFFalha no login, ocorreu um erro: %1$Login failed, an error occurred. %1 WebClientpErro no login, ocorreu um erro. Resposta do servidor: %16Login failed, an error occurred. Server response: %1 WebClientTFalha no login, e-mail ou senha invlidos.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_pt-BR.ts000066400000000000000000001714671305627404700217550ustar00rootroot00000000000000 AboutDialogBase About Synergy Sobre o Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Desconhecido Version: Versão: &Ok Ok ActionDialogBase Configure Action Configurar Ação Choose the action to perform Escolha a ação a ser executada Press a hotkey Pressione a tecla de atalho Release a hotkey Solte a tecla de atalho Press and release a hotkey Pressione e solte a tecla de atalho only on these screens somente nessas telas Switch to screen Mude para tela Switch in direction Mude de direção left esquerda right direita up acima down abaixo Lock cursor to screen Travar cursor na tela toggle alternar on ligar off desligar This action is performed when Essa ação é executada quando the hotkey is pressed a tecla de atalho é pressionada the hotkey is released a tecla de atalho é solta AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Tecla de atalho Enter the specification for the hotkey: Entre com a descrição da tecla de atalho: MainWindow &Start Início &File Arquivo &Edit Editar &Window Janela &Help Ajuda <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>A sua versão do Synergy está desatualizada. Versão <b>%1</b> está disponível para <a href="%2">download</a>.</p> Program can not be started Programa não pode ser iniciado The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. O executável <br><br>%1<br><br>não pôde ser iniciado com êxito. Por favor, verifique se você tem permissões suficientes para executar este programa. Synergy client not found Cliente Synergy não foi encontrado. The executable for the synergy client does not exist. O executável para o cliente do synergy não existe. Hostname is empty Nome do servidor: Please fill in a hostname for the synergy client to connect to. Por favor, preencha um nome do servidor para o cliente Synergy se conectar. Cannot write configuration file Não foi possível gravar as configuração The temporary configuration file required to start synergy can not be written. O arquivo temporário de configuração, necessário para iniciar o Synergy, não pode ser gravado. Configuration filename invalid Nome do arquivo de configuração inválido You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Você não preencheu um arquivo de configuração válido para o servidor do Synergy. Você quer procurá-lo agora? Synergy server not found Servidor do Synergy não foi encontrado The executable for the synergy server does not exist. O executável para o servidor do synergy não existe. Synergy terminated with an error Synergy terminou com um erro Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy fechou inesperadamente retornando o código %1.<br><br>Por favor veja o log para detalhes. &Stop Parar Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy foi iniciado. Synergy is running. Synergy esta rodando. Synergy is not running. Synergy não esta rodando. Unknown Desconhecido Synergy Synergy Browse for a synergys config file Selecionar um arquivo de configuração synergys Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Gravar a configuração como... Save failed Gravação falhou Could not save configuration to file. Não foi possível salvar a configuração no arquivo. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Nome da tela: &Server IP: IP do servidor &Start Início Use existing configuration: Usar a configuração existente:Use a configuração e &Configuration file: Arquivo de configuração: &Browse... Navegar... Configure interactively: Configurar interativamente: &Configure Server... Configurar servidor Ready Pronto Log Registro &Apply Aplicar IP addresses: Endereço ip: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Sobre o Synergy... &Quit Sair Quit Sair Run Rodar S&top Parar Stop Parar S&how Status Mostrar Status &Hide &Ocultar Hide Ocultar &Show &Exibir Show Exibir Save configuration &as... Gravar a configuração como... Save the interactively generated server configuration to a file. Salvar a configuração do servidor gerada dinamicamente para um arquivo. Settings Configurações Edit settings Editar configurações Run Wizard Executar o assistente NewScreenWidget Unnamed Sem nome PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Configurar Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Configurações do Synergy (*.sgc);;Todos os arquivos (*.*) Synergy Configurations (*.conf);;All files (*.*) Configurações do Synergy (*.conf);;Todos os arquivos (*.*) System tray is unavailable, quitting. A área de notificação não está disponível, saindo. ScreenSettingsDialog Screen name is empty O nome de exibição está vazio. The screen name cannot be empty. Please either fill in a name or cancel the dialog. O nome de exibição não pode ser vazio. Por favor preencha o nome ou cancele. Screen name matches alias Nome de exibição corresponde o apelido The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Configurações da tela Screen &name: Nome da tela: A&liases Apelidos &Add Adicionar &Remove Remover &Modifier keys Teclas modificadoras &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Nenhuma &Ctrl: Ctrl: Al&t: Alt: M&eta: Meta: S&uper: Super: &Dead corners Cantos Top-left Superior-esquerdo Top-right Superior-direito Bottom-left Inferior-esquerdo Bottom-right Inferior-direito Corner Si&ze: Tamanho do Canto: &Fixes Correções Fix CAPS LOCK key Trava a tecla CAPS LOCK Fix NUM LOCK key Trava a tecla CAPS LOCK Fix SCROLL LOCK key Trava a tecla SCROLL LOCK Fix XTest for Xinerama Corrigir XTest para o Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Tela: <b>%1</b></center><br>Clique duplo para editar configurações<br>Arraste a tela para a lixeira para remove-la. ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Configuração do servidor Screens and links Telas e links Drag a screen from the grid to the trashcan to remove it. Arraste uma tela para a lixeira para remove-la. Configure the layout of your synergy server configuration. Configure a disposição na sua configuração do servidor synergy. Drag this button to the grid to add a new screen. Arraste este botão para o grid para adicionar uma nova tela. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Arrste novas telas para o grid ou mova as existentes. Arraste uma tela para a lixeira para remove-la. Clique duplo numa tela para editar as suas configurações. Hotkeys Teclas de Atalho &Hotkeys Teclas de Atalho &New Novo &Edit Editar &Remove Remover A&ctions Ações Ne&w Novo E&dit Editar Re&move Remover Advanced server settings Configurações avançadas de servidor &Switch Trocar Switch &after waiting Trocar após aguardar ms ms Switch on double &tap within Ligar em toque duplo dentro &Options Opções &Check clients every Verificar os clientes a cada Use &relative mouse moves Usar movimentos relativo do mouse S&ynchronize screen savers Sincronize proteções de tela Don't take &foreground window on Windows servers Não tome janela de primeiro plano em servidores Windows Ignore auto config clients &Dead corners Cantos To&p-left Superior-esquerdo Top-rig&ht Superior-direito &Bottom-left Inferior-esquerdo Bottom-ri&ght Inferior-direito Cor&ner Size: Tamanho do Canto: SettingsDialog Save log file to... Salvar o arquivo de log em... Elevate Synergy Elevar privilégios de execução do Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Você quer elevar os privilegios de execução do Synergy? Isso permite ao Synergy interagir com processos privilegiados e com o UAC, mas pode causar problemas com processos sem privilégios. Eleve os privilégios de execução somente se você realmente precisar. SettingsDialogBase Settings Configurações Sc&reen name: Nome de Exibição: P&ort: Porta: &Interface: Interface Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Registrando &Logging level: Nível do log: Log to file: Salvar log em: Browse... Navegar... Error Erro &Language: &Idioma: &Miscellaneous Diversos Warning Aviso Note Nota Info Info Debug Depurar Debug1 Depurar1 Debug2 Depurar2 SetupWizard Setup Synergy Configurar Synergy Please select an option. Por favor, selecione uma opção Please enter your email address and password. Por favor informe o seu endereço de e-mail e senha. SetupWizardBase Setup Synergy Configurar Synergy Welcome Bem-vindo Thanks for installing Synergy! Obrigado por instalar o Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy permite que você compartilhe seu mouse e teclado facilmente entre vários computadores na sua área de trabalho, além de ser gratuito e de código aberto. Basta mover o mouse para fora da borda da tela de um computador para outro. Você pode até mesmo compartilhar todas as suas áreas de transferência. Tudo que você precisa é de uma conexão de rede. Synergy é multiplataforma (funciona em Windows, Mac OS X e Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Servidor ou Cliente? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Desconhecido WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Falha no login, e-mail ou senha inválidos. Login failed, an error occurred. %1 Falha no login, ocorreu um erro: %1 Login failed, an error occurred. Server response: %1 Erro no login, ocorreu um erro. Resposta do servidor: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_pt-PT.qm000066400000000000000000000514121305627404700217470ustar00rootroot000000000000008}S -u>(Z = nbj#14(E1vGEv.3_%e=Jw9F(@( ;H}H0O #O FO Gs]DVE /eUN,DYu:D]l_ g} $>*?l2ChC 9_:(:3h  BC$ZB#J."QJ-izEK@d*l .攄J" (G( n4.d0C@Ty,L#A{46>!(z>JB 3*=Tzk@d2 %@~ C)*}F=nvC@V5$ I_H JzE k#7 v~;e > -5  Pn>+ d&v ~5= ք~ ȹF ȹ" ȹM' aAi |/ F) F4 Z) 5 KG i @{g RV RV RVL R T# V40  |*A c5[ s"T sE c? F+F Ҫ ^ /* 4p? d- i! r- zk+ PF ¦eL x46 ]^^FO1\L=/> 7d& r//7-%kC<}k4.6>+iM`&Ok&OkAboutDialogBase"Acerca de Synergy About SynergyAboutDialogBaseDesconhecidoUnknownAboutDialogBase VersoVersion:AboutDialogBase:Seleccionar a ao a executarChoose the action to performActionDialogBaseDefinir a aoConfigure ActionActionDialogBase.Manter o cursor no ecrLock cursor to screenActionDialogBase<Pressionar uma tecla de atalhoPress a hotkeyActionDialogBaseNPressionar e largar uma tecla de atalhoPress and release a hotkeyActionDialogBase4Largar uma tecla de atalhoRelease a hotkeyActionDialogBase"Mudar na direcoSwitch in directionActionDialogBase"Mudar para o ecrSwitch to screenActionDialogBase8Esta ao executada quandoThis action is performed whenActionDialogBase baixodownActionDialogBaseesquerdaleftActionDialogBasedesligadooffActionDialogBase ligadoonActionDialogBase&apenas nestes ecrsonly on these screensActionDialogBasedireitarightActionDialogBase>a tecla de atalho pressionadathe hotkey is pressedActionDialogBase6a tecla de atalho largadathe hotkey is releasedActionDialogBasealternartoggleActionDialogBasecimaupActionDialogBaseTColoque a descrio para a tecla de atalho'Enter the specification for the hotkey:HotkeyDialogBaseTecla de atalhoHotkeyHotkeyDialogBase&Editar&Edit MainWindow&Ficheiro&File MainWindow &Ajuda&Help MainWindow&Iniciar&Start MainWindow &Parar&Stop MainWindow&Janela&Window MainWindow<p>A tua verso do Synergy est desatualizada. Verso<b>%1</b> est agora disponivel <a href="%2">para download</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowdSeleccionar um ficheiro de configurao de synergy!Browse for a synergys config file MainWindowjNo foi possivel escrever no ficheiro de configuraoCannot write configuration file MainWindowBFicheiro de configurao invlidoConfiguration filename invalid MainWindowpNo foi possvel guardar a configurao para o ficheiro.%Could not save configuration to file. MainWindowPO nome de computador no est preenchidoHostname is empty MainWindowPor favor coloque o nome de computador ao qual o cliente Synergy vai ligar-se?Please fill in a hostname for the synergy client to connect to. MainWindow>O programa no consegue iniciarProgram can not be started MainWindow<Guardar a configurao como...Save configuration as... MainWindow Falhou o registo Save failed MainWindowSynergySynergy MainWindowHO cliente Synergy no foi encontradoSynergy client not found MainWindow8Synergy no est em execuoSynergy is not running. MainWindow0Synergy est em execuoSynergy is running. MainWindow,Synergy est a iniciarSynergy is starting. MainWindowPO servidor de synergy no foi encontradoSynergy server not found MainWindowSynergy terminou inesperadamente com o erro %1.<br><br>Por favor, verifique o registo de log para mais detalhes.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow2Synergy terminou com erro Synergy terminated with an error MainWindowZO executvel de cliente de Synergy no existe5The executable for the synergy client does not exist. MainWindow^O executvel de servidor de synergy no existe.5The executable for the synergy server does not exist. MainWindowO programa<br><br>%1<br><br>, embora exista, no teve xito a iniciar. Por favor, verifique se tem permisses suficientes para o executar.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowNo foi possvel escrever no ficheiro temporrio de configurao de synergy, o qual indispensvel para o iniciar.NThe temporary configuration file required to start synergy can not be written. MainWindowDesconhecidoUnknown MainWindowNo colocaste um ficheiro de configurao vlido para o servidor de synergy. Queres seleccionar o ficheiro de configurao agora?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow*&Acerca de Synergy...&About Synergy...MainWindowBase&Aplicar&ApplyMainWindowBase&Explorar... &Browse...MainWindowBase4Ficheiro de &configurao:&Configuration file:MainWindowBase.&Configurar Servidor...&Configure Server...MainWindowBase&Esconder&HideMainWindowBase &Sair&QuitMainWindowBase &IP do servidor: &Server IP:MainWindowBase&Mostrar&ShowMainWindowBase&Iniciar&StartMainWindowBase0Configurao interativa:Configure interactively:MainWindowBase$Alterar definies Edit settingsMainWindowBaseEsconderHideMainWindowBaseEndereos IP: IP addresses:MainWindowBase$Registo de eventosLogMainWindowBaseSairQuitMainWindowBase ProntoReadyMainWindowBaseExecutarRunMainWindowBaseUsar assistente Run WizardMainWindowBaseM&ostrar Estado S&how StatusMainWindowBase &PararS&topMainWindowBase>Guardar a configurao &como...Save configuration &as...MainWindowBaseGuardar a configurao gerada interactivamente para um ficheiro.@Save the interactively generated server configuration to a file.MainWindowBaseNome do ecr: Screen name:MainWindowBaseDefiniesSettingsMainWindowBaseMostrarShowMainWindowBase PararStopMainWindowBaseSynergySynergyMainWindowBase>Usar uma configurao guardada:Use existing configuration:MainWindowBaseSem nomeUnnamedNewScreenWidget$Configurar Synergy Setup SynergyPluginWizardPagetConfigurao de synergy (*.conf);;Todos os ficheiros (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectrConfigurao de synergy (*.sgc);;Todos os ficheiros (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectzA rea de notificao no est disponivel disponivel, saindo.%System tray is unavailable, quitting.QObject>O nome do ecr no foi definidoScreen name is emptyScreenSettingsDialogO nome do ecr no pode estar vazio. Preenche a nome ou fecha a janela.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialog&Adicionar&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBase(&Cantos inacessveis &Dead cornersScreenSettingsDialogBaseCo&rreces&FixesScreenSettingsDialogBase(&Teclas de modulao&Modifier keysScreenSettingsDialogBase&Remover&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBase&Nomes al&ternativosA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase.Canto inferior esquerdo Bottom-leftScreenSettingsDialogBase,Canto inferior direito Bottom-rightScreenSettingsDialogBase&Di&menso do canto: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase4Corrigir a tecla CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase2Corrigir a tecla NUM LOCKFix NUM LOCK keyScreenSettingsDialogBase8Corrigir a tecla SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase8Corrigir XTest para XineramaFix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBase NenhumNoneScreenSettingsDialogBaseS&uper:S&uper:ScreenSettingsDialogBase&Nome do ecr: Screen &name:ScreenSettingsDialogBase*Configuraes de ecrScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBase.Canto superior esquerdoTop-leftScreenSettingsDialogBase,Canto superior direito Top-rightScreenSettingsDialogBase<center>Ecr: <b>%1</b></center><br>duplo clique para alterar as definies<br>Arrastar o ecr para o lixo para o removero
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel0Canto &inferior esquerdo &Bottom-leftServerConfigDialogBase4&Verificar clientes a cada&Check clients everyServerConfigDialogBase(&Cantos inacessveis &Dead cornersServerConfigDialogBase&Editar&EditServerConfigDialogBase"&Teclas de atalho&HotkeysServerConfigDialogBase &Novo&NewServerConfigDialogBase&Opes&OptionsServerConfigDialogBase&Remover&RemoveServerConfigDialogBase&Alternar&SwitchServerConfigDialogBase &AesA&ctionsServerConfigDialogBase@Definies avanadas do servidorAdvanced server settingsServerConfigDialogBase.Canto inferior direit&o Bottom-ri&ghtServerConfigDialogBase|Configurar a disposio na configurao do servidor de synergy:Configure the layout of your synergy server configuration.ServerConfigDialogBase&Dimenso do Ca&nto: Cor&ner Size:ServerConfigDialogBaserNo tirar o &foco da janela activa nos servidores Windows0Don't take &foreground window on Windows serversServerConfigDialogBaselArrastar um ecr da grelha para o lixo para o remover.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaseFArrastar novos ecrs para a grelha ou mover os existentes. Arrastar um ecr para o lixo para o remover. Faa duplo clique num ecr para alterar as suas definies.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBase|Arrastar este boto para a grelha para adicionar um novo ecr.1Drag this button to the grid to add a new screen.ServerConfigDialogBase&AlterarE&ditServerConfigDialogBase Teclas de atalhoHotkeysServerConfigDialogBase No&voNe&wServerConfigDialogBaseRe&moverRe&moveServerConfigDialogBase@S&incronizar protectores de ecrS&ynchronize screen saversServerConfigDialogBase Ecrs e ligaesScreens and linksServerConfigDialogBase0Configurao do servidorServer ConfigurationServerConfigDialogBase.Alternar &aps aguardarSwitch &after waitingServerConfigDialogBase@Alternar ao tocar duas &vezes emSwitch on double &tap withinServerConfigDialogBase0Canto su&perior esquerdo To&p-leftServerConfigDialogBase.Canto superior &direito Top-rig&htServerConfigDialogBaseLUtilizar movimentos &relativos do ratoUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBase Elevar o SynergyElevate SynergySettingsDialog\Guardar ficheiro de registo de eventos para...Save log file to...SettingsDialog&Interface: &Interface:SettingsDialogBase&Linguagem: &Language:SettingsDialogBase$&Nivel de registo:&Logging level:SettingsDialogBaseExplorar... Browse...SettingsDialogBaseDepuraoDebugSettingsDialogBaseDepurao1Debug1SettingsDialogBaseDepurao2Debug2SettingsDialogBaseErroErrorSettingsDialogBaseInformaoInfoSettingsDialogBase(Ficheiro de registo: Log to file:SettingsDialogBase$Registo de eventosLoggingSettingsDialogBaseNotificaoNoteSettingsDialogBaseP&orto:P&ort:SettingsDialogBaseNome do ecr: Sc&reen name:SettingsDialogBaseDefiniesSettingsSettingsDialogBase AvisoWarningSettingsDialogBase>Por favor selecciona uma opo.Please select an option. SetupWizard$Configurar Synergy Setup Synergy SetupWizard(Servidor ou Cliente?Server or Client?SetupWizardBase$Configurar Synergy Setup SynergySetupWizardBaseSynergy permite que uses o teu rato e teclado para controlar vrios computadores na tua secretria em simultneo, gratuito e Open Source. Basta mover o rato para um lado ou para outro para mudar de ecr. Podes at copiar e colar de um ecr para o outro. Precisas apenas de uma ligao de rede. O Synergy cross-platform (funciona em Windows, Mac OS X e Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseDObrigado por instalares o Synergy!Thanks for installing Synergy!SetupWizardBaseBem-vindo(a)WelcomeSetupWizardBaseDesconhecidoUnknownVersionCheckerSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_pt-PT.ts000066400000000000000000001715021305627404700217630ustar00rootroot00000000000000 AboutDialogBase About Synergy Acerca de Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Desconhecido Version: Versão &Ok &Ok ActionDialogBase Configure Action Definir a ação Choose the action to perform Seleccionar a ação a executar Press a hotkey Pressionar uma tecla de atalho Release a hotkey Largar uma tecla de atalho Press and release a hotkey Pressionar e largar uma tecla de atalho only on these screens apenas nestes ecrãs Switch to screen Mudar para o ecrã Switch in direction Mudar na direcção left esquerda right direita up cima down baixo Lock cursor to screen Manter o cursor no ecrã toggle alternar on ligado off desligado This action is performed when Esta ação é executada quando the hotkey is pressed a tecla de atalho é pressionada the hotkey is released a tecla de atalho é largada AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Tecla de atalho Enter the specification for the hotkey: Coloque a descrição para a tecla de atalho MainWindow &Start &Iniciar &File &Ficheiro &Edit &Editar &Window &Janela &Help &Ajuda <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>A tua versão do Synergy está desatualizada. Versão<b>%1</b> está agora disponivel <a href="%2">para download</a>.</p> Program can not be started O programa não consegue iniciar The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. O programa<br><br>%1<br><br>, embora exista, não teve êxito a iniciar. Por favor, verifique se tem permissões suficientes para o executar. Synergy client not found O cliente Synergy não foi encontrado The executable for the synergy client does not exist. O executável de cliente de Synergy não existe Hostname is empty O nome de computador não está preenchido Please fill in a hostname for the synergy client to connect to. Por favor coloque o nome de computador ao qual o cliente Synergy vai ligar-se Cannot write configuration file Não foi possivel escrever no ficheiro de configuração The temporary configuration file required to start synergy can not be written. Não foi possível escrever no ficheiro temporário de configuração de synergy, o qual é indispensável para o iniciar. Configuration filename invalid Ficheiro de configuração inválido You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Não colocaste um ficheiro de configuração válido para o servidor de synergy. Queres seleccionar o ficheiro de configuração agora? Synergy server not found O servidor de synergy não foi encontrado The executable for the synergy server does not exist. O executável de servidor de synergy não existe. Synergy terminated with an error Synergy terminou com erro Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy terminou inesperadamente com o erro %1.<br><br>Por favor, verifique o registo de log para mais detalhes. &Stop &Parar Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy está a iniciar Synergy is running. Synergy está em execução Synergy is not running. Synergy não está em execução Unknown Desconhecido Synergy Synergy Browse for a synergys config file Seleccionar um ficheiro de configuração de synergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Guardar a configuração como... Save failed Falhou o registo Could not save configuration to file. Não foi possível guardar a configuração para o ficheiro. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Nome do ecrã: &Server IP: &IP do servidor: &Start &Iniciar Use existing configuration: Usar uma configuração guardada: &Configuration file: Ficheiro de &configuração: &Browse... &Explorar... Configure interactively: Configuração interativa: &Configure Server... &Configurar Servidor... Ready Pronto Log Registo de eventos &Apply &Aplicar IP addresses: Endereços IP: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Acerca de Synergy... &Quit &Sair Quit Sair Run Executar S&top &Parar Stop Parar S&how Status M&ostrar Estado &Hide &Esconder Hide Esconder &Show &Mostrar Show Mostrar Save configuration &as... Guardar a configuração &como... Save the interactively generated server configuration to a file. Guardar a configuração gerada interactivamente para um ficheiro. Settings Definições Edit settings Alterar definições Run Wizard Usar assistente NewScreenWidget Unnamed Sem nome PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Configurar Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Configuração de synergy (*.sgc);;Todos os ficheiros (*.*) Synergy Configurations (*.conf);;All files (*.*) Configuração de synergy (*.conf);;Todos os ficheiros (*.*) System tray is unavailable, quitting. A área de notificação não está disponivel disponivel, saindo. ScreenSettingsDialog Screen name is empty O nome do ecrã não foi definido The screen name cannot be empty. Please either fill in a name or cancel the dialog. O nome do ecrã não pode estar vazio. Preenche a nome ou fecha a janela. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Configurações de ecrã Screen &name: &Nome do ecrã: A&liases Nomes al&ternativos &Add &Adicionar &Remove &Remover &Modifier keys &Teclas de modulação &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Nenhum &Ctrl: &Ctrl: Al&t: Al&t: M&eta: M&eta: S&uper: S&uper: &Dead corners &Cantos inacessíveis Top-left Canto superior esquerdo Top-right Canto superior direito Bottom-left Canto inferior esquerdo Bottom-right Canto inferior direito Corner Si&ze: Di&mensão do canto: &Fixes Co&rrecções Fix CAPS LOCK key Corrigir a tecla CAPS LOCK Fix NUM LOCK key Corrigir a tecla NUM LOCK Fix SCROLL LOCK key Corrigir a tecla SCROLL LOCK Fix XTest for Xinerama Corrigir XTest para Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Ecrã: <b>%1</b></center><br>duplo clique para alterar as definições<br>Arrastar o ecrã para o lixo para o remover ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Configuração do servidor Screens and links Ecrãs e ligações Drag a screen from the grid to the trashcan to remove it. Arrastar um ecrã da grelha para o lixo para o remover. Configure the layout of your synergy server configuration. Configurar a disposição na configuração do servidor de synergy Drag this button to the grid to add a new screen. Arrastar este botão para a grelha para adicionar um novo ecrã. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Arrastar novos ecrãs para a grelha ou mover os existentes. Arrastar um ecrã para o lixo para o remover. Faça duplo clique num ecrã para alterar as suas definições. Hotkeys Teclas de atalho &Hotkeys &Teclas de atalho &New &Novo &Edit &Editar &Remove &Remover A&ctions &Ações Ne&w No&vo E&dit &Alterar Re&move Re&mover Advanced server settings Definições avançadas do servidor &Switch &Alternar Switch &after waiting Alternar &após aguardar ms ms Switch on double &tap within Alternar ao tocar duas &vezes em &Options &Opções &Check clients every &Verificar clientes a cada Use &relative mouse moves Utilizar movimentos &relativos do rato S&ynchronize screen savers S&incronizar protectores de ecrã Don't take &foreground window on Windows servers Não tirar o &foco da janela activa nos servidores Windows Ignore auto config clients &Dead corners &Cantos inacessíveis To&p-left Canto su&perior esquerdo Top-rig&ht Canto superior &direito &Bottom-left Canto &inferior esquerdo Bottom-ri&ght Canto inferior direit&o Cor&ner Size: Dimensão do Ca&nto: SettingsDialog Save log file to... Guardar ficheiro de registo de eventos para... Elevate Synergy Elevar o Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Definições Sc&reen name: Nome do ecrã: P&ort: P&orto: &Interface: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Registo de eventos &Logging level: &Nivel de registo: Log to file: Ficheiro de registo: Browse... Explorar... Error Erro &Language: &Linguagem: &Miscellaneous Warning Aviso Note Notificação Info Informação Debug Depuração Debug1 Depuração1 Debug2 Depuração2 SetupWizard Setup Synergy Configurar Synergy Please select an option. Por favor selecciona uma opção. Please enter your email address and password. SetupWizardBase Setup Synergy Configurar Synergy Welcome Bem-vindo(a) Thanks for installing Synergy! Obrigado por instalares o Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy permite que uses o teu rato e teclado para controlar vários computadores na tua secretária em simultâneo, é gratuito e Open Source. Basta mover o rato para um lado ou para outro para mudar de ecrã. Podes até copiar e colar de um ecrã para o outro. Precisas apenas de uma ligação de rede. O Synergy é cross-platform (funciona em Windows, Mac OS X e Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Servidor ou Cliente? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Desconhecido WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_ro.qm000066400000000000000000000465361305627404700214360ustar00rootroot00000000000000<*5G7VE*nV?hg ` F+*X*/V*%*0*.+f+g+` #G7iGz&pJ=Lb>hU`XY+Z+xx.>3}Su>(Z = nbj 47,vBEv. _#!e8hw9$l%& 8;H}H,bO !dO A O A]?,VE /+GUN(Yu:>l_ } !*; l.=>) 4:$:/ > <$Z=J)"QJu-iz?@d&l *攄XJ(A^( n4.d,@Ty({0h6>z[>J=h!O 3=Tk@d.H"%C%D}F8(nzC;V1"p I_ Jz? k#2 v~6 9 -5 Pn9K d# ~58 ք~Y ȹ\ ȹ u ȹG a< |* F% F0[ Z% 0 KG Q @{g RVz RV RVGG R T!- V4,  |*< c0 s s@ c:. F'. Ҫ ^ /&+ 4p: d)u i! . r+ zk! P@W ¦eG x41 ]^^@1\Ft=A> 2 r/7(kC7k/.1>'}iGOk&OkAboutDialogBaseSobre o Synergy About SynergyAboutDialogBaseNecunoscutUnknownAboutDialogBaseVersiune:Version:AboutDialogBaseBAlege aciunea pentru a o efectuaChoose the action to performActionDialogBase"Confirm AciuneaConfigure ActionActionDialogBase6Blocheaz cursorul la ecranLock cursor to screenActionDialogBase(Apas o tast rapidPress a hotkeyActionDialogBaseFApsaci _i eliberaci o tast rapidPress and release a hotkeyActionDialogBase2Elibereaz o tast rapidRelease a hotkeyActionDialogBase$Comut n direciaSwitch in directionActionDialogBaseComut la ecranSwitch to screenActionDialogBaseFAceast aciune este executat cndThis action is performed whenActionDialogBasejosdownActionDialogBase stngaleftActionDialogBaseDesligadooffActionDialogBase LigadoonActionDialogBase*doar pe aceste ecraneonly on these screensActionDialogBasedreaptarightActionDialogBase6o tast rapid este apsatthe hotkey is pressedActionDialogBase:o tast rapid este eliberatthe hotkey is releasedActionDialogBase comuttoggleActionDialogBasesusupActionDialogBaseRIntrodu specificaie pentru tasta rapid:'Enter the specification for the hotkey:HotkeyDialogBase Tast rapidHotkeyHotkeyDialogBase&Editeaz&Edit MainWindow&Fiier&File MainWindow&Ajutor&Help MainWindow &Start&Start MainWindow &Stop&Stop MainWindow&Fereastr&Window MainWindowdRsfoici pentru un fi_ierul de configurare synergy!Browse for a synergys config file MainWindowRFiierul de configurare nu poate fi scrisCannot write configuration file MainWindowBArquivo de configurao invlido.Configuration filename invalid MainWindowRNu sa putut salva configuraia n fiier.%Could not save configuration to file. MainWindow*Numele gazd este golHostname is empty MainWindowTe rog s complectezi numele de gazda pentru clientul synergy la care s te conectezi.?Please fill in a hostname for the synergy client to connect to. MainWindow8Programul nu poate fi pornitProgram can not be started MainWindow6Salveaz configuraia ca...Save configuration as... MainWindowSalvare euat Save failed MainWindowSynergySynergy MainWindowDClientul Synergy nu poate fi gsitSynergy client not found MainWindow&Synergy nu ruleaz.Synergy is not running. MainWindow Synergy ruleaz.Synergy is running. MainWindow"Synergy pornete.Synergy is starting. MainWindowDClientul Synergy nu poate fi gsitSynergy server not found MainWindowSynergy a terminat n mod nea_teptat cu un cod %1.<br><br>V rugm s consultaci jurnalul pentru detalii.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow8Synergy terminou com um erro Synergy terminated with an error MainWindow^Executabilul pentru clientul synergy nu exist.5The executable for the synergy client does not exist. MainWindow^Executabilul pentru clientul synergy nu exist.5The executable for the synergy server does not exist. MainWindow*Executabilul<br><br>%1<br><br>nu a putut fi pornit cu succes, dei exist. Te rog verific dac ai suficiente permisiuni pentru a rula acest program.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowFiierul de configurare temporar necesar pentru a porni Synergy nu poate fi scrisNThe temporary configuration file required to start synergy can not be written. MainWindowNecunoscutUnknown MainWindow Nu ati completat un fi_ier de configurare valabil pentru serverul synergy. Dorici s rsfoici pentru un fi_ierul de configurare acum?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow"Despre Synergy...&About Synergy...MainWindowBase Aplic&ApplyMainWindowBaseRsfoiete... &Browse...MainWindowBase,Fiier de configurare:&Configuration file:MainWindowBase,Configureaz Server...&Configure Server...MainWindowBaseAscunde &HideMainWindowBase&Ieire&QuitMainWindowBase$IP-ul Server-ului: &Server IP:MainWindowBaseAfi_eaz&ShowMainWindowBase &Start&StartMainWindowBase0Configurare interactiv:Configure interactively:MainWindowBase"Editeaz setrile Edit settingsMainWindowBaseAscunde HideMainWindowBaseAdrese IP: IP addresses:MainWindowBaseLogLogMainWindowBase IeireQuitMainWindowBaseGataReadyMainWindowBasePorneteRunMainWindowBase"Pornete Expertul Run WizardMainWindowBaseArat Statutul S&how StatusMainWindowBaseStopS&topMainWindowBase6Salveaz configuraia ca...Save configuration &as...MainWindowBaseSalvaci configuracia generat interactiv a serverului ntr-un fi_ier.@Save the interactively generated server configuration to a file.MainWindowBase&Nume de utilizator: Screen name:MainWindowBase SetriSettingsMainWindowBaseAfi_eaz ShowMainWindowBaseStopStopMainWindowBaseSynergySynergyMainWindowBaseBFolosete configuraie existent:Use existing configuration:MainWindowBase AnonimUnnamedNewScreenWidget&Configurare Synergy Setup SynergyPluginWizardPagehConfiguraii Synergy (*.conf);;Toate Fiierele (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectfConfiguraii Synergy (*.sgc);;Toate Fiierele (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObject\Bara de sistem nu este disponibil, renunai.%System tray is unavailable, quitting.QObject2Numele de ecran este gol.Screen name is emptyScreenSettingsDialog&Adaug&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBaseColuri moarte &Dead cornersScreenSettingsDialogBaseCorecii&FixesScreenSettingsDialogBase(Modificator de taste&Modifier keysScreenSettingsDialogBase&Elimin&RemoveScreenSettingsDialogBase Shift:&Shift:ScreenSettingsDialogBaseAliasuriA&liasesScreenSettingsDialogBase &Alt:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseStnga-jos Bottom-leftScreenSettingsDialogBaseDreapta-jos Bottom-rightScreenSettingsDialogBase&Mrimea colurilor: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase6Corectreaz tasta CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase4Corectreaz tasta NUM LOCKFix NUM LOCK keyScreenSettingsDialogBase:Corectreaz tasta SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase@Corecteaz XTest pentru XineramaFix XTest for XineramaScreenSettingsDialogBase Meta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseNici unulNoneScreenSettingsDialogBase Super:S&uper:ScreenSettingsDialogBaseNume de ecran. Screen &name:ScreenSettingsDialogBaseSetri de ecranScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBaseStnga-susTop-leftScreenSettingsDialogBaseDreapta-sus Top-rightScreenSettingsDialogBase<center>Ecran: <b>%1</b></center><br>Dublu click pentru editare de setri<br>Glisai ecranul ctre coul de gunoi pentru al eliminao
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelStnga-jos &Bottom-leftServerConfigDialogBase0Verific clieni fiecare&Check clients everyServerConfigDialogBaseColuri moarte &Dead cornersServerConfigDialogBase&Editeaz&EditServerConfigDialogBase&Taste rapide&HotkeysServerConfigDialogBaseNou&NewServerConfigDialogBaseOpiuni&OptionsServerConfigDialogBase&Elimin&RemoveServerConfigDialogBase Comut&SwitchServerConfigDialogBaseAciuniA&ctionsServerConfigDialogBase,Setari avansate serverAdvanced server settingsServerConfigDialogBaseDreapta-jos Bottom-ri&ghtServerConfigDialogBase^Configurai aspectul serverului vostru synergy.:Configure the layout of your synergy server configuration.ServerConfigDialogBaseMrime coluri Cor&ner Size:ServerConfigDialogBasedNu luaci fereastre de prim-plan pe servere Windows0Don't take &foreground window on Windows serversServerConfigDialogBaseGlisai un ecran de pe gril ctre coul de gunoi pentru al elimina.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase>Glisai ecrane noi pe gril sau mut cele existente. Glisai un ecran ctre coul de gunoi pentru al elimina. Click dublu pe un ecran pentru ai edita setrile.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasetGlisai acest buton pe gril pentru a aduga un nou ecran.1Drag this button to the grid to add a new screen.ServerConfigDialogBaseEditeazE&ditServerConfigDialogBaseTaste rapideHotkeysServerConfigDialogBaseNouNe&wServerConfigDialogBaseEliminRe&moveServerConfigDialogBase>Sincronizare protector de ecranS&ynchronize screen saversServerConfigDialogBase$Ecrane i legturiScreens and linksServerConfigDialogBase0Configurrile ServeruluiServer ConfigurationServerConfigDialogBase4Comut dup o ateptare deSwitch &after waitingServerConfigDialogBaseNSchimb la atingere dubla n interiorulSwitch on double &tap withinServerConfigDialogBaseStnga-sus To&p-leftServerConfigDialogBaseDreapta-sus Top-rig&htServerConfigDialogBaseRFolosete micri relative ale mouse-uluiUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaseBSalveaz fiier jurnal pentru ...Save log file to...SettingsDialogInterfa: &Interface:SettingsDialogBase Limba: &Language:SettingsDialogBaseNivel logging&Logging level:SettingsDialogBaseRsfoiete: Browse...SettingsDialogBaseDepanareDebugSettingsDialogBaseDepanare1Debug1SettingsDialogBaseDepanare2Debug2SettingsDialogBase EroareErrorSettingsDialogBaseInformaoInfoSettingsDialogBaseLog n fiier Log to file:SettingsDialogBaseLoggingLoggingSettingsDialogBaseNotNoteSettingsDialogBase Port:P&ort:SettingsDialogBaseNume ecran: Sc&reen name:SettingsDialogBase SetriSettingsSettingsDialogBaseAvertismentWarningSettingsDialogBase8Te rog selecteaz o opiune.Please select an option. SetupWizard&Configurare Synergy Setup Synergy SetupWizard$Server sau Client?Server or Client?SetupWizardBase&Configurare Synergy Setup SynergySetupWizardBaseSynergy v permite s partajaci cu u_urinc mouse-ul _i tastatura ntre mai multe computere de pe birou, si este gratuit _i open source. Doar mutaci mouse-ul de pe marginea ecranului pe un calculator pe altul. Puteci chiar partaja toate clipboarduri tale. Tot ce trebuie este o conexiune la recea. Sinergia este cross-platform (funccioneaz pe Windows, Mac OS X _i Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseJVa multumim ca a-ti instalat Synergy!Thanks for installing Synergy!SetupWizardBaseBine aci venitWelcomeSetupWizardBaseNecunoscutUnknownVersionCheckerSynergySynergyZeroconfService $synergy-1.8.8-stable/src/gui/res/lang/gui_ro.ts000066400000000000000000001701321305627404700214350ustar00rootroot00000000000000 AboutDialogBase About Synergy Sobre o Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Necunoscut Version: Versiune: &Ok Ok ActionDialogBase Configure Action Confirmă Acțiunea Choose the action to perform Alege acțiunea pentru a o efectua Press a hotkey Apasă o tastă rapidă Release a hotkey Eliberează o tastă rapidă Press and release a hotkey Apăsaţi şi eliberaţi o tastă rapidă only on these screens doar pe aceste ecrane Switch to screen Comută la ecran Switch in direction Comută în direcția left stânga right dreapta up sus down jos Lock cursor to screen Blochează cursorul la ecran toggle comută on Ligado off Desligado This action is performed when Această acțiune este executată când the hotkey is pressed o tastă rapidă este apăsată the hotkey is released o tastă rapidă este eliberată AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Tastă rapidă Enter the specification for the hotkey: Introdu specificație pentru tasta rapidă: MainWindow &Start &Start &File &Fișier &Edit &Editează &Window &Fereastră &Help &Ajutor <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started Programul nu poate fi pornit The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Executabilul<br><br>%1<br><br>nu a putut fi pornit cu succes, deși există. Te rog verifică dacă ai suficiente permisiuni pentru a rula acest program. Synergy client not found Clientul Synergy nu poate fi găsit The executable for the synergy client does not exist. Executabilul pentru clientul synergy nu există. Hostname is empty Numele gazdă este gol Please fill in a hostname for the synergy client to connect to. Te rog să complectezi numele de gazda pentru clientul synergy la care să te conectezi. Cannot write configuration file Fișierul de configurare nu poate fi scris The temporary configuration file required to start synergy can not be written. Fișierul de configurare temporar necesar pentru a porni Synergy nu poate fi scris Configuration filename invalid Arquivo de configuração inválido. You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Nu ati completat un fişier de configurare valabil pentru serverul synergy. Doriţi să răsfoiţi pentru un fişierul de configurare acum? Synergy server not found Clientul Synergy nu poate fi găsit The executable for the synergy server does not exist. Executabilul pentru clientul synergy nu există. Synergy terminated with an error Synergy terminou com um erro Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy a terminat în mod neaşteptat cu un cod %1.<br><br>Vă rugăm să consultaţi jurnalul pentru detalii. &Stop &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy pornește. Synergy is running. Synergy rulează. Synergy is not running. Synergy nu rulează. Unknown Necunoscut Synergy Synergy Browse for a synergys config file Răsfoiţi pentru un fişierul de configurare synergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Salvează configurația ca... Save failed Salvare eșuată Could not save configuration to file. Nu sa putut salva configurația în fișier. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Nume de utilizator: &Server IP: IP-ul Server-ului: &Start &Start Use existing configuration: Folosește configurație existentă: &Configuration file: Fișier de configurare: &Browse... Răsfoiește... Configure interactively: Configurare interactivă: &Configure Server... Configurează Server... Ready Gata Log Log &Apply Aplică IP addresses: Adrese IP: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Despre Synergy... &Quit &Ieșire Quit Ieșire Run Pornește S&top Stop Stop Stop S&how Status Arată Statutul &Hide Ascunde Hide Ascunde &Show Afişează Show Afişează Save configuration &as... Salvează configurația ca... Save the interactively generated server configuration to a file. Salvaţi configuraţia generată interactiv a serverului într-un fişier. Settings Setări Edit settings Editează setările Run Wizard Pornește Expertul NewScreenWidget Unnamed Anonim PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Configurare Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Configurații Synergy (*.sgc);;Toate Fișierele (*.*) Synergy Configurations (*.conf);;All files (*.*) Configurații Synergy (*.conf);;Toate Fișierele (*.*) System tray is unavailable, quitting. Bara de sistem nu este disponibilă, renunțați. ScreenSettingsDialog Screen name is empty Numele de ecran este gol. The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Setări de ecran Screen &name: Nume de ecran. A&liases Aliasuri &Add &Adaugă &Remove &Elimină &Modifier keys Modificator de taste &Shift: Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Nici unul &Ctrl: &Ctrl: Al&t: &Alt: M&eta: Meta: S&uper: Super: &Dead corners Colțuri moarte Top-left Stânga-sus Top-right Dreapta-sus Bottom-left Stânga-jos Bottom-right Dreapta-jos Corner Si&ze: Mărimea colțurilor: &Fixes Corecții Fix CAPS LOCK key Corectrează tasta CAPS LOCK Fix NUM LOCK key Corectrează tasta NUM LOCK Fix SCROLL LOCK key Corectrează tasta SCROLL LOCK Fix XTest for Xinerama Corectează XTest pentru Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Ecran: <b>%1</b></center><br>Dublu click pentru editare de setări<br>Glisați ecranul către coșul de gunoi pentru al elimina ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Configurările Serverului Screens and links Ecrane și legături Drag a screen from the grid to the trashcan to remove it. Glisați un ecran de pe grilă către coșul de gunoi pentru al elimina. Configure the layout of your synergy server configuration. Configurați aspectul serverului vostru synergy. Drag this button to the grid to add a new screen. Glisați acest buton pe grilă pentru a adăuga un nou ecran. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Glisați ecrane noi pe grilă sau mută cele existente. Glisați un ecran către coșul de gunoi pentru al elimina. Click dublu pe un ecran pentru ai edita setările. Hotkeys Taste rapide &Hotkeys &Taste rapide &New Nou &Edit &Editează &Remove &Elimină A&ctions Acțiuni Ne&w Nou E&dit Editează Re&move Elimină Advanced server settings Setari avansate server &Switch Comută Switch &after waiting Comută după o așteptare de ms ms Switch on double &tap within Schimbă la atingere dubla în interiorul &Options Opțiuni &Check clients every Verifică clienți fiecare Use &relative mouse moves Folosește mișcări relative ale mouse-ului S&ynchronize screen savers Sincronizare protector de ecran Don't take &foreground window on Windows servers Nu luaţi fereastre de prim-plan pe servere Windows Ignore auto config clients &Dead corners Colțuri moarte To&p-left Stânga-sus Top-rig&ht Dreapta-sus &Bottom-left Stânga-jos Bottom-ri&ght Dreapta-jos Cor&ner Size: Mărime colțuri SettingsDialog Save log file to... Salvează fișier jurnal pentru ... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Setări Sc&reen name: Nume ecran: P&ort: Port: &Interface: Interfață: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Logging &Logging level: Nivel logging Log to file: Log în fișier Browse... Răsfoiește: Error Eroare &Language: Limba: &Miscellaneous Warning Avertisment Note Notă Info Informação Debug Depanare Debug1 Depanare1 Debug2 Depanare2 SetupWizard Setup Synergy Configurare Synergy Please select an option. Te rog selectează o opțiune. Please enter your email address and password. SetupWizardBase Setup Synergy Configurare Synergy Welcome Bine aţi venit Thanks for installing Synergy! Va multumim ca a-ti instalat Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy vă permite să partajaţi cu uşurinţă mouse-ul şi tastatura între mai multe computere de pe birou, si este gratuit şi open source. Doar mutaţi mouse-ul de pe marginea ecranului pe un calculator pe altul. Puteţi chiar partaja toate clipboarduri tale. Tot ce trebuie este o conexiune la reţea. Sinergia este cross-platform (funcţionează pe Windows, Mac OS X şi Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Server sau Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Necunoscut WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_ru.qm000066400000000000000000000534711305627404700214400ustar00rootroot00000000000000^gL+[H4)SWYVu5'-2*HE6<- G:VE-DVFg 3` j+*R*2$*%*0*j++g+` !G:cGz)vJDJLbDU`(X"Y.gZ.xx.>6}Su>(Z = nbj 4S/vIZPTEv._#Me;|w98'n'N ;H}H/.O !O HO I.]E|%VE M. UN+Yu:Eul_ } "*>l1aDD 7:':1 ` C$$ZC_ J,"QJ}-izFM@d)l -{攄J(H:S$O( n4.d.@Ty+|L#A{2 z>MJD u{ 3=Tk@d1ycNd% @~ }C(H}F;:nlC>h4 " I_ JzF k#6 v~9 < -5 Pn 5bun?-y~G]$ r/ 7+kC:k2p.4>*iQ=:&OkAboutDialogBase ?@>3@0<<5 About SynergyAboutDialogBase58725AB=>UnknownAboutDialogBase5@A8O:Version:AboutDialogBase@K15@8B5 459AB285 4;O 2K?>;=5=8OChoose the action to performActionDialogBase*>=D83C@0F8O 459AB28OConfigure ActionActionDialogBase20:@5?8BL :C@A>@ =0 M:@0=Lock cursor to screenActionDialogBase.06<8B5 3>@OGCN :;028HCPress a hotkeyActionDialogBaseF06<8B5 8 >B?CAB8B5 3>@OGCN :;028HCPress and release a hotkeyActionDialogBase2B?CAB8B5 3>@OGCN :;028HCRelease a hotkeyActionDialogBase65@5:;NG8BLAO 2 =0?@02;5=88Switch in directionActionDialogBase,5@5:;NG8BLAO =0 M:@0=Switch to screenActionDialogBase<-B> 459AB285 2K?>;=O5BAO :>340This action is performed whenActionDialogBase=87downActionDialogBase 2;52>leftActionDialogBase 2K:;.offActionDialogBase:;NG8BLonActionDialogBase,">;L:> =0 MB8E M:@0=0Eonly on these screensActionDialogBase 2?@02>rightActionDialogBase,3>@OG0O :;028H0 =060B0the hotkey is pressedActionDialogBase0B?CI5=0 3>@OG0O :;028H0the hotkey is releasedActionDialogBase5@5:;NG8BLtoggleActionDialogBase 25@EupActionDialogBase@2548B5 >?8A0=85 3>@OG59 :;028H8'Enter the specification for the hotkey:HotkeyDialogBase>@OG0O :;028H0HotkeyHotkeyDialogBase& 540:B8@>20BL&Edit MainWindow &$09;&File MainWindow&><>IL&Help MainWindow !B0@B&Start MainWindow!B>?&Stop MainWindow &:=>&Window MainWindow<p> 0H0 25@A8O Synergy CAB0@5;0. 5@A8O <b>%1</b> 4>ABC?=0 4;O <a href="%2">A:0G820=8O</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowB#:070BL D09; :>=D83C@0F88 Synergy!Browse for a synergys config file MainWindowR52>7<>6=> 87<5=8BL :>=D83C@0F8>==K9 D09;Cannot write configuration file MainWindowF<O D09;0 :>=D83C@0F88 =5?@028;L=>5Configuration filename invalid MainWindowP5 2>7<>6=> A>E@0=8BL D09; :>=D83C@0F88.%Could not save configuration to file. MainWindow<O E>AB0 ?CAB>Hostname is empty MainWindow>60;C9AB0 70?>;=8B5 8<O E>AB0 2 :;85=B5 Synergy 4;O A>548=5=8O.?Please fill in a hostname for the synergy client to connect to. MainWindow@@>3@0<<0 =5 <>65B 1KBL 70?CI5=0Program can not be started MainWindow:!>E@0=8BL :>=D83C@0F8N :0:...Save configuration as... MainWindow*!>E@0=5=85 =52>7<>6=> Save failed MainWindowSynergySynergy MainWindow0;85=B Synergy =5 =0945=Synergy client not found MainWindow(Synergy >AB0=>2;5=0.Synergy is not running. MainWindow"Synergy @01>B05B.Synergy is running. MainWindow(Synergy 70?CA:05BAO.Synergy is starting. MainWindow0!5@25@ Synergy =5 =0945=Synergy server not found MainWindowSynergy 7025@H8;0AL =5>6840==> A :>4>< 2KE>40 %1.<br><br>>60;C9AB0 ?@>A<>B@8B5 log-D09; 4;O 45B0;59.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow:Synergy 7025@H8;0AL A >H81:>9 Synergy terminated with an error MainWindow\A?>;=O5<K9 D09; 4;O :;85=B0 Synergy =5 =0945=5The executable for the synergy client does not exist. MainWindow^5 =0945= 2K?>;=O5<K9 D09; 4;O A5@25@0 Synergy.5The executable for the synergy server does not exist. MainWindow@>3@0<<0/D09; <br><br>%1<br><br> 5 <>65B 1KBL 70?CI5=0, => >=0 8A?@02=0. @>25@LB5 - 4>AB0B>G=> ;8 C 20A ?@02 4;O 70?CA:0.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindow@5<5==K9 D09; :>=D83C@0F88, 8A?>;L7CNI89AO 4;O 70?CA:0 Synergy, 701;>:8@>20= 4;O 70?8A8.NThe temporary configuration file required to start synergy can not be written. MainWindow58725AB=>Unknown MainWindowK =5 C:070;8 ?@028;L=K9 D09; :>=D83C@0F88 A5@25@0 Synergy. 5;05B5 C:070BL 53> A59G0A?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow Synergy&About Synergy...MainWindowBase&@8<5=8BL&ApplyMainWindowBase17>@... &Browse...MainWindowBase$$09; :>=D83C@0F88:&Configuration file:MainWindowBase&0AB@>8BL A5@25@...&Configure Server...MainWindowBase !:@KBL&HideMainWindowBase &KE>4&QuitMainWindowBaseIP A5@25@0: &Server IP:MainWindowBase>:070BL&ShowMainWindowBase !B0@B&StartMainWindowBase82B><0B8G5A:0O :>=D83C@0F8O:Configure interactively:MainWindowBase$7<5=8BL =0AB@>9:8 Edit settingsMainWindowBase !:@KBLHideMainWindowBaseIP 04@5A0: IP addresses:MainWindowBase C@=0;LogMainWindowBase KE>4QuitMainWindowBase >B>2>ReadyMainWindowBase0?CAB8BLRunMainWindowBase 0?CAB8BL 0AB5@ Run WizardMainWindowBase>:070BL AB0BCA S&how StatusMainWindowBaseAB0=>28BLS&topMainWindowBase8!>E@0=8BL :>=D83C@0F8N :0:..Save configuration &as...MainWindowBasev!>E@0=8BL 02B><0B8G5A:8 35=5@8@>20==CN :>=D83C@0F8N 2 D09;.@Save the interactively generated server configuration to a file.MainWindowBase<O M:@0=0: Screen name:MainWindowBase0AB@>9:8SettingsMainWindowBase>:070BLShowMainWindowBaseAB0=>28BLStopMainWindowBaseSynergySynergyMainWindowBaseNA?>;L7>20BL ACI5AB2CNICN :>=D83C@0F8N:Use existing configuration:MainWindowBase57 =0720=8OUnnamedNewScreenWidget"0AB@>8BL Synergy Setup SynergyPluginWizardPage\>=D83C@0F8O Synergy (*.conf);;A5 D09;K (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectZ>=D83C@0F8O Synergy (*.sgc);;A5 D09;K (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectb!8AB5<=K9 B@M9 =5 4>ABC?5=, 7025@H5=85 ?@>3@0<<K.%System tray is unavailable, quitting.QObject"<O M:@0=0 ?CAB>5Screen name is emptyScreenSettingsDialog<O M:@0=0:Screen name matches aliasScreenSettingsDialog0720=85 =5 <>65B 1KBL ?CABK<. >60;C9AB0, ;81> 70?>;=8BL 8<O 8;8 >B<5=8BL 480;>3.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialog0720=85 M:@0=0 =5 <>65B 1KBL ?>E>68<, =0 A524>=8<. >60;C9AB0 C40;8B5 A524>=8< 8;8 ?><5=O9B5 <O M:@0=0iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog>1028BL&AddScreenSettingsDialogBase Ctrl:&Ctrl:ScreenSettingsDialogBase5@B2K5 C3;K &Dead cornersScreenSettingsDialogBase$8:A8@>20=85&FixesScreenSettingsDialogBase(;028H8-<>48D8:0B>@K&Modifier keysScreenSettingsDialogBase#40;8BL&RemoveScreenSettingsDialogBase Shift:&Shift:ScreenSettingsDialogBaseA524>=8<KA&liasesScreenSettingsDialogBaseAlt:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase86=89 ;52K9 Bottom-leftScreenSettingsDialogBase86=89 ?@0289 Bottom-rightScreenSettingsDialogBase 07<5@ C3;0: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase*$8:A8@>20BL CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase($8:A8@>20BL NUM LOCKFix NUM LOCK keyScreenSettingsDialogBase.$8:A8@>20BL SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase<$8:A8@>20BL XTest 4;O XineramaFix XTest for XineramaScreenSettingsDialogBase Meta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBase5BNoneScreenSettingsDialogBase Super:S&uper:ScreenSettingsDialogBase<O M:@0=0: Screen &name:ScreenSettingsDialogBase 0AB@>9:8 M:@0=0Screen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBase5@E=89 ;52K9Top-leftScreenSettingsDialogBase5@E=89 ?@02K9 Top-rightScreenSettingsDialogBase<center>-:@0=: <b>%1</b></center><br>2>9=>9 I5;G>: 4;O @540:B8@>20=8O :>=D83C@0F88<br>5@5BO=8B5 M:@0= 2 :>@78=C 4;O C40;5=8Oo
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel&86=89 ;52K9 &Bottom-leftServerConfigDialogBase4@>25@OBL :;85=B>2 :0&64K5&Check clients everyServerConfigDialogBase5@B2K5 C3;K &Dead cornersServerConfigDialogBase& 540:B8@>20BL&EditServerConfigDialogBase &>@OG85 :;028H8&HotkeysServerConfigDialogBase &>2K9&NewServerConfigDialogBase &?F88&OptionsServerConfigDialogBase#40;8BL&RemoveServerConfigDialogBase5@5:;NG8BAO&SwitchServerConfigDialogBase5&9AB28OA&ctionsServerConfigDialogBase@>?>;=8B5;L=K5 =0AB@>9:8 A5@25@0Advanced server settingsServerConfigDialogBase86=89 ?@02K&9 Bottom-ri&ghtServerConfigDialogBasev0AB@>8BL @0A?>;>65=85 :>=D83C@0F88 0H53> A5@25@0 Synergy.:Configure the layout of your synergy server configuration.ServerConfigDialogBase 07&<5@ C3;0: Cor&ner Size:ServerConfigDialogBaseb5 45@60BL >:=> A5@25@0 ?>25@E 2A5E (4;O Windows)0Don't take &foreground window on Windows serversServerConfigDialogBasej5@5BO=8B5 M:@0= A A5B:8 2 :>@78=C GB>1K C40;8BL 53>.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase45@5BO=8B5 =>2K9 M:@0= =0 A5B:C 8;8 ?5@5428=LB5 ACI5AB2CNI85. 5@5BO=8B5 M:@0= 2 :>@78=C GB>1K C40;8BL 53>. 2>9=>9 I5;G>: =0 M:@0=5 4;O 53> :>=D83C@0F88.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasex5@5BO=8B5 MBC :=>?:C =0 A5B:C 4;O 4>102;5=8O =>2>3> M:@0=0.1Drag this button to the grid to add a new screen.ServerConfigDialogBase 5&40:B8@>20BLE&ditServerConfigDialogBase>@OG85 :;028H8HotkeysServerConfigDialogBase >&2K9Ne&wServerConfigDialogBase#40&;8BLRe&moveServerConfigDialogBase4!&8=E@>=878@>20BL 70AB02:8S&ynchronize screen saversServerConfigDialogBase-:@0=K 8 A2O78Screens and linksServerConfigDialogBase(>=D83C@0F8O A5@25@0Server ConfigurationServerConfigDialogBase65@5:;NG8BAO ?>A;5 >6840=8OSwitch &after waitingServerConfigDialogBaseT5@5:;NG8BAO ?> 42>9=><C =060B8N 2 B5G5=88Switch on double &tap withinServerConfigDialogBase5@E=89 &;52K9 To&p-leftServerConfigDialogBase5@E=89 &?@02K9 Top-rig&htServerConfigDialogBaseLA?>;L7>20BL &@>4=K5 =0AB@>9:8 :C@A>@0Use &relative mouse movesServerConfigDialogBase<A5:msServerConfigDialogBaseK C25@5=K GB> E>B8B5 ?>2KH0BL Synergy? -B> ?>72>;8B Synergy 2708<>459AB2>20BL A ?>2KH0NI8< ?@>F5AA>< 8 UAC 480;>3><, => <>65B 2K720BL ?@>1;5<K A =5?>2KH5==K<8 ?@>F5AA0<8. >2KH09B5 Synregy B>;L:> 5A;8 MB> 459AB28B5;L=> =5>1E>48<>.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogP>2KA8BL ?@828;5388 ?@8;>65=8O (4;O UAC)Elevate SynergySettingsDialog.!>E@0=8BL log-D09; 2...Save log file to...SettingsDialog=B5@&D59A: &Interface:SettingsDialogBase /7K:: &Language:SettingsDialogBase2#@>25=L 70?8A8 2 6C@=0?;:&Logging level:SettingsDialogBase& 07=>5&MiscellaneousSettingsDialogBase17>@... Browse...SettingsDialogBaseB;04:0DebugSettingsDialogBaseB;04:01Debug1SettingsDialogBaseB;04:02Debug2SettingsDialogBase H81:0ErrorSettingsDialogBase=D>@<0F8OInfoSettingsDialogBase20?8AK20BL 6C@=0; 2 D09;: Log to file:SettingsDialogBase C@=0;LoggingSettingsDialogBase0<5B:0NoteSettingsDialogBase &>@B:P&ort:SettingsDialogBase<O M:&@0=0: Sc&reen name:SettingsDialogBase0AB@>9:8SettingsSettingsDialogBase@54C?@5645=85WarningSettingsDialogBasen>60;C9AB0 22548B5 20H 04@5A M;5:B@>==>9 ?>GBK 8 ?0@>;L-Please enter your email address and password. SetupWizard6>60;C9AB0, 2K15@8B5 >?F8N.Please select an option. SetupWizard"0AB@>8BL Synergy Setup Synergy SetupWizard$!5@25@ 8;8 ;85=B?Server or Client?SetupWizardBase"0AB@>8BL Synergy Setup SynergySetupWizardBaseSynergy ?>72>;O5B 20< ?@>AB> 8 ;53:> @01>B0BL A >4=8< =01>@>< :;0280BC@K 8 <KH:8 <564C =5A:>;L:8<8 :><?LNB5@0<8. -B> 15A?;0B=>5 ?@8;>65=85 A >B:@KBK< 8AE>4=K< :>4><. @>AB> ?>42548B5 :C@A>@ 70 :@09 M:@0=0. K B0:65 <>65B5 >1J548=OBL 1CD5@K >1<5=0. A5 GB> 20< =C6=> MB> A5B52>5 ?>4:;NG5=85. Synergy MB> :@>AA-?;0BD>@<5==>5 ?@8;>65=85, :>B>@>5 @01>B05B =0 Windows, Mac OS X 8 Linux.ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBase:!?0A81> 70 CAB0=>2:C Synergy!Thanks for installing Synergy!SetupWizardBase >1@> ?>60;>20BLWelcomeSetupWizardBase58725AB=>UnknownVersionCheckerP>9B8 =5 C40;>AL, ?@>87>H;0 >H81:0. %1$Login failed, an error occurred. %1 WebClientp>9B8 =5 C40;>AL, ?@>87>H;0 >H81:0. B25B A5@25@0: %16Login failed, an error occurred. Server response: %1 WebClientj5C40G=0O ?>?KB:0, email 8;8 ?0@>;L 22545=K A >H81:>9(Login failed, invalid email or password. WebClientSynergySynergyZeroconfService ) , synergy-1.8.8-stable/src/gui/res/lang/gui_ru.ts000066400000000000000000002003021305627404700214340ustar00rootroot00000000000000 AboutDialogBase About Synergy О программе <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Неизвестно Version: Версия: &Ok Ок ActionDialogBase Configure Action Конфигурация действия Choose the action to perform Выберите действие для выполнения Press a hotkey Нажмите горячую клавишу Release a hotkey Отпустите горячую клавишу Press and release a hotkey Нажмите и отпустите горячую клавишу only on these screens Только на этих экранах Switch to screen Переключиться на экран Switch in direction Переключиться в направлении left влево right вправо up Вверх down Вниз Lock cursor to screen Закрепить курсор на экран toggle Переключить on Включить off выкл. This action is performed when Это действие выполняется когда the hotkey is pressed горячая клавиша нажата the hotkey is released Отпущена горячая клавиша AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Горячая клавиша Enter the specification for the hotkey: Введите описание горячей клавиши MainWindow &Start Старт &File &Файл &Edit &Редактировать &Window &Окно &Help &Помощь <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p> Ваша версия Synergy устарела. Версия <b>%1</b> доступна для <a href="%2">скачивания</a>.</p> Program can not be started Программа не может быть запущена The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Программа/файл <br><br>%1<br><br> Не может быть запущена, но она исправна. Проверьте - достаточно ли у вас прав для запуска. Synergy client not found Клиент Synergy не найден The executable for the synergy client does not exist. Исполняемый файл для клиента Synergy не найден Hostname is empty Имя хоста пусто Please fill in a hostname for the synergy client to connect to. Пожалуйста заполните имя хоста в клиенте Synergy для соединения. Cannot write configuration file Невозможно изменить конфигурационный файл The temporary configuration file required to start synergy can not be written. Временный файл конфигурации, использующийся для запуска Synergy, заблокирован для записи. Configuration filename invalid Имя файла конфигурации неправильное You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Вы не указали правильный файл конфигурации сервера Synergy. Желаете указать его сейчас? Synergy server not found Сервер Synergy не найден The executable for the synergy server does not exist. Не найден выполняемый файл для сервера Synergy. Synergy terminated with an error Synergy завершилась с ошибкой Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy завершилась неожиданно с кодом выхода %1.<br><br>Пожалуйста просмотрите log-файл для деталей. &Stop Стоп Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy запускается. Synergy is running. Synergy работает. Synergy is not running. Synergy остановлена. Unknown Неизвестно Synergy Synergy Browse for a synergys config file Указать файл конфигурации Synergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Сохранить конфигурацию как... Save failed Сохранение невозможно Could not save configuration to file. Не возможно сохранить файл конфигурации. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Имя экрана: &Server IP: IP сервера: &Start Старт Use existing configuration: Использовать существующую конфигурацию: &Configuration file: Файл конфигурации: &Browse... Обзор... Configure interactively: Автоматическая конфигурация: &Configure Server... Настроить сервер... Ready Готово Log Журнал &Apply &Применить IP addresses: IP адреса: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... О Synergy &Quit &Выход Quit Выход Run Запустить S&top Остановить Stop Остановить S&how Status Показать статус &Hide Скрыть Hide Скрыть &Show Показать Show Показать Save configuration &as... Сохранить конфигурацию как.. Save the interactively generated server configuration to a file. Сохранить автоматически генерированную конфигурацию в файл. Settings Настройки Edit settings Изменить настройки Run Wizard Запустить Мастер NewScreenWidget Unnamed Без названия PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Настроить Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Конфигурация Synergy (*.sgc);;Все файлы (*.*) Synergy Configurations (*.conf);;All files (*.*) Конфигурация Synergy (*.conf);;Все файлы (*.*) System tray is unavailable, quitting. Системный трэй не доступен, завершение программы. ScreenSettingsDialog Screen name is empty Имя экрана пустое The screen name cannot be empty. Please either fill in a name or cancel the dialog. Название не может быть пустым. Пожалуйста, либо заполнить имя или отменить диалог. Screen name matches alias Имя экрана: The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Название экрана не может быть похожим, на Псевдоним. Пожалуйста удалите Псевдоним или поменяйте Имя экрана ScreenSettingsDialogBase Screen Settings Настройки экрана Screen &name: Имя экрана: A&liases Псевдонимы &Add Добавить &Remove Удалить &Modifier keys Клавиши-модификаторы &Shift: Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Нет &Ctrl: Ctrl: Al&t: Alt: M&eta: Meta: S&uper: Super: &Dead corners Мертвые углы Top-left Верхний левый Top-right Верхний правый Bottom-left Нижний левый Bottom-right Нижний правий Corner Si&ze: Размер угла: &Fixes Фиксирование Fix CAPS LOCK key Фиксировать CAPS LOCK Fix NUM LOCK key Фиксировать NUM LOCK Fix SCROLL LOCK key Фиксировать SCROLL LOCK Fix XTest for Xinerama Фиксировать XTest для Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Экран: <b>%1</b></center><br>Двойной щелчок для редактирования конфигурации<br>Перетяните экран в корзину для удаления ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Конфигурация сервера Screens and links Экраны и связи Drag a screen from the grid to the trashcan to remove it. Перетяните экран с сетки в корзину чтобы удалить его. Configure the layout of your synergy server configuration. Настроить расположение конфигурации Вашего сервера Synergy. Drag this button to the grid to add a new screen. Перетяните эту кнопку на сетку для добавления нового экрана. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Перетяните новый экран на сетку или передвиньте существующие. Перетяните экран в корзину чтобы удалить его. Двойной щелчок на экране для его конфигурации. Hotkeys Горячие клавиши &Hotkeys &Горячие клавиши &New &Новый &Edit &Редактировать &Remove Удалить A&ctions Де&йствия Ne&w Но&вый E&dit Ре&дактировать Re&move Уда&лить Advanced server settings Дополнительные настройки сервера &Switch Переключится Switch &after waiting Переключится после ожидания ms мсек Switch on double &tap within Переключится по двойному нажатию в течении &Options &Опции &Check clients every Проверять клиентов ка&ждые Use &relative mouse moves Использовать &родные настройки курсора S&ynchronize screen savers С&инхронизировать заставки Don't take &foreground window on Windows servers Не держать окно сервера поверх всех (для Windows) Ignore auto config clients &Dead corners Мертвые углы To&p-left Верхний &левый Top-rig&ht Верхний &правый &Bottom-left &Нижний левый Bottom-ri&ght Нижний правы&й Cor&ner Size: Раз&мер угла: SettingsDialog Save log file to... Сохранить log-файл в... Elevate Synergy Повысить привилегии приложения (для UAC) Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Вы уверены что хотите повышать Synergy? Это позволит Synergy взаимодействовать с повышающим процессом и UAC диалогом, но может вызвать проблемы с неповышенными процессами. Повышайте Synregy только если это действительно необходимо. SettingsDialogBase Settings Настройки Sc&reen name: Имя эк&рана: P&ort: П&орт: &Interface: Интер&фейс: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Журнал &Logging level: Уровень записи в журна?л: Log to file: Записывать журнал в файл: Browse... Обзор... Error Ошибка &Language: Язык: &Miscellaneous &Разное Warning Предупреждение Note Заметка Info Информация Debug Отладка Debug1 Отладка1 Debug2 Отладка2 SetupWizard Setup Synergy Настроить Synergy Please select an option. Пожалуйста, выберите опцию. Please enter your email address and password. Пожалуйста введите ваш адрес электронной почты и пароль SetupWizardBase Setup Synergy Настроить Synergy Welcome Добро пожаловать Thanks for installing Synergy! Спасибо за установку Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy позволяет вам просто и легко работать с одним набором клавиатуры и мышки между несколькими компьютерами. Это бесплатное приложение с открытым исходным кодом. Просто подведите курсор за край экрана. Вы также можете объединять буферы обмена. Все что вам нужно это сетевое подключение. Synergy это кросс-платформенное приложение, которое работает на Windows, Mac OS X и Linux. Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Сервер или Клиент? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Неизвестно WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Неудачная попытка, email или пароль введены с ошибкой Login failed, an error occurred. %1 Войти не удалось, произошла ошибка. %1 Login failed, an error occurred. Server response: %1 Войти не удалось, произошла ошибка. Ответ сервера: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_si.qm000066400000000000000000000012451305627404700214150ustar00rootroot00000000000000 AboutDialogBase About Synergy Synergy ගැන විස්තර <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: &Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left වම right up උඩ down යට Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started වැඩසටහන ඇරඹිය නොහැක The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show පෙන්වන්න Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed නිර්නාමික PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings තිර සැකසුම Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info විස්තර Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_sk-SK.qm000066400000000000000000000022431305627404700217310ustar00rootroot00000000000000ahko zdie>ae mya a klvesnicu medzi viacermi po ta mi na stole, je to zadarmo a Open Source. Len presune kurzor myai mimo okraj jednho po ta a na obrazovke na alaie. M~ete dokonca zdie>ae vaetky vaae schrnok. Vaetko,  o potrebujete, je pripojenie k sieti. Synergy je cross-platformov (prca na Windows, Mac OS X a Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBasesynergy-1.8.8-stable/src/gui/res/lang/gui_sk-SK.ts000066400000000000000000001610041305627404700217430ustar00rootroot00000000000000 AboutDialogBase About Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: &Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left right up down Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Informácie Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy vám umožní ľahko zdieľať myš a klávesnicu medzi viacerými počítačmi na stole, je to zadarmo a Open Source. Len presunúť kurzor myši mimo okraj jedného počítača na obrazovke na ďalšie. Môžete dokonca zdieľať všetky vaše schránok. Všetko, čo potrebujete, je pripojenie k sieti. Synergy je cross-platformové (práca na Windows, Mac OS X a Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_sl-SI.qm000066400000000000000000000032551305627404700217340ustar00rootroot00000000000000 AboutDialogBase About Synergy O Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Neznano Version: Različica: &Ok V redu ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left right up down Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Neznano Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Informacije Debug Debug1 Debug2 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy omogoča preprosto souporabo miške in tipkovnice med mnogimi računalniki na vaši mizi. Je brezplačen in prostokodni program. Miškin kazalec lahko preprosto premaknemo preko roba ekrana enega računalnika na ekran drugega. Omogoča tudi souporabo odložišča. Vse kar potrebujete je mrežna povezava. Synergy podpira mnogo operacijskih sistemov (npr. Windows, Mac OS X in Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Neznano WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_sq-AL.qm000066400000000000000000000474331305627404700217300ustar00rootroot000000000000003}Su>(Z &= nbj 4G,vDEv._"e8rw9$D$  b;H}H,:O !DO CO D]AVE S+ UN'Yu:Al_ } !*:l.]@@ 4:$:. $Z?;J)"QJ-izBa@d&l *k攄LJg(D*( n4.d+@Ty(bL#>{/d6>>zI>J@"#? 3=Tk@d. %C%"}F88ntC;N0"F I_ JzB k#2 v~6 9 -5 Pn9W d# ~58 ք~ ȹ ȹ W ȹI` a? |* F% F07 Z% 0o KG } RVx RV RVI" R T! V4  |*? c0 s sB c:6 F' Ҫ ^ /% 4p: d)E i! r- zk3 PC1 x41{ ]^C^Co=7> 2bun< r/7(kC7k/b.1>'[iI&Ok&OkAboutDialogBaseRreth Sunergy About SynergyAboutDialogBaseE PanjohurUnknownAboutDialogBaseVersioni:Version:AboutDialogBase>Zgjidh veprimin qe do te kryeshChoose the action to performActionDialogBase$Veprim KonfigurimiConfigure ActionActionDialogBase0Blloko kursorin ne ekranLock cursor to screenActionDialogBase6Shtypni nje tast shpejtesiePress a hotkeyActionDialogBaseTShtypni dhe leshojeni tastin e shpejtesisePress and release a hotkeyActionDialogBase<Leshojeni tastin e shpejtesiseRelease a hotkeyActionDialogBaseKalo ne adreseSwitch in directionActionDialogBaseKalo ne ekranSwitch to screenActionDialogBase(Ky veprim merret kurThis action is performed whenActionDialogBase poshtedownActionDialogBase majtasleftActionDialogBasejo aktivoffActionDialogBase aktivonActionDialogBase(Vetem ne keto ekraneonly on these screensActionDialogBasedjathtasrightActionDialogBaseFtasti i shpejtesise eshte i shtypurthe hotkey is pressedActionDialogBaseBtasti i shpejtesise eshte leshuarthe hotkey is releasedActionDialogBasendrysho gjendjetoggleActionDialogBaselartupActionDialogBaseZVendos specifikimin per tastin e shpejtesise:'Enter the specification for the hotkey:HotkeyDialogBaseTast shpejtesieHotkeyHotkeyDialogBase&Ndrysho&Edit MainWindow&Skedar&File MainWindow&Ndihme&Help MainWindow &Fillo&Start MainWindow &Ndalo&Stop MainWindow&Dritare&Window MainWindow`Kerko per nje skedarin e konfigurimit te Synergy!Browse for a synergys config file MainWindow`Nuk mund te shkruaje skedarin e konfiguracionitCannot write configuration file MainWindowZEmri i skedarit te konfiguracionit i pa sakteConfiguration filename invalid MainWindowZNuk mund te ruaje skedarin e konfiguracionit.%Could not save configuration to file. MainWindow0Emri i hostit eshte boshHostname is empty MainWindow~Ju lutem vendosni nje host te klientit qe deshironi te lidheni.?Please fill in a hostname for the synergy client to connect to. MainWindow8Programi nuk mund te fillojeProgram can not be started MainWindow4Ruaj konfiguracionin si...Save configuration as... MainWindowRuajtja deshtoi Save failed MainWindowSynergySynergy MainWindow$Klienti nuk u gjetSynergy client not found MainWindow6Synergy nuk po ekzekutohet.Synergy is not running. MainWindow$Synergy po fillon.Synergy is starting. MainWindow4Serveri Synergy nuk u gjetSynergy server not found MainWindowSynergy ndaloi papritur me nje kod gabimi %1.<br><br> Ju lutem shikoni detajet e te dhenave.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow8Synergy ndaloi nga nje gabim Synergy terminated with an error MainWindowxSkedari i ekzekutueshem per serverin e synergy nuk egziston.5The executable for the synergy client does not exist. MainWindowxSkedari i ekzekutueshem per serverin e synergy nuk egziston.5The executable for the synergy server does not exist. MainWindowfSkedari i ekzekutueshem <br><br>%1<br><br>nuk startoi ne menyre te suksesshme, meqe ai nuk egziston. Kontrolloni nese keni te drejta te mjaftueshme per te ekzekutuar kete program.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowSkedari i perkohshem qe eshte i nevojshem per te startuar Synergy nuk mund te shkruhet.NThe temporary configuration file required to start synergy can not be written. MainWindowE PanjohurUnknown MainWindowNuk keni krijuar nje skedar konfiguracioni per serverin synergu. Deshironi te kerkoni per nje skedar konfiguracioni tani?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow Rreth Synergy...&About Synergy...MainWindowBase&Apliko&ApplyMainWindowBaseShfleto... &Browse...MainWindowBase4Skedari i konfiguracionit:&Configuration file:MainWindowBase*Konfiguro Serverin...&Configure Server...MainWindowBase &Fshih&HideMainWindowBase&Dil&QuitMainWindowBase&IP e Serverit: &Server IP:MainWindowBase &Shfaq&ShowMainWindowBase &Fillo&StartMainWindowBase2Konfiguracion Interaktiv:Configure interactively:MainWindowBase(Ndrysho konfigurimet Edit settingsMainWindowBase FshihHideMainWindowBaseIP adresa: IP addresses:MainWindowBaseTe dhenaLogMainWindowBaseDilQuitMainWindowBaseGatiReadyMainWindowBaseEkzekutoRunMainWindowBase(Ekzekuto Magjistarin Run WizardMainWindowBaseShfaq Statusin S&how StatusMainWindowBase NdaloS&topMainWindowBase6Rruaj konfiguracionin si...Save configuration &as...MainWindowBasetRuaj konfiguracionit interaktiv te serverit ne nje skedar.@Save the interactively generated server configuration to a file.MainWindowBaseEmri i ekranit: Screen name:MainWindowBaseKonfigurimeSettingsMainWindowBase ShfaqShowMainWindowBase NdaloStopMainWindowBaseSynergySynergyMainWindowBase@Perdorni konfiguracionin aktual:Use existing configuration:MainWindowBase PaemerUnnamedNewScreenWidgetVendos Synergy Setup SynergyPluginWizardPagehKonfiguracioni i Synergy (*.conf);;Te gjithe (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectfKonfiguracioni i Synergy (*.sgc);;Te gjithe (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectdIkona e sistemin nuk eshte aktive, duke e mbyllur.%System tray is unavailable, quitting.QObject2Emri i ekranit eshte boshScreen name is emptyScreenSettingsDialogShto&AddScreenSettingsDialogBase Ctrl:&Ctrl:ScreenSettingsDialogBase Kende te vdekura &Dead cornersScreenSettingsDialogBaseRregullime&FixesScreenSettingsDialogBase$Celesat modifikues&Modifier keysScreenSettingsDialogBaseHiq&RemoveScreenSettingsDialogBase Shift&Shift:ScreenSettingsDialogBaseEmertimetA&liasesScreenSettingsDialogBaseAlt:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseMajtas-poshte Bottom-leftScreenSettingsDialogBase Djtathtas-poshte Bottom-rightScreenSettingsDialogBase$Madhesia e kendit: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase2Rregullo tastin CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase0Rregullo tastin NUM LOCKFix NUM LOCK keyScreenSettingsDialogBase6Rregullo tastin SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase6Rregullo XTest per XineramaFix XTest for XineramaScreenSettingsDialogBaseMbi:M&eta:ScreenSettingsDialogBaseMbiMetaScreenSettingsDialogBase AsnjeNoneScreenSettingsDialogBaseSuperior:S&uper:ScreenSettingsDialogBaseEmri i ekranit: Screen &name:ScreenSettingsDialogBase,Konfigurimet e EkranitScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBaseSuperiorSuperScreenSettingsDialogBaseLart-MajtasTop-leftScreenSettingsDialogBaseLart-Djathtas Top-rightScreenSettingsDialogBase<center>Ekran: <b>%1</b></center><br>Dopjo klik per te ndryshuar konfigurimet<br>Zhvendos ekranit ne kosh per ta fshireo
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelMajtas-poshte &Bottom-leftServerConfigDialogBase.&Kontrollo klientet cdo&Check clients everyServerConfigDialogBase Kende te vdekura &Dead cornersServerConfigDialogBase&Ndrysho&EditServerConfigDialogBase(Tastet e shpejtesise&HotkeysServerConfigDialogBaseI Ri&NewServerConfigDialogBase&Mundesi&OptionsServerConfigDialogBaseHiq&RemoveServerConfigDialogBase&Ndrysho&SwitchServerConfigDialogBase VeprimA&ctionsServerConfigDialogBaseHKonfigurime te avancuara te serveritAdvanced server settingsServerConfigDialogBaseDjathtas-poshte Bottom-ri&ghtServerConfigDialogBasehKonfiguroni paraqitjen e konfiguraciont te serverit.:Configure the layout of your synergy server configuration.ServerConfigDialogBase$Madhesia e Kendit: Cor&ner Size:ServerConfigDialogBaserMos i jepni prioritet dritareve ne serverat me SO Windows0Don't take &foreground window on Windows serversServerConfigDialogBaseZKalo ekranit nga rrjeta ne kosh per ta fshire9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaseTKaloni ekranet e reja ne rrjet ose levizni ato egzistuesit rreth tij. Zhvendos ekranit ne kosh per ta fshire Dopjo klik mbi nje ekran per te ndryshuar konfigurimet e tij.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBaserKaloni kete buton ne rrjet per te shtuar nje ekran te ri.1Drag this button to the grid to add a new screen.ServerConfigDialogBaseModifikoE&ditServerConfigDialogBase(Tastet e shpejtesiseHotkeysServerConfigDialogBaseI riNe&wServerConfigDialogBase&HiqRe&moveServerConfigDialogBase>Sinkronizo mbrojtesit e ekranitS&ynchronize screen saversServerConfigDialogBase&Ekranet dhe lidhjetScreens and linksServerConfigDialogBase2Konfiguracioni i ServeritServer ConfigurationServerConfigDialogBase.Ndrysho pasi te preseshSwitch &after waitingServerConfigDialogBase8Kaloni ne lidhje te dyfishteSwitch on double &tap withinServerConfigDialogBaseLart-majtas To&p-leftServerConfigDialogBaseLart-djathtas Top-rig&htServerConfigDialogBaseBBeni levizjet perkatese te mausitUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBase Jeni te sigurte qe doni te permiresoni Synergy? Kjo i jep mundesi Synergy te bashkeveproje me procese te larta dhe UAC, por ju mund te shkaktoni probleme me proceset e uleta. Permiresoni Synergy vetem nese ju nevojitet.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialog"Permireso SynergyElevate SynergySettingsDialogFRruaj dokumentin e te dhenave ne...Save log file to...SettingsDialog&Nderfaqja &Interface:SettingsDialogBase &Niveli i hyrjes&Logging level:SettingsDialogBaseShfleto... Browse...SettingsDialogBaseRregulloDebugSettingsDialogBaseRregullo1Debug1SettingsDialogBaseRregullo2Debug2SettingsDialogBase GabimErrorSettingsDialogBaseInformacionInfoSettingsDialogBase Hyr ne dokument: Log to file:SettingsDialogBaseDuke hyreLoggingSettingsDialogBase ShenimNoteSettingsDialogBase Porta:P&ort:SettingsDialogBaseEmri i ekranit: Sc&reen name:SettingsDialogBaseKonfigurimeSettingsSettingsDialogBaseLajmerimWarningSettingsDialogBase:Ju lutem zgjidhni nje opsion.Please select an option. SetupWizardVendos Synergy Setup Synergy SetupWizard$Server apo Klient?Server or Client?SetupWizardBaseVendos Synergy Setup SynergySetupWizardBaseSunergy ju mundeson lehtesisht te ndani mausin dhe tastieren me disa komopjutera te tjere ne tavolinen tuaj, eshte FALAS dhe me KOD TE HAPUR. Vetem levizni mausin nga kompjuteri juaj ne nje kompjuter tjeter. Madje mund te beni ndani te gjitha ekranet. Ju duhet vem nje lidhje interneti. Sunergy eshte nje platformi e gjere (punon ne Windows, MAC OS X dhe Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseE PanjohurUnknownVersionCheckerSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_sq-AL.ts000066400000000000000000001701511305627404700217330ustar00rootroot00000000000000 AboutDialogBase About Synergy Rreth Sunergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown E Panjohur Version: Versioni: &Ok &Ok ActionDialogBase Configure Action Veprim Konfigurimi Choose the action to perform Zgjidh veprimin qe do te kryesh Press a hotkey Shtypni nje tast shpejtesie Release a hotkey Leshojeni tastin e shpejtesise Press and release a hotkey Shtypni dhe leshojeni tastin e shpejtesise only on these screens Vetem ne keto ekrane Switch to screen Kalo ne ekran Switch in direction Kalo ne adrese left majtas right djathtas up lart down poshte Lock cursor to screen Blloko kursorin ne ekran toggle ndrysho gjendje on aktiv off jo aktiv This action is performed when Ky veprim merret kur the hotkey is pressed tasti i shpejtesise eshte i shtypur the hotkey is released tasti i shpejtesise eshte leshuar AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Tast shpejtesie Enter the specification for the hotkey: Vendos specifikimin per tastin e shpejtesise: MainWindow &Start &Fillo &File &Skedar &Edit &Ndrysho &Window &Dritare &Help &Ndihme <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started Programi nuk mund te filloje The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Skedari i ekzekutueshem <br><br>%1<br><br>nuk startoi ne menyre te suksesshme, meqe ai nuk egziston. Kontrolloni nese keni te drejta te mjaftueshme per te ekzekutuar kete program. Synergy client not found Klienti nuk u gjet The executable for the synergy client does not exist. Skedari i ekzekutueshem per serverin e synergy nuk egziston. Hostname is empty Emri i hostit eshte bosh Please fill in a hostname for the synergy client to connect to. Ju lutem vendosni nje host te klientit qe deshironi te lidheni. Cannot write configuration file Nuk mund te shkruaje skedarin e konfiguracionit The temporary configuration file required to start synergy can not be written. Skedari i perkohshem qe eshte i nevojshem per te startuar Synergy nuk mund te shkruhet. Configuration filename invalid Emri i skedarit te konfiguracionit i pa sakte You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Nuk keni krijuar nje skedar konfiguracioni per serverin synergu. Deshironi te kerkoni per nje skedar konfiguracioni tani? Synergy server not found Serveri Synergy nuk u gjet The executable for the synergy server does not exist. Skedari i ekzekutueshem per serverin e synergy nuk egziston. Synergy terminated with an error Synergy ndaloi nga nje gabim Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy ndaloi papritur me nje kod gabimi %1.<br><br> Ju lutem shikoni detajet e te dhenave. &Stop &Ndalo Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy po fillon. Synergy is running. Synergy is not running. Synergy nuk po ekzekutohet. Unknown E Panjohur Synergy Synergy Browse for a synergys config file Kerko per nje skedarin e konfigurimit te Synergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Ruaj konfiguracionin si... Save failed Ruajtja deshtoi Could not save configuration to file. Nuk mund te ruaje skedarin e konfiguracionit. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Emri i ekranit: &Server IP: &IP e Serverit: &Start &Fillo Use existing configuration: Perdorni konfiguracionin aktual: &Configuration file: Skedari i konfiguracionit: &Browse... Shfleto... Configure interactively: Konfiguracion Interaktiv: &Configure Server... Konfiguro Serverin... Ready Gati Log Te dhena &Apply &Apliko IP addresses: IP adresa: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Rreth Synergy... &Quit &Dil Quit Dil Run Ekzekuto S&top Ndalo Stop Ndalo S&how Status Shfaq Statusin &Hide &Fshih Hide Fshih &Show &Shfaq Show Shfaq Save configuration &as... Rruaj konfiguracionin si... Save the interactively generated server configuration to a file. Ruaj konfiguracionit interaktiv te serverit ne nje skedar. Settings Konfigurime Edit settings Ndrysho konfigurimet Run Wizard Ekzekuto Magjistarin NewScreenWidget Unnamed Paemer PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Vendos Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Konfiguracioni i Synergy (*.sgc);;Te gjithe (*.*) Synergy Configurations (*.conf);;All files (*.*) Konfiguracioni i Synergy (*.conf);;Te gjithe (*.*) System tray is unavailable, quitting. Ikona e sistemin nuk eshte aktive, duke e mbyllur. ScreenSettingsDialog Screen name is empty Emri i ekranit eshte bosh The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Konfigurimet e Ekranit Screen &name: Emri i ekranit: A&liases Emertimet &Add Shto &Remove Hiq &Modifier keys Celesat modifikues &Shift: Shift Shift Shift Ctrl Ctrl Alt Alt Meta Mbi Super Superior None Asnje &Ctrl: Ctrl: Al&t: Alt: M&eta: Mbi: S&uper: Superior: &Dead corners Kende te vdekura Top-left Lart-Majtas Top-right Lart-Djathtas Bottom-left Majtas-poshte Bottom-right Djtathtas-poshte Corner Si&ze: Madhesia e kendit: &Fixes Rregullime Fix CAPS LOCK key Rregullo tastin CAPS LOCK Fix NUM LOCK key Rregullo tastin NUM LOCK Fix SCROLL LOCK key Rregullo tastin SCROLL LOCK Fix XTest for Xinerama Rregullo XTest per Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Ekran: <b>%1</b></center><br>Dopjo klik per te ndryshuar konfigurimet<br>Zhvendos ekranit ne kosh per ta fshire ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Konfiguracioni i Serverit Screens and links Ekranet dhe lidhjet Drag a screen from the grid to the trashcan to remove it. Kalo ekranit nga rrjeta ne kosh per ta fshire Configure the layout of your synergy server configuration. Konfiguroni paraqitjen e konfiguraciont te serverit. Drag this button to the grid to add a new screen. Kaloni kete buton ne rrjet per te shtuar nje ekran te ri. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Kaloni ekranet e reja ne rrjet ose levizni ato egzistuesit rreth tij. Zhvendos ekranit ne kosh per ta fshire Dopjo klik mbi nje ekran per te ndryshuar konfigurimet e tij. Hotkeys Tastet e shpejtesise &Hotkeys Tastet e shpejtesise &New I Ri &Edit &Ndrysho &Remove Hiq A&ctions Veprim Ne&w I ri E&dit Modifiko Re&move &Hiq Advanced server settings Konfigurime te avancuara te serverit &Switch &Ndrysho Switch &after waiting Ndrysho pasi te presesh ms ms Switch on double &tap within Kaloni ne lidhje te dyfishte &Options &Mundesi &Check clients every &Kontrollo klientet cdo Use &relative mouse moves Beni levizjet perkatese te mausit S&ynchronize screen savers Sinkronizo mbrojtesit e ekranit Don't take &foreground window on Windows servers Mos i jepni prioritet dritareve ne serverat me SO Windows Ignore auto config clients &Dead corners Kende te vdekura To&p-left Lart-majtas Top-rig&ht Lart-djathtas &Bottom-left Majtas-poshte Bottom-ri&ght Djathtas-poshte Cor&ner Size: Madhesia e Kendit: SettingsDialog Save log file to... Rruaj dokumentin e te dhenave ne... Elevate Synergy Permireso Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Jeni te sigurte qe doni te permiresoni Synergy? Kjo i jep mundesi Synergy te bashkeveproje me procese te larta dhe UAC, por ju mund te shkaktoni probleme me proceset e uleta. Permiresoni Synergy vetem nese ju nevojitet. SettingsDialogBase Settings Konfigurime Sc&reen name: Emri i ekranit: P&ort: Porta: &Interface: &Nderfaqja Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Duke hyre &Logging level: &Niveli i hyrjes Log to file: Hyr ne dokument: Browse... Shfleto... Error Gabim &Language: &Miscellaneous Warning Lajmerim Note Shenim Info Informacion Debug Rregullo Debug1 Rregullo1 Debug2 Rregullo2 SetupWizard Setup Synergy Vendos Synergy Please select an option. Ju lutem zgjidhni nje opsion. Please enter your email address and password. SetupWizardBase Setup Synergy Vendos Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Sunergy ju mundeson lehtesisht te ndani mausin dhe tastieren me disa komopjutera te tjere ne tavolinen tuaj, eshte FALAS dhe me KOD TE HAPUR. Vetem levizni mausin nga kompjuteri juaj ne nje kompjuter tjeter. Madje mund te beni ndani te gjitha ekranet. Ju duhet vem nje lidhje interneti. Sunergy eshte nje platformi e gjere (punon ne Windows, MAC OS X dhe Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Server apo Klient? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown E Panjohur WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_sr.qm000066400000000000000000000001651305627404700214260ustar00rootroot00000000000000@<0F8X5InfoSettingsDialogBase ) , synergy-1.8.8-stable/src/gui/res/lang/gui_sr.ts000066400000000000000000001602201305627404700214360ustar00rootroot00000000000000 AboutDialogBase About Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: &Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left right up down Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info Информације Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_sv.qm000066400000000000000000000532141305627404700214350ustar00rootroot00000000000000^+[H4)SWYu'2*vD<,G:VE-,VEg G` vs+**2*%*0 *++gR+`}G:kGz)ZJCLbDU`2XPY.UZ.xx. >60}Su>](Z = Unbj 4~/dvHZOEv._#Ce;fw9n'\'N ;H}H/O !O GO H|]EH|%VE -UN+ Yu:Dl_ u} !*=lb1[DDW 7u:':1  B$ZCyJ,"QJ-izE@d)l -g攄J(H:S$1( n4.d.@Ty+pL#A{2z>MJC 3 =T8k@d0ycN$f6%@~C(4}F;&nbC><3" I_ JzE k#5 v~9 < -5 a Pn 5bun>y~F$ r`/E7+kC:k2Z.4>O*yiP&Ok&OkAboutDialogBaseOm Synergy About SynergyAboutDialogBase OkndUnknownAboutDialogBaseVersion:Version:AboutDialogBase>Vlj funktion som skall utfrasChoose the action to performActionDialogBaseKonfigureraConfigure ActionActionDialogBase2Ls muspekaren till skrmLock cursor to screenActionDialogBase2Tryck ned en snabbtangentPress a hotkeyActionDialogBaseFTryck ned och slpp en snabbtangentPress and release a hotkeyActionDialogBase*Slpp en snabbtangentRelease a hotkeyActionDialogBase Vxla i riktningSwitch in directionActionDialogBase Vxla till skrmSwitch to screenActionDialogBase"Detta utfrs nr This action is performed whenActionDialogBasenerdownActionDialogBasevnsterleftActionDialogBaseAvoffActionDialogBaseponActionDialogBase.endast p dessa skrmaronly on these screensActionDialogBase hgerrightActionDialogBase0snabbtangenten trycks inthe hotkey is pressedActionDialogBase*snabbtangenten slppsthe hotkey is releasedActionDialogBase skiftatoggleActionDialogBaseuppupActionDialogBase.Beskriv snabbtangenten:'Enter the specification for the hotkey:HotkeyDialogBaseSnabbtangentHotkeyHotkeyDialogBase&Redigera&Edit MainWindow Arkiv&File MainWindow Hjlp&Help MainWindow Start&Start MainWindow Stopp&Stop MainWindowFnster&Window MainWindow<p>Du kr inte den senaste versionen av Synergy. Version <b>%1</b> finns tillgnglig fr <a href="%2">nedladdning</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowRBlddra efter Synergys konfigurationsfil.!Browse for a synergys config file MainWindowDKan inte spara konfigurationsfilenCannot write configuration file MainWindowZNamnet p konfigurationsfilen r inte giltigtConfiguration filename invalid MainWindowPKunde inte spara konfiguration till fil.%Could not save configuration to file. MainWindow8Vrddatornamnet r inte sattHostname is empty MainWindowFyll i det vrddatornamn som Synergyklienten skall ansluta till.?Please fill in a hostname for the synergy client to connect to. MainWindow6Programmet kan inte startasProgram can not be started MainWindow4Spara konfiguration som...Save configuration as... MainWindowSparades inte Save failed MainWindowSynergySynergy MainWindow:Synergyklienten hittades inteSynergy client not found MainWindow$Synergy krs inte.Synergy is not running. MainWindowSynergy krs.Synergy is running. MainWindow Synergy startas.Synergy is starting. MainWindow8Synergyservern hittades inteSynergy server not found MainWindowSynergyterminalen avslutades ovntat med avbrottskoden %1.<br><br>Kontrollera loggdatan fr detaljer.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow<Synergy avslutades med ett fel Synergy terminated with an error MainWindowrDen exekverbara filen fr Synergyklienten existerar inte.5The executable for the synergy client does not exist. MainWindowhDen krbara filen fr Synergyservern existerar inte.5The executable for the synergy server does not exist. MainWindow2Programmet<br><br>%1<br><br>kunde inte startas, men det finns. Var vnlig och kontrollera att du har tillrckliga rttigheter fr att kra detta program.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowDen tillflliga konfigurationsfilen som krvs fr att kunna starta Synergy kan inte skapas.NThe temporary configuration file required to start synergy can not be written. MainWindow OkndUnknown MainWindowDu har inte fyllt i en giltig konfigurationsfil fr Synergyservern. Vill du blddra efter konfigurationsfilen nu?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindowOm Synergy...&About Synergy...MainWindowBaseVerkstll&ApplyMainWindowBaseBlddra... &Browse...MainWindowBase$Konfigurationsfil:&Configuration file:MainWindowBase*Konfigurera server...&Configure Server...MainWindowBaseDlj&HideMainWindowBaseAvsluta&QuitMainWindowBaseServerns IP: &Server IP:MainWindowBaseVisa&ShowMainWindowBase Start&StartMainWindowBase0Konfigurera interaktivt:Configure interactively:MainWindowBase&ndra instllningar Edit settingsMainWindowBaseDljHideMainWindowBaseIP-adresser: IP addresses:MainWindowBaseLoggLogMainWindowBaseAvslutaQuitMainWindowBaseKlarReadyMainWindowBaseKrRunMainWindowBaseKr guiden Run WizardMainWindowBaseVisa Status S&how StatusMainWindowBase S&toppS&topMainWindowBase4Spara konfiguration som...Save configuration &as...MainWindowBaseSpara den interaktivt genererade serverkonfigurationen till en fil.@Save the interactively generated server configuration to a file.MainWindowBaseSkrmnamn: Screen name:MainWindowBaseInstllningarSettingsMainWindowBaseVisaShowMainWindowBase StoppStopMainWindowBaseSynergySynergyMainWindowBase>Anvnd befintlig konfiguration:Use existing configuration:MainWindowBaseNamnlsUnnamedNewScreenWidget Stll in Synergy Setup SynergyPluginWizardPagedSynergy-konfigurationer (*.conf);;Alla filer (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectbSynergy-konfigurationer (*.sgc);;Alla filer (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectJSystemfltet otillgngligt, avslutar.%System tray is unavailable, quitting.QObject&Skrmnamnet r tomtScreen name is emptyScreenSettingsDialog.Skrmnamn matchar aliasScreen name matches aliasScreenSettingsDialogSkrmnamnet kan inte vara tomt. Fyll i ett namn eller avbryt dialogrutan.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogSkrmnamnet kan inte vara samma som en alias. Var vnlig att antingen ta bort alias eller ndra skrmnamnet.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialogLgg till&AddScreenSettingsDialogBase &Ctrl:&Ctrl:ScreenSettingsDialogBaseDda hrn &Dead cornersScreenSettingsDialogBaseKorrigeringar&FixesScreenSettingsDialogBase*Modifieringstangenter&Modifier keysScreenSettingsDialogBaseTa bort&RemoveScreenSettingsDialogBase Shift:&Shift:ScreenSettingsDialogBase AliasA&liasesScreenSettingsDialogBaseAlt:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase(Nedre vnstra hrnet Bottom-leftScreenSettingsDialogBaseNedre hger Bottom-rightScreenSettingsDialogBase Hrnets storlek: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase&Korrigera CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase$Korrigera NUM LOCKFix NUM LOCK keyScreenSettingsDialogBase*Korrigera SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase8Korrigera XTest fr XineramaFix XTest for XineramaScreenSettingsDialogBase Meta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBase IngenNoneScreenSettingsDialogBase Super:S&uper:ScreenSettingsDialogBaseSkrmnamn: Screen &name:ScreenSettingsDialogBase$SkrminstllningarScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBasever vnsterTop-leftScreenSettingsDialogBasever hger Top-rightScreenSettingsDialogBase<center>Skrm:<b>%1</b></center><br>Dubbelklicka fr att ndra instllningar<br>Dra skrmen till papperskorgen fr att ta bort deno
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel(Nedre vnstra hrnet &Bottom-leftServerConfigDialogBase4Kontrollera klienter varje&Check clients everyServerConfigDialogBaseDda hrn &Dead cornersServerConfigDialogBase&Redigera&EditServerConfigDialogBaseSnabbtangenter&HotkeysServerConfigDialogBaseNy&NewServerConfigDialogBaseAlternativ&OptionsServerConfigDialogBaseTa bort&RemoveServerConfigDialogBase Vxla&SwitchServerConfigDialogBasetgrderA&ctionsServerConfigDialogBase<Avancerade serverinstllningarAdvanced server settingsServerConfigDialogBase$Nedre hgra hrnet Bottom-ri&ghtServerConfigDialogBasedKonfigurera layouten p din Synergy-konfiguration.:Configure the layout of your synergy server configuration.ServerConfigDialogBaseHrnstorlek: Cor&ner Size:ServerConfigDialogBase\Anvnd inte frgrundsfnster p Windowsservrar0Don't take &foreground window on Windows serversServerConfigDialogBaseDra en skrm frn rutntet till papperskorgen fr att ta bort den.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaseXDra nya skrmar till rutntet eller flytta runt existerande. Dra en skrm till papperskorgen fr att ta bort den. Dubbelklicka p en skrm fr att ndra dess instllningar.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBaseDra den hr knappen till rutntet fr att lgga till en ny skrm.1Drag this button to the grid to add a new screen.ServerConfigDialogBase ndraE&ditServerConfigDialogBaseSnabbtangenterHotkeysServerConfigDialogBaseNyNe&wServerConfigDialogBaseTa bortRe&moveServerConfigDialogBase4Synkronisera skrmslckareS&ynchronize screen saversServerConfigDialogBase$Skrmar och lnkarScreens and linksServerConfigDialogBase&ServerkonfigurationServer ConfigurationServerConfigDialogBase$Vxla efter vntanSwitch &after waitingServerConfigDialogBase<Vxla eller dubbelklicka inutiSwitch on double &tap withinServerConfigDialogBase&vre vnstra hrnet To&p-leftServerConfigDialogBase"vre hgra hrnet Top-rig&htServerConfigDialogBase6Anvnd relativa musrrelserUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBaser du sker p att du vill frhja Synergys behrighet? Detta lter Synergy interagera med frhjda processer och UAC-dialogen, men kan skapa program med processer som inte r frhjda. Frhj Synergys behrighet enbart om du verkligen mste.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialog4Frhj Synergys behrighetElevate SynergySettingsDialog*Spara loggfil till...Save log file to...SettingsDialogGrnssnitt: &Interface:SettingsDialogBase Sprk: &Language:SettingsDialogBaseLoggningsniv:&Logging level:SettingsDialogBase&vrigt&MiscellaneousSettingsDialogBaseBlddra: Browse...SettingsDialogBase FelskDebugSettingsDialogBaseFelsk1Debug1SettingsDialogBaseFelsk2Debug2SettingsDialogBaseFelErrorSettingsDialogBaseInfoInfoSettingsDialogBaseLogga till fil: Log to file:SettingsDialogBaseLoggningLoggingSettingsDialogBaseNoteringNoteSettingsDialogBase Port:P&ort:SettingsDialogBaseSkrmnamn: Sc&reen name:SettingsDialogBaseInstllningarSettingsSettingsDialogBaseVarningWarningSettingsDialogBase`Var vnlig skriv din e-postaddress och lsenord.-Please enter your email address and password. SetupWizard(Vlj ett alternativ.Please select an option. SetupWizard Stll in Synergy Setup Synergy SetupWizard(Server eller klient?Server or Client?SetupWizardBase Stll in Synergy Setup SynergySetupWizardBaseMed Synergy kan du enkelt dela din mus och ditt tangentbord med flera datorer p ditt skrivbord, och det r Fri och ppen mjukvara. Fr bara muspekaren ver kanten p en datorskrm fr att den skall dyka upp p nsta. Du kan till och med dela utklipp. Allt du behver r en ntverksanslutning. Synergy r multiplattform (fungerar p bde Windows, Mac OS X och Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseHTack fr att du installerar Synergy!Thanks for installing Synergy!SetupWizardBaseVlkommenWelcomeSetupWizardBase OkndUnknownVersionCheckerfInloggning misslyckades, ett problem intrffade. %1$Login failed, an error occurred. %1 WebClientInloggning misslyckades, ett problem intrffade. Server svar: %16Login failed, an error occurred. Server response: %1 WebClient|Inloggning misslyckades, ogiltig e-postaddress eller lsenord.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_sv.ts000066400000000000000000001712021305627404700214440ustar00rootroot00000000000000 AboutDialogBase About Synergy Om Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Okänd Version: Version: &Ok &Ok ActionDialogBase Configure Action Konfigurera Choose the action to perform Välj funktion som skall utföras Press a hotkey Tryck ned en snabbtangent Release a hotkey Släpp en snabbtangent Press and release a hotkey Tryck ned och släpp en snabbtangent only on these screens endast på dessa skärmar Switch to screen Växla till skärm Switch in direction Växla i riktning left vänster right höger up upp down ner Lock cursor to screen Lås muspekaren till skärm toggle skifta on off Av This action is performed when Detta utförs när the hotkey is pressed snabbtangenten trycks in the hotkey is released snabbtangenten släpps AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Snabbtangent Enter the specification for the hotkey: Beskriv snabbtangenten: MainWindow &Start Start &File Arkiv &Edit &Redigera &Window Fönster &Help Hjälp <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Du kör inte den senaste versionen av Synergy. Version <b>%1</b> finns tillgänglig för <a href="%2">nedladdning</a>.</p> Program can not be started Programmet kan inte startas The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Programmet<br><br>%1<br><br>kunde inte startas, men det finns. Var vänlig och kontrollera att du har tillräckliga rättigheter för att köra detta program. Synergy client not found Synergyklienten hittades inte The executable for the synergy client does not exist. Den exekverbara filen för Synergyklienten existerar inte. Hostname is empty Värddatornamnet är inte satt Please fill in a hostname for the synergy client to connect to. Fyll i det värddatornamn som Synergyklienten skall ansluta till. Cannot write configuration file Kan inte spara konfigurationsfilen The temporary configuration file required to start synergy can not be written. Den tillfälliga konfigurationsfilen som krävs för att kunna starta Synergy kan inte skapas. Configuration filename invalid Namnet på konfigurationsfilen är inte giltigt You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Du har inte fyllt i en giltig konfigurationsfil för Synergyservern. Vill du bläddra efter konfigurationsfilen nu? Synergy server not found Synergyservern hittades inte The executable for the synergy server does not exist. Den körbara filen för Synergyservern existerar inte. Synergy terminated with an error Synergy avslutades med ett fel Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergyterminalen avslutades oväntat med avbrottskoden %1.<br><br>Kontrollera loggdatan för detaljer. &Stop Stopp Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy startas. Synergy is running. Synergy körs. Synergy is not running. Synergy körs inte. Unknown Okänd Synergy Synergy Browse for a synergys config file Bläddra efter Synergys konfigurationsfil. Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Spara konfiguration som... Save failed Sparades inte Could not save configuration to file. Kunde inte spara konfiguration till fil. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Skärmnamn: &Server IP: Serverns IP: &Start Start Use existing configuration: Använd befintlig konfiguration: &Configuration file: Konfigurationsfil: &Browse... Bläddra... Configure interactively: Konfigurera interaktivt: &Configure Server... Konfigurera server... Ready Klar Log Logg &Apply Verkställ IP addresses: IP-adresser: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Om Synergy... &Quit Avsluta Quit Avsluta Run Kör S&top S&topp Stop Stopp S&how Status Visa Status &Hide Dölj Hide Dölj &Show Visa Show Visa Save configuration &as... Spara konfiguration som... Save the interactively generated server configuration to a file. Spara den interaktivt genererade serverkonfigurationen till en fil. Settings Inställningar Edit settings Ändra inställningar Run Wizard Kör guiden NewScreenWidget Unnamed Namnlös PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Ställ in Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy-konfigurationer (*.sgc);;Alla filer (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy-konfigurationer (*.conf);;Alla filer (*.*) System tray is unavailable, quitting. Systemfältet otillgängligt, avslutar. ScreenSettingsDialog Screen name is empty Skärmnamnet är tomt The screen name cannot be empty. Please either fill in a name or cancel the dialog. Skärmnamnet kan inte vara tomt. Fyll i ett namn eller avbryt dialogrutan. Screen name matches alias Skärmnamn matchar alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Skärmnamnet kan inte vara samma som en alias. Var vänlig att antingen ta bort alias eller ändra skärmnamnet. ScreenSettingsDialogBase Screen Settings Skärminställningar Screen &name: Skärmnamn: A&liases Alias &Add Lägg till &Remove Ta bort &Modifier keys Modifieringstangenter &Shift: Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Ingen &Ctrl: &Ctrl: Al&t: Alt: M&eta: Meta: S&uper: Super: &Dead corners Döda hörn Top-left Över vänster Top-right Över höger Bottom-left Nedre vänstra hörnet Bottom-right Nedre höger Corner Si&ze: Hörnets storlek: &Fixes Korrigeringar Fix CAPS LOCK key Korrigera CAPS LOCK Fix NUM LOCK key Korrigera NUM LOCK Fix SCROLL LOCK key Korrigera SCROLL LOCK Fix XTest for Xinerama Korrigera XTest för Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Skärm:<b>%1</b></center><br>Dubbelklicka för att ändra inställningar<br>Dra skärmen till papperskorgen för att ta bort den ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Serverkonfiguration Screens and links Skärmar och länkar Drag a screen from the grid to the trashcan to remove it. Dra en skärm från rutnätet till papperskorgen för att ta bort den. Configure the layout of your synergy server configuration. Konfigurera layouten på din Synergy-konfiguration. Drag this button to the grid to add a new screen. Dra den här knappen till rutnätet för att lägga till en ny skärm. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Dra nya skärmar till rutnätet eller flytta runt existerande. Dra en skärm till papperskorgen för att ta bort den. Dubbelklicka på en skärm för att ändra dess inställningar. Hotkeys Snabbtangenter &Hotkeys Snabbtangenter &New Ny &Edit &Redigera &Remove Ta bort A&ctions Åtgärder Ne&w Ny E&dit Ändra Re&move Ta bort Advanced server settings Avancerade serverinställningar &Switch Växla Switch &after waiting Växla efter väntan ms ms Switch on double &tap within Växla eller dubbelklicka inuti &Options Alternativ &Check clients every Kontrollera klienter varje Use &relative mouse moves Använd relativa musrörelser S&ynchronize screen savers Synkronisera skärmsläckare Don't take &foreground window on Windows servers Använd inte förgrundsfönster på Windowsservrar Ignore auto config clients &Dead corners Döda hörn To&p-left Övre vänstra hörnet Top-rig&ht Övre högra hörnet &Bottom-left Nedre vänstra hörnet Bottom-ri&ght Nedre högra hörnet Cor&ner Size: Hörnstorlek: SettingsDialog Save log file to... Spara loggfil till... Elevate Synergy Förhöj Synergys behörighet Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Är du säker på att du vill förhöja Synergys behörighet? Detta låter Synergy interagera med förhöjda processer och UAC-dialogen, men kan skapa program med processer som inte är förhöjda. Förhöj Synergys behörighet enbart om du verkligen måste. SettingsDialogBase Settings Inställningar Sc&reen name: Skärmnamn: P&ort: Port: &Interface: Gränssnitt: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Loggning &Logging level: Loggningsnivå: Log to file: Logga till fil: Browse... Bläddra: Error Fel &Language: Språk: &Miscellaneous &Övrigt Warning Varning Note Notering Info Info Debug Felsök Debug1 Felsök1 Debug2 Felsök2 SetupWizard Setup Synergy Ställ in Synergy Please select an option. Välj ett alternativ. Please enter your email address and password. Var vänlig skriv din e-postaddress och lösenord. SetupWizardBase Setup Synergy Ställ in Synergy Welcome Välkommen Thanks for installing Synergy! Tack för att du installerar Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Med Synergy kan du enkelt dela din mus och ditt tangentbord med flera datorer på ditt skrivbord, och det är Fri och Öppen mjukvara. För bara muspekaren över kanten på en datorskärm för att den skall dyka upp på nästa. Du kan till och med dela utklipp. Allt du behöver är en nätverksanslutning. Synergy är multiplattform (fungerar på både Windows, Mac OS X och Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Server eller klient? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Okänd WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Inloggning misslyckades, ogiltig e-postaddress eller lösenord. Login failed, an error occurred. %1 Inloggning misslyckades, ett problem inträffade. %1 Login failed, an error occurred. Server response: %1 Inloggning misslyckades, ett problem inträffade. Server svar: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_th-TH.qm000066400000000000000000000072111305627404700217250ustar00rootroot00000000000000 AboutDialogBase About Synergy เกี่ยวกับเรา Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: รุ่น: &Ok &ตกลง ActionDialogBase Configure Action กำหนดค่าการกระทำ Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left ซ้าย right ขวา up ขึ้น down ลง Lock cursor to screen toggle on เปิด off ปิด This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &เริ่มต้น &File &ไฟล์ &Edit &แก้ไข &Window &หน้าต่าง &Help &ช่วยเหลือ <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop &หยุด Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start &เริ่มต้น Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready พร้อมแล้ว Log บันทึกการเปลี่ยนแปลง &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit &ออก Quit ออก Run เปิดทำงาน S&top Stop หยุด S&how Status &Hide &ซ่อน Hide ซ๋อน &Show &แสดง Show แสดง Save configuration &as... Save the interactively generated server configuration to a file. Settings ตั้งค่า Edit settings แก้ไขการตั้งค่า Run Wizard NewScreenWidget Unnamed ยังไม่มีชื่อ PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings ตั้งค่าหน้าจอ Screen &name: A&liases &Add &เพิ่ม &Remove &ลบออก &Modifier keys &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &แก้ไข &Remove &ลบออก A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings ตั้งค่า Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info ข้อมูล Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy ช่วยให้คุณสามารถแบ่งปันเมาส์และแป้นพิมพ์ระหว่างคอมพิวเตอร์หลายเครื่องบนโต๊ะทำงานของคุณและก็ฟรีและ Open Source เพียงแค่เลื่อนเมาส์ของคุณปิดขอบของหน้าจอคอมพิวเตอร์เครื่องหนึ่งของเมื่อไปยังอีก คุณยังสามารถแบ่งปันทั้งหมดของ clipboards ของคุณ ทั้งหมดที่คุณต้องมีการเชื่อมต่อเครือข่าย Synergy เป็นข้ามแพลตฟอร์ม (เมื่อใช้งานบน Windows, Mac OS X และ Linux) Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_tr-TR.qm000066400000000000000000000477351305627404700217700ustar00rootroot00000000000000*'ge`{+**.*%*0(*++g<+`G7 Gz&WJ3&@}Su>;(Z = nbj4 ,vA]ZIVEv._ e8w9r$W$Zr .;H}H+O O @bO A]=|"VE *UN'Yu:=l_ +*9lh-<< 3:$:._  ;$Z;J){"QJ-iz>[@d&l **攄J(@( n4.d+@Ty(EL#:{/k6> z>cJ< 3=Tbk@d-ycG0%@~C%)}F7nzC90y I_ Jz> k#2] v~6< -5 E Pn8 d! ~58x ~qH ք~ ȹ. ȹ ȹI a: |*j F% F/ Z% / KG @{# RV RVh RVG R T i V4  |*;C c06 s, s> F' Ҫ ^ /& 4p9M d) i! Z r3 zk P? ¦eGu x40 ]^7^?1\F=5> 2 y~?O! rb/=7(kC7Fk..12>w'ViJ+ &Tamam&OkAboutDialogBase Synergy hakk1nda About SynergyAboutDialogBaseBilinmeyenUnknownAboutDialogBase Srm:Version:AboutDialogBase>Gerekle_tirilecek eylemi seinChoose the action to performActionDialogBase"Eylemi yap1land1rConfigure ActionActionDialogBase*0mleci ekrana sabitleLock cursor to screenActionDialogBase(K1sayol tu_una bas1nPress a hotkeyActionDialogBase8K1sayol tu_una bas1p b1rak1nPress and release a hotkeyActionDialogBase,K1sayol tu_unu b1rak1nRelease a hotkeyActionDialogBaseYn dei_tirSwitch in directionActionDialogBaseEkran1 dei_tirSwitch to screenActionDialogBase,0_lem gerekle_tiindeThis action is performed whenActionDialogBase a_a1downActionDialogBasesolleftActionDialogBase kapal1offActionDialogBasea1konActionDialogBase(Sadece bu ekranlardaonly on these screensActionDialogBasesarightActionDialogBase$K1sayol tu_u aktifthe hotkey is pressedActionDialogBase(K1sayol tu_u serbestthe hotkey is releasedActionDialogBaseDei_tirtoggleActionDialogBase yukar1upActionDialogBase>K1sayol tu_u iin tan1mlama gir'Enter the specification for the hotkey:HotkeyDialogBaseK1sayolHotkeyHotkeyDialogBase&Dzenle&Edit MainWindow &Dosya&File MainWindow&Yard1m&Help MainWindow&Ba_lat&Start MainWindow&Dur&Stop MainWindow&Pencere&Window MainWindow<p>Synergy versiyonunuz eski. Versiyon <b>%1</b> haz1r. 0ndirmek iin <a href="%2">t1klay1n</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindow:Synergy ayar dosyas1na gz at!Browse for a synergys config file MainWindow.Ayar dosyas1 yaz1lamad1Cannot write configuration file MainWindow2Geersiz ayar dosyas1 ad1Configuration filename invalid MainWindow*Ayarlar kaydedilemedi%Could not save configuration to file. MainWindow"Anabilgisayar bo_Hostname is empty MainWindowvLtfen Synergy'nin balanmas1 iin bir bilgisayar ad1 girin?Please fill in a hostname for the synergy client to connect to. MainWindow*Program ba_lat1lamad1Program can not be started MainWindowAyarlar1 kaydetSave configuration as... MainWindowKaydetme hatas1 Save failed MainWindowSynergySynergy MainWindow0Synergy al1c1y1 bulamad1Synergy client not found MainWindow$Synergy al1_m1yorSynergy is not running. MainWindow"Synergy al1_1yorSynergy is running. MainWindow Synergy ba_l1yorSynergy is starting. MainWindow6Synergy sunucusu bulunamad1Synergy server not found MainWindowSynergy %1 hata kod ile sonland1r1ld1.<br><br>Detaylar iin hata gnlne bak1n1z.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowPSynergy bir hata yznden sonland1r1ld1. Synergy terminated with an error MainWindowTSynergy iin al1_an kullan1c1 makine yok.5The executable for the synergy client does not exist. MainWindowNSynergy iin al1_an sunucu makine yok.5The executable for the synergy server does not exist. MainWindowjal1_t1r1labilir<br><br>%1<br><br>mevcut olmas1na ramen ba_ar1l1 olarak ba_lat1lamad1. Ltfen bu program1 al1_t1rabilmek iin yeterli yetkiye sahip olup olmad11n1z1 kontrol edin.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindowGeici ayar dosyas1 Synergy'nin ba_lamas1 iin gerekli, zerine kaydedilemezNThe temporary configuration file required to start synergy can not be written. MainWindowBilinmeyenUnknown MainWindowSynergy sunucusu iin geerli bir ayar dosyas1 olu_turmad1n1z. Bu ayar dosyas1na _imdi gz atmak ister misiniz?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow Synergy hakk1nda&About Synergy...MainWindowBase Uygula&ApplyMainWindowBase&Ara_t1r... &Browse...MainWindowBase&Ayar dosyas1:&Configuration file:MainWindowBase&Sunucu ayarla&Configure Server...MainWindowBase &Gizle&HideMainWindowBase &1k1_&QuitMainWindowBase&Sunucu IP: &Server IP:MainWindowBase&Gster&ShowMainWindowBase&Ba_lat&StartMainWindowBase:0nteraktif olarak yap1land1r:Configure interactively:MainWindowBase Ayarlar1 dzenle Edit settingsMainWindowBase GizleHideMainWindowBaseIP adresleri: IP addresses:MainWindowBaseKay1t ktLogMainWindowBase 1k1_QuitMainWindowBase Haz1rReadyMainWindowBaseal1_t1rRunMainWindowBase$Sihirbaz1 al1_t1r Run WizardMainWindowBaseDurumu Gster S&how StatusMainWindowBaseDurS&topMainWindowBase,Ayarlar1 farkl1 kaydetSave configuration &as...MainWindowBase0nteraktif olarak olu_turulmu_ olan sununu yap1land1rmas1n1 dosyaya kaydet.@Save the interactively generated server configuration to a file.MainWindowBaseEkran ad1: Screen name:MainWindowBaseAyarlarSettingsMainWindowBase GsterShowMainWindowBaseDurStopMainWindowBaseSynergySynergyMainWindowBase.Varolan ayarlar1 kullanUse existing configuration:MainWindowBase0simsizUnnamedNewScreenWidgetSynergy Kurulum Setup SynergyPluginWizardPageVBildirim alan1 kullan1lam1yor, kapat1l1yor.%System tray is unavailable, quitting.QObjectEkran ismi bo_Screen name is emptyScreenSettingsDialogEkran ismi bo_ b1rak1lamaz. Ltfen bir ad girin yada iptal edin.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogEkran ismiyle takma ad ayn1 olamaz. Ltfen takma ad1 silin yada ekran ad1n1 dei_tirin.iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialogEkle&AddScreenSettingsDialogBaseCtrl&Ctrl:ScreenSettingsDialogBase&Kr nokta &Dead cornersScreenSettingsDialogBaseDzeltmeler&FixesScreenSettingsDialogBase&&Dei_tirici tu_lar&Modifier keysScreenSettingsDialogBase Kald1r&RemoveScreenSettingsDialogBase&Shift:&Shift:ScreenSettingsDialogBaseTakma adlarA&liasesScreenSettingsDialogBase Al&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBaseSol-alt Bottom-leftScreenSettingsDialogBaseSa-alt Bottom-rightScreenSettingsDialogBaseK_e boyutu: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase&BYK YAZMAYI kapatFix CAPS LOCK keyScreenSettingsDialogBaseNUM LOCK kapatFix NUM LOCK keyScreenSettingsDialogBase"SCROLL LOCK kapatFix SCROLL LOCK keyScreenSettingsDialogBase8XTest iin Xinerama y1 onar.Fix XTest for XineramaScreenSettingsDialogBase M&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseYokNoneScreenSettingsDialogBase Sper:S&uper:ScreenSettingsDialogBaseGrnen isim: Screen &name:ScreenSettingsDialogBaseEkran Ayarlar1Screen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SperSuperScreenSettingsDialogBaseSol-stTop-leftScreenSettingsDialogBaseSa-st Top-rightScreenSettingsDialogBase<center>Ekran: <b>%1</b></center><br>ift t1klayarak ayarlar1 dzenleyin <br>p kutusundan silmek iin ekranda srkleyino
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModelAlt-sol &Bottom-leftServerConfigDialogBase>Her zaman kullan1c1lar1 denetle&Check clients everyServerConfigDialogBase&Kr nokta &Dead cornersServerConfigDialogBase&Dzenle&EditServerConfigDialogBaseK1sayollar&HotkeysServerConfigDialogBase &Yeni&NewServerConfigDialogBase&Seenekler&OptionsServerConfigDialogBase Kald1r&RemoveServerConfigDialogBase&Dei_tir&SwitchServerConfigDialogBaseEylemlerA&ctionsServerConfigDialogBase0Geli_mi_ sunucu ayarlar1Advanced server settingsServerConfigDialogBaseAlt-Sa Bottom-ri&ghtServerConfigDialogBasevLtfen sinerji sunucu yap1land1rma dzeninizi yap1land1r1n.:Configure the layout of your synergy server configuration.ServerConfigDialogBaseK_e Boyutu: Cor&ner Size:ServerConfigDialogBasenLtfen nplan penceresini Windows sunucular1na almay1n.0Don't take &foreground window on Windows serversServerConfigDialogBasetIzgaradan 1kartmak iin p kutusuna srkleyin ve silin.9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase~Izgaraya yeni ekranlar1 srkleyin veya evresinde mevcut olanlar1 ta_1y1n. Silmek iin p tenekesine ekran1 srkleyin. Kendi ayarlar1n1z1 dzenlemek iin bir ekran zerine ift t1klay1n.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasetYeni bir ekran eklemek iin bu butonu 1zgaraya srkleyin.1Drag this button to the grid to add a new screen.ServerConfigDialogBase DzenE&ditServerConfigDialogBaseK1sayollarHotkeysServerConfigDialogBaseYeniNe&wServerConfigDialogBase Kald1rRe&moveServerConfigDialogBase2Ekran koruyucular1 e_itleS&ynchronize screen saversServerConfigDialogBase0Ekranlar ve Balant1lar1Screens and linksServerConfigDialogBase*Sunucu Yap1land1rmas1Server ConfigurationServerConfigDialogBasest-sol To&p-leftServerConfigDialogBasest-Sa Top-rig&htServerConfigDialogBaseJ&0li_kili mouse harekelerini kullan1nUse &relative mouse movesServerConfigDialogBasemsmsServerConfigDialogBase Synergyi YkseltElevate SynergySettingsDialog*Log dosyas1 kaydet...Save log file to...SettingsDialogArayz: &Interface:SettingsDialogBase&Dil &Language:SettingsDialogBase"Kay1t Seviyesi : &Logging level:SettingsDialogBaseAra_t1r... Browse...SettingsDialogBaseHata Ay1klaDebugSettingsDialogBaseHata Ay1kla1Debug1SettingsDialogBaseHata Ay1kla2Debug2SettingsDialogBaseHataErrorSettingsDialogBase BilgiInfoSettingsDialogBase"Dosyaya kaydet :  Log to file:SettingsDialogBaseLog kay1tlar1LoggingSettingsDialogBaseNotNoteSettingsDialogBase Port:P&ort:SettingsDialogBaseEkran ad1: Sc&reen name:SettingsDialogBaseAyarlarSettingsSettingsDialogBase Uyar1WarningSettingsDialogBaseZLtfen e-posta adresinizi ve _ifrenizi girin.-Please enter your email address and password. SetupWizard4Ltfen seiminizi yap1n1z.Please select an option. SetupWizardSynergy Kurulum Setup Synergy SetupWizard,Sunucu veya Kullan1c1?Server or Client?SetupWizardBaseSynergy Kurulum Setup SynergySetupWizardBaseSynergy, ayn1 mouse ve klavye ile birden ok bilgisayar1 kontrol etmenizi salayan zgr ve A1k Kaynak Kodlu bir uygulamad1r. Yapman1z gereken mouse imlecinizi bilgisayar ekran1ndan dierine srklemek. Synergy ayn1 zamanda ortak bir panoya da izin vermektedir yani bilgisayarlar aras1 kopyala/yap1_t1r yapman1za da olanak tan1r. Tek gereken bilgisayarlar1n1z aras1nda kurulu_ olan network balant1s1. Synergy, oklu platform destei de vemektedir (Windows, Linux ve Mac OS X i_letimde sistemlerinde al1_1r). ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseVSinerji yklediiniz iin te_ekkr ederiz !Thanks for installing Synergy!SetupWizardBaseHo_ GeldinizWelcomeSetupWizardBaseBilinmeyenUnknownVersionCheckerVGiri_ ba_ar1s1z, bir hata meydana geldi. %1$Login failed, an error occurred. %1 WebClienttGiri_ ba_ar1s1z, bir hata meydana geldi. Sunucu yan1t1: %16Login failed, an error occurred. Server response: %1 WebClientVGiri_ ba_ar1s1z, e-posta yada _ifre yanl1_.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_tr-TR.ts000066400000000000000000001707141305627404700217730ustar00rootroot00000000000000 AboutDialogBase About Synergy Synergy hakkında <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Bilinmeyen Version: Sürüm: &Ok &Tamam ActionDialogBase Configure Action Eylemi yapılandır Choose the action to perform Gerçekleştirilecek eylemi seçin Press a hotkey Kısayol tuşuna basın Release a hotkey Kısayol tuşunu bırakın Press and release a hotkey Kısayol tuşuna basıp bırakın only on these screens Sadece bu ekranlarda Switch to screen Ekranı değiştir Switch in direction Yönü değiştir left sol right sağ up yukarı down aşağı Lock cursor to screen İmleci ekrana sabitle toggle Değiştir on açık off kapalı This action is performed when İşlem gerçekleştiğinde the hotkey is pressed Kısayol tuşu aktif the hotkey is released Kısayol tuşu serbest AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Kısayol Enter the specification for the hotkey: Kısayol tuşu için tanımlama gir MainWindow &Start &Başlat &File &Dosya &Edit &Düzenle &Window &Pencere &Help &Yardım <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Synergy versiyonunuz eski. Versiyon <b>%1</b> hazır. İndirmek için <a href="%2">tıklayın</a>.</p> Program can not be started Program başlatılamadı The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Çalıştırılabilir<br><br>%1<br><br>mevcut olmasına rağmen başarılı olarak başlatılamadı. Lütfen bu programı çalıştırabilmek için yeterli yetkiye sahip olup olmadığınızı kontrol edin. Synergy client not found Synergy alıcıyı bulamadı The executable for the synergy client does not exist. Synergy için çalışan kullanıcı makine yok. Hostname is empty Anabilgisayar boş Please fill in a hostname for the synergy client to connect to. Lütfen Synergy'nin bağlanması için bir bilgisayar adı girin Cannot write configuration file Ayar dosyası yazılamadı The temporary configuration file required to start synergy can not be written. Geçici ayar dosyası Synergy'nin başlaması için gerekli, üzerine kaydedilemez Configuration filename invalid Geçersiz ayar dosyası adı You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy sunucusu için geçerli bir ayar dosyası oluşturmadınız. Bu ayar dosyasına şimdi göz atmak ister misiniz? Synergy server not found Synergy sunucusu bulunamadı The executable for the synergy server does not exist. Synergy için çalışan sunucu makine yok. Synergy terminated with an error Synergy bir hata yüzünden sonlandırıldı. Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy %1 hata kod ile sonlandırıldı.<br><br>Detaylar için hata günlüğüne bakınız. &Stop &Dur Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy başlıyor Synergy is running. Synergy çalışıyor Synergy is not running. Synergy çalışmıyor Unknown Bilinmeyen Synergy Synergy Browse for a synergys config file Synergy ayar dosyasına göz at Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Ayarları kaydet Save failed Kaydetme hatası Could not save configuration to file. Ayarlar kaydedilemedi MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Ekran adı: &Server IP: &Sunucu IP: &Start &Başlat Use existing configuration: Varolan ayarları kullan &Configuration file: &Ayar dosyası: &Browse... &Araştır... Configure interactively: İnteraktif olarak yapılandır: &Configure Server... &Sunucu ayarla Ready Hazır Log Kayıt kütüğü &Apply Uygula IP addresses: IP adresleri: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Synergy hakkında &Quit &Çıkış Quit Çıkış Run Çalıştır S&top Dur Stop Dur S&how Status Durumu Göster &Hide &Gizle Hide Gizle &Show &Göster Show Göster Save configuration &as... Ayarları farklı kaydet Save the interactively generated server configuration to a file. İnteraktif olarak oluşturulmuş olan sununu yapılandırmasını dosyaya kaydet. Settings Ayarlar Edit settings Ayarları düzenle Run Wizard Sihirbazı Çalıştır NewScreenWidget Unnamed İsimsiz PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Synergy Kurulum Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. Bildirim alanı kullanılamıyor, kapatılıyor. ScreenSettingsDialog Screen name is empty Ekran ismi boş The screen name cannot be empty. Please either fill in a name or cancel the dialog. Ekran ismi boş bırakılamaz. Lütfen bir ad girin yada iptal edin. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Ekran ismiyle takma ad aynı olamaz. Lütfen takma adı silin yada ekran adını değiştirin. ScreenSettingsDialogBase Screen Settings Ekran Ayarları Screen &name: Görünen isim: A&liases Takma adlar &Add Ekle &Remove Kaldır &Modifier keys &Değiştirici tuşlar &Shift: &Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Süper None Yok &Ctrl: Ctrl Al&t: Al&t: M&eta: M&eta: S&uper: Süper: &Dead corners &Kör nokta Top-left Sol-üst Top-right Sağ-üst Bottom-left Sol-alt Bottom-right Sağ-alt Corner Si&ze: Köşe boyutu: &Fixes Düzeltmeler Fix CAPS LOCK key BÜYÜK YAZMAYI kapat Fix NUM LOCK key NUM LOCK kapat Fix SCROLL LOCK key SCROLL LOCK kapat Fix XTest for Xinerama XTest için Xinerama yı onar. ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Ekran: <b>%1</b></center><br>Çift tıklayarak ayarları düzenleyin <br>Çöp kutusundan silmek için ekranda sürükleyin ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Sunucu Yapılandırması Screens and links Ekranlar ve Bağlantıları Drag a screen from the grid to the trashcan to remove it. Izgaradan çıkartmak için çöp kutusuna sürükleyin ve silin. Configure the layout of your synergy server configuration. Lütfen sinerji sunucu yapılandırma düzeninizi yapılandırın. Drag this button to the grid to add a new screen. Yeni bir ekran eklemek için bu butonu ızgaraya sürükleyin. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Izgaraya yeni ekranları sürükleyin veya çevresinde mevcut olanları taşıyın. Silmek için çöp tenekesine ekranı sürükleyin. Kendi ayarlarınızı düzenlemek için bir ekran üzerine çift tıklayın. Hotkeys Kısayollar &Hotkeys Kısayollar &New &Yeni &Edit &Düzenle &Remove Kaldır A&ctions Eylemler Ne&w Yeni E&dit Düzen Re&move Kaldır Advanced server settings Gelişmiş sunucu ayarları &Switch &Değiştir Switch &after waiting ms ms Switch on double &tap within &Options &Seçenekler &Check clients every Her zaman kullanıcıları denetle Use &relative mouse moves &İlişkili mouse harekelerini kullanın S&ynchronize screen savers Ekran koruyucuları eşitle Don't take &foreground window on Windows servers Lütfen önplan penceresini Windows sunucularına almayın. Ignore auto config clients &Dead corners &Kör nokta To&p-left Üst-sol Top-rig&ht Üst-Sağ &Bottom-left Alt-sol Bottom-ri&ght Alt-Sağ Cor&ner Size: Köşe Boyutu: SettingsDialog Save log file to... Log dosyası kaydet... Elevate Synergy Synergyi Yükselt Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Ayarlar Sc&reen name: Ekran adı: P&ort: Port: &Interface: Arayüz: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Log kayıtları &Logging level: Kayıt Seviyesi : Log to file: Dosyaya kaydet : Browse... Araştır... Error Hata &Language: &Dil &Miscellaneous Warning Uyarı Note Not Info Bilgi Debug Hata Ayıkla Debug1 Hata Ayıkla1 Debug2 Hata Ayıkla2 SetupWizard Setup Synergy Synergy Kurulum Please select an option. Lütfen seçiminizi yapınız. Please enter your email address and password. Lütfen e-posta adresinizi ve şifrenizi girin. SetupWizardBase Setup Synergy Synergy Kurulum Welcome Hoş Geldiniz Thanks for installing Synergy! Sinerji yüklediğiniz için teşekkür ederiz ! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy, aynı mouse ve klavye ile birden çok bilgisayarı kontrol etmenizi sağlayan Özgür ve Açık Kaynak Kodlu bir uygulamadır. Yapmanız gereken mouse imlecinizi bilgisayar ekranından diğerine sürüklemek. Synergy aynı zamanda ortak bir panoya da izin vermektedir yani bilgisayarlar arası kopyala/yapıştır yapmanıza da olanak tanır. Tek gereken bilgisayarlarınız arasında kuruluş olan network bağlantısı. Synergy, çoklu platform desteği de vemektedir (Windows, Linux ve Mac OS X işletimde sistemlerinde çalışır). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Sunucu veya Kullanıcı? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Bilinmeyen WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Giriş başarısız, e-posta yada şifre yanlış. Login failed, an error occurred. %1 Giriş başarısız, bir hata meydana geldi. %1 Login failed, an error occurred. Server response: %1 Giriş başarısız, bir hata meydana geldi. Sunucu yanıtı: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_uk.qm000066400000000000000000000542451305627404700214310ustar00rootroot00000000000000^1+[H4*$SWYu'3+OF6<-oG:VE-VGIg ` +*"*2*%\*0*++gj+`G:mGz)JE*LbEU`X~Y.Z/xx..>6d}S=u>(Z = nbj!C4+/vJZQEv._#e;zw9x'(w;H}H/O "O I~O J*]F|&KVE '.uUN+Yu:Ful_ } "Z*> lz1EnE 7:(':28 B D$ZDIJ-2"QJE-izG=@d*Zl -攄J (I:S$( n4.d/O@Ty+L#B{3T4z>JD 3B=Tk@d1xycPh%@~ GC(}F;8n`C>^4L# I_ JzGt k#6@ v~9 < -5 Pn 5bun?+y~HM%1 r/U7,MkC:k2.5>*iROK&OkAboutDialogBase@> Synergy About SynergyAboutDialogBase52V4><>UnknownAboutDialogBase5@AVO:Version:AboutDialogBase8815@VBL 4VN, I> 28:>=CTBLAOChoose the action to performActionDialogBase 0;0HBC20==O 4V9Configure ActionActionDialogBase60:@V?8B8 :C@A>@ 70 5:@0=><Lock cursor to screenActionDialogBase00B8A=VBL 30@OGC :;02VHCPress a hotkeyActionDialogBaseL0B8A=VBL B0 2V4?CABVBL 30@OGC :;02VHCPress and release a hotkeyActionDialogBase2V4?CABVBL 30@OGC :;02VHCRelease a hotkeyActionDialogBase$5@5EV4 2 =0?@O<:CSwitch in directionActionDialogBase 5@5EV4 =0 5:@0=Switch to screenActionDialogBase.&O 4VO 28:>=CTBLAO :>;8This action is performed whenActionDialogBase2=87downActionDialogBase 2;V2>leftActionDialogBase 28<:.offActionDialogBase 22V<:.onActionDialogBase*BV;L:8 =0 F8E 5:@0=0Eonly on these screensActionDialogBase 2?@02>rightActionDialogBase030@OG0 :;02VH0 =0B8A=CB0the hotkey is pressedActionDialogBase030@OG0 :;02VH0 2V4?CI5=0the hotkey is releasedActionDialogBase?5@5:;NG8B8toggleActionDialogBase 225@EupActionDialogBaseJ:06VBL A?5F8DV:0FVN 30@OG>W :;02VHV:'Enter the specification for the hotkey:HotkeyDialogBase0@OG0 :;02VH0HotkeyHotkeyDialogBase 5403C20==O&Edit MainWindow$09;&File MainWindow>?><>30&Help MainWindow !B0@B&Start MainWindow!B>?&Stop MainWindow V:=>&Window MainWindow<p>0H0 25@AVO Synergy 70AB0@V;0. 0@07 4>ABC?=0 25@AVO <b>%1</b> 4;O <a href="%2">7020=B065==O</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowB:06VBL D09; :>=DV3C@0FVW Synergy!Browse for a synergys config file MainWindowZ5<>6;82> 74V9A=8B8 70?8A C D09; :>=DV3C@0FVWCannot write configuration file MainWindowF5?@028;L=5 V<'O D09;C :>=DV3C@0FVWConfiguration filename invalid MainWindowJ5<>6;82> 715@53B8 D09; :>=DV3C@0FVW.%Could not save configuration to file. MainWindow*<'O E>ABC =5 2:070=5Hostname is empty MainWindowC4L ;0A:0 2:06VBL V<'O E>ABC 4> O:>3> ?>28=5= ?@8T4=0B8AO :;VT=B Synergy.?Please fill in a hostname for the synergy client to connect to. MainWindow<@>3@0<0 =5 <>65 1CB8 70?CI5=0Program can not be started MainWindow615@53B8 :>=DV3C@0FVN O:...Save configuration as... MainWindow$>A8;:0 715@565==O Save failed MainWindowSynergySynergy MainWindowF5 7=0945=> 6>4=>3> :;VT=B0 SynergySynergy client not found MainWindow"Synergy 7C?8=5=>.Synergy is not running. MainWindowSynergy ?@0FNT.Synergy is running. MainWindow"Synergy 70?CI5=>.Synergy is starting. MainWindow>5<>6;82> 7=09B8 A5@25@ SynergySynergy server not found MainWindowSynergy 7025@H8;0AL =5>GV:C20=> 7 :>4>< of %1.<br><br>C4L ;0A:0 ?5@53;O=LB5 log-70?8A8 4;O 45B0;59.fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow:Synergy 7025@H5=0 7 ?><8;:0<8 Synergy terminated with an error MainWindowd8:>=C20=>W ?@>3@0<8 4;O :;VT=B0 Synergy =5 VA=CT.5The executable for the synergy client does not exist. MainWindowd8:>=C20=>W ?@>3@0<8 4;O A5@25@C Synergy =5 VA=CT.5The executable for the synergy server does not exist. MainWindow8:>=C20=89 D0; <br><br>%1<br><br>=5 <>65 70?CAB8B8AL, E>G0 2V= VA=CT. C4L ;0A:0, ?5@52V@B5 G8 C 0A 4>AB0B=L> ?@02 4;O 70?CA:C FVTW ?@>3@0<8.The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindow"8<G0A>289 D09; :>=DV3C@0FVW, O:89 =5>1EV4=89 4;O 70?CA:C Synergy 701;>:>20=89 4;O 70?8AC.NThe temporary configuration file required to start synergy can not be written. MainWindow52V4><>Unknown MainWindow8 =5 70?>2=8;8 ?@028;L=89 D09; :>=DV3C@0FVW 4;O A5@25@0 Synergy . 060TB5 7@>18B8 F5 70@07?You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindow@> Synergy&About Synergy...MainWindowBase0AB>AC20B8&ApplyMainWindowBase5@53;O4... &Browse...MainWindowBase$$09; :>=DV3C@0FVW:&Configuration file:MainWindowBase*0;0HBC20B8 A5@25@...&Configure Server...MainWindowBase@8E>20B8&HideMainWindowBase0:@8B8&QuitMainWindowBaseIP A5@25@C: &Server IP:MainWindowBase>:070B8&ShowMainWindowBase !B0@B&StartMainWindowBase20;0HBC20B8 V=B5@0:B82=>:Configure interactively:MainWindowBase. 5403C20B8 =0;0HBC20==O Edit settingsMainWindowBase@8E>20B8HideMainWindowBaseIP 04@5A8: IP addresses:MainWindowBase>3LogMainWindowBase0:@8B8QuitMainWindowBase >B>2>ReadyMainWindowBase0?CAB8B8RunMainWindowBase&0?CAB8B8 ><VG=8:0 Run WizardMainWindowBase>:070B8 AB0BCA S&how StatusMainWindowBaseC?8=8B8S&topMainWindowBase615@53B8 :>=DV3C@0FVN O:...Save configuration &as...MainWindowBase|15@53B8 V=B5@0:B82=> 735=5@>20=C :>=DV3C@0FVN A5@25@0 C D09;.@Save the interactively generated server configuration to a file.MainWindowBase<'O 5:@0=C: Screen name:MainWindowBase0;0HBC20==OSettingsMainWindowBase>:070B8ShowMainWindowBaseC?8=8B8StopMainWindowBaseSynergySynergyMainWindowBaseB8:>@8AB0B8 VA=CNGC :>=DV3C@0FVN:Use existing configuration:MainWindowBase57 =0728UnnamedNewScreenWidget(AB0=>2;5==O Synergy Setup SynergyPluginWizardPage\>=DV3C@0FVO Synergy (*.conf);;AV D09;8 (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObjectZ>=DV3C@0FVO Synergy (*.sgc);;AV D09;8 (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObject^!8AB5<=89 B@59 =54>ABC?=89, 74V9A=NTBLAO 28EV4.%System tray is unavailable, quitting.QObject&<'O 5:@0=C ?>@>6=TScreen name is emptyScreenSettingsDialogF<'O 5:@0=C A?V2?040T 7 ?A524>=V<><Screen name matches aliasScreenSettingsDialog<'O 5:@0=C =5 <>65 1CB8 ?>@>6=V<. C4L ;0A:0 2:06VBL V<'O 01> A:0AC9B5 4V0;>3.SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialog<'O 5:@0=C =5 <>65 1CB8 B0:8< A0<8< O: ?A524>=V<. C4L ;0A:0 2840;VBL ?A524>=V< 01> 7<V=VBL V<'O 5:@0=CiThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialog >40B8&AddScreenSettingsDialogBase Ctrl:&Ctrl:ScreenSettingsDialogBase5@B2V :CB8 &Dead cornersScreenSettingsDialogBase$V:A0FVO&FixesScreenSettingsDialogBase(;02VHV-<>48DV:0B>@8&Modifier keysScreenSettingsDialogBase840;8B8&RemoveScreenSettingsDialogBase Shift:&Shift:ScreenSettingsDialogBaseA524>=V<8A&liasesScreenSettingsDialogBaseAlt:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase86=V9 ;V289 Bottom-leftScreenSettingsDialogBase86=V9 ?@0289 Bottom-rightScreenSettingsDialogBase >7<V@ :CB0: Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBase&$V:AC20B8 CAPS LOCKFix CAPS LOCK keyScreenSettingsDialogBase$$V:AC20B8 NUM LOCKFix NUM LOCK keyScreenSettingsDialogBase*$V:AC20B8 SCROLL LOCKFix SCROLL LOCK keyScreenSettingsDialogBase8$V:AC20B8 XTest 4;O XineramaFix XTest for XineramaScreenSettingsDialogBase Meta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBase >4=0NoneScreenSettingsDialogBase Super:S&uper:ScreenSettingsDialogBase<'O 5:@0=C: Screen &name:ScreenSettingsDialogBase&0;0HBC20==O 5:@0=CScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBase5@E=V9 ;V289Top-leftScreenSettingsDialogBase5@E=V9 ?@0289 Top-rightScreenSettingsDialogBase<center>:@0=: <b>%1</b></center><br>>42V9=89 :;V: 4;O @5403C20==O =0;0HBC20=L<br>5@5BO3=VBL 5:@0= C :>H8: 4;O 2840;5==Oo
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel86=V9 ;V289 &Bottom-leftServerConfigDialogBase25@52V@OB8 :;VT=BV2 :>6=V&Check clients everyServerConfigDialogBase5@B2V :CB8 &Dead cornersServerConfigDialogBase 5403C20==O&EditServerConfigDialogBase0@OGV :;02VHV&HotkeysServerConfigDialogBase >289&NewServerConfigDialogBase ?FVW&OptionsServerConfigDialogBase840;8B8&RemoveServerConfigDialogBase5@5EV4&SwitchServerConfigDialogBaseVWA&ctionsServerConfigDialogBase<>40B:>2V =0;0HBC20==O A5@25@0Advanced server settingsServerConfigDialogBase86=V9 ?@0289 Bottom-ri&ghtServerConfigDialogBasen0;0HBC20B8 @>7B0HC20==O :>=DV3C@0FVW A5@25@0 Synergy .:Configure the layout of your synergy server configuration.ServerConfigDialogBase >7<V@ :CB0: Cor&ner Size:ServerConfigDialogBaseX5 70;8H0B8 2V:=> A5@25@0 725@EC (C Windows)0Don't take &foreground window on Windows serversServerConfigDialogBaseN5@5BO3=VBL 5:@0= C :>H8: 4;O 2840;5==O9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBase>5@5BO3C9B5 =>2V 5:@0=8 =0 AVB:C 01> ?5@5AC209B5 VA=CNGV <VAFO<8. 5@5BO3=VBL 5:@0= 2 :>H8:, I>1 2840;8B8 9>3>. >42V9=89 :;V: =0 5:@0=V 4;O 9>3> =0;0HBC20==O.Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasen5@5BO3=VBL FN :=>?:C =0 AVB:C, I>1 4>40B8 =>289 5:@0=.1Drag this button to the grid to add a new screen.ServerConfigDialogBase 5403C20B8E&ditServerConfigDialogBase0@OGV :;02VHVHotkeysServerConfigDialogBase >289Ne&wServerConfigDialogBase840;8B8Re&moveServerConfigDialogBase.!8=E@>=V7C20B8 70AB02:8S&ynchronize screen saversServerConfigDialogBase :@0=8 V 72'O7:8Screens and linksServerConfigDialogBase(>=DV3C@0FVO A5@25@0Server ConfigurationServerConfigDialogBase05@5EV4 ?VA;O >GV:C20==OSwitch &after waitingServerConfigDialogBaseX5@5EV4 ?VA;O ?>42V9=>3> =0B8A:0==O ?@>BO3><Switch on double &tap withinServerConfigDialogBase5@E=V9 ;V289 To&p-leftServerConfigDialogBase5@E=V9 ?@0289 Top-rig&htServerConfigDialogBaseT8:>@8AB>2C20B8 @V4=V =0;0HBC20==O :C@A>@CUse &relative mouse movesServerConfigDialogBase<A5:msServerConfigDialogBaseV9A=> 1060TB5 ?V428I8BL @V25=L 4>ABC?C Synergy? &O 4VO 4>72>;8BL Synergy 1CB8 C 270T<>4VW 7 ?@>F5A0<8, O:V <0NBL ?V428I5=V9 @V25=L 4>ABC?C, B0 4V0;>3C UAC (:>=B@>;L >1;V:>28E 70?8AV2 :>@8ABC20GV2). ;5 F5 <>65 28:;8:0B8 ?@>1;5<8 7 ?@>F5A0<8, O:V <0NBL 728G09=89 @V25=L 4>ABC?C. V428IC9B5 @V25=L 4>ABC?C Synergy BV;L:8 2 B><C 28?04:C, :>;8 F5 4V9A=> ?>B@V1=>.Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialog@V428IVBL @V25=L 4>ABC?C SynergyElevate SynergySettingsDialog,15@53B8 log-D09; 2...Save log file to...SettingsDialog=B5@D59A: &Interface:SettingsDialogBase >20: &Language:SettingsDialogBase V25=L 70?8AC:&Logging level:SettingsDialogBase&>40B:>2>&MiscellaneousSettingsDialogBase5@53;O4... Browse...SettingsDialogBase0;03>465==ODebugSettingsDialogBase0;03>465==O1Debug1SettingsDialogBase0;03>465==O2Debug2SettingsDialogBase><8;:0ErrorSettingsDialogBase=D>@<0FVOInfoSettingsDialogBase"0?8AC20B8 C D0;: Log to file:SettingsDialogBase 0?8ALoggingSettingsDialogBase@8<VB:0NoteSettingsDialogBase >@B:P&ort:SettingsDialogBase<'O 5:@0=C: Sc&reen name:SettingsDialogBase0;0HBC20==OSettingsSettingsDialogBase>?5@5465==OWarningSettingsDialogBasexC4L ;0A:0 2:06VBL 04@5AC 20H>W 5;5:B@>==>W ?>HB8 B0 ?0@>;L.-Please enter your email address and password. SetupWizard4C4L ;0A:0, >15@VBL >?FVN.Please select an option. SetupWizard(AB0=>2;5==O Synergy Setup Synergy SetupWizard"!5@25@ G8 :;VT=B?Server or Client?SetupWizardBase(AB0=>2;5==O Synergy Setup SynergySetupWizardBaseSynergy 4>72>;8BL 0< ;53:> 28:>@8AB>2C20B8 <8H:C B0 :;02V0BC@C <V6 45:V;L:><0 :><?'NB5@0<8 70 20H8< AB>;><, V F5 7>2AV< 157:>HB>2=89 B0 2V4:@8B89 ?@>4C:B. "V;L:8 ?V4254VBL :C@A>@ <8H:8 4> :@0N >4=>3> 7 :><?'NB5@V2 V 2V= 02B><0B8G=> ?5@5<VAB8BLAO =0 V=H89. "0:>6 <>6=0 28:>@8AB>2C20B8 >48= 1CD5@ >1<V=C <V6 45:V;L:><0 :><?'NB5@0<8. A5 I> =5>1EV4=>, F5 <5@56525 7'T4=0==O. Synergy O2;OTBLAO <V6?;0BD>@<>28< ?@>4C:B>< (?@0FNT 7 Windows, Mac OS X B0 Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBase@O:CT<> 70 2AB0=>2;5==O Synergy!Thanks for installing Synergy!SetupWizardBaseVB05<>WelcomeSetupWizardBase52V4><>UnknownVersionCheckerFEV4 A:0A>20=>, 28=8:;0 ?><8;:0. %1$Login failed, an error occurred. %1 WebClientlEV4 A:0A>20=>, 28=8:;0 ?><8;:0. V4?>2V4L A5@25@0: %16Login failed, an error occurred. Server response: %1 WebClient\EV4 A:0A>20=>, =5?@028;L=0 04@5A0 01> ?0@>;L.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfService ) , synergy-1.8.8-stable/src/gui/res/lang/gui_uk.ts000066400000000000000000002006431305627404700214350ustar00rootroot00000000000000 AboutDialogBase About Synergy Про Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Невідомо Version: Версія: &Ok OK ActionDialogBase Configure Action Налаштування дій Choose the action to perform Виберіть дію, що виконується Press a hotkey Натисніть гарячу клавішу Release a hotkey Відпустіть гарячу клавішу Press and release a hotkey Натисніть та відпустіть гарячу клавішу only on these screens тільки на цих екранах Switch to screen Перехід на екран Switch in direction Перехід в напрямку left вліво right вправо up вверх down вниз Lock cursor to screen Закріпити курсор за екраном toggle переключити on ввімк. off вимк. This action is performed when Ця дія виконується коли the hotkey is pressed гаряча клавіша натиснута the hotkey is released гаряча клавіша відпущена AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Гаряча клавіша Enter the specification for the hotkey: Вкажіть специфікацію гарячої клавіші: MainWindow &Start Старт &File Файл &Edit Редагування &Window Вікно &Help Допомога <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Ваша версія Synergy застаріла. Зараз доступна версія <b>%1</b> для <a href="%2">завантаження</a>.</p> Program can not be started Програма не може бути запущена The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Виконуваний фал <br><br>%1<br><br>не може запуститись, хоча він існує. Будь ласка, перевірте чи у Вас достатньо прав для запуску цієї програми. Synergy client not found Не знайдено жодного клієнта Synergy The executable for the synergy client does not exist. Виконуваної програми для клієнта Synergy не існує. Hostname is empty Ім'я хосту не вказане Please fill in a hostname for the synergy client to connect to. Будь ласка вкажіть ім'я хосту до якого повинен приєднатися клієнт Synergy. Cannot write configuration file Неможливо здійснити запис у файл конфігурації The temporary configuration file required to start synergy can not be written. Тимчасовий файл конфігурації, який необхідний для запуску Synergy заблокований для запису. Configuration filename invalid Неправильне ім'я файлу конфігурації You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Ви не заповнили правильний файл конфігурації для сервера Synergy . Бажаєте зробити це зараз? Synergy server not found Неможливо знайти сервер Synergy The executable for the synergy server does not exist. Виконуваної програми для серверу Synergy не існує. Synergy terminated with an error Synergy завершена з помилками Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy завершилась неочікувано з кодом of %1.<br><br>Будь ласка перегляньте log-записи для деталей. &Stop Стоп Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy запущено. Synergy is running. Synergy працює. Synergy is not running. Synergy зупинено. Unknown Невідомо Synergy Synergy Browse for a synergys config file Вкажіть файл конфігурації Synergy Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Зберегти конфігурацію як... Save failed Посилка збереження Could not save configuration to file. Неможливо зберегти файл конфігурації. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: Ім'я екрану: &Server IP: IP серверу: &Start Старт Use existing configuration: Використати існуючу конфігурацію: &Configuration file: Файл конфігурації: &Browse... Перегляд... Configure interactively: Налаштувати інтерактивно: &Configure Server... Налаштувати сервер... Ready Готово Log Лог &Apply Застосувати IP addresses: IP адреси: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... Про Synergy &Quit Закрити Quit Закрити Run Запустити S&top Зупинити Stop Зупинити S&how Status Показати статус &Hide Приховати Hide Приховати &Show Показати Show Показати Save configuration &as... Зберегти конфігурацію як... Save the interactively generated server configuration to a file. Зберегти інтерактивно згенеровану конфігурацію сервера у файл. Settings Налаштування Edit settings Редагувати налаштування Run Wizard Запустити Помічника NewScreenWidget Unnamed Без назви PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Встановлення Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Конфігурація Synergy (*.sgc);;Всі файли (*.*) Synergy Configurations (*.conf);;All files (*.*) Конфігурація Synergy (*.conf);;Всі файли (*.*) System tray is unavailable, quitting. Системний трей недоступний, здійснюється вихід. ScreenSettingsDialog Screen name is empty Ім'я екрану порожнє The screen name cannot be empty. Please either fill in a name or cancel the dialog. Ім'я екрану не може бути порожнім. Будь ласка вкажіть ім'я або скасуйте діалог. Screen name matches alias Ім'я екрану співпадає з псевдонімом The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Ім'я екрану не може бути таким самим як псевдонім. Будь ласка видаліть псевдонім або змініть ім'я екрану ScreenSettingsDialogBase Screen Settings Налаштування екрану Screen &name: Ім'я екрану: A&liases Псевдоніми &Add Додати &Remove Видалити &Modifier keys Клавіші-модифікатори &Shift: Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None Жодна &Ctrl: Ctrl: Al&t: Alt: M&eta: Meta: S&uper: Super: &Dead corners Мертві кути Top-left Верхній лівий Top-right Верхній правий Bottom-left Нижній лівий Bottom-right Нижній правий Corner Si&ze: Розмір кута: &Fixes Фіксація Fix CAPS LOCK key Фіксувати CAPS LOCK Fix NUM LOCK key Фіксувати NUM LOCK Fix SCROLL LOCK key Фіксувати SCROLL LOCK Fix XTest for Xinerama Фіксувати XTest для Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>Екран: <b>%1</b></center><br>Подвійний клік для редагування налаштувань<br>Перетягніть екран у кошик для видалення ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Конфігурація сервера Screens and links Екрани і зв'язки Drag a screen from the grid to the trashcan to remove it. Перетягніть екран у кошик для видалення Configure the layout of your synergy server configuration. Налаштувати розташування конфігурації сервера Synergy . Drag this button to the grid to add a new screen. Перетягніть цю кнопку на сітку, щоб додати новий екран. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Перетягуйте нові екрани на сітку або пересувайте існуючі місцями. Перетягніть екран в кошик, щоб видалити його. Подвійний клік на екрані для його налаштування. Hotkeys Гарячі клавіші &Hotkeys Гарячі клавіші &New Новий &Edit Редагування &Remove Видалити A&ctions Дії Ne&w Новий E&dit Редагувати Re&move Видалити Advanced server settings Додаткові налаштування сервера &Switch Перехід Switch &after waiting Перехід після очікування ms мсек Switch on double &tap within Перехід після подвійного натискання протягом &Options Опції &Check clients every Перевіряти клієнтів кожні Use &relative mouse moves Використовувати рідні налаштування курсору S&ynchronize screen savers Синхронізувати заставки Don't take &foreground window on Windows servers Не залишати вікно сервера зверху (у Windows) Ignore auto config clients &Dead corners Мертві кути To&p-left Верхній лівий Top-rig&ht Верхній правий &Bottom-left Нижній лівий Bottom-ri&ght Нижній правий Cor&ner Size: Розмір кута: SettingsDialog Save log file to... Зберегти log-файл в... Elevate Synergy Підвищіть рівень доступу Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. Дійсно бажаєте підвищить рівень доступу Synergy? Ця дія дозволить Synergy бути у взаємодії з процесами, які мають підвищеній рівень доступу, та діалогу UAC (контроль облікових записів користувачів). Але це може викликати проблеми з процесами, які мають звичайний рівень доступу. Підвищуйте рівень доступу Synergy тільки в тому випадку, коли це дійсно потрібно. SettingsDialogBase Settings Налаштування Sc&reen name: Ім'я екрану: P&ort: Порт: &Interface: Інтерфейс: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging Запис &Logging level: Рівень запису: Log to file: Записувати у фал: Browse... Перегляд... Error Помилка &Language: Мова: &Miscellaneous &Додатково Warning Попередження Note Примітка Info Інформація Debug Налагодження Debug1 Налагодження1 Debug2 Налагодження2 SetupWizard Setup Synergy Встановлення Synergy Please select an option. Будь ласка, оберіть опцію. Please enter your email address and password. Будь ласка вкажіть адресу вашої електронної пошти та пароль. SetupWizardBase Setup Synergy Встановлення Synergy Welcome Вітаемо Thanks for installing Synergy! Дякуємо за встановлення Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy дозволить Вам легко використовувати мишку та клавіатуру між декількома комп'ютерами за вашим столом, і це зовсім безкоштовний та відкритий продукт. Тільки підведіть курсор мишки до краю одного з комп'ютерів і він автоматично переміститься на інший. Також можна використовувати один буфер обміну між декількома комп'ютерами. Все що необхідно, це мережеве з'єднання. Synergy являється міжплатформовим продуктом (працює з Windows, Mac OS X та Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? Сервер чи клієнт? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Невідомо WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Вхід скасовано, неправильна адреса або пароль. Login failed, an error occurred. %1 Вхід скасовано, виникла помилка. %1 Login failed, an error occurred. Server response: %1 Вхід скасовано, виникла помилка. Відповідь сервера: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_ur.qm000066400000000000000000000024441305627404700214320ustar00rootroot00000000000000 AboutDialogBase About Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Version: &Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left right up down Lock cursor to screen toggle on off This action is performed when the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> Program can not be started The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found The executable for the synergy server does not exist. Synergy terminated with an error Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy is running. Synergy is not running. Unknown Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Run S&top Stop S&how Status &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Edit settings Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add &Remove &Modifier keys &Shift: Shift Ctrl Alt Meta Super None &Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: &Miscellaneous Warning Note Info معلومات Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy آپ کو آسانی سے اپنا ما٘وس اور کیبورڈ متعدد کمپیوٹرز کے ساتھ استعمال کرنے کی سہولت میسر کرتا ہے۔Synergy مفت اور اوپن سورس ہے۔ صرف ایک کمپیوٹر اسکرین کے کنارے سے دوسرے پر اپنے ماؤس لے جائیں اور بس۔ آپ تمام کمپیوٹرز کے کلپ بورڈ ایک دوسرے کے ساتھ تبدیل بھی کر سکتے ہیں۔ یہ سب کرنے کے لیے صرف ایک نیٹ ورک کنکشن کی ضرورت ہے۔ Synergy متعدد آپریٹنگ سسٹمز (ونڈوز، میک OS X اور لینکس) کے ساتھ استعمال کیا جا سکتا ہے Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_vi.qm000066400000000000000000000117551305627404700214270ustar00rootroot00000000000000 f VE }++`U`XY x<}SH4 v ZV w(J P 3_@~ ȹ ȹ  ȹ F F  Z @{U RV RV RV R  s s r+y~  r>iSOk&OkAboutDialogBase(Thng tin v Synergy About SynergyAboutDialogBaseKhng bitUnknownAboutDialogBasePhin bn:Version:AboutDialogBase8Lnh ny c thc hin khi This action is performed whenActionDialogBase xungdownActionDialogBasetrileftActionDialogBasettoffActionDialogBasebtonActionDialogBasephirightActionDialogBaselnupActionDialogBaseBt u&Start MainWindowDng&Stop MainWindow<p>Phin bn Synergy ca bn  ci. Phin bn mi <b>%1</b>  c  <a href="%2">ti v</a>.</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowBChng trnh khng th khi ng.Program can not be started MainWindowSynergySynergy MainWindow&Synergy khng chy.Synergy is not running. MainWindow$Synergy ang chy.Synergy is running. MainWindow.Synergy ang khi ng.Synergy is starting. MainWindow<Khng tm thy my ch SynergySynergy server not found MainWindow0Synergy  ngng v li  Synergy terminated with an error MainWindowKhng bitUnknown MainWindowBt u&StartMainWindowBase"Chnh sa ci t Edit settingsMainWindowBase ThotQuitMainWindowBaseSn sngReadyMainWindowBaseChyRunMainWindowBase&Hin th tnh trng S&how StatusMainWindowBaseDngS&topMainWindowBaseCi tSettingsMainWindowBaseSynergySynergyMainWindowBaseThm&AddScreenSettingsDialogBase Ctrl:&Ctrl:ScreenSettingsDialogBaseXa&RemoveScreenSettingsDialogBaseShift: &Shift:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase Ctrl CtrlScreenSettingsDialogBase KhngNoneScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBaseXa&RemoveServerConfigDialogBaseNgn ng: &Language:SettingsDialogBaseThng tinInfoSettingsDialogBaseCi tSettingsSettingsDialogBaseJHy nhp ti khon email v mt khu.-Please enter your email address and password. SetupWizardSc mnh tng hp cho php bn d dng chia s chut v bn phm gia nhiu my tnh trn bn ca bn, v n l min ph v m ngun m. Ch cn di chuyn chut ca bn khi cc cnh ca mn hnh mt my tnh khc. Bn thm ch c th chia s tt c cc clipboards ca bn. Tt c bn cn l mt kt ni mng. Synergy l nn tng cho (hot ng trn Windows, Mac OS X v Linux).ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBaseKhng bitUnknownVersionChecker~ng nhp tht bi, ti khon email hoc mt khu khng hp l.(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_vi.ts000066400000000000000000001625431305627404700214420ustar00rootroot00000000000000 AboutDialogBase About Synergy Thông tin về Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown Không biết Version: Phiên bản: &Ok Ok ActionDialogBase Configure Action Choose the action to perform Press a hotkey Release a hotkey Press and release a hotkey only on these screens Switch to screen Switch in direction left trái right phải up lên down xuống Lock cursor to screen toggle on bật off tắt This action is performed when Lệnh này được thực hiện khi the hotkey is pressed the hotkey is released AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey Enter the specification for the hotkey: MainWindow &Start Bắt đầu &File &Edit &Window &Help <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>Phiên bản Synergy của bạn đã cũ. Phiên bản mới <b>%1</b> đã có để <a href="%2">tải về</a>.</p> Program can not be started Chương trình không thể khởi động. The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. Synergy client not found The executable for the synergy client does not exist. Hostname is empty Please fill in a hostname for the synergy client to connect to. Cannot write configuration file The temporary configuration file required to start synergy can not be written. Configuration filename invalid You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? Synergy server not found Không tìm thấy máy chủ Synergy The executable for the synergy server does not exist. Synergy terminated with an error Synergy đã ngừng vì lỗi Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. &Stop Dừng Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy đang khởi động. Synergy is running. Synergy đang chạy. Synergy is not running. Synergy không chạy. Unknown Không biết Synergy Synergy Browse for a synergys config file Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... Save failed Could not save configuration to file. MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: &Server IP: &Start Bắt đầu Use existing configuration: &Configuration file: &Browse... Configure interactively: &Configure Server... Ready Sẵn sàng Log &Apply IP addresses: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... &Quit Quit Thoát Run Chạy S&top Dừng Stop S&how Status Hiển thị tình trạng &Hide Hide &Show Show Save configuration &as... Save the interactively generated server configuration to a file. Settings Cài đặt Edit settings Chỉnh sửa cài đặt Run Wizard NewScreenWidget Unnamed PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy Configurations (*.conf);;All files (*.*) System tray is unavailable, quitting. ScreenSettingsDialog Screen name is empty The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name matches alias The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. ScreenSettingsDialogBase Screen Settings Screen &name: A&liases &Add Thêm &Remove Xóa &Modifier keys &Shift: Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Super None Không &Ctrl: Ctrl: Al&t: M&eta: S&uper: &Dead corners Top-left Top-right Bottom-left Bottom-right Corner Si&ze: &Fixes Fix CAPS LOCK key Fix NUM LOCK key Fix SCROLL LOCK key Fix XTest for Xinerama ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration Screens and links Drag a screen from the grid to the trashcan to remove it. Configure the layout of your synergy server configuration. Drag this button to the grid to add a new screen. Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. Hotkeys &Hotkeys &New &Edit &Remove Xóa A&ctions Ne&w E&dit Re&move Advanced server settings &Switch Switch &after waiting ms Switch on double &tap within &Options &Check clients every Use &relative mouse moves S&ynchronize screen savers Don't take &foreground window on Windows servers Ignore auto config clients &Dead corners To&p-left Top-rig&ht &Bottom-left Bottom-ri&ght Cor&ner Size: SettingsDialog Save log file to... Elevate Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. SettingsDialogBase Settings Cài đặt Sc&reen name: P&ort: &Interface: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging &Logging level: Log to file: Browse... Error &Language: Ngôn ngữ: &Miscellaneous Warning Note Info Thông tin Debug Debug1 Debug2 SetupWizard Setup Synergy Please select an option. Please enter your email address and password. Hãy nhập tài khoản email và mật khẩu. SetupWizardBase Setup Synergy Welcome Thanks for installing Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Sức mạnh tổng hợp cho phép bạn dễ dàng chia sẻ chuột và bàn phím giữa nhiều máy tính trên bàn của bạn, và nó là miễn phí và mã nguồn mở. Chỉ cần di chuyển chuột của bạn khỏi các cạnh của màn hình một máy tính khác. Bạn thậm chí có thể chia sẻ tất cả các clipboards của bạn. Tất cả bạn cần là một kết nối mạng. Synergy là nền tảng chéo (hoạt động trên Windows, Mac OS X và Linux). Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown Không biết WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. Đăng nhập thất bại, tài khoản email hoặc mật khẩu không hợp lệ. Login failed, an error occurred. %1 Login failed, an error occurred. Server response: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_zh-CN.qm000066400000000000000000000375051305627404700217310ustar00rootroot00000000000000'}S3u>(Z "= /nbjW4 "v4Z8Ev._+e*w93NB ;H}H"JO O 3O 4F]1|VE3!YUNYu:1l_} *,eln#00 (1::$ /$Z/J ."QJK-iz2-@dl 攄Jc(3:S( n]4.d"@TyL#.{$ tzo>J0` 3=T k@d#yc7%@~Cj}F*vn C,% I_p Jz2` k#'( v~)] + -5 Pn+C d ~5* ~q8D ք~ ȹ ȹ ȹ9" a/8 |! F F%) Z %_ KG @{ w RVn RVF RV7 R + T V4h  |*/| c% s s2 c+ F Ҫ ^ /% 4p,+ d i! \ r+ zk1 P2 ¦e7 x4& ]^ Y^3j1\71=> &bun-'y~3 r 2/C7okC* k$.&[> Ki9[xn[&OkAboutDialogBaseQsNSynergy About SynergyAboutDialogBaseg*wUnknownAboutDialogBaserHg,Version:AboutDialogBase b鉁bgLvLN:Choose the action to performActionDialogBaseLN:MnConfigure ActionActionDialogBase[cN\O^ULock cursor to screenActionDialogBasec N p.Press a hotkeyActionDialogBasec N NN*.q6Tg~_Press and release a hotkeyActionDialogBaseg~_p.Release a hotkeyActionDialogBaseeTRcbSwitch in directionActionDialogBase RcbR0\O^USwitch to screenActionDialogBase_S & &eT/u(kdLN:This action is performed whenActionDialogBaseN edownActionDialogBase]leftActionDialogBaseyu(offActionDialogBaseT/u(onActionDialogBaseNNW(N\O^UN only on these screensActionDialogBaseSOrightActionDialogBase p.c N the hotkey is pressedActionDialogBase p.g~_the hotkey is releasedActionDialogBaseRcbtoggleActionDialogBaseN eupActionDialogBaseQep.vf'Enter the specification for the hotkey:HotkeyDialogBasep.HotkeyHotkeyDialogBase&Edit MainWindoweN&File MainWindow^.R&Help MainWindow_Y&Start MainWindowP\kb&Stop MainWindowzS&Window MainWindow<p>`kcW(Ou(vSynergyrHg,g NeN g erH <b>%1</b> SN <a href="%2">N }</a>0</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowmOSynergyMneN!Browse for a synergys config file MainWindowN QQeMneNCannot write configuration file MainWindowMneNT ^lConfiguration filename invalid MainWindowN O[XMnR0eN%Could not save configuration to file. MainWindow N;g:T N:zzHostname is empty MainWindow0N:Synergy[b7znNN*u(NcvN;g:T ?Please fill in a hostname for the synergy client to connect to. MainWindow z ^elT/RProgram can not be started MainWindowO[XMnR0eNSave configuration as... MainWindowO[XY1% Save failed MainWindowSynergySynergy MainWindowg*b~R0Synergy[b7zSynergy client not found MainWindowSynergylg ЈLSynergy is not running. MainWindowSynergykcW(ЈLSynergy is running. MainWindowSynergykcW(T/RSynergy is starting. MainWindowg*b~R0Synergyg RzSynergy server not found MainWindowTSynergyaY~kbЈL QNx %10<br><br>gw Qe_N`0fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindowSynergyV~kbЈL Synergy terminated with an error MainWindow(Synergy[b7zvSbgLz ^N [XW(05The executable for the synergy client does not exist. MainWindow&Synergyg RzSbgLz ^N [XW(05The executable for the synergy server does not exist. MainWindownSbgLz ^<br><br>%1<br><br>lg bRЈL }q6z ^g,[XW(0hgO`f/T&g ЈLkdz ^vgCP0The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindow,T/RSynergyb@vN4eMneNN SQ0NThe temporary configuration file required to start synergy can not be written. MainWindowg*wUnknown MainWindowLO`lg N:Synergyg RznNN*Su(vMneN0sW(mOȑMneNTYou have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindowQsNSynergy &&About Synergy...MainWindowBase^u(&ApplyMainWindowBasemO & &Browse...MainWindowBase MneN&Configuration file:MainWindowBase ng Rz &&Configure Server...MainWindowBase&HideMainWindowBaseQ&QuitMainWindowBase g RzIP &Server IP:MainWindowBasef>y:&ShowMainWindowBase_Y&StartMainWindowBase NNMnConfigure interactively:MainWindowBasen Edit settingsMainWindowBaseHideMainWindowBaseIPW0W@ IP addresses:MainWindowBasee_LogMainWindowBaseQQuitMainWindowBaseQY[kReadyMainWindowBaseЈLRunMainWindowBaseЈLT[ Run WizardMainWindowBasef>y:r` S&how StatusMainWindowBaseP\kbS&topMainWindowBase O[XMnR0 &Save configuration &as...MainWindowBase"O[XNNMnubvMnR0eN0@Save the interactively generated server configuration to a file.MainWindowBase\O^UT  Screen name:MainWindowBasenSettingsMainWindowBasef>y:ShowMainWindowBaseP\kbStopMainWindowBaseSynergySynergyMainWindowBaseOu(]g vMnUse existing configuration:MainWindowBaseg*T}T UnnamedNewScreenWidgetnSynergy Setup SynergyPluginWizardPage>SynergyMneN(*.conf);;b@g eN (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObject<SynergyMneN(*.sgc);;b@g eN (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObject|~bXvN Su( z ^Q0%System tray is unavailable, quitting.QObject \O^UT N:zzScreen name is emptyScreenSettingsDialog\O^UT [^R+T Screen name matches aliasScreenSettingsDialog.\O^UT N N:zz0XkQeNN*T [WbQs[hF0SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialog*\O^UT N NR+T vT Smbfe9R+T 0iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialogmR&AddScreenSettingsDialogBase Ctrl&Ctrl:ScreenSettingsDialogBasek{ &Dead cornersScreenSettingsDialogBaseOe9&FixesScreenSettingsDialogBaseOe9c .&Modifier keysScreenSettingsDialogBaseR d&RemoveScreenSettingsDialogBase Shift:&Shift:ScreenSettingsDialogBaseR+T A&liasesScreenSettingsDialogBaseAltAl&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase]N  Bottom-leftScreenSettingsDialogBaseSN  Bottom-rightScreenSettingsDialogBasek{Y'\ Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBaseOY caps lock.Fix CAPS LOCK keyScreenSettingsDialogBaseOY num lock.Fix NUM LOCK keyScreenSettingsDialogBaseOY scroll lock.Fix SCROLL LOCK keyScreenSettingsDialogBase OY XineramavXTestFix XTest for XineramaScreenSettingsDialogBase MetaM&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseeNoneScreenSettingsDialogBase SuperS&uper:ScreenSettingsDialogBase\O^UT  Screen &name:ScreenSettingsDialogBase\O^UnScreen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase~SuperScreenSettingsDialogBase]N Top-leftScreenSettingsDialogBaseSN  Top-rightScreenSettingsDialogBaset<center>\O^Un: <b>%1</b></center><br>SQNOe9n<br>\\O^UbR0^~{geydo
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel]N  &Bottom-leftServerConfigDialogBase[b7zhgThg&Check clients everyServerConfigDialogBasek{ &Dead cornersServerConfigDialogBase&EditServerConfigDialogBasep.&HotkeysServerConfigDialogBasee^&NewServerConfigDialogBase y&OptionsServerConfigDialogBaseR d&RemoveServerConfigDialogBaseRcb&SwitchServerConfigDialogBaseLN:A&ctionsServerConfigDialogBaseg Rz~nAdvanced server settingsServerConfigDialogBaseSN  Bottom-ri&ghtServerConfigDialogBase(nSynergyg RzMnv\O^U^\@0:Configure the layout of your synergy server configuration.ServerConfigDialogBasek{Y'\ Cor&ner Size:ServerConfigDialogBase(N yRRMSzSW(Windowsg RVhN 0Don't take &foreground window on Windows serversServerConfigDialogBase"Nh<[PN-bR\O^UR0WW>hvۈLR d09Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBaselbR\O^UVh R0QhhvۈLR d0 SQ\O^UQvn0Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBase bRkdc R0h<[PN-ۈLmR\O^U01Drag this button to the grid to add a new screen.ServerConfigDialogBaseE&ditServerConfigDialogBasep.HotkeysServerConfigDialogBasee^Ne&wServerConfigDialogBaseR dRe&moveServerConfigDialogBase T ke\O^UObS&ynchronize screen saversServerConfigDialogBase \O^UTTcScreens and linksServerConfigDialogBase g RzMnServer ConfigurationServerConfigDialogBase {I_TRcbSwitch &after waitingServerConfigDialogBaseSQtapRcbSwitch on double &tap withinServerConfigDialogBase]N  To&p-leftServerConfigDialogBaseSN  Top-rig&htServerConfigDialogBaseOu(vQsv hRO\Use &relative mouse movesServerConfigDialogBasekymsServerConfigDialogBase`xn[elevate SynergyT OQASynergyTelevatedz NNTUAC[hF OFf/S_wNRT^elevatedz NNv0Sg W(O`vePbMElevate Synergy0Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to.SettingsDialogNSynergyElevate SynergySettingsDialogO[Xe_eN &Save log file to...SettingsDialoguLb &Interface:SettingsDialogBase &Language:SettingsDialogBasee_{I~&Logging level:SettingsDialogBaseQvN&MiscellaneousSettingsDialogBasemO & Browse...SettingsDialogBaseDebugSettingsDialogBase1Debug1SettingsDialogBase2Debug2SettingsDialogBaseErrorSettingsDialogBaseO`oInfoSettingsDialogBase _UR0eN Log to file:SettingsDialogBasee_׋_ULoggingSettingsDialogBaselaNoteSettingsDialogBasezSP&ort:SettingsDialogBase \O^UT y: Sc&reen name:SettingsDialogBasenSettingsSettingsDialogBasefTJWarningSettingsDialogBaseQe`v{W0W@T[x0-Please enter your email address and password. SetupWizard bNN* yPlease select an option. SetupWizardnSynergy Setup Synergy SetupWizard"kd{g:O\N: g Rzf/[b7zServer or Client?SetupWizardBasenSynergy Setup SynergySetupWizardBase*SynergyQAO`{g~W0W(O`RQlhLN YS{g:NKQqNO`v hT.v [QM9^vN_e>nNx0O`Sꉁ\ hc NNS{g:v\O^UyQR0SNN*\O^U\1LN0uSNQqNO`vRj4g0O`b@vNNf/NN*Q~܏c0Synergyf/^sSvSNЈLNWindows Mac OS XTLinux 0ZSynergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).SetupWizardBasea"`[SynergyThanks for installing Synergy!SetupWizardBasek"WelcomeSetupWizardBaseg*wUnknownVersionCheckerv{_UY1% QN0 %1$Login failed, an error occurred. %1 WebClient&v{_UY1% QN0 g RVhV^ %16Login failed, an error occurred. Server response: %1 WebClientv{_UY1% {W0W@b[x0(Login failed, invalid email or password. WebClientSynergySynergyZeroconfServicesynergy-1.8.8-stable/src/gui/res/lang/gui_zh-CN.ts000066400000000000000000001674141305627404700217450ustar00rootroot00000000000000 AboutDialogBase About Synergy 关于Synergy <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown 未知 Version: 版本: &Ok 确定 ActionDialogBase Configure Action 行为配置 Choose the action to perform 选择要执行的行为 Press a hotkey 按下热键 Release a hotkey 松开热键 Press and release a hotkey 按下一个键然后松开 only on these screens 仅仅在这些屏幕上 Switch to screen 切换到屏幕 Switch in direction 方向切换 left right 右侧 up 上方 down 下方 Lock cursor to screen 锁定指针于屏幕 toggle 切换 on 启用 off 禁用 This action is performed when 当……时启用此行为 the hotkey is pressed 热键被按下 the hotkey is released 热键被松开 AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey 热键 Enter the specification for the hotkey: 输入热键的说明: MainWindow &Start 开始 &File 文件 &Edit 编辑 &Window 窗口 &Help 帮助 <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>您正在使用的Synergy版本有些过时了,有新版 <b>%1</b> 可以 <a href="%2">下载</a>。</p> Program can not be started 程序无法启动 The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. 可执行程序<br><br>%1<br><br>没有成功运行,虽然程序本身存在。请检查你是否有运行此程序的权限。 Synergy client not found 未找到Synergy客户端 The executable for the synergy client does not exist. Synergy客户端的可执行程序不存在。 Hostname is empty 主机名为空 Please fill in a hostname for the synergy client to connect to. 请为Synergy客户端设置一个用于连接的主机名 Cannot write configuration file 不能写入配置文件 The temporary configuration file required to start synergy can not be written. 启动Synergy所需的临时配置文件不可写。 Configuration filename invalid 配置文件名非法 You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? 你没有为Synergy服务端设置一个可用的配置文件。需要现在浏览配置文件吗? Synergy server not found 未找到Synergy服务端 The executable for the synergy server does not exist. Synergy服务端可执行程序不存在。 Synergy terminated with an error Synergy因错终止运行 Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy意外终止运行,退出代码 %1。<br><br>请查看输出日志了解详情。 &Stop 停止 Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy正在启动 Synergy is running. Synergy正在运行 Synergy is not running. Synergy没有运行 Unknown 未知 Synergy Synergy Browse for a synergys config file 浏览Synergy配置文件 Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... 保存配置到文件 Save failed 保存失败 Could not save configuration to file. 不能保存配置到文件 MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: 屏幕名: &Server IP: 服务端IP &Start 开始 Use existing configuration: 使用已有的配置: &Configuration file: 配置文件: &Browse... 浏览… Configure interactively: 交互配置: &Configure Server... 设置服务端… Ready 准备完毕 Log 日志 &Apply 应用 IP addresses: IP地址 Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... 关于Synergy… &Quit 退出 Quit 退出 Run 运行 S&top 停止 Stop 停止 S&how Status 显示状态 &Hide 隐藏 Hide 隐藏 &Show 显示 Show 显示 Save configuration &as... 保存配置到… Save the interactively generated server configuration to a file. 保存通过交互配置生成的配置到文件。 Settings 设置 Edit settings 编辑设置 Run Wizard 运行向导 NewScreenWidget Unnamed 未命名 PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy 设置Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy配置文件(*.sgc);;所有文件 (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy配置文件(*.conf);;所有文件 (*.*) System tray is unavailable, quitting. 系统托盘不可用,程序退出。 ScreenSettingsDialog Screen name is empty 屏幕名为空 The screen name cannot be empty. Please either fill in a name or cancel the dialog. 屏幕名不能为空。请填入一个名字或者关闭对话框。 Screen name matches alias 屏幕名对应别名 The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. 屏幕名不能与别名相同,请取消或者更改别名。 ScreenSettingsDialogBase Screen Settings 屏幕设置 Screen &name: 屏幕名: A&liases 别名 &Add 添加 &Remove 删除 &Modifier keys 修改按键 &Shift: Shift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super 超级 None &Ctrl: Ctrl: Al&t: Alt: M&eta: Meta: S&uper: Super: &Dead corners 死角 Top-left 左上角 Top-right 右上角 Bottom-left 左下角 Bottom-right 右下角 Corner Si&ze: 死角大小 &Fixes 修改 Fix CAPS LOCK key 修复caps lock键 Fix NUM LOCK key 修复num lock键 Fix SCROLL LOCK key 修复scroll lock键 Fix XTest for Xinerama 修复Xinerama的XTest ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>屏幕设置: <b>%1</b></center><br>双击以修改设置<br>将屏幕拖到废纸篓来移除 ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration 服务端配置 Screens and links 屏幕和联接 Drag a screen from the grid to the trashcan to remove it. 从格子中拖动屏幕到垃圾桶进行删除。 Configure the layout of your synergy server configuration. 设置Synergy服务端配置的屏幕布局。 Drag this button to the grid to add a new screen. 拖动此按钮到格子中进行添加屏幕。 Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. 拖动屏幕(图标)到网格中或者移动已经在网格中的屏幕的位置。 拖动屏幕到垃圾桶进行删除。 双击屏幕编辑其设置。 Hotkeys 热键 &Hotkeys 热键 &New 新建 &Edit 编辑 &Remove 删除 A&ctions 行为 Ne&w 新建 E&dit 编辑 Re&move 删除 Advanced server settings 服务端高级设置 &Switch 切换 Switch &after waiting 等待后切换 ms 毫秒 Switch on double &tap within 双击tap切换 &Options 选项 &Check clients every 客户端检查周期 Use &relative mouse moves 使用相关的鼠标动作 S&ynchronize screen savers 同步屏幕保护 Don't take &foreground window on Windows servers 不要移动前台窗口在Windows服务器上 Ignore auto config clients &Dead corners 死角 To&p-left 左上角 Top-rig&ht 右上角 &Bottom-left 左下角 Bottom-ri&ght 右下角 Cor&ner Size: 死角大小 SettingsDialog Save log file to... 保存日志文件… Elevate Synergy 评价Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. 您确定要elevate Synergy吗? 这会允许Synergy和elevated进程交互和UAC对话框,但是可能引起一切和非elevated进程交互的问题。只有在你需要的时候才Elevate Synergy。 SettingsDialogBase Settings 设置 Sc&reen name: 屏幕名称: P&ort: 端口: &Interface: 界面 Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging 日志记录 &Logging level: 日志等级 Log to file: 记录到文件 Browse... 浏览… Error 错误 &Language: 语言: &Miscellaneous 其他 Warning 警告 Note 注意 Info 信息 Debug 调试 Debug1 调试1 Debug2 调试2 SetupWizard Setup Synergy 设置Synergy Please select an option. 请选择一个选项 Please enter your email address and password. 请输入您的邮箱地址和密码。 SetupWizardBase Setup Synergy 设置Synergy Welcome 欢迎 Thanks for installing Synergy! 感谢您安装Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy允许你轻松地在你办公桌上多台计算机之间共享你的鼠标和键盘,它免费并且开放源代码。你只要将鼠标(指针)从一台计算机的屏幕边缘移出到另一个屏幕就行了。甚至可以共享你的剪贴板。你所需要的仅仅是一个网络连接。Synergy是跨平台的(可以运行于Windows,Mac OS X和Linux)。 Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? (此计算机作为)服务端还是客户端? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown 未知 WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. 登录失败,邮箱地址或密码错误。 Login failed, an error occurred. %1 登录失败,出错了。 %1 Login failed, an error occurred. Server response: %1 登录失败,出错了。 服务器回应: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/lang/gui_zh-TW.qm000066400000000000000000000377131305627404700217640ustar00rootroot00000000000000(]}S3u>{(Z = nbjU4 #6v5%Z9BEv._-e+Nw9FB ;H}H"O O 4\O 4]2v|VE"UNDYu:27l_g} *-ln$w1r1 (:O:$ 0X$Z0J "QJA-iz2@dNl !o攄J_(4:S( nc4.d"@TyL#/{% dzo>J1 3=T k@d$:yc8p%@~C}F+n&C-T& I_Z Jz3 k#' v~* ,2 -5 Pn+ d ~5+ ~q8 ք~ ȹ ȹ ȹ9 a/ |! F F% Z= & KG @{ k RVt RV0 RV8B R  T V4\  |*0 c&M s s3J c,| F Ҫ ^ / 4p, d I i! N r+ zk/ P3} ¦e8 x4& ]^ U^41\7=> 'bun-y~3- r 0/+7kC*k%>.'> i9x[&OkAboutDialogBaseeSynergy... About SynergyAboutDialogBaseg*wUnknownAboutDialogBaserHg,Version:AboutDialogBasexdljWLvRO\Choose the action to performActionDialogBase-[RO\Configure ActionActionDialogBase[Lock cursor to screenActionDialogBase c N _cwuPress a hotkeyActionDialogBasec N _e>_cwuPress and release a hotkeyActionDialogBase e>_cwuRelease a hotkeyActionDialogBaseRceTSwitch in directionActionDialogBaseRcہSwitch to screenActionDialogBaseWLkdRO\ uvThis action is performed whenActionDialogBaseN downActionDialogBase]leftActionDialogBaseܕoffActionDialogBaseU_onActionDialogBaseSW(N R^Uoy:only on these screensActionDialogBaseSrightActionDialogBase ]c N _cwuthe hotkey is pressedActionDialogBase ]e>_cwuthe hotkey is releasedActionDialogBaseIctoggleActionDialogBaseN upActionDialogBase8Qe_cwu-['Enter the specification for the hotkey:HotkeyDialogBase_cwuHotkeyHotkeyDialogBase}/&Edit MainWindowjhH&File MainWindow^kR&Help MainWindowU_R&Start MainWindowP\kb&Stop MainWindowz&Window MainWindow|<p>O`vSynergyrHg,]}Y* rHg, <b>%1</b>]}SN <a href="%2">N </a>0</p>o

Your version of Synergy is out of date. Version %1 is now available to download.

 MainWindowpNxdNJ-[j!Browse for a synergys config file MainWindowq!l[Qe-[jCannot write configuration file MainWindow-[jjhHT z1q!eHConfiguration filename invalid MainWindowq!lQ2[X-[jhH0%Could not save configuration to file. MainWindowfT z1N zzv}Hostname is empty MainWindow,ˏ8Qesynergy[b6z#cvfT z10?Please fill in a hostname for the synergy client to connect to. MainWindow g*U_Rz ^Program can not be started MainWindowQ2[X-[...Save configuration as... MainWindowQ2[XY1eW Save failed MainWindowSynergySynergy MainWindowb~N R0Synergy[b6zSynergy client not found MainWindowSynergyN W(KO\N-0Synergy is not running. MainWindowSynergykcW(KO\N-0Synergy is running. MainWindowSynergykcW(U_RN-0Synergy is starting. MainWindowb~N R0SynergyO:g VhSynergy server not found MainWindowVSynergyGR0/ P\kbKO\ /x %1<br><br>s}0`lSSÀe劌0fSynergy terminated unexpectedly with an exit code of %1.

Please see the log output for details. MainWindow SynergyGR0/ P\kbKO\ Synergy terminated with an error MainWindow"Synergy[b6zWLjN [XW(05The executable for the synergy client does not exist. MainWindow"SynergyO:g VhWLjN [XW(05The executable for the synergy server does not exist. MainWindow`g*bRU_RWLj<br><br>%1<br><br> Q{rjhH[XW( jgWLz ^k P-[0The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. MainWindow*q!l[Qeu(NU_Rsynergyvf[X-[jNThe temporary configuration file required to start synergy can not be written. MainWindowg*wUnknown MainWindowDO`lg 8Qeg eHvsynergyO:g Vh-[j O`sW(p-[jUYou have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? MainWindoweSynergy...&About Synergy...MainWindowBaseau(&ApplyMainWindowBase p... &Browse...MainWindowBase-[j&Configuration file:MainWindowBase-[O:g Vh...&Configure Server...MainWindowBase&HideMainWindowBase╋&QuitMainWindowBaseO:g Vh(&S) IP: &Server IP:MainWindowBase oy:(&S)&ShowMainWindowBaseU_R&StartMainWindowBase NRW0-[Configure interactively:MainWindowBase}/ Edit settingsMainWindowBaseHideMainWindowBase IPW0W@: IP addresses:MainWindowBaseLogMainWindowBase╋QuitMainWindowBasenPReadyMainWindowBaseWLRunMainWindowBase WL-[|H Run WizardMainWindowBaseoy:raK S&how StatusMainWindowBaseP\kbS&topMainWindowBaseQ2[X-[...Save configuration &as...MainWindowBaseQ2[XRaKubv-[jhH0@Save the interactively generated server configuration to a file.MainWindowBase oy:T z1 Screen name:MainWindowBase-[SettingsMainWindowBaseoy:ShowMainWindowBaseP\kbStopMainWindowBaseSynergySynergyMainWindowBaseOu( g -[jUse existing configuration:MainWindowBaseg*T}T UnnamedNewScreenWidget-[Synergy Setup SynergyPluginWizardPage@Synergy -[j (*.conf);;b@g jhH (*.*)0Synergy Configurations (*.conf);;All files (*.*)QObject>Synergy -[j (*.sgc);;b@g jhH (*.*)/Synergy Configurations (*.sgc);;All files (*.*)QObjectg*S_|}q]Qwk kcW(╋0%System tray is unavailable, quitting.QObjectoy:T z1N zzv}Screen name is emptyScreenSettingsDialogoy:T z1vT eR%T Screen name matches aliasScreenSettingsDialog@Screen name_Xk XkQescreen namebSm0SThe screen name cannot be empty. Please either fill in a name or cancel the dialog.ScreenSettingsDialogNScreen nameN R%T vT R*dR%T bOe9screen name0iThe screen name cannot be the same as an alias. Please either remove the alias or change the screen name.ScreenSettingsDialogmR&AddScreenSettingsDialogBase&undefinedCtrl:&Ctrl:ScreenSettingsDialogBasek{ &Dead cornersScreenSettingsDialogBaseOkc&FixesScreenSettingsDialogBaseRu&Modifier keysScreenSettingsDialogBaseyd&RemoveScreenSettingsDialogBase &undefinedShift:&Shift:ScreenSettingsDialogBaseR%T A&liasesScreenSettingsDialogBase&undefinedl&t:Al&t:ScreenSettingsDialogBaseAltAltScreenSettingsDialogBase]N  Bottom-leftScreenSettingsDialogBaseSN  Bottom-rightScreenSettingsDialogBase ҄=Y'\ Corner Si&ze:ScreenSettingsDialogBaseCtrlCtrlScreenSettingsDialogBaseOkcCAPS LOCKuFix CAPS LOCK keyScreenSettingsDialogBaseOkcNUM LOCKuFix NUM LOCK keyScreenSettingsDialogBaseOkcSCROLL LOCKuFix SCROLL LOCK keyScreenSettingsDialogBase OkcXineramavXTestFix XTest for XineramaScreenSettingsDialogBase&undefined&eta:M&eta:ScreenSettingsDialogBaseMetaMetaScreenSettingsDialogBaseNoneNoneScreenSettingsDialogBase &undefined&uper:S&uper:ScreenSettingsDialogBase oy:T z1 Screen &name:ScreenSettingsDialogBaseoy:-[Screen SettingsScreenSettingsDialogBase ShiftShiftScreenSettingsDialogBase SuperSuperScreenSettingsDialogBase]N Top-leftScreenSettingsDialogBaseSN  Top-rightScreenSettingsDialogBasep<center>^U: <b>%1</b></center><br>dN}/-[<br>bRՇ^UWW>{RNydo
Screen: %1

Double click to edit settings
Drag screen to the trashcan to remove itScreenSetupModel]N e &Bottom-leftServerConfigDialogBasekϖY\fBjgT[b6z&Check clients everyServerConfigDialogBasek{ &Dead cornersServerConfigDialogBase}/&EditServerConfigDialogBase_cwu&HotkeysServerConfigDialogBasee^&NewServerConfigDialogBasex&OptionsServerConfigDialogBaseyd&RemoveServerConfigDialogBaseRc&SwitchServerConfigDialogBaseRO\A&ctionsServerConfigDialogBaseO:g Vh2-[Advanced server settingsServerConfigDialogBaseSN e Bottom-ri&ghtServerConfigDialogBase -[synergyO:g Vh-[OH\@:Configure the layout of your synergy server configuration.ServerConfigDialogBase ҄=Y'\ Cor&ner Size:ServerConfigDialogBase(W(WindowsO:g VhN N-N srSRMfoz0Don't take &foreground window on Windows serversServerConfigDialogBase_}h{RNyd9Drag a screen from the grid to the trashcan to remove it.ServerConfigDialogBasebbRe^U}h{RNyd0 dʇ^UN}/-[0Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings.ServerConfigDialogBasebRkdc }h AboutDialogBase About Synergy 關於Synergy... <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> <p> Keyboard and mouse sharing application. Cross platform and open source.<br /><br /> Copyright © 2012-2016 Symless Ltd.<br /> Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><br /> Synergy is released under the GNU General Public License (GPLv2).<br /><br /> Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br /> The Synergy GUI is based on QSynergy by Volker Lanz.<br /><br /> Visit our website for help and info (symless.com). </p> Unknown 未知 Version: 版本: &Ok 確定 ActionDialogBase Configure Action 設定動作 Choose the action to perform 選擇要執行的動作 Press a hotkey 按下快捷鍵 Release a hotkey 放開快捷鍵 Press and release a hotkey 按下後放開快捷鍵 only on these screens 只在下列螢幕顯示 Switch to screen 切換至 Switch in direction 切換方向 left right up down Lock cursor to screen 鎖定至 toggle 轉換 on 開啟 off 關閉 This action is performed when 執行此動作,當 the hotkey is pressed 已按下快捷鍵 the hotkey is released 已放開快捷鍵 AddClientDialog Dialog TextLabel Ignore auto connect clients HotkeyDialogBase Hotkey 快捷鍵 Enter the specification for the hotkey: 輸入快捷鍵設定: MainWindow &Start 啟動 &File 檔案 &Edit 編輯 &Window 視窗 &Help 幫助 <p>Your version of Synergy is out of date. Version <b>%1</b> is now available to <a href="%2">download</a>.</p> <p>Version %1 is now available, <a href="%2">visit website</a>.</p> <p>你的Synergy版本已經太舊, 版本 <b>%1</b>已經可以至 <a href="%2">下載</a>。</p> Program can not be started 未能啟動程序 The executable<br><br>%1<br><br>could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program. 未能成功啟動執行檔<br><br>%1<br><br>,儘管該檔案存在,請檢查執行程序權限設定。 Synergy client not found 找不到Synergy客戶端 The executable for the synergy client does not exist. Synergy客戶端執行檔不存在。 Hostname is empty 電腦名稱不能空白 Please fill in a hostname for the synergy client to connect to. 請輸入synergy客戶端要連接的電腦名稱。 Cannot write configuration file 無法寫入設定檔 The temporary configuration file required to start synergy can not be written. 無法寫入用以啟動synergy的暫存設定檔 Configuration filename invalid 設定檔檔案名稱無效 You have not filled in a valid configuration file for the synergy server. Do you want to browse for the configuration file now? 你沒有輸入有效的synergy伺服器設定檔,你需要現在瀏覽設定檔嗎? Synergy server not found 找不到Synergy伺服器 The executable for the synergy server does not exist. Synergy伺服器執行檔不存在。 Synergy terminated with an error Synergy遇到錯誤,停止運作 Synergy terminated unexpectedly with an exit code of %1.<br><br>Please see the log output for details. Synergy遇到錯誤,停止運作,錯誤碼 %1<br><br>詳細情況可參考記錄日誌。 &Stop 停止 Please add the server (%1) to the grid. Please drag the new client screen (%1) to the desired position on the grid. Failed to detect system architecture. Cancel Failed to download Bonjour installer to location: %1 Do you want to enable auto config and install Bonjour? This feature helps you establish the connection. Auto config feature requires Bonjour. Do you want to install Bonjour? Synergy is starting. Synergy正在啟動中。 Synergy is running. Synergy正在運作中。 Synergy is not running. Synergy不在運作中。 Unknown 未知 Synergy Synergy Browse for a synergys config file 瀏覽以選擇設定檔 Synergy is now connected, You can close the config window. Synergy will remain connected in the background. Security question Do you trust this fingerprint? %1 This is a server fingerprint. You should compare this fingerprint to the one on your server's screen. If the two don't match exactly, then it's probably not the server you're expecting (it could be a malicious user). To automatically trust this fingerprint for future connections, click Yes. To reject this fingerprint and disconnect from the server, click No. Save configuration as... 儲存設定至... Save failed 儲存失敗 Could not save configuration to file. 無法儲存設定至檔案。 MainWindowBase Synergy Synergy Ser&ver (share this computer's mouse and keyboard): Screen name: 顯示名稱: &Server IP: 伺服器(&S) IP: &Start 啟動 Use existing configuration: 使用舊有設定檔: &Configuration file: 設定檔: &Browse... 瀏覽... Configure interactively: 互動地設定: &Configure Server... 設定伺服器... Ready 準備 Log 記錄 &Apply 應用 IP addresses: IP地址: Fingerprint: &Client (use another computer's mouse and keyboard): Auto config &About Synergy... 關於Synergy... &Quit 離開 Quit 離開 Run 執行 S&top 停止 Stop 停止 S&how Status 顯示狀態 &Hide 隱藏 Hide 隱藏 &Show 顯示(&S) Show 顯示 Save configuration &as... 儲存設定至... Save the interactively generated server configuration to a file. 儲存動態生成的設定至檔案。 Settings 設定 Edit settings 編輯 Run Wizard 執行設定精靈 NewScreenWidget Unnamed 未命名 PluginManager Failed to get plugin directory. Failed to get profile directory. Failed to download plugin '%1' to: %2 %3 Could not get Windows architecture type. Could not get Linux architecture type. PluginWizardPage Setup Synergy 設定Synergy Please wait... Error: %1 Setup complete. Downloading '%1' plugin (%2/%3)... Plugins installed successfully. Generating SSL certificate... Downloading plugin: %1 (1/%2) Getting plugin list... QObject Synergy Configurations (*.sgc);;All files (*.*) Synergy 設定檔 (*.sgc);;所有檔案 (*.*) Synergy Configurations (*.conf);;All files (*.*) Synergy 設定檔 (*.conf);;所有檔案 (*.*) System tray is unavailable, quitting. 未能取得系統工具欄,正在離開。 ScreenSettingsDialog Screen name is empty 顯示名稱不能空白 The screen name cannot be empty. Please either fill in a name or cancel the dialog. Screen name必填,請填入screen name或取消。 Screen name matches alias 顯示名稱相同於別名 The screen name cannot be the same as an alias. Please either remove the alias or change the screen name. Screen name不能與別名相同,請刪除別名或修改screen name。 ScreenSettingsDialogBase Screen Settings 顯示設定 Screen &name: 顯示名稱: A&liases 別名 &Add 添加 &Remove 移除 &Modifier keys 功能鍵 &Shift: &undefinedShift: Shift Shift Ctrl Ctrl Alt Alt Meta Meta Super Super None None &Ctrl: &undefinedCtrl: Al&t: &undefinedl&t: M&eta: &undefined&eta: S&uper: &undefined&uper: &Dead corners 死角 Top-left 左上 Top-right 右上 Bottom-left 左下 Bottom-right 右下 Corner Si&ze: 角落大小: &Fixes 修正 Fix CAPS LOCK key 修正CAPS LOCK鍵 Fix NUM LOCK key 修正NUM LOCK鍵 Fix SCROLL LOCK key 修正SCROLL LOCK鍵 Fix XTest for Xinerama 修正Xinerama的XTest ScreenSetupModel <center>Screen: <b>%1</b></center><br>Double click to edit settings<br>Drag screen to the trashcan to remove it <center>螢幕: <b>%1</b></center><br>雙擊以編輯設定<br>拖動螢幕至垃圾筒以移除 ServerConfigDialog Configure server ServerConfigDialogBase Server Configuration 伺服器設定 Screens and links 螢幕和連結 Drag a screen from the grid to the trashcan to remove it. 從網格上拖動螢幕至垃圾筒以移除 Configure the layout of your synergy server configuration. 設定synergy伺服器設定佈局 Drag this button to the grid to add a new screen. 拖動此按鈕至網格以添加新螢幕 Drag new screens to the grid or move existing ones around. Drag a screen to the trashcan to delete it. Double click on a screen to edit its settings. 拖動新螢幕至網格或在網格上拖動螢幕以改變佈局位置。 拖動螢幕至垃圾筒以移除。 雙擊螢幕以編輯設定。 Hotkeys 快捷鍵 &Hotkeys 快捷鍵 &New 新建 &Edit 編輯 &Remove 移除 A&ctions 動作 Ne&w 新建 E&dit 編輯 Re&move 移除 Advanced server settings 伺服器進階設定 &Switch 切換 Switch &after waiting 切換前稍後 ms 微秒 Switch on double &tap within 於多少時間內雙擊滑鼠進行切換 &Options 選項 &Check clients every 每隔多少時間檢查各客戶端 Use &relative mouse moves 使用滑鼠相對移動方式 S&ynchronize screen savers 同步螢幕保護程式 Don't take &foreground window on Windows servers 在Windows伺服器上中不獲取前景視窗 Ignore auto config clients &Dead corners 死角 To&p-left 左上方 Top-rig&ht 右上方 &Bottom-left 左下方 Bottom-ri&ght 右下方 Cor&ner Size: 角落大小: SettingsDialog Save log file to... 儲存記錄至檔案... Elevate Synergy 以管理員身份使用 Synergy Are you sure you want to elevate Synergy? This allows Synergy to interact with elevated processes and the UAC dialog, but can cause problems with non-elevated processes. Elevate Synergy only if you really need to. 你是否肯定以管理員身份使用 Synergy ? 這將會容許 Synergy 接觸系統程序及 UAC 使用者帳戶控制,但可能會與非管理員身份執行的程式發生問題。請認真考慮。 SettingsDialogBase Settings 設定 Sc&reen name: 顯示名稱: P&ort: 端口 &Interface: 網絡界面: Elevate mode &Hide on startup &Network Security Use &SSL encryption (unique certificate) Logging 記錄日誌 &Logging level: 記錄等級: Log to file: 記錄至檔案: Browse... 瀏覽... Error 錯誤 &Language: 語言 &Miscellaneous &雜項 Warning 警告 Note 通知 Info 訊息 Debug 偵錯 Debug1 偵錯1 Debug2 偵錯2 SetupWizard Setup Synergy 設定Synergy Please select an option. 請挑選一選項。 Please enter your email address and password. 請輸入你的email和密碼 SetupWizardBase Setup Synergy 設定Synergy Welcome 歡迎 Thanks for installing Synergy! 感謝您安裝Synergy! Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux). Synergy是能讓您於多台電腦之間共享一組鍵盤與滑鼠的自由、開源軟體。您只須將滑鼠移出電腦螢幕邊緣就能遊走於不同電腦之間,甚至能共用每台電腦的系統剪貼簿。這些功能僅需依靠一條網路線連結,而且Synergy是跨平台的(可於Windows、Mac OS X及Linux上執行)。 Activate &Activate now... Email: Password: <a href="https://symless.com/account/reset/">Forgot password</a> &Skip activation &Server (share this computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html> &Client (use another computer's mouse and keyboard) <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html> Server or Client? 伺服器端或客戶端? SslCertificate Failed to get profile directory. SSL certificate generated. SSL fingerprint generated. Failed to find SSL fingerprint. VersionChecker Unknown 未知 WebClient An error occurred while trying to sign in. Please contact the helpdesk, and provide the following details. %1 Login failed, invalid email or password. 登入失敗,無效的email或密碼 Login failed, an error occurred. %1 登入失敗,錯誤。 %1 Login failed, an error occurred. Server response: %1 登入失敗,錯誤。 伺服器: %1 An error occurred while trying to query the plugin list. Please contact the help desk, and provide the following details. %1 Get plugin list failed, invalid user email or password. Get plugin list failed, an error occurred. %1 Get plugin list failed, an error occurred. Server response: %1 ZeroconfService zeroconf server detected: %1 zeroconf client detected: %1 Zero configuration service Error code: %1. Unable to start the zeroconf: %1. Synergy Synergy Failed to get local IP address. Please manually type in server address on your clients %1 synergy-1.8.8-stable/src/gui/res/mac/000077500000000000000000000000001305627404700174145ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/res/mac/Info.plist000066400000000000000000000016401305627404700213650ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleDisplayName Synergy CFBundleExecutable Synergy CFBundleIconFile Synergy.icns CFBundleIdentifier synergy CFBundleInfoDictionaryVersion 6.0 CFBundleName Synergy CFBundlePackageType APPL CFBundleShortVersionString 1.8.8 CFBundleVersion 1.8.8 NSHumanReadableCopyright © 2012-2016, Symless Ltd synergy-1.8.8-stable/src/gui/res/mac/QSynergy.icns000066400000000000000000003632161305627404700220660ustar00rootroot00000000000000icnsics#H??|>|>????|>|>??ics8xxxxxxxxxxxxxxxxxxxxxxxxRRRНRRR|RRRНRRRRХRRRRRRRRR|RRis32qga70ffec8231 ffgihb725423 fjfgkd843352fgfgeda4134331figef353`dfid 15327jkjlh043043 153273537134331 =43352 <25423<131;0jgkeff jfigff ligfjfheegfgf fegif eife` hljkjǃ ̓ ́ʝ ˟ ɝʞǝr`tdffseigffuhgfjf oeegfgffegif ehfd` lpoonDEEF> 00131353133431;̀253Á 32451@̃131@͇0?΃s8mk%<<%CCCIIC__%%3433213 =2332H3f keefdmmghgf kefjffefkefghgekefggekefggefkehhfgge kfefgfhfffbfifgffhfifjf_hfgfedkfhfgfffhfhefffegffkmkfˀNjт̋Ё͉̉̀́ŇԂŅ΂́Ѓπǟ̓Ǟ̈́Ȟ΃Ǟ΁ǞǞ ˡځǞ̀ftcefdmwfhgfudfjffefudfghgeudfggeudfggefudhhfggesfefgfhfffbfifgffhfifjf_hfgfedkfhfgfffhfheffegefoprofLFHFGÀ311010΀3343423Ё3421π2343.ρ25353.҂˿12435313҂ʁ3343 4223Cσ̂443441Bσ΃33431Bτ̅31B΃ˈ13431B΁͉343253 1B̋3123342C̏H2331B̀ڔ33L̊l8mk =ii=MMIIIIV@@UMM==ii  VU @@ @@ UU  ii==MMU@@UIIIIMM=ii= it32!mccbdZ<211*fZ>3233fqdegf[>38?3bdefeegf[>3121fgfef[>323jjfjgdfhgf[>3228535?mdfef[>322345$bfefeef[>3'__bfdeefgf[>32202113`ffefef[>323233+Ummdfef[>323/*$$*defefef[>323434-ggfeef[>3233Ucidfgf[>3248Yfef[>3&dfef[>3223.gcefef[>32313/Uggf[>3242*UZffgf[>32<*gdffef[>32345/cefef[>3232/Ufdefgf[>321.3cf[>343*ief[>323+dgdf[>323-Uef[>34*mffhf[>323$mffgf[>3$gfgf[>3*_ddeefefZ>322/6bffefddfdX>23232334ffeefefg?U?32321fefefed532321dfgffgfc`_41303232_befegc320'?jdfefefa-323432*_fefgffhUU8.2232345jfm$343235nfefeefgf331237gfefeffd.38_fgfa054223233/ffefefgfedaU0613fefhfefgc313fgfgegfhf332313fgfgeehmUH.313fgfgfU3322313gfgfeffciU-32?Uffgfefg038cfgefeff3*cfefefc131dfggfefc1322dfefc132dfefc132dfefeei432dfgcd_531232dfd??232dfd232dfdUU232dfdUU232dfdUU232dfdUU232srqrpqUU232U232U232U232U232U232232?23253123243213213213221313*038U-32?3322313UH.3133323133130613054223233/.38331237$3432358.2232345-323432*320'?41303232532321U?32321H23232334I322/6J3*J3$J323$J34*J323-J323+J343*J321.3J3232/J32345/J32<*J3242*J32313/J3223.J3&J3248J3233J323434-J323/*$$*J323233+J32202113J3'J322345$J3228535?J323J3121J38?3J3233K211*sdbccrfqfgedqfqfgeefedbqfefgfqfghfdgjfjjqfefdmqfeefefbqfgfeedfb__qfefeff`qfefdmmUqfefefedqfeefggqfgfdicUqfefYqfefdqfefecgqfggUqfgffZUqfeffdgqfefecqfgfedfUqfcqfeiqfdgdqfeUqfhffmqfgffmrfgfgrfefeedd_qdfddfeffbU?gfefeeffdefefef_`cfgffgfdcgefeb_afefefdjUUhffgfef_mfjfgfeefefndffefefgafgf_UadefgfefeffcgfefhfeffhfgegfgfUUmheegfgfUfgfgfUUicffefgfggfefgffUffefegfccfefefccfefggfdcfefdcfefdieefefd_dcgfd?dfddfdUdfdUdfdUdfdUdfdUqprqrsØ˗̪˗̪˗̪˗̪˗˗̿˗ߵ˘ʵ˙͵˙͵͗͵˖͵͕ӵ͕ε͗ʪU͗Ư͘ڪU͙͂͘˫˙͙ˀ¥͚͚Μڟ˜ƪʜ́ʛ͜˛͝ӁߋΟ̆ɋˢ̃˿ʁ˟̃ρͤ̃ͥ̄¥ͬͫʮˀͩ˨ʨͦ˥ρͤΤˢ͡ˠ͟΀͜˛˚ ͗˕΀͑˖͏΃͉˃ˈʀ͇·ʇԉåᇇdbcc܉f݈fgedqf݈fgeefedb݈fefgf݈fghfdgjfjj݈fefdm݈feefefb݈fgfeedfb__݈fefeff`݈fefdmmU݈fefefed݈feefgg݈fgfdicU݈fefY݈fefd݈fefecg݈fggU݈fgffZU݈feffdg݈fefec݈fgfedfU݈fc݈fei݈fdgd݈feU݈fhffm݈fgffmމfgfg܈fefeedd_܇dfddfeffbU?gfefeeffdefefef_`cfgffgfdcgefeb_afefefdjUUhffgfef_mfjfgfeefefndffefefgafgf_UadefgfefeffcgfefhfeffhfgegfgfUmheegfgfUfgfgfUicffefgfggfefgffUffefegfccfefefccfefggfdcfefdcfefdieefefd_dcgfd?dfddfdUdfdUdfdUdfdUdfdטU}|~}|}_`aU232U͗́232U͗́232U͗́232U͗́232͗́232?͗́232135͗́234˘́231͙́231͙́2231͗́131͖́*3͕Ƃ830͕?23-˗Ͽ3132233˗̅313.HΘ̅313233̅͘313˙̅3160͙̆/332322450€˙83.˚732133͚ҋ532343$˜ԋ5432322.8Μɋ*234323-ʁ͜Ԍ?'023˜Ŀ23230314ʁ̑͝123235Ɇ˟͑12323?Ũˢ͑43323232Ṹ͟ʑ6/223Uˤѿ*3Uͥԕ$3Uڕ$323Uڕ*43UԖ-323Ù+323Uӛ*343UƜ3.123U̪/2323Uˡ/54323ÚϢ*<23U*2423Uɪ/31323U.3223Uȫ&3U̬͂8423Ù3323U˱-434323UѲ*$$*/323U +332323Uʻ31120223Ùſ'3U$543223U?5358223Ũ323U˃1213Uʀ3?83Uƿ3323U*112Ut8mk@.433333333333333333333334.FɱF ^^ VbaaaaddaaaabVKK ee L󻛚L || (998DD899(ʋ++Xihh~~hhiX@@[[ii!!;XX;[[uuu[;;!XX!ii@[[@XXiihhgg+~~+'|QPQQQQQQQQQQPQ|б'9@@99dz++98_%#$$$$$$$$#%_8 D@@D  L|h""h|L   ddaE##Ea!! KdĪssdK Ub!!bUbEEbad##daaaah ha`_@""@_` d%%d F^##^F.$$.3$$33$$33$$33ˏ33{@++@{33QQ33QQ33QQ33QQ33QQ33QQ33QQ33QQ33QQ33QQ33QQ33QQ33QQ33QQ33{@++@{33ˏ33$$33$$33$$3.$$.F^##^F d%%d `_@""@_`ah haaaad##dabEEbUb!!bU KdĪssdK !!aE##Eadd   L|h""h|L  D@@D 8_%#$$$$$$$$#%_89dz++99@@9'|QPQQQQQQQQQQPQ|б'+~~+gghhiiXX@[[@ii!XX!;;u[uu[[;XX;!!ii[[@@Xihh~~hhiX++ʋ(998DD899( || L󻛚L ee KKVbaaaaddaaaabV ^^ FɱF.433333333333333333333334.ic08{ jP ftypjp2 jp2 Ojp2hihdrcolr"cdefjp2cOQ2R \ PXX`XX`XX`XX`XX`dKakadu-3.2 zϽ[&ߴJZ ?#E )T1Mˌ:I!rwÄ]@;R ϼ|xXK* qBJ|#U`!tjxh&\zY@ 8;IrRZȢ1@}`٨}Jem:-<Ȩ]$c3Ͻ0 uLu8F r}'*AjyE\ E4Tc (ҺRk@ @4I ]Aɘhwy> ` uŷg T͏0ˣ=$O8\ѩ@v̥lM~?8iH?G:ٴBf 8jRLW*̴l tlR`_wyˆҙ2,n4fg,y @L<J1񃜽.Qw| VrGr#^3XniO=hg_#?ba!&p+nOlMY j/'%6H|t9Rg%C77]5i*k, (_sPt1 !5yij*9W^ޢ'/ͧ}۝γ2gnaUNA7gpOܽ  '_w3Yt`hV]\\,1rMd|k mS*~BK;޷c\,r9]@FESoH- 'Ih jaX~Lۛ@`  nhba1~H 7sPN>y=ﵚA}[phs#.p 8-._\Lv,xcϣtH?_Țba}jmDHZ#A~h4$F郩:iPYg\.-qQJ=?C,L܀}QfJȳ V'EϟQE%"jWV懲i6WڜuWH]M[ _Mdd [>PR뙢x+uƕ<ԎS>."$Yub'[%K!vq&Ѡuo戴V۴Xl-iYCe@ J5狙^֏sk '\^f*1~c85g[SYƝb8h*H}dwkw|߉|Q{^Y@oB܅I @hh'Tkޘ3 Mp.CI \ʢOP'jǂΆDzSNX^90 {*r wMX%^Bu*3(w}SyA X`^-hlo$5$g=M\%m8ˑdu.$Q(>v)Vd0:ဵ|LsY]dMB.t,yr bẃoD"%t7\q͉[4\x&ڊ ߓwVsƍ)㥍#-q^ |gP*h|u;<#4e%b_,dz2.Sg!%Qꑉq9&d{,, ?@Q1T+,T`00#hf~ruuߊ,'ݰi/Y@UJhCKd)"~BK%<}>BJx 0GԐ>"Fno!f+żGW&?R&)&znjb m}s ||Krc7׏]O`90)SڧѵX31Aze}iU 4=xrg)R[Sp㉭P+Q/b! oozc3JCGC  I%_̄ՠg}bhf4@ /@(Lj c~"Q7 wJ-)Iƒ@ShrE"S 1^Â7yl2K3nRMzcbހE9DI#j ˑ+"" )?^&GۺꟘ;-wF, {6DL4T*wwOO==^Bٙ};oAJU+~:`1QuU##)eǰ`y_GjrL#٨Qj,>tdH3rbCf)p Urߑ|~$-oidv.w?Nk@p| `8R0>|c3^R޷P`^wؽ3E'6#6픧۞}VTkgS~~sg!g<[X[ <=BFEͻvثgQe@nk ch+c)|9i鴋 u1;=0_K湼#-KP C*$p$ۘa\L}3EEqR*.ܜRGm9b&+nO۟kCퟺ;vgϮk˳n$\hPtN:7^$SGR2C'9#Bt~:@e/7HJ|Q$p5O-CBI1nc2= ; 7tÖ~Ax!`2;qD/'=[ތf0m Qw.{=xUBSn$6X@]@"ݱڬ{"'Y >;8t2< Iۿgoźe>Pt|g5p|P XRոm>PfTҪGq! 9B!&{QXC[ːrq;nאIF[(Я`G!WagPc$#.ͅg*I;#ԏ3n"*6D]\)ByH?Ӕ*MGU9cȡ,vh) WOecm{ ( hy:{HXN@"kthjBJ}=M3yƳ0 LÛsAN٧64HKFstݻE22Ϗ$5ao;lLKǠfe#gpC\yU{g0g4 ߨq@~hvN$x :cV.C絲l#8!vg GfVvf63;Ejث4Xn:ۆ7=WQgVkd1\#[D̂5'3*+aA"Ur,WLנq?4 }!S͖| T:r͜4LciL<.";_,}ZCbDVX7v/Xe )Up)b(RF'x=GDm 갺 )-[)lBKݹU>足G4R,!3b9$.{N }N!&/&̙7OX6A QiauDeg п0IŠt ,Z\lU)%G@vRnN ;!8fgQW5axYdU G+`B_Cj'ޕr&CNl{i]g]XҚ)e n]\o/cS)p9XQKuÖZ&4&~,iX-d3@ 2w!htYt"8G=uDl׫ =X=&_E"M}Fj[iW^ƽvנa.bsS cu Ws]ŧۀ!b[6%0ԕsyJCF1+\R遠 ̨n \K@g)E3"%{x?v%h"U}xr(࿇/PrzhCbEbWs4w^$/C7[EluB"ϐ#gL'R'SI Yw{w=TT 2seJ d -!;] mv'چmĦ>pFŪs}:Lԓ ^9ሒ/>z⬀JdžDοUKV_P]dMTt5fhmc$ { 9=jPW{ǀI\ZT 4ɱ>ʨ)Ӟ+ZS04hw𒲅Zԅqf)D|dn]ixm0sK:+0(e0ah.l&EEiF_.3__7=ꀍ};1e΅Dl[x'=IЄJfVYi'Nt~+$9䈮(3t֖;Hzr/vA\Y?&``ԮwCkߋTg/,cA5V߻} \$C*x2:7Ӟ"/ØT _,\}K!ww M;Y/ۗ:(TW@*r6LJ0$6w1dh‚_ ˻~qh1E_%hOQhQ+/ {HGۡ֠&/!J fCR!~w@_k*3|1=|y6yxtm 7.yxZ7=/Hqu͡O~iyxmKL"&`nuRC'< 7%j> kaw&[bdf :>a4NC0Rї{]t)iҹ"H#XX |SD1ftY@g(a(~bf ƥcQjjdO?7h.<^N[<ro̧2v@x})I{4Y%_uwyI Df­oළ6Cu=N U9W m.UIo}FMe/\" @R^%qgLY-+M#䀶vg*= ;`|08\d1j[sxһ0|>^C&jعܣKԽ1Hz&hk|7!Y8@k6 +Pj4W! 0/cL7WD~$[ y%H:t4z/\6}-Oi`wH<{$$ 4NI6A+pl~ׇ¾,\ :bQeActH{gc*ͥHDGɳzk&2s{Y?fy؟w3-B?/Xljv ڰ߆3rZybEeNb] ;\N9^A՗1[iu ۯrqsM-N7gs>?5` rGl~^<Sr sUom[[izWf2RCU3'Y˦š5&⾳3B!"tN_~}pO")qPPkeSr;eA K?/Ң9Rt3+ ZZ Zn@@IÉݧ3z F^9h`gh[+w{7^}v7 wm{PqѰB*+LDs]k$4]I/#F tq1ۧ@t `T%N8J]5%϶p#hBnib>a؆ ]95w Ю M8^S4>JFE3˳0ώGƺ(QbȪsTGU4gBM$Q}OUKocѨa!/:(r澈vHӞx̾_x񥏏C&CO('#Oh Rs؝vqCEմ}j@OwhϺ }~wK)gxX w&L;hj8$V[08AYc/TT*؝' bm1܈Oɥ"JSa2Zn|J]7{;>wu HDErܽ&&ж~lP<ǃ<0%<*9T0PP0wg%F{M۱5(TꨎR k]8St_*ߨRMzQzv%Ć* [<@(wk/vܠUN•D]{A^hǜdn A_$eSQwk慚p\(Y^=|:AQ Rs6 8&g^ O8dy#g D4&|Bo#ޕzO̟o*n79Ւ71@m1VsF t4*bgjbp% a "ڎJȘKX z/@gc{ e}_)smg8kmv5+HrIWš?Z+AwXKs _MJ?a/ԩ+>UWN5[X*K#ְNKIPkoꇧ` ֲ Q #Rއ>^)q=5-'K*-a6 /mP<]Y#c}z.^Pœ3* 8j`k:pf[܁cͯ?);;1ၙ4'^ ֏1H) P&-yfB z\՜}2 N\k`r$`jE%S$TNW\V%,,0hahqm@$Qߏn^X@mZMԥ&-j, J@.'H#jn NCkK3a'AMs]7Drn//FxYHOT. ր'ý QŘf;y->*F]` #,7$x?;:w'Ҋq]:@E-&jghICXs&c"uUt#hCeQt-ltdOڮt|0~6nB=Ӗ@:6 U - sLtu3wDD(r;K'k,Ԣ qd^G0k˖H9Љր[dgqWtcԄ&LR04 V7ĬcALT3qYӣNd8qI#Åح-u:WЄh@= wNs|-=m7h{i麍<{|}Y#wM۞uSIŤ-67N =G}>dZN%^Y_uфYBZ\F%GSt 5x<-08tq{Q6BdZM4٣8Lc&.a姴a9Ck;`4d>83--0/PY} O,>|Ek6q_>ut'=N*l5)˖@a ,`ip(tF{\N;*HY4Zbw52lZBuRP@hVyjSe,8jH3RbSh pEqfQm%v0UatV;BqV͸ pW t{##n,+hdnH*] mH瘝Apc_EPl^Hn0&JQdzCIzzB7T@L2KMIF"@q9 zMe"pPÊa4!Xf2s'/.gcHJp;F||Nr.sPHؐ1ٮ{ QK)WJfm @)WNi7[fF]>T  ʙsJTs/m.n~FRq,P7Ԏ9MoKr&qmM(ʖ-~}I&pU9t@Ur;d4b(c 'SifR\*s;)BN7y/+gjOۙ 9,9-yL*_=r|\؆L3$ kbhKJr9RCy馉%"y~ X:avVRC]s3 J1qF${Bz*D@ LX5]}S{mh֝{g+̢h+:M!mt?qvG D WBVïVƈg`fv/">|dξlӆ6@nLs>qM ?lwD&bsxDy􃤽.f/6 5$Zzj|$w쪋`6rqі"sE{g,cdz$>3 Ӏ_` (tm)DVyN kVl1tew[EPcË|U%B5-Æ٠mo*vMvdE˕]8h!R M;N.6ppb l/-BϲFiJA ['p)@E͟$ ?@ƽ@5.טG. n,ӧ }`do"ۢR-ú wE Κ0cD7jFYkFWef?{5bڡBN]Jaq)隰Y#I4%5o`dƅ*hmtL\NSib7*_)큋zQ.zYm`Cel O% }&~P-!G|C9 'c&HJGPN;)Zl979zTtFd8?ukuq1ӣ T a^t#mshB>UpNfoH/^>A1XXyTu3 c6Yg6_n?Pyñx<}H.(s]](H4WJV8@fZOai_[QV͈#&M}zq7ttqyp%]yz__.e~gS.> 4pL 7~팤Hq M,pVQ򫩾4TwJYl;Џwx,%2S)7J(Kiouz7,go2>M=ٗק[N"ӇW&,5I  ݥTr`L2P HkqMb W`9Y˓ Z!]6Esrܹurv"8$ľ{~oH)H_Ɖ %`Gek Z az!$RO DDExO3>]KȾdݥC\e&|tj1eVdgEW be%^bk[}!e{r(JVp鄄?[B#9,P]dRk_Y$8OlSAtU]/8cz` "_y2~7{RL^P#["~ra @Q7 /E/ `FSɍor'WrKs>(^Jqm!aW$zAuY=7pΘμw/;uβj:fG3]rElJk^|_Q/^Q=f*=QDqR Dby?%2n:Rm {JYO8Nj9;]] ~p }ۄ sl6[Yk`mq/m <(Z:Y-?n(\d Xkt! bc||@{46 !| BeFW>wT %*96E4"{nI}%4ͤ0eE>}Bz%!8^1#M{-,kh-˗#SgTSĀ0 CL.f8傀!JP\d,yHb.|5f:P`jdggY:cvCXRጧ @ rئ ?ZepŨvIM C:Rǝ6ca]K>oz1зK@FUR2 xk3Gh[J飚9k*i!mZ!VnB行^2{`$xBjN>U?e^zp4bf\֜n X7$x=Q+j{7pnU=)eFPCTgM3pyvxjџ8N'FRXTPlpZ\\!Ӛ_X-Qcp5 dw?7nw9H|6"O2_fT"1Ó/Tnh)]H>3zw6@x(#~~sڶW 3s]>m[hd';!a,Ytît^_1g/J(3=V\Df+/sܷdFG( C4k!jёYrXך6|Ny9巍4H5WpbZd5GDw&>LŚM-" $ \W [۳mȋͫ.>>KJ5,\!qYz r3 ?y9Uc|ֳp\eE;d h%a|M A-B ;rUPS@#NkVnhE4@'@VqUAm+v%ìvČ; ~'"8 P?'#lðL:ʴ5?:o-TJ,NI Hk #u[zK'K415eeÃ6i_"Vnlݚ`6޳3\hAo2M2ȹ˘E d~KźMAۜ6{޿IHKKN(f ͸dt  vEyInl&ΔY*~X?CתQEӶ#o9cԒz9g qN]$"!+HkKUz\iD"6#^D7K\=A<;zbV}Z*J=B$[ !=(&TwIKgy/kDJq* ku).ܦMoۻ29A_*gNW=_km0Ԛg"(cmK.}&a 咢q) ҕS8W?_3m` px7`rƺ :UITX]gF ߚvڌh "J%t8S rxunM3 {q_O>6*OGԑ~b}Ow7a1{+R4^Rڈ ĵpc0:Vpbwqňo }rq'TZmE@u`)Th>V7?Nޥ'0T&>Gv _c& fNXl5$?%Yae@x(bݝ)k]EZq/)[`!^{KHSzSI"e dt`EzRKsJ+[G5l* Nՙ|Kp;=Roюg& mE5NBMŅcaILS1aV*"<[(!8.ڟ=xN4 \ |Tfe/Mv;E[PW8|۶yzMBУ&Z6qA SO0 ?aOzуM<w_.~LJ=X}[j.dY11b2M=Ⳉ*{!v~qj|M_A[]\4lF5e\A~LuV7d =_*P_:&*;uVXsl{|:#qH! ?ӼFKI$ޖ/}ZCVr/ݿk?0λf7s`wybxq <஑;T2uoE?̷ޤw}^Q_L8=vo^;~c$L3ۛhۄg]8o[16$ƭמ2lT21ŢS J S8ZŸVs Θx:%GPPG.|z:U;wkV8 wxŇ:[Y*%4OylE{3/Tr7 {bAZ +VL@Xv-Ìq]Ѳņv!:wۋt{ 2Q|ꈂuHӜ- @낗M+W%5Md}{0fZ2<_Hח.i@e]md@om/◗ɓ!LA 1@8Y>*1E;&p t fž|~hh"x "~^\kӯåP1dkhMc +y+[s_h[2*r4Jbd y߾hTk$qYRwxG%EHwn֔a5]ݩȵƳ30ԗY΂QR A ߩHvqWy9xOD"A! ק$ zxB(ņam|@`)705u,؍HtuhΨ*BL3 |#tzjGOa_=Y~I 6l".M&E,䘭M x mϽ6: I;~!T28>бvn B 4.&)P'O!ƥ8  6pkm¦onW?Ԝޟ6VžxGZEei0MNպc b 9f@ -,ߊ/+&_W(W`k'ypȽl`qx4?*> a.TYF{_kgq XI- emA #>`rS\Eaj*7fY:b8]%:FoAr?ψɲRґʞ ,QZhxZ OxK⮩ =)8E(\4]W`s8VQS`kO[D&/-A@YӏU$+iiUQ{_%28 Kt~n#-Nd|hGa0ݮIZN0Xle2J`y ~T9ŹߍUo6+`7 =@Ma9TKT]% ڲm[Bi%o6uY͚Vf}1s1аVjTc=+>lJWf-l9 &;g&:-/iJ:|Za_)r`T50ka;*8[n̤v~YIry`~pJ#1 3$ǥ{*#FM@7|;ċ(f%%q7_/ef1+u&Qzn ]1gwZpEeap'"GD8Ajb(QB̲圖fIŵ .<6*h(:e0+)7mEq0 k3ݎDG9[(8\K ZJNw` vVg5*HΊfUHDbvB 6:k+_X`DNOvf6qRU <]8?E>XQ¶{Ie"0HuQ{irRYr~x, Q)߆w3EXklrŇ\loGD>:zK=h"٨ZgEa@ 5>e:iBjR\ahmH X8By4Nl@O\_}3oX`;k[q9zD֔]J{jXDv Kuuk^gʬvl$z⪅t#&0D@,4Hm#X|Ft^o}PL64)ZA6z-kqJ)gku=ya y.=Ȗg*ȘhD5LoH.#P-"Kɵ/ B(/&}JÞKL|Bj\B!\EYI912Jq`n?l"RM=ey]{ԳlRvN6k8Y xp\0:qv-9Bt) u*2oJZG_F'u'AwduGiz/KRjVeLL}^X,io/9*c;u9W)R( k/.TDȰ8OٖWTq\qqQ/NAsu3422ӁD>qjPF{Amݤ)#cM7Q<] YnɯA1>As1CQ! 3͗)UN52Җc-(l3\Ne#qj$=sEaz~[&LB>:$YJ0 iYq(_Ck$khD%8@@@@tM|h>g#E1* N 6LDX6 W67izEId@t Z=5XIep|D:B6ja[mnAeCwoxѓDX>b=8Gۉ 0y`Ɋ8ǨӁ߼t4O+]3(S.б`{567[G6D <%k]p0 "\<mv2Qse' ,&Rk2æN2*MC$Ð|57( ;XEH #ep9NsfF9f{T0hJQlX]`QocR R^K8D YXҍEj%M_Ũ(>ﹲmT U- #Ɵuz 4O~~QQm jvfx6]Dpo[S!kEQ.y|zNO+OIlfVz%ʫ%lˢˮP-'e7=X??y }Ì֗dHZZzMF@Jf`*qi.aPUnZ:J%Nu աP'Ǖ|1N00ǦtY)9uͶ;s9_ڟ [D(N^j kzH"M1y9掉LRJJ1P}@kc\ѱMzǔ@oQ@؄i1X k.[Q9k6!^›!Mߦ*#d1Eg2IG$)-JJ!bta' &m_ĝ ^ 'Y^mvM4B}+NͱAt2J Haˤ4RiqP;=Xj>8vIC6̇go 1~aM5 Y> %4霖Tϖ,v7' %q,M]1DK ̕v%\`"n`%bBwkI`^_Nho;&ɍGڏNdӺ]UknJXQd#l`jf! PS&V/VK5ɘ1[k>|n{!/eUG,pctNT%-8]v~ y1@G9*3q2#=Bg6Fj"[WQ*<(I 8K];VS_Gy*͠pj:a )| Yu  F1"<3 ?"rbo3)(XZB.ܵOqW{3w$麯ƣ?_h\wBi "JNbDD7.]{:"R؞k\ "ٿ鮡buںߪm.Xx+rjҗ:D -"|*+!>1füe!Kui."_|F TySL (-;@j^!#M_4/} b8[,Gpē H9c MsP紮z$ܒ$K8p8c0l.x^?.9+0󎶶XӚn 0,~I XU'q4*/rmo4fࡾ?;3-_EUv2-Kv8pvJO4oY ̴`"Pe]_"WYSxP(ZF}C sZB@zHa6D^su&/|%~=`6|,괧P+EFrOIi0zgPt!9̞%o~B~y}C&Z) +z s? 7k?5 |m$X-.42m/M/N2'0+͠):R%EuU ꈭ~eb  QX09+ [gi3mh%d;9 Hu[t$@dwWx)-0LjCM_(>UZL17/YꇛQ-7[lxQ%> BiZyXT3c7ͼ}X(M?c9FZVI0)k/ns$ܢӻZX]z.Ij]0UΓ}/3xEgM3V^NrZ(i-wådWo NKcS}<͋p-4́ޘbY^F@NFwH8Xu.٥20H9=%`I]D*:{t ~1McUB#Td;>y?lr]~ɶ\-K h[fPCrZS8G/c#Ich3jTϚe] ]=g)hҮ_Wvi6R͏kz#m8[k֓Xރ(0CѼȃiy{]jEHO ,mH|0uOՂ-*n)5>}2''e9 V7(+z PHI]*&0BKr$05Mu+CQǍd5B`ҥkk&Ҋ% >]XV kifKﱖ4>2mnx 1% N_;J r6.3-$Zi"䶧jCUt8 T]FoD`x4#BDeV]P'@ָqK,+MgkHwhsn9.F`?g2%a34]qCn;COxm*߈S1HiJX;{JoxgFF2|e6QTeJ.O,yahC=X %SUQͻ[_Mh~RG #Xf ,ˬnKQ]^DUJ{@1 Fɍ S0qH.nYܨ&<'9 dNg9(FRk7]SWv?LV/R' 0Բ ΖPŝ,-]>D+ԿԶ!즑 }+지2'#]*&Og|\ =2q<_I]_18sKF"k o{VI*gq'OЍZhO?= d>mͨSoZd6n˂dvK+*$_dcFQg|`'^ U3ң%N^_i&VQ1$gCsML,|D6z5A] M(`O4u4.?m4y= c4`VCewKb`G$7x1Rgo6\gN[g7~^a[AP]9r 3p]1`+ruci^UxWU(څnYG(R(@H Q'3Ko{p|gBuвM.qyq3+K^uců-狼fss`'R*Tf=`*vK/BR6aPc)L'Isak?[J).-,PI9J gZ's։~1O*6q8WNiͬ|^ޯ.ihb^m8t空L 2Lzx D/ `!-,F !TN,nL)4nȴρ su>} Z#KЕKe>R;&~ 40aqYLJ~˹Nܝ)^^|ZǢwe74t?m{EչkPGYrJ>u?*#%% 㙕r2/:oe%n;՟hiS^[Nd(\߂9R5@0.%Bf;{[D%KרAwޠ r+7^Rg@h@fPy'y(T}h%1g ץY j){R+^Wn ©HV)=rsʺ\~-5lcN_a`([_=^xPegzK\nbP\4\t^I-kI[ 7 ܼkxyjt,:YBP=!KdwL%΃25ȍTN&`Q@6_l- 3N<d NVR-d,e澢Ivꠟ;PeU4yXACة׵&rf80Qrv zM[}EY(ouEОprx+n@X{}*鐟=qxѡ1-n -o` 8͊JQGpb`.WW_ քQn,{F}>8es gלv#%.&-n)˃s0((QIn(O<:5( Pb[|2C)軄#9~n"7&)O<[YPZ#6"PC]܍Jum9:޴/ƨq땭r *8\)o\A5`IxU4x`ޚR&;JCxCc(Ÿ|&x@DZ>Pbasr)!5&@wځz2~zbuOH,R5֭}Q H70oE wP jQ;7!|b!݉0ZDR!3/v:Y{q7Y:sl6H`&| )LݓR#I IBpE-ͼlsەp(m-pu#hmE o%UYnǚ%!)fnvpd7cPjg:; ג ߥ Ku6X)1ȭ >05zb?\Klݼv(+h{(ETD'\!liDe/[nE9e2@ 3xEI7hlg\ԃNAp8p;0t'Kst{;ψ~knrO uQF4^bvaM#}rPXb؂C $&y7Nxi;X9au'a3n;C4E ).}c]8EZ]ȥΐ壏ŭO\zVk'f kl7XP]8Q$M mmΥqW,%ܬ^^ rLzcLP@ItLۮpẒ8;ߟ &sΥZ/hIJBϑۦL% ^ZEHPҙ8$9=nblDmii(jq#.'6J^O?9B8KέU%*`V%6MjfT!go9~+ry`'l'ONGլ3#rOp'aikio}ܧj(Ҹ+f n~6_ޖZ d!=IԗKLųQnS Ȟ hc fRyDZZTBq 2NϠ-DHUTVf+\qʀ2gԪ"yUM(3>[;O'OXJ3ylJn;A>o:q0;.1`0lj[o' wb60)0H|i Q9ᅫ|5$KnL?%$ޗI4WX}X֎kq{;1)dGxfCNVp1>!\M@#pPWIBG[b;LٟwYHce:U5 g̷)1lt'-uV8;.s~8: FXU*V E;Ӂr)us:jԴ?, z(݇7Ӭ!lHb@2^ew0 qߗH,2Hˤ}' \>wdnEv@.3<|Txy.?=଒X)N9D0Gh:rEyoun&yzPT UG$XaNlhx;tTd%J';wD\qm`y*-B ˝挝Ԡb̋shĤo4PvY%nHϾNgrfl!l>~ ;[ /n\4Nq6 ojkڅ# &8)lMPj"=Ӄ*&͠B.XE/FRV$mF::A&eW!le?>ʁ%P*j(('8D Ugh-r%6Qbe>jlϾ/w #(y e﹨VZvAIsFcT4Yf^a LL`ZGW懲st`:Xj6]hCMb)zrC3P`Y, e^H{d Wvp7/nP~X9z1Ko3b.Se||q\V~s5ڕt7{`-wtD uW%#1~TO~z1u qf~Y2E˶*^u:1q`l5ûs.X^A7^*HSKgҮ4rl\g%},=n7}_b|)F،sEd7m>u؇ȡ2J|.CZFw!0$ Le71OkÕTcm<==Bi.i]o":Dܚ.'?V5v(ecp8-TRo{"Se j (j٦^vJWVayϨ}jcX#a5f~癷 @,rὋ[XXI"5nquo#Z:-jAwS*g݋p+u^0%}pIN`Pޗ[zR̅?IQ|탬a;^{I+HI /x=~yW9KYU6 ?.Dl@~֠S nS6^O>lKNx<s}$- dH`Bie1EʀP͒#6c^7 A\Y:"{IiBdr"ZKXO`֨ p>\[T2&~NN"dVS7S45ߚs7@msRR]Weh ~YI#*&^4I)  ?K8 f# ju'h|iZBՃ@w'6|A,.3lPŨ !f?eI=-ɜVxr' wk7_Sh 7*L#Q,tZR^ =&%uOT{$h>R}y-UEճWixn?n˟ɋ,1!4`m`e$Z\-PZ娳KꬽryL@Bt^G}Pv#`Ԣ79F>ٻ\K`*FO߽7.Û*Bw!3˳%Rka/¶ *ڀ%]u!<%'5ȨDFn@KFB.$_# \%}CgCóϯF ڹPvGE+ 9޺cl4 y3Om!I Ir'?^6cA}t*Gŕ\]e`*RG "CP:J̑r<\Ua||!KzJ”ПZ$"W }!ۼ?h1¹a(j[p r]~NoB3p8pGʨ{LQ*2W05ɧ^2nwz:PF(U!$.NguEF_Xtwu`)Nc-Y 8+ZRf ¢%T;H: vҾ)y$RFkK:j'љ7VTP1wt6ښIO,6.a^*Y=EIw%U˿ǯW߈)Ȉ );F}ټ{ٛ=Z9yxơsoɥZ?ȕ#+\Pvx| K|0iYmm*"B~Ԇ= #2-P(Qs-?{(gY~7g< l8۟BvI|"NrbSȪa" 7k4L)*lV=߂(͟QoW8dQ& U|AjVj*iXʊD%M璤X-RM~T+EvǩT!讥㿈 YU'šl %%Uhky,Nۆ5e Y"y=9Vpu~t*6]ԧD[t݅ԃ iL$Xθ0 G<=prU*D?_XK af]k {3n!Ar}OY\ g}wl~źOH{?ҢAձЧ.k u beSjA8'[餿I'r-{2%LpN+dn?>3QU#cߕU]`!$?COEGtxԖ[Dj'Ө};VL %ԡ* [[jQ|rZCD! <[~2'ۚ┠B1 St<|MʦN>D%8 8xX@V$6`Ȱ~~Z~#LVe4䀯N˦p ,3?`sq+iN fcPo6~/1t=I܅Bez+@N:v|+<UR5BFCH%I7䢿i4,n,3NpVP XuQ?;|zڱ3N9NcUΕ wcFQΒk΃KZX7UrIJ%F.8+xr/|5fqQ+c4opX3(^s[X~b)Lx7o'# 1s 2dm3= ~A>i}!x4 yPC^0(UF@)(&5C޹䤁ii Ӫ-r(b$zj9eQtpg5#AqA[V(sp \,gXnj^,xL^BsT#N&mœ9.rV;i汭( LrQʵ9k]FMn~vL}eV܊N1V>R( Tg5Wn*|qb%[l{tl% |@'M2>?<06%{DaM!wchM&2,hi4b @:~cPTRʅAdR} q[`S}3k˲&_&KuLAr`E`bǗu[?lTfv4ORk '\ ?o(bAb< r ScJ|(OvyG#|GP#T2;,=& 6e)tq;ծ)0m)%˭CVUY!(6A߻2le}8?LNqN۷҈'n4135rWVG5 nMLA[*KKJE7R/7²{? Y6G1xWXk?_#G@_K:T3_1я-ŐP % XEOGr"PՕ$ 7ISed5/v}g1ސA:)B<>w;ۛ9B7jfI(+%=MSJc.{w6&YzÜIsTj7Fs4(e(FnrK 2N}D(ʮG17 M6f+L}anQu5?n^G9KmΓU^O4]s4T!OpJ*y?fQ9Đ؉Bc5ye7o {A 8 Xj`4t>,leZ%ϒ]'tWuk5߸,M[Q^Kv%D-Mw- jwob$&)bqWs|yJP*$VHD? })~A)`關Kw "pM\@Lh Bm ָk1#o)D(fJf=(STlI! d}4 :ED֣]FMe`Y Y%u;B^B嶌)֌d_n ˕WQKh$*5Cˑt$dF2I~LL~|>7ge'KjyBJW@1D?O[*4bh ~٣uW⿁[*3AyCqlNY2 1;33d}G{}ODAgu"oU@rWG~$!hP*wcYS,uދY ~n? >_8\1%+!W.zѯMr<irq+S*ÄyN&pmyB Cg=F TZ-JѠ,cPOs6 $|bunyV*[֓[*ͪFDrr*lb}kC%tgnEkXZQAQs+S;xl۔aϭ2Mb\lVGCbudU$S 8!}DL QFL0#dgaFx7wK`VEoa0.l=BT4^!kYVԡlYcyAqڒQ;)BE֎VV!.kCk8s]ySr^ I]* PE;@ʄHd,ѸKrD"KwČɌ{: 3NjQ!ަ0m9crML?GdCt쀾z {D" fLRx}>Sl$8K:0 9#ZYܧ*Kb D-$D̐ O#ԺN}=L?쮰A_`hVd?؆[`}nPD'(QX{LU:a'HpY@BOфy 0ȳEr*>qZe[h灘{0H>&m5N M tAzHߎrkTV)cw;`IkTuwIr:Faa}/lX2epl|nPvt/zQ82gޞ)]a&]L g6dRʉHY0UbOK%4~d ( Vr[@E #Ao*hlȷc9&..Vū%^״VN?-ac'bz9a}1J_*gG`ғiݒnk۱_+n1^ٌTi]@ge 587 ϕ s!%Ct:H\0$]}QRGer|ڹ vB9Ei_ ҅ЮO~&B_+ :.48_/40k!Ǟ?C' "n_2W&Tm_5_Czs-,ڽ)/n3J# a~r^:y][w<4 ̟-ƞO+U4P!P EfgoX)5|83z屫\`D糡hI԰3 ^.>^TacP@"^Lhkh/ˮ2a}=KKK2vzbo| ]:֠\Eښg䣄#YҦ%%Fp0&҂qY /]u;)%$.{sȾ5A+y ?8_k*3ykU6 ): v)^|BWd6 6`I.ɓ"`G{fsdթ)]7›_$sb‹J8㝜 ,|r%т`g|Bma SԎs4S낻A!]pb80L>@}ՂGbMYѹeTY#tpZɲtկv0Ų?dt;Woos6O o<+@8NO"sڙ=ZuvAC /CshG5lE"-"2d[=$zlU{sQ*p﹋ysℤR]0nߜB7o-W!8N4thJb.~6lB#Q[%nJ"I6;?g&t ) ֢lcF0Lɤ : 9XnQ3l[LfcvȊCΎ]iV~?;ݞH'MX|q)6Vl "iߒo+usisl IT iݥlN>/V(4"DU$ y2f`T) =:l[_AF&t O.@ss]6:P[lό/Sge}9 Z%[y<pG#s}͊{xjY.?F0Y%!8-З(TJKg{<'9OS[^[#sugsp+BndZlGlUF /^˨5cxĻ09[6cr^gcj6tԛ0ި@4$ڑn qi0v81blQY[^ $e'|t~G^W6Hw oˢK!SskSp{OM͵]p4f6D"vM|"Qcy2ԫMD0bhWQu ~gǚU)=y2!9kE"JiiX %rCry-;eU|/Sr>vb0,RS+g . OH۩} :k(K-h3]#lNxMjn7gDk*kxWH|k)[.5AdB.Wji ϬJkk88xxW,nB+Dn=(Ωӕ#3t-P[pym(sy#iL~];OjCn] lb”P\@Lz  @8XD ( յdq['c[wxpȠO_&*E˸Zvf-Ee`EE /%XGC$îQ{\#5.?^,sȌIMzfAU'/VBmVB2h,S"IǯKteYąf%Y$2$޾kk(`z0-I:޸2LV]YK_!l/HTB8!pl|!n8Jci>E5Sj'U3<:8GFa4D˴ '3JLPݼմ *LP FGZk7 < aVh~ ɲhwzHs]ֽeګ̟%ٔp-B2Ӄv UA+5"h"xkwB(՝j%?lAf\Mz^[mWȈ'tP1ͻq+XrM3Jr]Srr<5n1sLAy.PixAt^!a+ Snw4y@bҐi ^l|Zxn~`42g<\y9b JgB wHӵ-c.EqCN!ٕ .KJuFoƷJ(9vMdٍZ¢HRIf gsTuk|c$5{Zsg*D9i7Z_M zve8a }ޡGX>㣺-h~!&W]APqBQ qgZ6)BB ~o &xdV46v݂(0ɝ!Q}Kdon6 Gwe\i(gDZvYszCIF[PZ Et(u Rzy*WǥM`zGǤLFX }rD ˤ{ Q雰K^ɽⵖOpM{գc*\^`4wZ sP1{-ATJڝ)bgj(^d=mVqJ#<{K Zld+R5)m[RC1؉^xhG.6@"?}Tz2)_=ӠιMw59ƽxRnuZjl_x=]' 'Z(=5lӌ`:+|?'#9wV*.pۂp7ߨU1kH pdHqŋ(Xp o'8?wki,*Bo"4cNՁړ̴] D1eLMnز24I ߛ9{M{"qr5}/+(\jQ?S UsAY8d,$3]f—\Xay!CSf'xϛc`qR8^fO}ԴiKiŖҝRH)&~pHOLjyD:Z_RF3ǻG^ASV-7bc%ɤ_:ċowh<.N &Iv% ?Cz>?O_%~'5Ω;^2w~ f"߉qdd-Qo=/* 0GGiЁslB)W4Cn-<܍y(馱~Z㐃S٘"u". OySu#7\ECNrm-ȣ=6mm4MUx|5+U`L; LzP2CZ51Scac9$o$s$D~YW+O0AWu|A3N? \/G%+[oU7 򭏏 ^;kM0U vėY!tMdAeZ~A1 0?q{1,^a}qޝPnpxp!\TXPbv4\ (eꀾk4rƌ7g(Cf\"b n=l:\k*b_~tR"9iOf}% 8ڧa2oGp[={؊/S۲J-BhW@i*Esy8?.?䣈K']QvejZ a6/^昃 h#.WOn AWQnY-, Pz QitK2)@ 2띞|qBc7XU־/}%(ni6'!-xyM1alM#khМ{88Nv1P;⊋D%&Y;#Yz/04ZҀ_f]`V,ct2}G<`'}N˒LI=@QU TmQ=Is!07nZZs .,_`zԉڄ7Dkft ӴCSsU 9I|u+_|zz4Z? g;O~ghr2{r'P%i7[]fD\jTaĵ\P!8텳qI?;Ӣ`") W@ajrf- uJs𔀹!=|񻲐pV#"̏:'ՑNZr(}Ʋ}X9&J;`0zSCARCD=_ؾ_mo[?c!bj%ׇG.LP !3#az:;1u,5ylM'VfA=nL5}2eBL؛.f{YBAߨ rԟ"\ʭf^ŵkՌQ!iRFRRO oHj3l[y b9#7>$g\Z%WLG˞u,4=e8<P1&tFXSCֳ ˛`hŒ22~mR9k KB9Z`M̱%.@(]vtnPS.-7 s#f|[Ѽ0gSd%9 ;/~;J7p%Yuۿݿrl?kS@dWj8SKļM}gsX7c^toT'5\/\8ƇQ''?_L͡l2&G-[avqPSh?!Yl^MB/ĝgi_cr3K'<\weHi)JKdB`P"7;V,]L>ŵM`Wi F &ͱH=nǦ:wW~s虯vPɒ/*7Et'ѱ3)$"{W^v4$ N1ThqTKWbnж~kuL5TS뜜`t]zڌx€0tӸ`NoB8r5{൲x}@ K:}IҺU @hȒИu[r]]c-AΓO8?k^Ⱥ/0\JFqАAeH23*. NUFaiXLUQjqpv-ž[m58Iik@O0MFf\E){:!oTqGQsMFdԫAE&4\@ꁨӛnyFg7u) a𳸮_!!%\dp#EMG@bM &$ۇM|plZ:Ub 7H5oEX [0&,B29o6.[6S C@" WboᵋY4 :XӺaZ m3 e:$H8+[f3W)-QJG gdRgX3W6 tm'O,8{SWI jn>ͯO>cA;'fM1UI!\_I4ǕoSn;&㥴Mܨ>R ;"zf0Yֿ!Q>t;k+$@4K$g/7k 8 713x\k\w7:ii ׻:Mik e3tAxVCj0 O-3eW3QV#s e*9n*0 3഑ML1 =PɿS2ѯ_}lD !Z՘T{0m"?(BŒqyto:Gz㶡Ꜳ=56?qQj=%!`z6PܭDK497zXk ؋AӑC3ST+j + 3'=tiGfHC$IS8xR'烬0w<:~;4dI:v (C~(J:*bgRt,AEHճuQR7^O'ʉ}C!\l4UǸ1tp}9 &VU=ֽO !%gH`@;yn,$ &S:zD 3=,5o5.bq,C,JF YDԽx@]в[D35X%FLb8$,9tAQt?Dqe@o!ב~;/ۛu@JK4`5p== <.+[3 n9׭y5{8E]1ߋ=E=A71(v\Í!V`?/"4nRȉˬ ,͝~*m!Xy'MrYàj75? B!{JNVK L [åN3rPKݐON3ѷF` ^h*?pe/}trk0Ʀ(%b6_iDwuo^dq,d2sS%4Ѻ1p!hPƥgk(yhaJU(6>ӎU㾦sy] |-Z lS=Dx*[N%|SnfRJT%n}p[;)sZc*EX K#H-y:k>L}O05 m=OJ!? $fh 7E/'g-@!zK=WZ/d Գ K j|Y# ->ޗ@|}/Q 4&t}xlFW0Ђ!6ola~ySg0 4C?5a6Qbmp EՋs!ر8!g\,+Eygaz*=Z$I5į @/m +Ih"oHo ܜXT{ď7H. KY׏t45>MfdcXM&5lLm6ϥL<2 _Gy#8X䌡Z.c =OM'iÉ(#YVy=KWxv*A".! s*nT96"ڰ.)V.`ѻ%޺E(cQJώ|aVд۩di##R~CLV>BCtkBV&XPv*nvl$p6fs^}>yldm3$=;R¯]yٱ#cO)!e/'#U^*e5Mp#Ckp=B?~!҆-R$/g78~ ϖT|>z}JZ%8]qN?s76 /I}cSO A #;%I 2%2+R.ݒџJ.ٻֿUc|UfY0@h/!jRYE[NKg5'Y#<<=sN էGxDKѰJ>ŁK9t* @R/ Rwv5i\e6kG3mwG쯥G>i8p@2P |l|8Jq= $E"+Ov*¥iiؗ7`N^-o7nƠd"Sj+r7D%veZ7J! ;DP<6(Wv%3zL{aAxBov@'p8wҖēDD1udt -tVbC#B|?Uk?h\5,MV:$3W?LƄjHtǩsM@K =m|khtbxe?&(+笭b~˴!(Ci=t:r#sUƓ~9 0r;^ԫB-_VO-HB=4ΉvD`!vxt:}J/G9# /Q#QʙV╟E{ݦ9XUG36r鷨semWCS@ BmԞeѼRu,v:WM뒢FRYI,g$ȃ-Y[uS)UfF1(F0\ \d\pq$q,5@kYm}hZk 2F= H&QZC-f;4i7x\"):\L@D`i |F- =xR%LAL+f|c̠yFxd@gNsa N2/2]<[zw]A$Egk!m?s9m}3Hh3 WOJf>XP~|S'm(aG~li+i> =иeY(| Wl hZsUy3mFsl%DŘr{>xbym3Or B A0e@Vb$tb_s=ᖌZ_"hXLIR)RGVWF\iSMF6. 7ҊIA Q|J8 +*}q9/>XAU^Dkl `"dEyoe0nd^ȕwZ_^'&+Lc l4fǎR~)Kĺ-#]zʓA~r^D^n͂4dN:_ ҃Jn\ICF*Pu:LL'jՌznzJ/#!d4v`h`RWLX W;C]+wN% `[iYCḔ(6IXBf;=qx0^"V}a|]h4A4hO@|p/OR>ʻ-QbՃjMYfy!B2$i{e=x8=I~(\Xzovapi_Ĩ@{EW]|*y!`x+)1I)T?MլOfDzڰ7Mg5Po fK `Hz('DQ1[4ٞ6wQb7RMcauK)FHЈ1UbԐfJ]py7h#8!lHS}9~] ٢~@< UQKH!. ˼?MITѺm{uL!1PxPOvۤ &5Y^߲eJgO0o3'u \C RTZP hhm*Ͼ /Oq./t(#$*<;SGQ4 5bGXROu3v?%=mO|հXۙvKFS;LZ`nP/gJ,kgF9n͘c:3<I8 09fD#BJj{A8VQ=ƛ=׽9bYrrWt j SE%}6Aǥ8tWzn@'aLe$C ^:|/$X%˛(0)~trCo~9\JܟÓSnAiAtq3(٨5a$b Z)=a 'S:n0s'9\} ܒ փy1g P/ | =(l. 4hB r3Wuz,&? 2%JULϚ$'ow"ʘ, R?ub(޾SBKrpy9h~m[-j֍9h. ͢LsS)T~A>IP,5_r LSKMG\]#/ii m*?11FSpVEYIuK.͚2<f8xJzpm)x:KŰyDwV$Kж>-t +4H&Nj0@P g5:̣@w<4sX#e?i>Ǹ:&h *̄k׼$lgވyO#5|ApmMi+hH^5[Å|9U]9ASoc7YUN;',WJXze+rRrXCX yyr g8k_=DzJ'\AWpR О ,WL1$>ԄW}򯺔96w% 2_M5o ZCWᒴ q:Ԝ4_C~rF8lKC*BZ>7,q(oJ5*.ʔQ |хU*=EݒO:0f֖vpBE8 m#uV|a4dq J+$p0ueq1˲/ {ĮA, aFUN3C(:;ԠϾv"A tm$!9+^qA2ZC b l!OjuNn_,;xQ[mPؙ2 =ƁqPJSTiKI&7S&Ɵ5{YS&Uo)}KQ6<M%6^ճ- KUȕSq|G@[g{ uQ{t me{_Bd1⊟J4$.:_pn2{gǒ\./V9L (7lWu~V<]GH1ދ|W7077NtP`uvުc&2C s9gKm:]jEW1j)uctuFkD}A`Fծ瑫?W}U(WUISXBx_D|*SMC`nc?M#K47 X MOmyOL&5,*^2t \~0Ԏ44ѵ#Q`uwTL07a.EF%HBM͉1\w`*`~iqQa4ǵPޮKGGّ 4+pʏ+}Xy:͚D o0aP<[]':&V<>ճ"BwBw6G9~}|$f#dtbEg c Kb6 PNKT > du]OrUj׵FQ44'ܦkq; W߭ ]n1:siɵ-=ɼAb9)*?*iNro*nݯt.&/ NA(f+2NOA/G;#v)/0[ƉN`_Gŝ\2}8SƥbXE`<.kGm[h:U>{^Hg✇8fr""ZɆhL]/HnKR.h 4k:6$f8s˷C& :u7B: hP!a/N< `:ՏP!פ1NkĢA9t8>?  8,k#vGHB{JsƓ!=^y&4Q]?M l~$5]{F<&V^JA'sU ^Ew=l`s~2l J@^_.IZL9ΕiZ֬vUQJ =KI[8}jhjCtv*m[POVjHL鰪_(K{!svOxع݀^H!DyY&q\]}r[dp0&9xmcySʎXr|+3ڣ*5_*yUʾ[+9g򿕼ʎQqUr0QV:d0]Z1UH͚E-{=#m]Y!ώ3E-vq{{9uӹfy(m)k zQJHGSon&_AK_->.9SBaNk1Y+40I!Kokfk0ԩΝzDP;$0r6KCz4U֐5luĖnӻ+!U%MJ Hg8.V]*&F%Ϫ9kmVS߆y(}"(5H(=o3ivFA EQO`cQ'\sn#&$@/j@U q\U!NR1T)'(/U\(B*`(f -bw.Qj}1gzםޙzĮa =vQ͗kM8(m3+d@Κ]inుʹs:dE*@ J?.}cMQzm6 ڼ> wfPhQS$f|vו-,VʾA8Rg"𼨒gpc xCٱ6sǶRZ"0z=K{*_r9hb=Pp;e怃D5'^Ȏ*p0ؚI^aC0 s㲲Th[ӭr֬8!pRo8rQ$,:ъNJ{pV>&1%z}KȞ<-tӑeM&Iq3ܗB6 ˜w24TkA cc9d !+! s&@_y>"k@:l!~:ui&lv 2kOFra5sp,(!wz1$TJzKfl~o5qjs1<CXSšcn&]⽢Xuk8y(z{!E7yFr<$=044I/X}OENV Yx2QFBU.͓Xa$8 Ï\}c{zʑ>D\!;_Ӣfv +z 7cx@wHί%:R?`>ZL&Kܩ*dE`:Ie.HD/&fEw <%,HѶ)}}mSad*Ha`TzXyV%,.CZh;u9hXrCiݚGΰY|qUGKvs;wQjZؚX~l.iZ)N$^i1pB){s0(Ê岈N1MԠ9-ŧvtD\Q&8ڷ㟧ܳK8LNnDz a>PsyT\WaCm9os3Ր׿ˑhmX?3 M{*(e" X:?\]_c >6? s"w̳ɮ}2!SnbB9 +PN13}*kv<ޱW&E}~iiZH}0Inc7b_QC詰 Fv^ݼ, >zv(cwTζ"?N$.^;iq4F&¨z{ qrNڝܚi IIP([;.Awʈ?";Yg Dma7 RG+ey[ʜWaWRr8x14xj1 ~ T˹|ߡ܉ԐEҚYj%+TRln%zVŰkO"O}𴛨&fOr/J >8%"e_y+੾ }pג/ ${WPSQm2Fp֖؏b#tgfSR]څ/fR~1K^s_aBÞ_})&JT} .aENa(<4 ~pq_\::M!ul/yLN l%rbOKL(cy_cx,"U8R ShBylZqn_%OD7+J~Rp ߞ?[L|V"x9^squPJ,Is*K6QSTf">3M\Qn} Oh=тi+|=|=Vy=۾,1  =VEky7k0C(4yAj;?{@_g@$J8ǡL`!q &t ySK@7pO|'3H dMa _{"Unnt"s U$jA'Ä'^[~DXG%ӓ hpgΚ )}~q}_Œ]'r,znRտ1[|`> ^zꐭߣ'vMhG_{^drr\&ha0If'b>ޮXбD)uz£Cm7tւ iUY?G,_P<' |6Ťg)z ;<%p~W%4)z(ޢ`tMTTu snőrrgMt鹸IJE^r4Wփ TeK~IYޅ fQ,r1* !hs~{8b!uD\|}kDXQ#Aw4POMt\f4QOm!~>8]=u~{i~Γ1WŵimǼ ru(SQ1c9 V{m\)Ȗ3&kւ5?`iL;[Oəe gOI\gF)|/_6$ܪq?*δw\ȴ^ktEZxCGsr 9 $њRں|O@ުFpQbx3xV-lDph/Wbac^i ][ 5I[d nSZȠD G[ɾ  D'IBPjAO|JD\!qT}!\,s*tnxc/p"̚4֩_-n o{ijk7*?nMXvn$< #Ȭ6IJv/J/gkOQ^T!PCVd(n }ˤx{C*]C[O~4 <k XfGd9 8IXr>Ԥ}=iӯ("̕e4dNGØG!nfe_G &tct9 7AĆ S ~dz~荄b<깇Cᣋǩz+n3]>?] Y7 ~)~eϳxt~x?f-1 _!>FGNڬh9睦ELaFVrAdyI7p %-V]((YF?$^rsf𳱲i7z$[`7e%W xY3vߵ 0-m6N}} 4R9yIvt-$] A?I\Y؂_Cr ey_D5ϧy5* u52M!_ 450>HtJщ.,_)ƶwi1dQ>(e:5U@D% b /h27)\̠xn%6n=SN \UqRyph=omTMCqj sސ%폎' _Z("f!3wI,A,R٥eV+OD7/FJ/̦䊾y뚌_6l?$iMf3F$ ',8YsZH~:rHૉ 7歽rDx$cO 7;$ Zyv z֬3e})B yIڛ$Xtw'9N@= )X,0KC({2@&#@Wca1 {}:ܟ<#r9F4"#f{g JmYKeh_$n[5֠ 1Nnσi e}rCiI;NYR7U|%۟pJ*R鶌aEߖ:? 1.xp&1*?.G:O㍉?м1;w)٥OC{=<\ |@ڰo'\doT:yZr5Ok?OiVHXcց5f¢~HZ'N.e2=lL A>ri\#\YsF: 6 gM:^쿄 nT ;K?[>?i2~ ߁>&OP=[vW?/ro)TOoUnnzINcZO뎑 ,^^1l#N]z!V7m KŊM xk1-:;f|Ůgp 6MYo XMOwI;Fۧ9@U-Cs$yFvǩp({^l1e'H8] e"KIہV㛴=da.["LZ_JO#gy<"^$ `e8`[[;x_*i,›rq=9`e/,E9D~rmJs-\&G*9 nnkC3 J;uQ2fڦIgЈ:%b5?:3ub;V,ASV;@3``ంME 形Ugks>}E~k"U2b(kHʉ$A,QY#I8;*[wry.CVeuPl -_V;l (X`RVa.n*}!56YK6ЏaKUxg,N7ؿ4 $E؟yߴ% ?=O"z@-`?qk֡/Gt3ʟG5B Sf:NlUW9b=o!VNMZSy27Zz=KO}cJ Gqpj`8U% ;Zz^gGh-2//F2|l+; {&&vmkKVJߦxqbW]fa9@ \J@*R/p-& \ouO)z?U|Y"`:/Mr1-@+y_$ /T0Qe&(W'@ *01DGkzg$P[&zZ3qrCeZ1cxb,uIwEs (Y#~A?'fnj\ǿ|93drR7_0dxW:$mmmmmm[a 3:`v3UJb#a}g>4Tň: O9gŐk 3-P'ImB%$Z;ނ}`;2-z?[үCSǿ6# cvxC%=":~,X&P|D1iu>Ԧs}a&?u܂VRdtfv%Os%^אzE:yߴb4H=N`IxhIQHbOv P8 jG,IX7?(Ư=aXi롩74Bnƕbeb$IM=!^_ԌƖH?rEL@?C4< WqRsБr[KXtHE;lG>~(\d.p%@лaBbY.||0v6QۤQ7]| _^L>dPSz``"=>ЅՆ̗+5?2o9#c 쵈8w~Ҳ.$r pP5^*"rn$aDs[Fs<U397x^Z7񮬈{joEb5҃#ubBJK)Q6 1{ $IF*IG/s (=e>`}%rHRu 9,eF:&;&ӕ) 6@,m*dmv?IKS>S8oݣ_)七w*Ŀm?*Ÿ1p6M,nEykzcK[0. sW]Z ;%SJQjm:m'Maη{%H|!0v@̊9/xqniz(+}MK MjC/?p%"]Ԇ ,cQy?ɚ;dXҙ8v2ѧsU~7l6ʰKnV9RjX=}i(]_^zwQ w[3 ns1n0˜=䰍uAz-db ϬEO8wP#F5dy`h4IWiagS&&Lnޛo-[ZeeyG[n僶N֚Pj7Nwg_Ms+lam'  "O>ЛTp F[c]|A2&;cA>lY9t 1 tRkolgKqiRN1j拼傪AC5eP| |&~kQ uwpy/S x.ٛ_f|xEi̖'YRCӊ̻+EQ%a}cJp,W*c_ݯá"QѺ&pP{4a0@)-[m2=7[(ЈlD+NrM-HEBBXLk`# }%(XaMH=ïʑ*qǡ%7eD$7+.,Q!b5MHs)x+-%3xF D@|@5qG~Jف|,8VAqY Þݥ{-w ؑ X.xPҕ¨{đr U==٢u b Dž59.J eT;rfWbVk'Q4*}8P3*OlbWf^o~5[e˛V*"5~)wxr\>L&BD׺1jI.S>HߚE=\[{ A~- Xt 9X'+1e!SJ5)39~rfNǖ&l%ު|Q}kG'K^ϓz-[/L7vfN j8QtMFl3m+;E0w)fUe$N؁hjO U!<"8PB`FBt ȟ*3%9 pPʕ@+C~/#L]s!~o,=9xնF~PVGYO!x C.óASjB.J P5Ԫ`8RA@/6N }*Q[ `=T寅 Cm_M!@P)m4:AbA՟AO=@`hCOj!Ǩ˭seYy0Ujš5km`tbJ׉ qw߿t8SvHS)V"BVlofep+ɟMLxI *j5|<(ͷRn6Nt*IŒ `#V{ ^uH'jğ3k [_a z.f-G5 zl(V|S(x`nIoDs_AԬDx}t­[^hzbp>j HDpp?BxPHF=.nPFZ,CCiC@O"W3ĚƧ8+oB@;#Zf*% H*=T}=b-u @.G(¾NTݰ3OQwp0W3!4({^b4o~-a‰LQ3PCC-󂌙Qqa  Cck<;ŋo-Uu!PXsNt*S Od{.TPY\QS*QHЇQ/(FK=)K^%cm,02Za\ ծAl>+ ݜ--gqr1R2g+bFH. Ϻi~Cskc=Nћeԑs2oف;fl#*U8i&6uA)$FwLlo4ki:Lgl4Ĩ:) m)=砾Z;ےH)j])$(ӺSo;`6~vHtp;ݯ9HdҦ18(ꓽyYW?kS*L =L&_l[ .q̓C;%2b_OX&?2x"vF .+vNBĐP-#%Ǧ_\_\z5~1#c_Q>7;p [ =f~Lvطds9O-'Tijd6yzh֚. mPZ7R\&Bǽ 1 *JN3Ca8 GZJl5t֪uv92jpHACcq SQ&D=uĀ_%ڲpաl+MlzֵΈޤv 2%6y*VJG,i7bE*h/^ऒOɫo6ql'kaCh` T_ N0*coG:8a¦`C ̮oGioGR?D =\ZM8i6V?p"bi#*I:4&Ț|$ʞ|+izHhE+](Q@PǩyeH,GqF!i%k)}򇂕!ʅYby,3~QݲԨD }0w@l0A```#oo_tӄ82 ^kotĮ !Bw׍vMEsWP/bO&+gQw8PtfV i4HPZ5wO64<ҮcX^yD,lTxL L6el5C+.y)wu|!EG(=L. 8/gIR%}oLi o`&igTU_Côz$CY%/a{P`.i6t\ IPkY3XovvJsҵſxF@K RFڼκQDc*JiB,N%TTzΆ-QA]Xnrz-5Y5 8iΟczݿp-*棥C{qe v˨͖yuFf5kaPDZH%&ЋD[ST\Ck'A/':M"Vo$e#qݕhj$}P&'؛r?CH 2.C @E\q.QнiFPhg~5Juh&Zyv&FNI 4}z}qt&jJHGX %r3DѬnoAm`N6TzKcqVO1 %z̙n%=S lc4 (B'X8VNp%_b1ʇsLJ8^Ms˦IiU_??eŷPux/>WXOo,&kf4w͡tty).cW^nq?J T nh/(kץu7Wj\ +jg%f.^r{4ߟIɵM<~XWh \L^z}ޞmɚ&(S='Cqy~tsi˲0W4]i eٔ% r/xolA4V{$ZE@R }['DrC';(RL3J仪yqTIwh-ą%`|Qۯys}8+Cz=Q5MҘ- X}ls賩*}.Vv;{wŽLΟ[3q>G^yyY˾ߑImr4B}(gj kج:8qXM\k94:37MfH^ӬfNՊftZXe25V n#-~ǛX_ Δ[!Krz})zNV)93QD-g;0Gj9`\Nzq~EG)v~,A7\pJS뱑{@3Uۃ{9p2Z#jpyScş Y7;%j-q Ώp#"k.?98"PXL%cs4AVCFnX.!,bE4k ,xhgVM'|'  =٣qJck8-nQpb $fܼ:|72P.ZhN~4o.$>.l0.z0#,yfn!s ;A82bTλPt5ߤl) i VXS4R&} ݙS\p>fbRpW a~}{>̬yI>X`sVIi JaZzSɫHl8XO #*`tme:i2C7~:SaGZwI:W`DEVu\6C?C3 װgghE+ XXeKC Ml:yNʼd,a1%~e/?>\nNeu4[pC$ϱ.[lnTW(sr#M8? 4~\xʒpgdf:Q5`b/aʻ*zٞ V+Y4x䵤;VZ+&U͸C-5!$yƧƽ2Pq;s6?A8^SK&^x夹cq aU  (w1p^)mP+TcOvSc3f"?JOF ;iu;G{8BiK5C QS[oOggajws*ba%o!~O\[pP 7ӉXQ {U\A{;fl[{'?cٽVyp-mA!Zd! vF _ef(|V}ș|/`Ds?"Mc}bE@| +`lKdy2lw݅uѺ' mӢK)Bkf}uǐn9@Rbqy+.3+Y j-|6Xơ Ѥ}F}:ؐud쩤* S\gѿbFIS!!7hLJ;&ϭp 0 [޼%2}'KnDFV|skkg6ST9Bx! "Ƿ]\yxWi*ZPb{=Dg@aՔ&X| I0f\q%7Qx;V.֣ӚGgH](N{9pF1j:75]\]KU-'X5^fX"eq|>5 %Ճh0 2~\gc>%'9@-;1cr9mH]tXr'&m ⦹QYJWEց#hkV,+ we}/\뿕ksyRj ЍcJwu>z)?'X-P<%^UǹK 9>'LO43h>{"hf!jީN@H Xz3ڐd]r;O!TN\*H9uVA鍆]bw0QAJBj*UCf]>7Zkd*iQ7ȎļQe |[?ڝ| *eIv9qNKD TQDŵnQIo@M 6;v,5~$ WGtѣKDRִGK(vxWPsJ@(SV3%PCoymr'sK7 Yc\]fyH6^JEdá% F>FvY5P2?əcM\#}XFXRf.'+欂Aw s?ɼUQp&3m0ԣr=Lj4O6-Skp.WªZ."w=ofM1-KMjX;ZyOI=IWN@#ѶNNzАA3e(WdT2|Etyn]%+;*+{LWNIxOu@"q=X;fܦ/Gߟ31e'fZhæ /|&2`*`KaΏrCLK4$-_NM}w\+ TnM+"l/J,Rer沫Ft#OҖ5?R6( 6"Uԏyʖ?b͏LJ][XWqV4,Pz+|q,w[q3f3&UO[2Фi%|\ù5]~ ǘ 5=LXS!SӚN}`ɛhnnnaXx k1{'0VJ1 Pe]W`AVCUsp[$[bE*u0ϵr3Ś4u9.UP!]W҇Y^_&r&qyF[Q>0r&}2n8)^Ǵ.qlaHٗVǡc|~MXahU=I޿8a_ߕm蟒4O͢>Z?U[ߩYg=}Vgn߱~Q@aX%990XXj !(;a YjP6D l̿{4+:=iu[[5D}^wo'K}3#.6B\@|FigT^b i mzcoW,ίV%:SDgm"N8K eoyzKdݙ. eE!eڗ@L\-3Pf| ]_/Set-r#I^S?iUGf 8÷8G%lnuqB#baeM# ).'sEAmwa~|)sWA0IKXV&VA!BE%,q|PAMnV6Μi@,(:Ħ>JV&`i%` IG YO XJcR&{9XTLW'h 4*ȑCLV7Zk%4/c%,D|O -/t)Yu7+#̠ 6D)=?+ϙ'ȿZ}o[V鹣gX tUlNU9q_Ze$StoN)daR0nnvȸG/nV¥PemWڣu9PV@ @t.ᚋЮq&jwb91jb;Óno4OJL4Uv;_hÕ wq/HrH(ot۫-L6;%ޝnzYm-piDtjӯENx\X lA&BViL'84&u%S :<Qffd4v(Vl!'KhP+/]#w%ϊパG W/Q.c-_4ֵlai*LSL6%*cubr[AxJBꨰ)?VէbEвeַT˜J&'{YXNFwb8$s톉JL1m7$[/H# R ҂G胉AڳOffveޝOx-sp }KgQ#p6glZuffQ 2_u] R>+U̿rOVLk7kg"gvxj\h/Ltw(*))jR| <G(9"p3;UG`_>%UJ,Vm߸#YJ:KA͓MzRf.8copGghkIC٧J^_y,3D{QCO\ӆ8kM=V=֞e^wY3pʹ.OD++% Yw.1___cNM5>mJ"9 6]GIn)עzKl^厾T3Z>УA5q4{ AA|y hO)Hs$@R=B0%,__+ ᮖjuaAK/yH~D9|o)[͒:h.sa侌\F*!mTBpb9k!^gq2_ fhdt XKw2z&M "E_?6bfx3YDx(-5ϰSڗڊCGaZi#*.\5v-x $s-ATsr蠖FcD[dN]ڃ,bMbԝFx`'w↟ *wbԨڜ\07:oVEQؖ)_%w6IPPyaC9 CLP .}2V}{sb R Y+Ɩ&CLjwxPL- Ύr9?|nW:fubT,Lu)r49ڨtKC'=ZMI߮AQJzxq7Gn)Iys6aZ $I$I$I$I$I-IՑRYU6XPP"h:́P8}frCnO!uU-T5Jt{YWr :-q~nl,]=_(q4p Iݡx|" aA S~ /Phʍ)?|li2GG^k#QcJS8MVV1M<J8e붂MCf񆘕;sXlS&X.GeFD"'\a|uGG@6";G[J)JR)JRFH:YcVS6tJO9߽!p? B\q3ex$I$I$I$I$I$O.m7m+P[v?Lsܲ4sL; ~ qw8 WJRpCǮѢUx$>ȓMźP1wt <6of!Xqwʒ~ Of 2O*うBziƒQ:Y0Pl rS=GX< ߣ?jY=X fTUG7a|[xXh7tPE63C.%7eI\Wi2۹u@ m`9lo3%(8O zYε 1}/풕Q联za:Mlܲ׀q[oLuR~QC WތSG$q^f[';Y_^HC8m`M^0'dEq{DM_u9%+~ոVQ?O7h?8a]kDue4r+X^wWY8-$I$I$I$I$I$I<wH-",@eCX~ՎF)8tVB<~C*:W.pÏ%0Q [Q|Ttұ܆2;[6-ų{Ã*Zwll{hsψ^GYsB\IY]\#mY-2\6[wK2dZҴn` fU3ԽE,mMOAT  5Ͳ&2#ꆕ#r6HM x/4Ӧ!JsE$!KͿi D\ﮙ+ *N5D!47 =3H.r}-^rjcOjG,,hkࡢ,I{"$:*]VUBr6&WJ&e+'>: {Y}}_Y(aQ D.=/mxGpJuG0|D `SKS B/ǯg16]i SX2#GF1uc"ea bqt(Tϣ1]3")rkQbqfWk so\;xzRd)3}RH\_▤w{z@OhPqϸabOl2UqW<J9jgCv-C| b iL)qRm?v8H==$AM ԥ7,N#S0sG(BBdO!Y'޶$ό_h ;hYHMȱ*sfem4fL)\*2kɥY-pIQOxstI[B?2v`}8]TխPxp&#Brl7zz ^&"" gx[CKJ:g/9ɍ2A\}L@^훕~}6r?9}\Ү]1%R TFkfYNe(LK 7WU ۋkJb[(ȇB",١~;y2g%1m|]8w5Hт} =_RCIGq x bZGM 䂋| Y3~oZ˧μڬ61z t83&9 u_²P4_ ~(zPK>0>m GAU[=ɜl-Jy8p%[NV15ŒHKj+"03T)N`wL5b$#A e:чlTq e~n6g^ݰQcYQ G;cgڨq3Aց=kDz#֎y'IVjӯ:Y:r."iQ}JZuL]%DÓ|QC7s OapQwD !)ٹ+ߢh>B)D#[A)Ces{lт֘ i8RwLnC1Ux>=g)= !e |ѶYZ$b,Q&R7=|l+Iˎc[ |zQ키<2ns(>M1 p Prl.!~ָT5KL/׼.`$S)wFh꼿GQ!n(L; e@\wtK¦=Dp k^vW1]8/sC,9@NnclWE'$XC'S7[,1wG+A|:Sq]s֫Aر =3w2QB}Ɇzi?ey X4%=Inx3ԇb,"jzZFA(&UUTvywN2PqT/ѓ6zR_VU^ݓi Fmq*t*wfk5.& Q+Ԋ]M}etg p&H dP@Rot";4BvJcq#gKdߧK27nCVΥ&DI; da'㛼,2FjivDMaYBJI*3wa9m}FXv.)L-;>; `ߖEgg0b}[nmjZ6/@HkH2ZC|X*ǿ ATJ qL3T,TU2uj 5d kaf yF {2mN{p*5l2TG^? M߆I|47O C>~v߆4ak?1?w :7~{gwy_a}kT|O[q'ptcb93s꺕Az-Tll䅃+.V^gSui#ђϜqv`B2qgbJv{ܹIRA7& "^$j㕳ϱƛj=xȄ#B.CibH{XTֶrQ468hNѱڎ^d$Y. XRT%+&|Ťi|2cK;uQPyˈ5$i BrW!6]Aog Do$Q?tW'ߣ`Xb/YVOۚt{ՈL]b=OA>nIOpq9$n|}Z,޾-m̱< #O "]eh3+^ixormWmT0,z?gF`~'@~e͂O,OQae }t4<vrcӺvIC:rJ[ǘp< SV⹛w z^v>DcfՉlpHƢEŪ#n06]|)ZCU&Piq3 bsdSꘗ%+~7v17jO^cQ5qYIl@'y*A_Zڦ;eA1__y4 E$ b_4_xՍx({^tی_Mڶʖ}n SH9>y-{Y:=$`W#$|oOS)0 @na1 (Gy&W9"n\XŸב&*qZMlI\>a m asb8xb%gg{3Z5=dP%b%\锵߂0*lHpb/ˈMQ91:̋$KKgDXpXJ^qJuۆEڶ:J0pC]jdװYHNi#>akk*lk11M&v>G$f8J0(+t |}Q[6(o]%54R[ëc-~r͈E2ƈd!g%4mpGFkW6L1&`XλEqZX9P jd$4i o ,!Mcb-"_p"膊$Cנih]CcXcH]̛oՎa]GY(#Zg`%>])0?&(q|V==7JTH<Cn+. f:>3wiUFlk G>u)d(Wp>|;a"ȺNm\Տx|lUUͯEwEJð<"W yZc!'A,8Vg8[(xP5,ToUnWS, P cVˤQyhق$Z2mtКGXð4,d# (8ս m6¶mTz+ 0X'fnTFfW!=6L&(2_^'U@>Ӆ.-H+?h du%Ө9(BzABos>MNЃt& SLO֑Co ]&R@K}o4Kޥ. >6:[} D.A/d?!\u Vt R0*WnOO#?2FPi()HBsJ^H(ߜ*GYl3B+RCrAT1Ås ,u+~$UK?*ҍƚ( )LEħ> 6Ul8I(>yèB|,;z7g/-td`cd#]"#R" "-KǖjO\v]ˆx ~E3nd(֔Ld)7c [Y?=83[Fgb(3yYAo vo>Oe2Dn._fy5߮Ԭ!_?6 pl]y^ETvK|(hy䠎 0 !_1癛J bh{,S8 ;0BZpLK |6!CDE~, g悽iSi.Q1 >v 4f qһie FPT~S_ؽHhּ2c2CO#YzD [&Bk8^F0 ;`@KhŶlŵZP,|K^%'7_I ~||'d-"Epmcnt/is&槇tPנ.ڏvD],v8b6y^$g`w͇PSdnƖYߢk|=Xbueސaax/W'[pa$Z) V3 }H+$+OG!Cj@66m$'͘ ,QkB<@5|D "q#7Y Q>LjcysNRC@Y1)|Jx:i XƩcd\:w$pY`<ڤwmLdW߼$Vs:̧Gh0n,˒DJN9](PՕGq6hbv_dyH#s"2vZhͷ -cLnۏ#4襹N)^)L^ VdS Wz}V6K7f%nt{O7Zd$:eJ"Oֱ"dG/nq;^b=8rWjN=#G L&\OUPr dotx$|è 'M@Z,ڳ갧ɇ@X!)|nۆw5肓鶃0^K|\eǦvȳNa4Fp+)ث~H v枷߶Ch*š@fY%,ihDΫ>.)D;K݁hТ ٴv$ZF&ﶎf5 2e}N3EL#k95yGϬYkYl !m5]\}Eӧf7fQYwCdK*mO_q S %^e6&;')_-@2AHg`BLWi`< 31njog1|x2{.) tV̄{m4 #vx\ӗ|@ GRSەX죷F:.#ٸذ7.imJ|V["8_.wCb} }ҋOGP*Q[Z`y_EeYO¢Ϛ3Ԧ *r_h417pr5(;aZ w:733`uM`j,۽ޕ&8'0Ў¼%~x?J9/yOOy7`z԰:y:CL|S^K:/kH1c%Au& P>" wA.7YUC[8FP= جڀLFkUJw 0 R}punqir|7N^ IUg}$ I8:bKs VYks= } -;!rČ4f!UqlPu|WǼMt_N!ĠLH:-D5 ,"K!0DpL}FfD(U2,g"Mq} lQ]!!*t-&pɹ 6$ё8p9Sw6g;)ר3{^8?^..P\oE2IW-Bmssynergy-1.8.8-stable/src/gui/res/mac/Synergy.icns000066400000000000000000004262431305627404700217450ustar00rootroot00000000000000icns,TOC His32&s8mkil32l8mkit32It8mk@ic08ic09:is32&?JHJKKDKIJJKJKIJK KKJD Kz/1-o 0110110011002010G103010.ZfQOdgdPMegfPOMdggfgWDOOPPOfgOPg\DOPOigfORO~n@{QMLCMLLMLL CLLMMCLMCLMLMQL0C2-.- m-..-+.--..,../s8mkuźʃGKMK Ǯii cc'e㈉hkh-' il32JKK)KJJKADK'JJK&IKAJKJKJKJJJK(KIIKJJKJDKJKIVKJJkPTv0110 0101~0101o-101,1/m 001*3/11010171n100u1/V1-~010&),.bfgXOOPMfgfgcPOafgYPOIdgXPLcgcPOObgfgeIPOOPOLfgeJPOgfgNPRgfNPOfgOPNg_JPOfgPOfgeOPwgdOQ_bSPpvXem~oun w{ vMLMLMKrMHrMKMLJNMLLMKmJLMMLMLMJMLLMLMLLOinTM.bH,ft-.--.--.%-.-.---.*.-+.-.-m-.--.L--.@)--.h--.6l8mk$gc}3BT29;7$ܙn*:'d`XVRXJ8'j{YՋHypWRob+%u"&`u2|=0QMhإsunT9#zi it32I 9PJMLLMOJS?  @UIOLJIKFR?  =UJOKIJKMISA 9TKLIJJKLKLHN> *NMJIJKLKLKMHRD  1QIJJKLKLJM> )OKIKLLKLHPF  /PKIKLKLHND  ;UEKKLKLJNH%6UIJK JLHRC 9REMKMHPF )NLJLKLHOG;UFKJJKLHPF9QFMKMHQE :QFMJK JLHQE ;RFLIKJN=?9A8  5QIKLLIIMRN?<8=/:VHKLLJIOP=?5  9SFMKLLIHRKB4  .VFNJK IHQMC0  4PJKJKLIPNB3 8WHK MKKLC2 'PFLK LJHQ=  3QJLK LLJMS:  +WHLK LJKMC. 2NILK LKIR>  +XGKJP< 2OILKMIMC +SHKLIJO)  &SILKR> 8QILKLJK9  1XGLKLHPP &SILK: 8QILKLHML +VHLKM6)QILKLJOE (UILKJLJ%  7OJLKMIMO ,UGKN6   'RIKLIMK )SHKLILQ  )SIKM6  +UHKLINL &SIKLIMN 2XHKLIMK EJLKLILP   =LOIKJKJLO3    JP:QJMK JLLMI !  ! EiDIIENMKLK LLKNMBM[!/7454436&  $E~HOXDGJIJIJJIKCMXCkI 9700/00/003;& E-%[TMON OOLZN@x!$7/.20.46) %D\S:%M@ECDAFB GRj1 +5/22130,8 %IXNqhhejhjlFo.411201212'%i~2220109$G /420210+%N613021/8J -22021/5K b23021/7L ;#31/6G*52021/7N a03021/5f8$21/6J+51/2104#I g/3021/7U 2 %31/5ke 62021.7C /  '1021/4$[ e '421/5hI42/31.9 Fx!$2121/4%X i #421/6_P 12/2108T }"%312103!_ k'61.:R n  '5/121204"_ p'3/221.:Q xL+2112104!^ e   '5202212-8S o  +11/21/9&` y[ )3402214"I y[ (050012,8 ex\ "+06102212/8' `pnQ  '(550012106$JqfpM  ($(1630022101/3gtfwX+$)%)25340/122102/5"  io\C15530//022102.5&k ~v #:*212102.5& n e'-6/2102.5'l`102102.5' n |5)6/2102.6'l }5+6/2102.6' n u#;,3102/6&lF,313.5& o|z6+402122-6'fu5,40212006  j 6*6/2122-8' m} y%8-312107!  l w$:,31 22-6&  l~ }7+5/21 21/.8% @7*5021 00-8' [ <*4121 210106"\ w4+5/21 2100217&  p =*4021 00217' r~:*41210/116*  k"9+30102214" ml#%5132212313!QmdljkfrV   Utdljgfeh_rTA\MTRSQUNXC  RtfkfefeeghghglbPRQMO NNTNYB  Rufidfeghghg fh^LNPOQPQPQPPQOOMPPZ>  )eoddeghgidma9HUNRPQPQPOPK\?   Bogfeghgh`ROPOP QOOM]?   >ogdfhhffghficLKQOPQPOL^@  GqdefhgfifTNQOP QPNLZ:  Ps_hghgejcKLSOP QPMNZ8Judfg fjarY>[JSOPJW= Or^iffghejcKLROQPOSJY> (dldjfghfjcLMROPOPOOZ7GqcghfghfheRNQPOOPIY?Or`iffghdla>HTNQPOSKX?Qqajfg fjaq[@[JSOPNQLX>PqajeghaROQPNQLX>Srbjegh_ONQOPNQKX?QrbjeghfjePNQPQPNQKY?Qqajeg hghgWMQPPRQQPNRLW>OqaieghhiihdgbHIVNMOOQPORLX<OraieghhihedhnmmpXBRWTTNMNOQQPORLV:@t`jeghhedelnmncSVO^E3K;FRWTTNMOQQPORLW-Hoefg hidekpkWPTU,  5E;FRVSNNRQPOPNW9Pubgfg$hiecmnTWJ 6AAVUMNQQPQL\> Oq_hfghiecoi]H 9HRVMPQPRI\3@u`jegfgieboh[G 8HSSMQPOPOW8 Hneg fhidolZC :ORPPRPL\>Lwcg fjegh]I GTONRPRJZ/4n`gfgfgheeqT  ?WSPQPOPOV8  Hofgfg fhhgjjL   1HQQPQPQL_1>{ahg iffkZ,BVLPQPQOU8  Gmehg hggqT AYPQL^/>|bhg hfkP?ROQPQOT7  Glfhg fidjdQRMRPQL`0BxchgheenJ?WQOPQOS9 4qchg hggqS qvRofkfgfhb"3SORc2*biegfeefS>U^OONY+^͔`bf^jigh gjjYl44J_38RJplB&STNT&gǭcmy^`fde ddf[jyZ 4JR0NcBYHNX(fӰIJ?4}tjmk mmi}l&U?'Ku|2}w^NX+^̺~qP2hW]\]Y`[,bpٰB !{|1{i=X't޳¸zna蹽E  21wRT,&ƹưĿC Q!~@cԶµ ǺB . ~Cmз¾ ¾K,Leҷ? 4Hhҷ Ċ,Jkֶ S  _J_ʹ ĺ:  8Hwി Ō*H!ƺ P  e=f׵ Ĺ: 9Xeʹ Œ* 'Hvಿ F fHʸ * ^~P_Ϸ @ ,dݳ"]C˸ Њ   *~W_Ϸ 9 cezܶ$dDú  *Ss嵿 µ3 f] Ź ƒ  kNs嵿 њ  m\ƹ ̚  m~Ns }"   Qv\ǸԐhyNv䲾̙   Vuf ˻½&  Xr] v׫ ħ%  ;pyTٵç# Yq}j˹%˚{ Xml`  xְºο}SnbqGϲºqQt^pgq}b бºǓz ~j  ϲºٓnx~i гº½u~k  вº Ġ~i вº~k  ѳ»¶}k β¹ ²Ѡ$m|}m  вĻŲt}}i  Ϭ¹zi  ܶ aӱĺ yf ϭ ²ѡ)n| g  ݴ ȯez yh  ծ i   ӹ¸ ~k  ҹ ĵd    f ڼ k ػʲ <  ͽĽת$ey h   #ت6mb      ǝ   ǭhJPOOPPNPLU<  ư QFQJML MQLXA  ǯ OERKOMNMLLJNKV=  ] =AVHOMNMNMKLHY> ȫ UFPLNM NLLIW< sí NASJNM NLLJY<   ʫ ZFQKNM NMKJX9  àxJLNLM NMJJV6  |ƫ 6\EPLMOGT< Ģ SCSJNMLOHU;  \ RDSJNMLMLJV5 ť ZERKNMLLMGS8 ĥ B?VINMOIT; ¥ '8YGOLMKNIT< XDSJNMKNHT< ¥ RDQKNMKNIV= ¦ ^GPLNLMKNHT< ¦ MJPKONNMKOHT>  § V=SLKLLNMKOIU< ¦nVLLMNI\/kԨ   aL:# Kc /rr]S ȶ#')oT44<=:>A6Iig j1:<;3,=l!)3¦ PTos,fH !8O^ :<1 X6.'S & Oa3z4c 6Wl5T, Wp"V 3R# Oy O ?*Kv 1{ne_5WVp\b2x  n 0%D  wF] Mp  I'n aJ]Ӗ3  :qčF Tơq/4]es"K64lGJC-ZabfNUfc4_X*GF/0/7=p5U@2+R6uK c7y c" ^#lk /151 : *ʄ@ BzJJⵍO Ds_8 ic08ӉPNG  IHDR\rfiCCPICC Profile8UoT?o\?US[IB*unS6mUo xB ISA$=t@hpS]Ƹ9w>5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Ic$J J `Nzi%(1s %0'4|ҹ^r >J D\4< ٲ08@l IL3y:7ul:ew HXw@v "y"l$Mڕ}"9,rwhASَ\9搻+Eg{ 81~CH$6>"nęÙs[wjYXJ(`&oKYEǵUi&r;9?7j<C xA|%pD<橯_]zA@ F'!N_Hg.yNUeǶapLg=n4:o,CsO|*?N#+>I'HK0RqGX_q~ҟ?5Pk;kt!va J_K /@wt$})ˈBR VEIضjjGLtQR93!_BdN?0 ,sIbhG*7q%)̜9(Q_s2B3(02)"`kم׹VKW^NjVjJ=t1/36:%mBnbzTbCЅE-"IMN# hA ;+cpyeh!RSt{m!ߙ#FBg; ;`Zaq^jq~|-;SQ=8R^v J]TqH#YK@D8mM>,1Zv^3pܴkۦw2'U|8z~@3Wr6ߜ5i\3`m@n'LATw}Bgӻn{fW}w E)lG^i y(5oY7: C LO{tKt& u_PCohlz%8N:ua=–+KޣJ G`{I'PR1tٜ4xаys`,eFPFMLF0򉀑jvMo~[^$8O.``ٯB3ﳾttRWf@oZ /+%)?loc=82QdKѥ#An~_zNRȴ.i YdggᵮѺs?j#EN{I J!b;F:]"%HSU)lNY-[iX6 u~b{!͖8"{aƏ$@I'0sԴonݿzT,/J;xHS[P' B?+k닠jSXO;_}@_< Pe^)sN̮#ßaViA%T^ )jc̈#a'V;nu'q[;\eH{ |m'cD]BB呉~WuCe'/xIC:|c\"| m32IYOgݎ` St%zB^z yU_ c\3o+?:݆{S(߅ 7?jV]uyy*uyh1lc8<ޯ#2@f χ!) c}-6rܬoHvlb[^Ug=u:w;pPkdAqHT(qt7ue dA{~&2jĹeޙݾ#u꠱H=K dH`8Aιĭ)>vٗ%waQ&I2|FXLԢ!-Cfae _#AF';hN Zdڔz,4%7k Gf6@4ShL3#*j\4c]LzZvѲTC iؔM§Lrʺg`lǠJ0ؑ#leX?"t=w$f5;<иpC/D56ǹ;6@;iQQ'*&}axŦO\SoD k; !P>/􅟮uUi178۲t)ƒp8 * Qu"?mh5:f/bf2OD}c1lf(gM$*nzc3fR|ͪW '~H~Z3V1n?~[$\lj;Dj^Vr n!@㚝J=꧱93kPrEf9t!~Hv n]sՏqѽm[>JԦ `CCnQx]n$ys4Xtw^%qٰ TQls @arOQ0e5g>rJ6o*MTmXǹ/|wz^Z N?Q! &qQxԨ_'ݟ@q2C%?ٳg6~ 8P HF.VxJH>;;TJޗӐ-Qz~I!HjX5ܙcA(>Ѕ~{'_i|ȐGqNd5:Y'@Vb|z-p;ޮ XL@3:N (1g8d RE6.w.S~X&q#]dyxM&#$8b(0i94Rf DAAÃ>`@a1Ѭ Q~3g$t|`fH 58~3{(F&P '~X:3;@?q`GHkA> NuC&ȑZnpab^ &Pb6>00L) <;‡1rNnMN0ׇPv nwTz-[Oj2*{ ^Q';63Nv tx;hESJfǹS O~zh̨Gg,LB 0pI|Hq16m9į:sq NI&pQ4SoYxNKd45sth^3hX?헆ƌ':s* ]At @ ~IIH7^dӖ+‰ > }b33R?I0/~aR1ko= T8מAP{2]OCc <&@<n&"qY ?"Uؐ Q3)']?wm9^>(kd%AU:(!Es{h!/^9k?r]T͚E!>JdP̐P_,HX'v̢(.ba!ZmL}Ϯ#R -TdP eml]L? sΩpt ) =h:ПDgѲ6HZ 3$-oxsCwS'N*{I$ygc a%1]vjρbNڶ', * o Fb F$X~?jνSN]jѠ ؖ 0HF7>2 l9Pp̅c<¥&܇en -2z6Z6V#Og>-֢'rBr2y, :?WAYm4ȴҊ6Rz/[MLnsECU94)ؔݼKV6dN!6l+,vfƎr'(o h  DO_ITPX#I?QM651rlo%gjV;(YSBbeՃ_sgO0aAq'ZÍp:Զ{͍\/s_aDc ;Q= a;.V9 7[D%|_ԛoWD!IЩ2lH$h vs*.E={7rCbmRV)თiؔ$l-\Րoz6nZF6 `R4L ;9I4K`W%+6\H5G.E ݷK^e i>f ǹse5Cg^RWqI7-+'ZB}W< |*^ 5{z9=~C W~r l'&HCΚ17uPXv 3N4Lߺ_ܝJ{pۊ#J(cI7p%6Ai.v|#y@mkZȚ괗|{c^؁؅[xVfڗt{/@Rrg~=+ς:,08c> 2]7%D?'o˲'l4Zss```{A s<TІ:̖q;RQɤo@c1g j0|O./+GD Rw)MTXn缐iC҇;%c ;Xf̈!D?ݸɯwarsji S}67LLa.iKf-ڐAH6jn[Lt'wyҎt,Y+m֏Iee;NBA`^kx}EdCJ$8+(?O|.Zs6U8pȤ?N66u+۸cͳ7 6Yw/<Х0A HsͲ^#}FLSA5eUO ڬ@ygyŅ!֊Fw-$݊ɭVD1?:vifHxח9ubUE+6g_wy(Xdvx;aT@á⯽^4 ֿ9fGp |U0dy(LꉚؘP3p6(wth6F1&@;ۈ͜bM eZRrOuώ}d8lk9'gz[ }^Xy+C#c{$)kV֫wK#Oن= O& 靻B{\TFd@9#2@>].#_߮:A @!_pʕm֭w5իfbДZK @&cyZAi+ qٶFL9C"Dƀ.lB)붮z^DR%aEu䲷Wf֬ʴٗ# 3\Ԃ-&ih1(0nZbP1P1qҰ}/Tpnh\٣Xb-%}-m¦tUԵ R>FLl׭ࢱQ[Arv7kTelShhJ{@9Ar35E* 0(nRBѡ6Xeb[2I1d$@ nkKm "Tl=O_uDL"o+31M6o/C)'B2t ?zP.ȴɵfܺu EL$7Tѥ*5+`i0i%|?B!  " ȓ#OO;?+(AOH?䜄%mf _)!Ut_5VѲE՟$*XȄ_Rt e t'pLEyAQb Ģ3eshQ9 A;VYpJ`aH}g2-JDUۮϚz*0 &b4 eXj B&Զ[؞R"ED(i/T-P 2?dw$]/PX:[v$tP YQ vPOH ]0kٺe۴-MC'5˞pp!9c[N&v]gGVǑ&T\E`L#r2*ȞY`-` gP~ +WlѐȖ&JrAOJxL+2yj6dRU,e?W sl2Vܶ!u(A *^gjP)SH/TXU01UbOEK(:!c㎬D[_ٴ:~PfʱBB# QPv=ɷWV$\p!AK&-D1;RdQP3 yݴ/ndυ2:`/x4m{x#JB}jQN$b.`1Xt$I5kLcP8 E0^+_yP^ )=0iO,23a &bд3/ɚV ۶X("ْ/3wߤ嵖=.cro@[0. `wD52ȸ@>)it?/jmHHF{ ʳ>ZL I{Z˖?&F"iSfx+eJki-F` $$>r2f*tU0?Ņu~'bISו |-D@fcg888"!Xgf@A7?PvFy b7kX .UlM422kpՓZ0~E#AD#(}::tdlCcW{jʿ 9Pݾ[ Ay3]p冏:s9L`JPK}:|lzQI %;7ѼBw,&iYk&':ۂ"jg2@GA3c cIs8 ? ?u |(RȦfZIzYАѼsrCHXYgIҳбIC8 TNP fV @ Z_pB$;&#5k_W_[j/Dcf'b C KA ^bP0jnǃn}%/)(qJȫ{؛Xw jTU鶝V!?(_0 4e:GJ6v0@#oͫC1n?,f:7l2`bcY1ZF'nʔ-jȩ͐;2u0h %Qe5:t-#;qjA/*Zw?=8?EO*ֲ_ؼwwt[c.vЛR=i~-B`a !@! }g`pcRVb1*@I ~" W_|3ؒ;v^-1H0Taw!j>sB$ßĂh>+ʇ^x7kcCrWz!1}2\- 3 !_d3F0.dڈ^(TX,3q{| 52Jōz<`N󴝗 F[ڗ#bAɀWznПȩk؆:hwDҚԎ-u 'udxڣ!+j. qmT?[Z ><ɉe$P6jDq $( Ub( .~!-0 mʩ# VK;@C#` m!毸 63x4˻~ѝ 4߽զ%?܁#@SZnB2 j}JM>@\h.ʿ'(Y rS㲙f9!ڌ*GMfdOʑnEv0*x9?@Xz@ْ577׭C?Q};`-E) I@h u=k.@V8ˋ͎ߡ?cG 41 ٜr8X#PA`ZM@9/+\yrlMp](m1KZo(5Pys5k18 Cʆ'S&qc W@!? cc 0whSCrwq<&$@ lw #ep3N'џ=z<9w;zN~(JؾLoȇ`'gi- zwnG[" `m78'4)@ΊBQBQւHvL~ĝ>['{ҟo=dkNg= Xĥ tc+9 0w,Xn= 3% 'ժNv)`+rB?ox#r@0Jqet&bem|<'"vT)(OͿn,>Ц Ď\|_ w,%Pw;L'Lwjy-װG+)o;Meaɜx$z҂Dk+Ot3X&?jUX=b~Ь7$[?W?qSk(GMS-P6P+Vްu?~CX<7c),|" O< pmʈ7_cWv84ʆ ?̿$3ո;̎smq$QZCiҧNK{v䥲~f MϾUOSϑ*+ɰ>6;S0qyO_aT `Y-6_;ZgM8ׯ_|zF]ʾc,AOD,MH?9 crc B\ciĚKofqm:QioPj^~t=Ls9'" Z r ?vJ 4 zN'G'_Cg7?ti+ocǝ7H>n/-W:oMH񳇌F;%TL铨qKu-١TW/ hu_rg( RcE ,`v$93Zϡ>c/ryvֵD ,pcYpLyL^.oLB| WucKؙie~c~Z5ׯZVk,R\CWG@IF00|Rp0{_'rm;3/HA_ SEz2iI26I?ni[^5${ԥ(87-_trT۸3lIu{v#՝F[HorPA䴤mP;9ء)t>zk4A ͲOc:}ؕmn; x}<4o#J9{2jmb\1r뤏KP%hSHfB.P`5ly%+48%-ڍqxk[{r  1?to>(d;x?ȵ7_zƂ˱PF9Ks?hX"'wyi?YӕB}~¼] qq1ҍ iR۷/_z閇P4WɼY؜(f/S?՚!N3ψNFV!Hm%[G=1L X3şod~YΎ5@6 $IK #cxȿQ fY1ۻYyѶ. .{܏vw)XY^^1q\A 4ut \ A9٬)2ѣ7Eο#־ۄH&Gv_(lIkđ>IDATl/>PL c|gQ^ A=tvN~?Н9S{Gz߼3^v9M,0%]@n wm8 ?]3Qa7mƻvG~x6.e .G_Ͽi+mMPEBalF]e8 KGBH/V]ё3,Mx_1%pDL'?P`lv3t`,j;hϤ>Op\*56Ș 24~^m˒s떽~򞅋Q|)Z>;U8ٶ:Q! Ӯ$@䴭gؠݱfyAm 'NqaN:qvCM0F6e\e}wtJ@9Րkg3LWsMz9b$!4W5PjY'~5:x&$߱pC>ʇl(oIrCGv]vulB%ɗ~;fۜ=rim׻3r#+pO)|Mg*KZw#! ,IZaZ& `_ n?H8(GVq͐Pr7,|Uoҗ,K:ۥD|/sf+G^ $:KJ]sҭ9u"7 Db 9[،@<,7%cHoyYON=xG"kF9)"_K9f`x.,} @JE=v[p3鞾>@ZZ`ϭV)/抯]z tα;x/wIUbBCY@u GerCpmKKxp1RNH=sz֡1ܫS}"cs7&pxwvU)$J )}/g n!h kCNEuH/"Cv.\S;#=wzD]D3v~/NJ6}&}odg̵ mYO9#ub-# =OņV u8/L!UBe153D U:eNmyH|$)r ue`]=P?z8FvE,Y5/_<~7:S(kE!m:|y=LF?ewzv(̀ݏڠK T85Q>8.|VNGts hL6X) 0/͇{r gR\h+`Nw@AWJex``tYڀWV\+M=`t QqϟTxxӵ9(Q$HqGiϐ$J4h~4H-!9װM8L>!u#T˹66RPBu['}ch趡#0,QmP ][CWR81Q$EFnϭ|\ˮfEJgY^Wugd:N is!҇"I~ȂFFi|@  j o6nF7p ! 1Oݗo9$aT@SԤD<+g(%3ɶ]Aqu >ƁgYރ Q @x9)VƭG `ـSf=f7J m6=~-tq Ʈe=tc ;XORJs|] WkXfSRqSn;HAd#F 'W`#l\tb1,) %|Qq &C_”K&jĦ\C7 (;qb[3I7xrSF9pTFzp0%)15Q*e}y7Os!619IDvu$/p_)1,GX5R\xZNIuDnZ,]C"<|7p2ak>lqe5ndQSӵypSlԟQoU!IT4 j.B@vynocHF6؅RA e\ r/GIeSt=e?vKe#`|R$-ajhՆO+<ϣ&sNk/tyF}Häڊ^QV8heKU(@̉7N:Z%Ds+mj(9gW`#|) $ $DZ4*wȑdaYZ+Т-. Q]ӐXٞaeh +P' 1"JXWAHgS *ZU[%Px IB!/G'͓Ͽ uPdCP/+ei8 BW|`v ܡg xZb޺תΡWL='eb X]=.ȍyIpE7g+U?H!jݡ_Y)S^,2i]I Mnўr_P |qnRk?I LxQX#ҟ@ǶiٲټWv< Z2?3 j8J8&mVw6\1ddy7ͥh!m軒RQaifA 0ι9_Cʲ?-vD- x?fM[v[.Qxd]`"ͻ #aB3(%}ۢ/C1ֳrŔyW!qZ[3h:khJu}2ǰ Q<yHY lkWX$$"Fv" `7cW9%hU-*KKM I3jJeÙ bBAɃnmE8(UFV` Rbyc" :-oƋ\?q~tk82=XO,8 rF*2*FQ8Fe< ,Tu?yAS) o,5U ^lbpe? =~ 鮁?ylW!IXoڤmWPeѥ? fA@\ՋBa?8_,/]Qsi 2: f H:ȫ9[jug E(`[#ab$x_\kg$Z\RІ ĚL=tçDlYĵ; ~ l 9暻.Ъ!%I<0%&PPɧ1ZMBBk5^ֵ XrJ ~~Ψt{՚P?t^vWR߁0(/ DȱRuN?  M0d,rr_B ܐS޸Fr0ͨ &O[ǸzH9g/gS=褽c9 M;um]W3y X.V-McgG?LB*(}FY߬)N oTtvXCciL['dƢ }kdV/)tE2&-!Ԗ2eǂBk)! A֒}GtݗLh3ˀ&<,} FXFrQG^O+Vk*Ȓ )y?y5Jg44/i-pw:/Q!^P9%ȅeEKy헆L4):@!<⇙&DQ}9Km_7RpdV}Mvu%2t~f^T7 ܫ jh:-uѯ٦: P.Vqf1EFT=D1wnЦpiͽ Z`&@+7KGoCLC_P߶G'wfj`PJ*b ~L@!'#_ ^GYl,<5`YI"Izu`CLx'n}.ŵ0L*|Qwj7ba1s5zDsڬu($3 m>qю'o޼hWB] Z(pVk!>vAY8lĢHuh`urvϦ/Y􁯌3rJ8QȻ9/x#1@]6F^{۬{H۷PyMR!pj"^sddL˶{?"t\Pᐨ׍R#@:4mmΉU=xG,,=O't+" ȉAk}X۳x?I>鞏's_."#|o5۴m?_X[{ /ٽ31Hj{Isa]6E<&v^1vL[E<9XT&AS>A |O<A( yg;C/u]Hz)JeaARl?'UR㿔 `6n4W$<.Ҍk Z!%"Yyp@f!nHaHc W3pG#jםvmH1/T*(vrqC!2,P,Q Ov[\iUݙi[*R(L3^lBCdFu25n/z1a0X;ym-M:LhܠYԟ]FU@?vn#3s|3.xb-hf::PTtZ?& ϕUK{Ϻ{[bՊmb iN.,OlEw$niы4ڹ4(1Ja,J(|'PZ Wr]I]S Lu`쉗AQ ŋ4@>t7-6dj2 _9+ke뜛GN9YN3b*"pPjvYqsbk=7zzUX-iY6DoF(SjY [T )^uŰ?zCfӝh S:}Ѫ4hI( u" NJ/j3yYq(wo K58pIJ/|/#]TU-躁۽&z $3LKܠݽ_]+5, 4뇧#;A+lgmt!ވŔ*l֜|)|C ]{>hZi $0' ,"Co/oNMD^.) ;sB 1W׷_UD:SI/V;̐QDۍeaD*jԶϞ֯{gmY}.1MXLtB E)v~Q=*NEo֋[(Ȩ jvf"PP#L4ޕGU]{d%%(TںBR.?EPlZ嫭]qibӪݱ .(& AH6Yfg~s߼d2 9{[Dvqv֖C= ~٧@MJA(g)?/:a7-دm]iM9@x,lxQ^(疾5Fέ8h~E!Zݶ gכQHO amĄLTDz D6| -5MӑKXSZ:Q(пaUkϭ\݆bMNw.9Z۾DM6C6 cCǝraX 4t)a ^P`"h3yG9Cŗz3bn\ךP&P`<%SJu?GBY)ABZbSI0< (ǔX<1mNٳ >k &7#gOH~&}az?9 _l9eKZNa#՗ijME=Z#sR2 #Nvf O@@]ȡ9E 4$oᦦuSfƪj@:@51xʱ@v ۿO|t2c&¦sd0>sş88^g?kjs(^&1)Y0Û$wp߷L)Uz3ǝpۿԦ: CʪͺA65Nc!ˢ['ߵcKEcFKkяK< >@+.m7}/pT݁jvbJva˓l Rvc ,ZCĈO!2xY%Gq sF D4Mb}? VϺ㱱bFļ)15S7 Tds8 2i $[BWj^zM4Ⱥi0W枛h|볎"ny]Z!Pbbh(>άHU,@RߍG6. 0p_eh o텟eg&f96h-H,Bΐ eE(-r;D9-< ׵p[[xɓq`@gˆG%X1M~X"1{ F|ڶ-p#JG()NJaS/{nt< jg^ @dAm}GUVH \yr{6z̓uUQuB ^? cbg.Dc<ȅՙ7,ēa銋Λ;Qp5E~dɠj]c6=٥}x-W=  &&" ctӑ>H=q,-M]QwZKLMbz3άb D`X,O ϵjL1TV?p=6WgF*C3 .)edD g~IϗskO Pќ#9o@j@gV1ʫx"D  `*S%Cn۫vv5)R`x#FA?n{䆊W2EÍσlk SaE$rKcpyda(EmjSP/B+ެ6^{wUpɪ??sĨӧ9RS6 ;N C#Ϝ8&:FyzΑǀ*X%_f4T~>\w[676ZKI2dII -䦜a>Ճ HMC46@ˁ tz_R2uX6(ڀ}?=/rdfU^[Cn{.0bU7=Xq'gHb݈Ζ]{0 = - @=4OR@) Dq<S$Y3n9Gj>SRL48ܣ& )^'%}E;nxE9cq$]w eTї՚>QB,_zW%?!~Qp“?ɃeoShn@:O~˺]P1<=?v.A"J.+:RA uy_(mcb?x2`~7t`eKGxrՀ  8SHwڃ:G|"[:,,]㟉LojKW~PnL<̙;3' 0_؟J0^bm?eJ͑ߩRJK/iKM K(M۟oxNE;HXja `3a?4m⾢`?Y[0P u参)Q)_Xʪ QUl|j^-B  d}>h<E9g[r?Sgj3xt5^?=`~e0?5`z. Y$pK*u& @tmT%"\Y fXھ6>LDј[b?~owkSx0\Fl + oҕy0uz aЪ;^bܗڼ:qW B0槩>MA_<&}Of -dѶA@<-/jԁ$C:@:jZ|V4⛋p!ߜNgvq4;Şy~bW4&T:_R ~Kww]PtU㏊C! EB>ۗ9+-؋-{4:#9_ n?󓵿_3?5lzXXR~9Pv5h 滣فC=ҕ )魗"ѵf|<DkbOt@R`~m~Zuwֹ#0"0c *7>8kxuawR& ~ dђ8} f_#'0t~wgU<~HO Я*@KR*berǶUˊz5i~H&o?-`#tLG";({;hW18{@~g@-0C˳֪BW>g(\̇0O:$\Pb=^!oME^ی!B> ZfxGg|r~ЈhԶiTбv@V-^[2jo ."';M#A] t9ᢼ\6DDq@|hf4 >ſ}f U;ON>vgKPp) @{Q,6V-Kb%"zo8dT^7mߴj7$J)DVHN;@4:e4WjUѾj59-1QIuHÖ`7E;KagWer} b{:+J햕_-o Ov@r@-CVvC\@՚τ.1r*@ڟBsg #>KBSGYG$iFƸwj#*~e<0IJHn2a˫کƭg.:v#0 qL HMW7DnŃz+] D Eh/P,9`O-+E0f@S IN^ZJMcZ)˯'EvzKs G*1b`!`% G@ X/#t;0Ed"K2"5Plkή~៏y+[) ` c_g m%SK Q6-{{ktG o45OO مFm%ZG+n׎@^1uigy3.nʙCD5o"|k,M9I*Z@}@Θ_L}{֝dFZaoX쳓X[9}b|A!5b4󙣎-}}uV50顕>ȦD B>P%cVm R[0׾awLkWroGF*Yr2^ГN@@BY?8mDq YRuԧw>BdW9hT^p6D֮ښ^ʲ~@ IMOBWIUWczYP|-V.'v`1 5 XQ[3d;s̙WU}1Yȴ"u1>XViM׼ƒٷ>=KT()Y" I"rEaFN\\٧j6,Pko ]WY㳏j*H[ WT̫ 'Olu>]I~Dt5?M8ROT,QkyջC_[dnS;ۣ=סߋ"\x9t*"*WP.,YTi WW!6h!#)7Jr߸ H 9k K̮z?z-CiRN!769W%0mjǣn?j8ob':`cgКaW/+D_^v۲ =nhMuD[D\\\*1y#ۉW$sp ^YQ&ӣlDE\O4ڸp( !ݟTp! $V<~LKA ӏ.QĢVǃK5]*B3GFwcmgp¤y33s-=*CĶYߝ& Y}LsB Qĩ\4}8|߲_C8ԁ]R PE}\K^yTj> }BO~h  3r b#xIʌWtQs0j$4&a$ѫLBLWT$Q7H J/ukCՖ׃,ё.HU_[$@9 VAհ qOz6SHh U-@R>:㏦ Q1FaΉ7|AIR5@WI`]5;V! A'@{N\..ƅG_!7suV$BlW=}i; F)A<.&Xax,38S(b׵*%31l #O-zQvaXOP5o6Zz&⻏^wkI/#&\%x/@{7S މjPh͔&mry>k7=ߪB#@fs_{덱п0-LZ~%Gpˈ{YXf^+_s-T>D@קƸ-9!r[2]3BcnCs?>*ԮeD|%4` :X2 pQSLPRaeyqĘ י5Fit )CdL$o$rpӶb>4+̹F_{Яki+x.+B.{L<۩ =UHcnf<>F ^e||pyv%b:iX'%8Iߔ? rw[vITVQN^dpYI"|#\cz[2M^S0[zIJ/HHȟ- Ic>彇,EEA)@z@ʶ{̝}gl ٰIv7|s9wΜGPMe#0#Pt_&rF`F' >0#T0TprF``'d8#0#P0PMcF`zB#0@# @w.7`F fzB3#03ܹ4F`F' >0#T0TprF``'d8#0#P0PMcF`zB#0@# @w.7`F fzB3#03ܹ4F`F' >0#T0TprF``'d8#0#P0PMcF`zB#0@# @w.7`F fzB3#03ܹ4F`F' >0#T0TprF``'d8#0#Ph6n#P ȇhdxc|`n0 oT#ˊ.,AG]uc]NRx=#P0PU.GbAc8("Ɗ裧?:%R- r7[XCOU-Q=<ҍzuM| #9)6V`@L^OA!^CE>9J(7*_~]4A ]| (X7Po񳊿!RE$Jvj;. ?<@!A;v^  ;Z(+Aq^{PfDQ|_xҭF2CtrHD#ju&(L^M _u̺5']˄s,Rn\\!RBJ%ɡj0p>]+Z$l%19#015tn] @n7G#tc#/^bzG/= EYs#I˖2O̤ ;L)ƍYӡ&.!5i!,PT}r+<tq8 :X)*Z|դN-:v3]vxN^RTE2 />RA @Oehk{O(`bsڭkc1! !F B '\GwqR{+H8bOP)U3/|U2s6r(mcK4Cb$7 vr$dzP/GԆi M=ˁf! n &"D|tU00oQڵ-_ޭ/~zw 8 R!T>t($42i/@HMs񟅛ۡ%c41AQ0q06ˉ][+WZq [ f.rhQF#ivst?@gn"A#h EeR !W=*6) 'nnnfy5xFzfm4c:^ϸN4Ipx&QtVx;Id<'N@@Eu:#ߠP4s,]h?{~ ejGE  uYN=̙40MAP=It#iE@?j'nj7}v y6 ;~xLlj;.jNVz~i9] ,Ҙtl@rPDRَyPЎf1C*IB"D\O֎j7 I{ĔyלpsNvTd=|mB;Z$Ksw?yW$_.5DCy"&VGbHX ffO޵t3<#A? 4,e0TF(Q_wo~.?^ֲl):|Vvq?TUK*1+hK62@OĆ~h5ҠQz'6eղ{Ȝbg_uv9D p̀3\A)Nth/~LsɎk1#y=u׆6뾚Ԅ0ːA,;&`„. u=+ψ?r|Oߝ6mޏ#>&/0DWk HrlC/syk{Q>t{-bLT0!x8qz{\3e3e]\٣C@w4@B5 :a}35T6I-OCD91Xrd\B64IOف@ޮD7ڏC= *ҩ1s$ "~2& a!R+=_niny5: +T = ]y2@2$bo I?&j?Q' ?OrN\p"3tK|x; _ VP QBHUDpDA~dį :xn!§mx +  _RQ|XTw5>|I Dǫ]ptde. ibB/L L?+Vc]«޾}i(bƧ]KycJfJvA$>9wTn G&HO7 󯙋9CQpնD2<=d 9^EzaA>%rۚG.ßˡA홧*/P-LIꏈ>_ rk Q۔$,ޣZf{V0^vv=&j I(Wl1\pzg!YS5*bIRYEBi̤$0vSrsaoAl;%' s0N<'uv_gV ?vR;lg!{GIr!&ѷ`Xi`2\0(4XhέXʞ oswDJ-11>3/Ft`tk!x#NH sT5!|'t7,W ovupރc[^sb=od rDޛڕ5B圽^|qH#DeDiK>gM1L O 7wE{dLE dBe"IMg0~ _{F=豉GD @tWp`^>ȡjzimLNl #O\P?mM wyЖd[vAS0EH#@acP O"/#TﻖJ_> 2?IWȃ,oo{bX@w)vj| !M r*iOwvzZz'VvIX+Pqär @e嵤Sڧ&> Y+nY'+sr;Ai]G— ٕc\W韀o#QmCEfBRojם䞠n,#]Tum_nLn0`"kN6^n߁Qŀ N[23 8?t~1A*G\{m8ፒo5 7{Niz`ۑyZwJ1D0V!vuW^/=w4iw`iKe )2Tʿ#ߣ?0"_@xBAE`3N"3rw:,+C+ W` f ?/8mD\lIpK&jFΝy틃lpmށtjt`=)]:RVy%]3x/C/v/dro (?&׈54nۿ8 %Wq/>h~!PT.qah 9 q*j1zey&%iJ0iЈ\ح1b,s08%gudIy153 }($MXDiJ()V AH+ ? __xedy`ڔO(gcDco?Z(걂"瀐#jϖD͢ŷ4|;=۲Cu'lK1!I%t0o_@`t1zDXwiu/wcra D%G̀X 9 x\#3>_ܣmu+ b,2|'#  :$y(}ߌ.v^-g9o6o{?`hzBZVHG: *[EЄm_xq(!%o>8X+@KNZp e,_OJ~ÒڼXW&Thx}o# c%h's3"[_G]ǀ]&6ua֜5%۲r+_!O~=DHM]}c4Id/ 1AWƌ : cq϶G@VZ#B*-UI$j:gu6n$ ^BnEF}>WUS63UP.VySw V-xqsۊ0IRVZz!JĿ#  B 0 T餥$m{_'{fz -Xxa|>`[? s~3c%v|vM8j~&WG-VP󇯿R_2LL%b&߈H fzi_tF}&L*a",J4 T!.^1^yTQ1*~kj W?L!gO>?uu̽᩺}SڌxTLUO ɘ!;#b참A3CH fA,Z{쩾c^?G}@xENKƪeVtcRZ9k=%)%Xr ^@V\DU" @Uv{5H''X\: a{o}i޽ziteXT@eiAbOD&GގHP+g?W;?b ȍ"@.%Bzd>1b" " B kd92%_Vtlwe &#Ĵ5B(*r\Lu cӠs+x섪NƄTsKuM3.{Gȷz+if& ?_wN_L\L?H$ Pt~ -PJ?qtfV)~8셁n!x&˭tB=[.K;ZHpis 0i=3?o @XsJlyԀK"0Qo^eh6N߀>[QQgWU;@$'j.iZz͡k_ӺdIn C,J0e9|J6~6뙡Pk˟̘u RQ;{,`84/=i.CkFh,F@fzUE^YjR"o6u(ZW7L s.V)";>ƨkǢɚ*>?TBt?+ zc'AC6巵8'NU UIYicג?mpƸ!c#ٟQ/IA :巷/N7͘N(ʯ\EqJV ̥X@UHʔ9[9nPy9_[=פ(i $R}gQ@iåPEF(L$%Ҡg L7N Qkk6 T^fQѻ bF@RJ ->.M-۲}, +wz$ _.+^^@6F  =8IMGPuÒ~ Kly)jK۽!_ɯ^M:`6{A+֋B4d/o G|7ksCētHoMdS_GmUC~;$8b6|NJ$/ߗn1ND$@Yɡs U-lpTx*~Hc3wZ"yԹW7۲I7.fЂ"@ tsJ$DOI+:wctcִ6 mV@#3`N&Ԉ[o_Urk0StBlؐBbcS$eUU| M3X8ߌ!iCIpzjzD=%&?$*RD jPiﰞ8?އ|I aeN}W{E'^c}6]oWƂx1E6 MoqZ(wW܃L `6pcAր?&}5̤pSo,4{L-\#53mDŽ DĀ_( 2ߝ`^w)L@bV:h&m3|s%L2ʿ X:(Zsm~ʪt7=S=k~Z6*b @]JCE(@ L0gfWSR$x0r% DP/iz:\租`S.LminRAfHM@JypLmt\I#&0AɩSS }~:Jy)RRש_W{{'ͽ2_31I/>X:%rB3x"z;7#pP aȭXTQ`,ǟcޯ)Kn'z|f߅t(L˸_uqnғ᳌k F4{ "%~wjԱp1PnŪ )i*L@ *_- aS_~<@KHWW3tvbR+" J744=s"`"g2st::.9fF/#b~[L}isX)GT oPQ6b v aitX9" I]Ra 9g`<4 LXxR] @)yP~h$2SȆ32~U?+XP@1ٯ߶t!Ilfhr m 8yi 82R ! aWgfNw?cɻνvnOV4 #1 xƥXn,,A%bՇSDL$~مIYMjC}c50!3%<(Ήb˻AmZz뒩s߷D )Kj/x/p}@Ԯ Js0#?vbs$y띔:q73S^;B1p _ UɰWe|㯴LqN׵&+`!QA\I7ŌFrbI~c`a'drƔ;Tf-ihr`Th |LnU.(` Q_/" yYSϺ#,'c~:$ [^l,LkE#Li}⩕G&m!@~M `+꽉)3>2??&9ԭ%C}0?-]_pݿx o>q! ~%RyqDk#;煅'M/f<^,8DZA`Q&dKL7Mhb 0n  ( @ tF'ϦO97u5w#Hx.V@_f HtƵ': NQVYUdH`OwPMZUJ$dzOOg&;+ğlSo7̽Sv7%0~r?~*SP$P*ԣm`#lGh}RdԌ)Lͬ4XЏh&,/ wriߕ:Ϲ$8kn)1 i? X?al  "Aǐ$cOΚI>']:8;dUT*ZpI.H |3t,[ݰ.o@?#1*RB~(P`,015-?'c ljw\oIAJ`$>%51ZM @Wi p{JH%0S75cF)Nc`DŽ #ɧ\ߎY5(+xM8YgO3NTF{e`ThnOMiy dAAp(39Idӏ7\%JzTLqDr mriU ?djm+}03`%RDLԁwd? |yd$3wQ'?mi$Gj$auG>3'¥7 @aT~Z'L11ѩHOisA`فZ5>unD"H -4jxD4ks.vKdWqsTǘ(V5Jà|$1}=FL \1X>Yuɋߕ?iUs?sj~*)M,}IWitR^Լy,g-@lf9W]FkMyXS&D @1Џ G?Pt-XgϺNHe&W^_0ae(W0a(acu12P}#ZLLB.J}C8d 0PJ0_*X*þz膷Z^tK؎̱U .J4>YH~.n뾌ɗUOU6@J`F($j28Bl0(N-П} @+rA/f^|P>HKYN/W}Q蟬سpX<}gŪVI35d"8~@@uG&M7=L8 IJBo} @?@K䒭i#:#e |R@˵Z?Tf% =x~ &O@h@}_>#+1^ H"@+HS _SLD`ȉ %kCcT(,_²S:r}I? \LLv.mjf۱քJY&) |^?|LR;v D@i l1=kYc] B3!HX7膙S^%jb?^Sv6A+j)o W}(,d `[<@0 HCB@@Dڋ Si2pZ}>U䏄k9yG՟rWFW0㐬q0="_USDn܃v"3Gްz}+f.Q4SJ6]q\#pDxִ!|gɂx﫹?>-RPuk8"c@LL}iaӦ;`"@fcx# @Q~cW5ϝ_E. ﯃aj<ėodΧtЬߞQM~ϫ֓Om=?Y1ͯbJhnBz@$/NČJN,$3e d&`|!yd3H=~fgČESOsvC\)Q>;?B }e O#0'~)D^I|ղ7XAѦໂlŹѤlto@ @>i`F-/[=H$jM,oG@aʑA%Ү"*I~f,.-ȼY QJQB3Py_7M J"!iSFN>nNjKc:#~ґxM 4K/m.K/L1;'Uٽ1d8ʎ )?D3/<ȷ/`(B'괅7L[xϬ7`RŌ)&c܎*&90nN|w{$% MD[`J(f7fDR?ܼ@-h,Lzڲ/lؿG~T тA*&N)Ld^8d]|̿ T}Gb/2]@څCu.:ß@4@C]Njϭ]k$#^jRǿ3/P5߱\a옍 |K!SfIcDVI|Fvw:2J[pr O[xl YAunNRDMLǂhuX ⊎>tM|%PPG1s'˞j4 AQ6-)+$VF2;軳ݏjGƣp T)eIb8aHkU._ՒVdykwYM?XAo!8hO@V@8= $/izgY}䰵~079H녁Gb 0|AҢA0 TNf@p¸S@d R?r T5sN}h[ $M=-yᤃҩ%FtD*E  )&r~V< \7ĨvUaC>)>)LLװOp o~\A:xooFbD{!Djq}5 j麿7ȷrE "bnT(?';>~o\"R;brk V &763l\w-@1gcZ 3U66;fN8o!@+r \8ɭ^{enʭ2x+@]O!T:$,o⛗4ru&?BFgU 4cj/.'=vyP{' A,!Ata8~w2T MĴOuCMۭkA5pb-Fρ$7}k03L%2TٕȯZ.4y?q0#4Ot!2WzӉpղg1YMn3VW#q!x U>J}l>SaG cJP.hq$u^'1zW5B`2P RK2Y/ g =S3Zѯ+9WrZohVK Nvf8^E7j{ 8bٰ&꺤 %QZy_&߻Û{]$nWEߝ)@Cȳu Çԝ<=wTgcB9 b hGU!8Z֬}O?3fT!0or<@8 )U!9uִd9 n>\4 n{+k=hsˮwsҋWA*S1ABu9"Euu/yL׫vqFUЫ&GNIG UkȭX"VcVq"Zzh83=7/4zٖm ǪjTShC|rϵTj?/t`Dz~L FSnD= am={t*_S'!cpe@wj2V2P`S;C"vp&N[x-//0*:w(@HĄt*>Ga)'/'jO[xG֕$_\dbKbKE@kۇJ͔0Iٶ* @@5FhXNgo}=v`i]Ph"=x}cڵɬj$.}&?0EtqC/˶W1ɒ u'_ UlZ S-m-lǧzTf'nQL𒅰px@IDAT䨩[3ONCu?* S?;ԭ|" )aQ6ys>v=C$Hn| D94 P9aQh~[< \rģxW}Mh#4 ӊ@f2p9"2u-lP#xCVd!V3ɡ?o?ǝk|J!V $D@Q Y ]rnuAngnي6n$IdZ  [v _7Im,I]"\ϵv/;>F:!y>g_}x@(r~潯>w;3"b* or\])ͮvOH>aX:X/>Q& p9c+g;;55GJByoXa+QgB߷#O|四2}|wW6F΂zX?3i* c+HwwHUO:"K`m_sW^[z+b~>@󽕔Y&)w$!&IZ |{Y(Qu֫X__/l[<%~ BU?^ZpK{^[Ǘm|b5IMr*Є 4 `mK'/HDɫ,zlcժA~HfhjhVYN~O N_"{9~"(9 ʏ=]?yߦe/S[V%w wf?Տ|/g&/5r~b#pT#.|\Z"q.z1c-1W5P&Xu,cgSDV8PG/(zP?j"_Z~&>onٲ|˳w\SICa/5cڸLӌ{I 4U+8KWv0@o' UvUkl"G$9- W4 21|4k %e17 Ք'Ku˲jhzq)/]۟^}?Q"'?]T]<"ihjc%j͞/ mAZ/`ʠA`IH9mڈQIu&S2UTPT#۟ʒiϟ9})d[@ar<'Aҧr}sۼ |[}ՏPXי7\ZZc Jz򴎀k[ůPضcd(aG *d7tdHʹ<Pxn9̆V ?8`'uanUUni?uBz+Z\HLr03Kv~YV9uyl~'v@ gLJ8bV~}}|j _2 )rײ|3pvP( H L˭KYt5f "w;94T;rD:F䏨BRK?@cPJ@N`J-:Caz\N0BIC; )>6=FVha&^!@ADaOWz5f݁ E4}z_1g&4_w("h,0nH"-@k?b%i,/x|7AM޼Uc&~hyk$U43/축O}u > uHj"PLYMɩSr @JwJW4Ç`Rjm}mx*B17(G%F@TVv3UsĠBp- A[2GY"@Pڷi|l& i-Q1/~jw "!掂bJvي5e# 2 T $e̢׿.|0ΥhAn+w](:%ړ\63庖T,Cap/'%6 -~{*IHuSS@̟][\Fz HB qH\ 퉓&A JDt?$4N~6;fΜ+By> bEeO.F瑚b#N8Mu-:0Lc4r"E3CN_k&ⴅExaE F`D߰!q|m &/4QT65(94ѐ~&ƒ)Rt\?(,h"?+ /tYaOVM2VC̎7_ƒ4c*C|{{!r놧xʧҍ_Zsj%7\E d79ՆI@IksdW;^T;sr`.ZD .Z)6O8a09" R$Sd'Zꘉg܁!2191晔fO4-䮵>U˾MZu2Vq;B$ɾ5zEi-ZSTo9aRIDㅶV5a^p@ Er iDe2E_:Bl#34nJe%?AC*c?K,(;;J"3ş7:P|نV&MVqm1c=@_2[}#Z%`Ca7Teι:1e8)9Lyg5Pϫ< C׸4j"s<׺s- IRp2?PGs9S_+_7[O"OqCDDL@&@t=o^j[N[mH#)̂;P *)@o KÆ0CLA+wTI4z #Y瘩g\P2,ScP8nëܶ߳o l8vR8Hcsjf Z(J>X.c߳vNѴͤ'FjK ߾IIH+?b@&JbEq5qarw_k3HG_C%qwG%G]\-\ yUGse!I}VLȾW)IsyP3Kɱ=>H @KkP;^[Ԝٗ#Gj:|*V,Ea?!oʷLE_HX^>H1!j.ϯ\/eٶAHf>y"`d t Yٗ?c]0ܤ DZՠ)GL T¥r*9*69P0ݥgskm0__\?pwph_} ~1eZxW=1" 2oLSXFg&!?EX ijH 䭆ĜF _ Hr!QoζI[> 3b.0<饟_lEٵ}_!'7&@&`~ӕ0<-Gh_^j072=jfF:|q.2bw0|t5V+>RB, w5>Xz D/\W^BTrd_ã8!4Ae/S``'N_]s|˞m46 /@%j*CTȳ;ZjS;m`Dfس^Wv  1U@ӿ`oVI$ W h8^ÁLvOh氡%,  O(-@Ţhb ݔ޿ʾR,9- 2 ?|wdzKYWO621@ bqe$s/.M J2ZR~F> 4@csVYرTqtHH 3CN<#Zaځ~: O3 ݸ_kjr?,)ARດ>˖ /Nԓ2`Tu2# 7jsbB+-@7)˾kC4&OyZ&$sֿFVHvn|,A5g<:YzDL}񥧜!ۋK ^+FuBf@tm`VĔ7)P/3hܒo1 =/+^B폥SWXÚ 6 ~X @/HZq]ahOI)ލn̛{>tP8H D"e??р7d(_Gadw][Dӓ :eخ9`*"3 ֆMMb)"NpR29uug?oeO[ʗ(Jx/  >an{ː B/@fD)sݻI`1S@w ?\(2͜˖%uprAS @G. ̻H2$-- 2e=EK8ᘉMܳBhY$z {+A5C~ᅟx?/5V(8@v?< *ds7 M(gʳA?Z߬]$Y싲d] cds杝K|MxjFz(be_fFr L?e108o);Ax0]}k(BBMKaC $l"AeبU.ÑD )3c 'kQ'^3_ 3d5YCOT3e͙uR'qQ\ڹ߳w\'UI#4 #PBPdfH&M/%2e5A|Ĺm%Wh$H˪KD fʚ֔! /(Q>{[gC#iG DT,!t~ ˺;A_,J0Ge Kgzk֘ Sd[GQ@d,L[r) ap3ˑ aƿ! 3k^˾ H˚#;yn!FE֌iFp6$>b:\D\ V ڎwnri\/Hf.i& F$Vf xX5S <ۯz9;(w&5 vdhab $M58qK޽o'<ٗpz2j W(MǤ纊bnvX:!I0C4]QcCw:lB!ʌ$3jz5gMo~u劚Wfm*TFr[6[dޑC+dsaxDĿrҨzށ}s9v/#=ћ%#4[MR !M}!KUw|up9-~G^ҨIK=]ju +pR(]ꇄ/YϬ]7` ww>E@] DЍ&7?,k W/`S@BCaR0<OtHZv_0"?F7v\ˑ_<ٰZ~][x盛 F=#Y_r]8 ]Ͻȯ])lQbS@wuD@TTsizM*eEʄkyDi;bψŪb+[f_`{am n5ow mO6JF`eSwr+V7{|"rB㨀~?U9)3i1r2!P<\LIiDlEEg^羯L FLZ}zݶPRGY *Inze ޷ͧʆl蔣>b+؊faR2",< F P 2TLg9{IeWi8 wJ~Zvg߾gZ:>\*#y2ڵf~va_ yO(3Xy>)1q|z( X @Ѿ \mM,\P:#$#ʡ}3?PW-!kϯDqTVt.X5ɭ\UK )T]S 23gatX(73@l҄Àzƀkx?fRDy) @4`dessHU7>HEj-Q^0Y}*Kuݎt0È0+[j&-$Rhrd7SZ&F;&F%pNH'r;:-\flm?wjMOà)2<RФK/K/OH~0=2 -#?čhU*gT{PE{1֠i`PUvcVc/xYĺi@rZ_})O/mtն,L si9wSR) T8 @8 x" 4Lbh: -*娪v CBu-?y[=;A 8ar  lk pL &%Λnm|#a$Ge+3 UVno)Cy(f\/ՐgA] Q| P [.!ڕWZ˜ʧ@q rTE&Id`Wy5=(;v,ȊaGf5 ~ zn1bW(Y ˆ u -OI(;#;ٻOiH 3 S KM@Ek[Ϙ_m6u=)`r *~إ1M A+>0"l|U3oo 0Ԓ[ u Lv} 6Bz &Wffĝb ['^Y7^?!$XQ@ s/kh?.1]J1U4ykx*t HhÐ\ nZZ+7ѶZH/<_#/'!@ZϓKV9Z&#cboF T&g)H?_6ףRk]IoL@`is8UgLs܃2AڗӮ[_ OH#J 0bDZgw,U$ m >#+ TՖi^pfa [?U3gX4MciJ w_W,o5܀A XV21$ UUFNiXv3g }p1((N&hjƬS5_9Wy2=zЇ"mDZb3DY=S(A@NU ;Q'~Lc[U+ e8kU]?!-Z) o7۷C.2|렲A08S-1PXZ+ K4/ R@SxBI!TD>}40EeRL{%oO6znI>tf> ZhÖ@?LU5?oB>A6pOꮧ_WԌ5=@1O\'T3$vzѳ]Ǔ0VU!AfY`_dc.hXkry ax?%)yGvC{&oWD[g!8/@Z"*F$q֭պkPs(}pFqu! a)@%H$KV"󋩢eoD KU6P?CݺWWeBXԁt5T@3T SA~ YeIaěJhݨo$0! $}s#=^FŘp,ʵ+SUFpEQjBZ{|ykA/ƒ(~=%!47lR@ Rgj0݁ TdF! ֊!!*kEw_JB7$8Gmk ښE@,r* dӘ[c7tiIM9 $4vtƷ %K?@Cx,ŝт\f9 1oGD 2$#kPɮ'H:ԑ&"4٦[c!"Aް  !:<{(NݰcnH(R `2d()n)J"'}J\ N5O+/}kI H.ؼFV5f7bh&m>~vG@NV 0F%H`A d)ݾi'-oqV # fr zPVP*ejw%P-WU- @l.[gVQgb#5b"P2kܪB2'@`io \A\Ct!^?vp8/( PF@sJo-Az+mi;fZ,׀V͌^2('"/it=~_p\'Tqmfqx?R|'!φD~nl"$ ?JX矁ea1h~b-.)j<ڱ9+]<JqG6׉x 1MRJ` ^J3q.Ip!&^%pu;DikFZqvҀ ,)1 Ij PQ`8͆bjߖ uq?I1A-ȵ P_`܋_oZL:A=Đ1vR!JUa ~AHI\)7IF R7NŰ/A|OU4}cx-MT*2r{E@`Ȓ3%[.C,lW lkD$\i?w~Za>$Uѥ5Ң/ߒ$vQUp6΂C@u//F-z%(/Dck}l8fsg,77hRWU,"[ XuA8M/B%{HՋM\)p7,Vb©8mmUzY7´sC/Kذ| + 'O6c,*AJ+M\-U$" Pz3c;f"z˚QH**(m0 3\\\Z`x 7N8k-^tW 0z}Orgy=XObz | @L#"o}w*S1V)N_+&^ S>I}l(w!ohj/<y$Jz3A~/;I4ƍbWޱW+@ gD(t0ԞͫGGk''o@ @B qE$4%w]x@@ V8r]󞿭+$XA QD8`1N&/ 9|%z$0SXS2 CuC2 Y1 .| =`b7L>}*8}P/rާMam µ0* L E;.^RSʽ/OD Q~h0J!+U3|d#Mx} @I0@Q%d@=/8o}u7znf]ė4acPڇ擷KUi> dݬ75cϹc.OmQ4(\K}'k/MMDxC,yWt|.cڅ7^=|vfh=_ws<:kY H!DwG-Ni7n{^&sEь@` 韲l@>Gk4BBUApUY7: /)%k'_5c$3k|;a.V['6nՆR6eWC_̜Yu5-8- tu`#FиqvXo~ Jb*Jr+vT@y Ig|;Mt05\+TOp}g IhF?eԋ.;V@@ 0B2Uڻ=D4 ,K̃Nz d 2>%Zx2Jˡ5FkH;{Xtyq٫ݥWEٿ~#{?uЇ#uh" \@T\fT|CJ24a*^zwdO>?n#j%-y)?Hgu=a+LRw!MH1JS <D%1* ^sϷK~#i$} Jɪy~wϢEC8w}H!cGبRՄ@Ǡ:.*&lVsbl *,Y[Z :9%;A!w52J5V݆rrC!MrcJd%sXT_W+$+ɵpt Q}-'`NpT@`D5J:"b=RTVwK{}tj'= +JF>lھn־O|ڲ6ke_2b   ]E)vnh] ޾/Dې/4LYTUXtUq_͓g|4.}v!q9`nb'K ΄8 :GuQi `ް==vznv~+  +bǕ|J# X=HUŞ]ʌ:ʁT <CFo`{1'NFoKU޿BVC}DfcTb `fl6[{k55{;ֳi L͸F1%3L DGP CSg|K?"+}5XN뉵w-^4ZE瑣^֭-nj}:fyszzOuQS4(C #U轒 @8bx6HR1[pTwN|۷֧4öt?vUm3c`o<;ٚq_qB!xz2nى?~g6M 0d쎰R^6@IDAT1X޻:~z #]+AuRKI߿{/^}9eQMg*Ld:~)0`G)r+"oy(p'@o-%_rE5~9]'z;yNqY`+8wu۶i D7(u h3}* x̱2'V\7scWN l pwQ#aՒeZtCGȈ<+jf=?|[vy0vӳu*G#8Q@@ 0 m8")b bο?|7LlDH_<(qɽ9ﻏᚗLgu"\D'Ho%q2 o-unRDW%uM}w2c /n»ZeRD s o>Q6v:%]]; `A:|72#?#);ށ;7r`#EkNި=:҉h+4&HӒI`scQSLD;o .Tк MmyOOBsuhx-'H^}}vV5p"W`+a# X?TRpJ$nC4~z\{)̂B5Aibq۟7uM@wՠm87 [xC#sF_67F3kewgG~|lf#SD^)< 0D YQn?{k ̵=+7!68V>IcPŧ@@ (D/3ڼMH98ïBޱ)M]/fj?5#>Dz oDڦa*SAı*7Vi/|ekpݼwqGv>me{湻Q2e\C IIn̛A$BV U } $$)eP/"cp}٨= "4=G^m}(d5;p~܂qNR bJgYlYsNdEH78l` $e/z0}`kCr3pBFf-$k0g]d9H ҆v=~W?m|.kWf[ŠY47{FBO{b ?ys'_KA!,':{-Z-$ HV{?s7^®ʟlFDϥ7ɼg#5/Rۈ`ҺJվM{SOw_sBN;]rO?ZX%^ 7*=¢.ǥr @u۵Gh:"=7?`W\ϻŞT=E(hOxwݼ_ϕl ٟ {# BӃ J@axfvݙ`zDlCk 6Dd>? =Cnjv:_>ϸ|*B0}l~;M*.=[?=<IŽ 3h( 0;dui/CUZ׃8bF0/O<eT_՟>˸ɷߕGJ6x'#Q | ,]x)/Nl& .Rg o  yO/ںgo? Pz~f~ǕL hb& *HmcvL;GP.-<ĦξbT$^ ͉^?_s<4jqr𒋼6c.ڶmdu$+(3ڬj Z7t,9ߟ̝u?&TTnO4$+XBQ@`"/ &у׏|ㆳBv!C,UFL5P3ݱ;s/:Rخ sO=/{KlL9Jr`gczF\Bc@|aHXd]j{|%˞T맯DUbvᏒb;r=Y5? ;dnpAchs."$޳{DǩlHNzng)jp(J \ 46VfC6r #O6%#@_i}o] VKRڨ{}ߴ=rozRwɊP]D rU޸/K|6z? |(xBTI>Y*,PA5䔘x]O\'Aa ¿#O$p[TC  HGVFZp{?" JkK~u)dA8"Y)7=b:՟^͞^gӟ.hx# _cG @Y5T$I3ivHǛΡ9)wЇ^Mk7П,6/h>%%͌~hw@AbwPC5ΏY#~'aǗ_@ ʦ;wz!Zuig_ֆW`JL=O,zJϞ .לmJ"P @_8 H.K:$kcYZޅMLn>?޸ŊkpO)T}%jBOf7QeCB/Rtݳ|;GZpDu; `4rf@D k)X3fS8YVuMc!U uf} v$.XV$䌇AB42Mx z89V")[4̾ݢt&1tjK'~wºj&_k|򯝶V|Gzy&rm'ݾ UȔ.7:yөHe|[Π !/,.Ddj7߃[UBн۶1ԌK v&i8d,!<3v}W>Һ Y7l:/2U4@o80*xqDZeiJ0qɮ-E[ۛ&IGZ\(%T)H}&'Zj5"M!_SeFeGuag N\EETfT1aLtLAx1c?ر+<RV j, EB% 9kc9|u}n%-V f1Q"4{WӌT8&:.:)Gb4eH(%B:A)_En>Rxu"kM7Ȃ C`GHq6Ϟ.Cs({1HYc>l@dc3(0q|VT(qAjD]w^7ș#M!47TLG:8 jVX]  bҜԈ %ƞSf7j:#9[ڤY`Re&VV$ .6ZJKyuNR>PpG hqq@b$HS  p\+4AqG#HG ߞ|Kk"$Bvkh6^ mAd  َ wG\^?7W*$ h45m6Z" iU`ֳvJIe @a I~YvwƱŜ}vIE=A# Sp0J$b  3dgI2urEzΤ0*曓#/ XCcNS僓`aI̼Zp"T͛V _-[,WIgH1Uz}isk4N.2WeU?'y>}>ݚ+%7 D@wPt@ (;\L >ѩx5EW9 ĂFF*~˷rDTWVH@}-]՛&hTD(NUYa%] 48N9J :QZ!0b *Ko{֦ P2Cf7W[B|Q=Ffq(8q *)ğT9Q7T3Ҽ~vPycIͭjHÌM FS픣)KWHڷJ~^1@߃\؂ ޷5bcc$ ! |q*06hK`egJj;xp׵"^jn9CǗ<_jHe#ӓx(A 0Bjj@DJ?ȸj`wGL*$@Ȋ&4kK` -* >wo Vx1>d %9f|'HS-ࡍO8MGE%D0|@xKrҐR]~!`hCTZw<0XTRo'+:VlҀtpPkv ~K 7?\rݸVó#Hy"!!C-*/jT0 Pq@`!Yyn2}6X;q(Q?~0n^Ze;)N}43g5HT+Y w0 R<ݕQ@ A`Ҥ5ˮ}(Im-! '|H]˞^{Zh|R9 @D & UKF/( ʗ{Xox+?&"e&ێL;+o@r+;MGph)ct#:"li9( @(,zV?E4@&7Q@@ 0D`k9] v: "@CCD(bhMYI` p1IGܚg#f"-?'X |*"sE;Q$U%Zb\CK5W}c!agBdڽɑݵyuNeDTLk.r3~xCl\Q@@ PmDUZ'OB_q0PXO[)9   l=n }q-嘐 $`~>$>L(X!T/L0O"Uai_Edd nO D~Im;=b욨KhB yu蓒Jco?@QlV=nMSIe(P s!f畐wY~U| Mڛl@\MΉZ}֩rglNCHj_F@5 Iudɮ+S eE@MadxTX 0*HeP6$EP7p!#$!DRٴƖu͢]uP}\D qUGזg}ʃ4J-c{:Ʒ%Ĥ `A\4M=|7p.VM VCn_xn a|P  ,5sb5_fu[]}HfkC:%%iES1'!eWڤ{(@eGYPl XvtE#_1򌳿9S4|Ie.,8Akz{]m>_\P?IkzVW9Wbn4;C(#'U%U~4KUSK:6>ܽ$@mK759kz{FrH#-Vd1UQ[}Zz]av9P|l3qJD($4]G5ZLĦ/ Qv"d+fӔ (yfYZu%ʖ%D:|&uOΊ)]pqLHΌndEIE$~%"P)ͬvq^ʅp~/'-pmҖ{Nܑ 1`E~Vn 2~pAuw-nT DQ@r ߄jiㆋ n&p? N&!nRR'77%i+yV!។d?)s Z!$elD;CGlY]A͚@;Z;+$4@^'!Y#tx]Y!m@+O@\Q!?-J*IvI~ޥ֍;+ /x VF[6yJ6Oޑ<8($͐vG6w~ .yNE I}e,_!(.$RBo-@"'pz. :Ȇeɟ9No82h"**DS9͋΍ ܡ*y*.I08n<͠Sc" T&d$ (g| g[EXkQ@` {)l"[[:bKy.; aH_iZCot6Äya+,Kex%ZiQk1kx.b,eي~ﻬ,hB^("@ˎ :c^*2Jn%8 Il 0jyUjl, qaN_hg-gb"7@O]4Y[5N6)IBIXѲGVGh HhBT^Qk9z?m$ H|YSH gFcWlV.-`3 }okH.@$J@W͛W2|,<@س8 Iо'#-!@@ T`#U͌4M93iOGSԊwxa-Solȝ8=[G Zj vONLx1⩄`+NeFZ?`JC~P V(H (/Do)'~|*>9\&xL4@Cѐ 3MiyZ6A.{l8n4Z?]7!M \ t(]|(O~ǎc}+ goÅ?07z6uO (- D!/Hkz3] a*cLi8eW`j.`026(}2̃'KU hBtD4*#?5i{^̯\ ?X_@0RکF xBl! {H[䤫9ɉrκE@`~ęUCc<9 >p  J9%:ŕ/.ù O013~W<_Ϧjune캌k?79dPe Nr)vIM pÆ }Q@ BK?ja'ٓo{A큤XÇ-v.y4]^sǵ:rnc+!&)(h6buKJK6(캬ðK{`5`_mƲnȤQeO[ ݞp#TeDG@fxdNBه?`L"|?[e YKRU 1U$e:V@L޶*r&МRk?ƿ:دaSc8ɁEST;_@hsQ@? +S/)',Ϥk~@'t$ Y))M5nK7O~yӉ)H|#SU @xlN[68JQP`>;t2?OCR&7[W)Ja8gqe~p|G$g{9zz@ġ0] 삡׷UOg.?7TPT#@,3ІSv6am*3Av|G)Ha,`;? =J 8Z ,^V~tI_ rg# ѐA+B]vLpGqH9LmCتcb>`$'IK+ (E-~UrVn gRN~Ǜ|Sl+(5cɇ*MrLRu SZzI+R[nsTFr?_aɸ* % v3 vdm 겖^IR"7H|X+=)N9 {``FgVZ x E>^1gL9Ӎg\fj_^I654>`0GxZ9KO4Z:̙0qe7Hv0ُxFpra[e$ajŠet; ^ȌUY @d\8P`w>P?^_Št`FDasf19{{<%] &`$BQp8'~:|)U~BJWH .sC67o*e6dfjnh2 )x% 3?1'0n `<PaB)+.lb!L0C!׬hl)y:TcF|0a' 1֔LλnRZ|a#IJgb-`"3eE珗[}ĉwlr1Abf1;ȳMvӵ P @@ @pR!zR{NotE5\YUތy ż{zwd{&$NyFUӕg cmͫO5nWBSZlxh t0x-iG|>R60>~W0"jL 鬏X?^l9s"25 _ﲪAk_p.^ ?BaT0}Z;x!otٚ{M68-iiUͭk&"Ҍ?M3;櫏lK35 HPfT P%cȷezz4lDLE(j!OzӾ fKZUdT0 8f70ݸu4)=0 VXEAVJLT* ]s/ЅS0dj8c I'Yl}_WT)xڟ8FׅNMaoe>BX&ja"-6@b\޺ҵ7.@hOpMSuC?Tk 9`Cԓ"?xkrB4ZXzxQ BAQQq 7չvi1h QD$/O<4ay0>h  @mDS|w1 ~g'PiHH#ßB~6wn~]M4ʧfĿB#gƖoɝKHA򴿣B'|GЧ@[tåjX<  -@E>M5>Bp ']qy0Et@EGT:`֙fy+WCR,PppƮʗap$[-zSWU @ԱZNO}d?( _mdGL9 T\iC_O@/DP$ a 70@X ej :AkfR,{$vU>{Ủ_O,S̔14G1>-$H]DOVq$P!ߩ7)JoW#jID!fmC9@@+:R  썭05S+ӎ;Wj9B$5aO>t8*wY.Ɍ;/ -m|bHCgZh 9-7xaMLvs(vˀ@HM>)6}$?8^ )ADe&<ן%E_1.?a=*>-@k _4Uo+Ф6yG.O`!&l<E' `54Zq r8e=0zsv䯎x,}FD~h? J@fdbZ6omkR. )%L^J P TwX$V( D႖jf@Ηa.orX==WGߔI{ Uuܙ*k&jLL QDclѨ1%ϘKKb]lX@ވ(6T/.;s;w,,w3{9s|;jd $fn WlXBj5@IDAT͢":XNO?sN .݈W#݂glX>3_|̚G_lD(7O xQwrY@Z@r]^~T%u|dX8!0!JJR|TC]Ygyy~ScOag(܄E4(ZAv5G4UF5 G#2Es%t#?Қ3>'Cб#(H$.gQ7)Qr]@8 -nF`#|lتgXmC}SV{rF3'r7ˁT1񧕔Wӭ:Zyԯ0O ~f:{;o{PяvNhsU)MtS+_ci!c#/9+p@tC Ű͉@. ~R?vF3sҸ5 'ޜiuc4e6tOVoi_g%HO'A̹EOؒ$JHlt'&Y`<ǒw%G} ˦V_1{,Y2y A1(~\!osyঊibG ,MKC=O-PQ̄%9/4YakV^"#m@,m>p\1]2ꞕ JQX Iai2-ΰI@6tt+"owh@H㗓,hJȅu*Ad!!:GSPw3h-ʚ U?8#ZR~Z?>_Ϊ+@i3=p^/nvtiDr~c!PArx%N/|USb0@3|0b_v=~{"pƦ}>DO>Ԛbݽ*s仒'N JsnGWEIJn7e= AKʈ062/5_@@ k?{[wf2aěL@#inOw-S/uKk/lEeص-Wog?1pP{<_g7 0[)y?k>"hK+<{fe/}5 ϧsɓ)ꥒ1h|R91ߚxV,1Ꭶ'}d B} *o'S/PO uKNd!PB5Y| c,M- qJ~Ċn^pr6 $@p6#Dû iO,wZ8\+ݠXݿb3WjU{^qɚ»z[@4"SSc맏yIG2$kHfDy %X\qۜUʕO0ɫ+>DROcɴWsƜpe镭%5ՃSpB8G|mY1s™O?XAp>KlX3i釿otO%i xa,416X֌BuOl!Ͽ]o Pa nbU z LAžs?|7V3 ja;CV#&_%7գգ3ᆳI1 "ۍAޚ"H#"aYZ=?5b!HeZMa5"r.# dzP9ȶ8{cW=u{PH70#0"M` }`>7ڃN} KPT$@ Kr ٙaǑ'i dUTy=M\& HlB3h{ѨӎeVIS"FƐ:b@ckԦjceN2(%#Dl8h @iI*? ѕ;t\m;R=/q G mx1oyO>DэVG-lyZ@+#Ovm "@FC>bsH[.0sT{'7k!8= ǹ<tE{ʥ_v<lrǾTx9REW.|?}bC#"~85y` 7?3Aa HrMjgx]TÖ0 ׈!¸xEG]ãmݾ~Ҽ.9 A,D 30P=飶9–oViR`Hy1Lp(Ie uܩx +$ѯ9 l0L U8rܥ}~݄W29 `v#+)H|fJnJo~(ezkngıHNtdD67O/ѫ[m5ӭ.Vʶ4FIfsc俬o4+ouߩ+~PR ?+`S)ZSۖe/ud <_saulݽ}vqݿY:͹)U{A=R87TϿ;Kxɑ2o>rK豊7y`|{U⏸.ݘ 2ICՑ+P>G_Tos~ݔ+ҧƋU Z×(ʭvR,V#]EC/1)pl9~vyL}Ra./|vc s&]0=+~YAD @hdPB_ ӽd&Tw-Ҝ{rLl!M ے-ǿJy"՘rHK]=Y~q%C@H`R4/.hۂ_L%AQwV7pڎ'_iu/͂?aZƢ4Lc'3&  ҷz^D=~0| D5 H>w9#~V{kBe6XQl.wFh.^vхr}sFHd0=dחwګxKvT40N3N| z ߂63>tZ-02WH @?P~3$_1XGWKG{Q@oMA˯:z~ CP]FzE=6TA9oA d| 'ϩ{!} HC hqzyuQhBYZۛQ>66?~{lA>mTI.x?CU 6[{qjb۝]i(%Qpd`CUAWYßd/*<:.|֝w/nJfICiOFk 䫾FL.]C |݈>sRy0 <)~M͟\U= H>+jYC6+ڄ:G6cT$_e1:TVuxz5iBԂE;|鴦]bk[N6X:P'Ac`PXH"lڊ8:mί+oJvLT68xy~5 )>6G=cw>ym=UA,Y? z1B߰٘u{&j ymFh؅ R>zf(m׫o_M$-yۣ- ur [5a*j ܓ|Zw5f6p G:z:1v76J./dqVp.ťP7.K*@A(-W^nG-K۸N G-+[ECP2jLеgjexD>wFdtBtvV KLlc|㛞|G%B2C;Nj=髗?0_`\=ۊ%4=={xbFW'n1>osQ}uSS8Q/ D@LAwd0LJocv'dO繒GĀDC >C/Hl"ZQ6,7] t}WsWG9{-y$Z&Q@H5yY˸-L(3CAi2}p Lz񗎪=ک̄b)y/=&G$ct]<iMbb)'Vؚ#go?pm\sH8Q޶akʉ5K-P y*%_jlS:[CCZGF.aqcU0 WԳ!SNdEsH֍]-ǪGlz ?zcj0(4և3C+c1a aNY3ٮX/+[Xi2 Ys_miߌO_IR vƙ!Fq `,Jag9 w P&F# ȥ&`mDlA }-&sE*#`#崪fI[8|NRC̓Ͻx_n? &oFbS4L8OVYG_Ϥ$+ M4a7%h>"r$)e.Q9*SH!<$}BQrvy/mVr ȥ8$mHZ~VTzK>XZik(93MY,kM܊.F3#1`:a*?wӺ^P~KÜɗ6>3T ӂ/n߆ 5HYb 6LU$ :֡gT7Ÿ б20v|iiH< d.\ S~D7?E%}v{_qʮ*BAUXOǠ]a/>BÉpULo73 `w`'5oѺ $DZib]P>ɝ8!ocN"ӉxqBT *VEEMs~O%o\}ZEكAڮ5 ɯ}J֏2&MtOY1 >ǟn'P@,Rd~SOjlu˪É֓vM6M訐l5S+I]6}8Ckz0H-KՋ>n~ѳ?15%$F"C@?_S4ƖnLNMO!E6 2:fm~*cC yӫ엮J ?sGVGQ؄ -`Id_끗LzyUkk:?2i0dQ3À"S ")77ƴ+ʫdB@ /À5W1$h9zުW{V]nWT*"޵!NUCzb,HlTw7$NLIannmÁ:3Á" M9ڽjjl;?]yUPt,k2 mf F @&rv "# &ynL`6*.l*s'y-x9,Ʌ [ꦾg`p&/l$mExtOwN1!B$6,aB"Rz,z=ܿ]*S @LŶQ?2T8 yVԂL+D ) O| B7M j󷎐y0_|O}n]UǻNȁJ°A V0GbO B;[{i+n()~SF[FleZZIm>tъ\&4`'aqJh~  9DkC}.1 X;E&h4WѻʹݱY8B|?/%7nK>D?On+3ğS1*a4": &@M=ykWUw^ˎ9`3U~LW$ &+XxlV8Ek *?fܤ?=*m42]`PqlnBBӰIP&&KpbxAܣG,9^h7e<'bo9& t246Zo;B{s|/[rTfJj{]ͅ(JdlL $ lTI3$ ?la-l6{|'n/YVMoHO1&~SC?+pҾX\hx<ε j~2ZA#2o:C? (G_1PLT`` xRLy[."W Lkpk! Uh;]&BBZ햻^|yY7&A9A%n?3&,`,*,oVModNaZ, B  bGPWsIXlbIVt%O$@l2,J Wf$Go f(܊}d8zl 3Ly4L @xʲ9`+P>ɪ}];!Gw$Hn476y suySO_1g13 YϺL@h9B{]0lHdDUIR> VhuGO VXjg.r ?VgL` A0jh@ Mh=ɂ^{cr` U7Au ]f2H>y#YbJe !%IHmO!r۟ȶgf"_ @@!&`IdX@eI`'?fy  Gb"C(On.5o |rQdѐVShƊ@Xf6;VMkB0J+/|sV8_Rص/cWUwZ6+&lxl"#q $z3Ic;ߊ7<OH LWd 蝹x?)pVA |!u p,!ӛʘXV7b4YԐK/PѶ 3O.\e] #2"@/ك&>~hE5!_ԾjPv?&)O9`?f6Z p|N <0VU4ݸre]KA+#qȈ/^Q2R טX "Tb߶ Wggz/P 0@rNb?3#t 8{-q]\X^t+tv % mGyXm ld,^Cրk5ws %3OaKĕSIGUΝ]OC~2i⌸U IZ5[r9hp~h$G $[1߂"}F]GN @ou}C6 G+(q_7q+b C2~#o!" )"@ @L(okXܲ.Yf |N20RFw3 C#M!@kh8U"zXeGm'ou>|ӊKZ@N *E$ ,,lJ/@p\T)i?\nym&@@Kx#ldNBVɐt@x脏PdqK.*p4ʺ+X=}UTh?㐕12Laӽ~K()R|Jy~~qt<_ EbORV yt0'MVk4c_a)e6^w~kίeY9&)D;|\N SA@T <;m ,lLtJhOgJVΏ5,j;g0{[Δ?ȴ!~Y:Yl.d/$Œ|? ^^x/~lwArR(V{ft\Y!`Rnۜ x/wXm$&RQ<% MMl9xU={I OMaŬ{5p[ӦNܦ?j`` ٦7IJz$Z͙6fըfi4̺[18;9k~ٍCbI 婝J=\'" m$)$>cfW%rҳdFf4̸N3klGHqc]ּ2 Ae QZLIBϸ1hOI(UmKHMX}PZH`c|3Q@/Q_sC@JwN#EqN_W81S8aO7aV]lBɻjzj"o?niG\(K X[rӾJC/C1MIz0 ^E-_$wRŮ 2;bmaPrG"J4oxfeJTwIEcm-֮`_cyO:GVͻV̸o8/@*yӯ9]b`!̭ bB)x>`URT_=75zm i#Q&e_6 7`h" Ej5}htBQo|a(F̕8`K.AġqG1V2!9Db. ~~}yCԦPq@`"s 6!b mqIj|M M}GC'A5 }(ļUcuS(Hbsd{Á2ERix}?d> '̪ыR3yq_K<'N\֌rK0laG6~I`H)W92Iу]\:>TUvH'b6` *G6#"=Mo \ ZŇ;;\?3D b!`Nve^̘=w:O!L\VuhľM6O ֜@׉ؽ{N᎔yksd_JԢOz+xFڀE  &o6fAeu3_SWZ v ?i_]da҈cH 2l0XEm(>ةڞ{^u?%􁓟c o[ܐn m@&`Gx'$(r_⤼W2ߎ9RGk,!@/hJ{ H43<^+ fHR1vcS,%?iYAh `5D!*$~Eq@]HXyN\7GN~.!/RE  %.#"RBY7 ɭT=&xf||^d26 UM?4 UskxC@msTJ0s8 `Ӈ#l!܄QQ%O.}S|~y#0B}~nzq0ZOC.Ho+7YbdQ0%q $ ^o~T%*?=aUsΪFyexdZژ:-$h;o};BH <)QUF\'Ui|k$~7գGj~)VU77M淾0m1,~z~q!́MA 0)( e,IFc%'CYݣޒTm'!n8UZ`/#mlV/^RCvk{iVqɈ<~2 Vh#0<Dӊ5Ã'2[u}J :Ravи?>dΕ#" NyB!M,=uִ~v{ϯ@Bcݞ@ r7.бh"W&{L^TnVq{;浿2]Y U?u+Î3)We#@#*os01@$+qMm+=]+lPkiHx/IZaI*Vʹnۻ7XkD?Ƅ?O&O6ul 572 uyiL%%PBHizo!)R'!a֌Fly^^2u#7^w63%0Og~ g>-3[n~`@#XsDYay]lq}{ѼԂV@upj%k k"|&\!j-W^ݺ.{ZP*9`~ R#_T9\%}h5Epڱ3%̞%ҊC 2Ic`?&2d[1>X'UBOi"wl} Ui4}bokkv!Aud"Xg69gwfڢIwXK) md)7?UjoL(I7G$TޟTLËߣ|Ǒ:ReQV1k7h57ݱ6/C`*3}O(0MX݅_z} f*q`Ieն=tըo[+ ~iIr̀,0D`|5^d?)!7}7}+¯BN'=Y#NcOrҝ@TD3jx}|xG%/~CD?pm9V9~jUls˝^_/)}[ $j~d3aGhEJbʙxi#0V3C3@kr/jW^G=ܺ}z[݃YRU'SBDrÁ _}81B Bv ۘjh%9V3'.g;`G:fd^̲#δv8kUîtA #Gg $:GH}'DuMUv$M}s;?մز^t1f09蓤/aidn00(,|q$!0VHl bH%f 0iJJi1WCMOw_fW?d<Q:C!Xq%1(ň'$~Yj* S&0>Vu뷷]0m.JAH {5j57ۉD}3!)]l9yzQ\ťϷ<آW^}8Iсك16"wu&9391܉̀LJ IT=g:̪N{۩E*bsC AN'*/޽Tyn*#wy7><%Duo޷x娘c1Vj^kscR=7{m+xWWĆtH^*iowzwj;KLp{?G_sL_3|82~Xv֓@bǖ!#R쑄_P,[YUFK36?7}9_kN6,S3b] wp5'ăc#0]ZA0Bh"iNDHą rYJ)EJU*2j?ܵɈLS׻W 4UC1A!c%@=/8nO7QMlSt ׸`5HO/idLLq-W\7;+EUhח} ] [S;\\'5>I ${Y!S@e}|JռE-iЬhJsq^ڿ {>LJ Y_OMy?19393ܑ"0•k? `;v꤅>]pY.hJخ,QV jj=|VwW8nWGwRg) m-DDЉᕤz&##C>39XTiHSoh+NU^wrihR *nAx8I f|ӹ`:߆wB{ 5DELGYd` {{E:#}D&Hp'Rbﵽ8{YۇsW!֡ZKO/e>|Tԍa7S"DUY00Ƌ[;dN4 CT :AL=A AuT)^1h1Ny%^>fwnwLu;* R:|A2moK HP9:&)d\Ljlh^뎞4aH;nbt`Sޱ㮬(jr$q6l>!U'j3*D&P݄Uf!Hi)e$&&I[@ϲYoqV O۫Dٱ ɱB.}ZT%ҧaA𣂶@Vr%hRY!mT+:|32蔇;K)dD9; }м! /}GAb+ۿ?Sb1^8Ag3|gPDmnA=2kt頼~޴V<E~h]͎9KX<1=knXn{(# gT9${R' | SwQmEqZsTF` 2E 1}Đ 8"211 ƀj d: (t3v G TLTOB?5vO|m9ʦoᖏA)7'ə%]X$@!ψw>8#K2βol^ Dt:{+jY5ۺ[V~t#s;g ϦI-OW(I} jtGqx=@0d8A/a?ff Q1}*HVH爊 J&K x*5B%J3Ro|%Ph100P}D1 E F(ht1}y^dG$.yɽQjj% <}!E!cQt?"_ZKˌ#>XB|g R?Yav0CCjJo:L ѽ3*C8jU詨;F`s @d`j!gF ʱ#Nu ra\o/1VC=\|)-֒T5f So3#0@! @ (w`F  %.0#؀rwF` PP2#0@! @ (w`F  %.0#؀rwF` PP2#0@! @ (w`F  %.0#؀rwF` PP2#0@! @ (w`F  %.0#؀rwF` PP2#0@! @ (w`F  %.0#؀rwF` PP2#0@! @ (w`F  %.0#؀rwF` PP2#0@! @ (w`F  %.0#Ky8ʪIENDB`icnV synergy-1.8.8-stable/src/gui/res/win/000077500000000000000000000000001305627404700174515ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/res/win/Synergy.rc000066400000000000000000000000731305627404700214370ustar00rootroot00000000000000IDI_ICON1 ICON DISCARDABLE "../icons/256x256/synergy.ico" synergy-1.8.8-stable/src/gui/src/000077500000000000000000000000001305627404700166525ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/src/AboutDialog.cpp000066400000000000000000000032041305627404700215470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "AboutDialog.h" #include #include AboutDialog::AboutDialog(QWidget* parent, const QString& synergyApp) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), Ui::AboutDialogBase() { setupUi(this); m_versionChecker.setApp(synergyApp); QString version = m_versionChecker.getVersion(); version = version + '-' + VERSION_STAGE + '-' + VERSION_REVISION; m_pLabelSynergyVersion->setText(version); QString buildDateString = QString::fromLocal8Bit(__DATE__).simplified(); QDate buildDate = QLocale("en_US").toDate(buildDateString, "MMM d yyyy"); m_pLabelBuildDate->setText(buildDate.toString(Qt::SystemLocaleLongDate)); // change default size based on os #if defined(Q_OS_MAC) QSize size(600, 380); setMaximumSize(size); setMinimumSize(size); resize(size); #elif defined(Q_OS_LINUX) QSize size(600, 330); setMaximumSize(size); setMinimumSize(size); resize(size); #endif } synergy-1.8.8-stable/src/gui/src/AboutDialog.h000066400000000000000000000021411305627404700212130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(ABOUTDIALOG__H) #define ABOUTDIALOG__H #include #include "VersionChecker.h" #include "ui_AboutDialogBase.h" class QWidget; class QString; class AboutDialog : public QDialog, public Ui::AboutDialogBase { Q_OBJECT public: AboutDialog(QWidget* parent, const QString& synergyApp = QString()); private: VersionChecker m_versionChecker; }; #endif synergy-1.8.8-stable/src/gui/src/Action.cpp000066400000000000000000000075021305627404700205770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Action.h" #include #include const char* Action::m_ActionTypeNames[] = { "keyDown", "keyUp", "keystroke", "switchToScreen", "switchInDirection", "lockCursorToScreen", "mouseDown", "mouseUp", "mousebutton" }; const char* Action::m_SwitchDirectionNames[] = { "left", "right", "up", "down" }; const char* Action::m_LockCursorModeNames[] = { "toggle", "on", "off" }; Action::Action() : m_KeySequence(), m_Type(keystroke), m_TypeScreenNames(), m_SwitchScreenName(), m_SwitchDirection(switchLeft), m_LockCursorMode(lockCursorToggle), m_ActiveOnRelease(false), m_HasScreens(false) { } QString Action::text() const { QString text = QString(m_ActionTypeNames[keySequence().isMouseButton() ? type() + 6 : type() ]) + "("; switch (type()) { case keyDown: case keyUp: case keystroke: { text += keySequence().toString(); if (!keySequence().isMouseButton()) { const QStringList& screens = typeScreenNames(); if (haveScreens() && !screens.isEmpty()) { text += ","; for (int i = 0; i < screens.size(); i++) { text += screens[i]; if (i != screens.size() - 1) text += ":"; } } else text += ",*"; } } break; case switchToScreen: text += switchScreenName(); break; case switchInDirection: text += m_SwitchDirectionNames[m_SwitchDirection]; break; case lockCursorToScreen: text += m_LockCursorModeNames[m_LockCursorMode]; break; default: Q_ASSERT(0); break; } text += ")"; return text; } void Action::loadSettings(QSettings& settings) { keySequence().loadSettings(settings); setType(settings.value("type", keyDown).toInt()); typeScreenNames().clear(); int numTypeScreens = settings.beginReadArray("typeScreenNames"); for (int i = 0; i < numTypeScreens; i++) { settings.setArrayIndex(i); typeScreenNames().append(settings.value("typeScreenName").toString()); } settings.endArray(); setSwitchScreenName(settings.value("switchScreenName").toString()); setSwitchDirection(settings.value("switchInDirection", switchLeft).toInt()); setLockCursorMode(settings.value("lockCursorToScreen", lockCursorToggle).toInt()); setActiveOnRelease(settings.value("activeOnRelease", false).toBool()); setHaveScreens(settings.value("hasScreens", false).toBool()); } void Action::saveSettings(QSettings& settings) const { keySequence().saveSettings(settings); settings.setValue("type", type()); settings.beginWriteArray("typeScreenNames"); for (int i = 0; i < typeScreenNames().size(); i++) { settings.setArrayIndex(i); settings.setValue("typeScreenName", typeScreenNames()[i]); } settings.endArray(); settings.setValue("switchScreenName", switchScreenName()); settings.setValue("switchInDirection", switchDirection()); settings.setValue("lockCursorToScreen", lockCursorMode()); settings.setValue("activeOnRelease", activeOnRelease()); settings.setValue("hasScreens", haveScreens()); } QTextStream& operator<<(QTextStream& outStream, const Action& action) { if (action.activeOnRelease()) outStream << ";"; outStream << action.text(); return outStream; } synergy-1.8.8-stable/src/gui/src/Action.h000066400000000000000000000056501305627404700202460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(ACTION_H) #define ACTION_H #include "KeySequence.h" #include #include #include class ActionDialog; class QSettings; class QTextStream; class Action { friend class ActionDialog; friend QTextStream& operator<<(QTextStream& outStream, const Action& action); public: enum ActionType { keyDown, keyUp, keystroke, switchToScreen, switchInDirection, lockCursorToScreen, mouseDown, mouseUp, mousebutton }; enum SwitchDirection { switchLeft, switchRight, switchUp, switchDown }; enum LockCursorMode { lockCursorToggle, lockCursonOn, lockCursorOff }; public: Action(); public: QString text() const; const KeySequence& keySequence() const { return m_KeySequence; } void loadSettings(QSettings& settings); void saveSettings(QSettings& settings) const; int type() const { return m_Type; } const QStringList& typeScreenNames() const { return m_TypeScreenNames; } const QString& switchScreenName() const { return m_SwitchScreenName; } int switchDirection() const { return m_SwitchDirection; } int lockCursorMode() const { return m_LockCursorMode; } bool activeOnRelease() const { return m_ActiveOnRelease; } bool haveScreens() const { return m_HasScreens; } protected: KeySequence& keySequence() { return m_KeySequence; } void setKeySequence(const KeySequence& seq) { m_KeySequence = seq; } void setType(int t) { m_Type = t; } QStringList& typeScreenNames() { return m_TypeScreenNames; } void setSwitchScreenName(const QString& n) { m_SwitchScreenName = n; } void setSwitchDirection(int d) { m_SwitchDirection = d; } void setLockCursorMode(int m) { m_LockCursorMode = m; } void setActiveOnRelease(bool b) { m_ActiveOnRelease = b; } void setHaveScreens(bool b) { m_HasScreens = b; } private: KeySequence m_KeySequence; int m_Type; QStringList m_TypeScreenNames; QString m_SwitchScreenName; int m_SwitchDirection; int m_LockCursorMode; bool m_ActiveOnRelease; bool m_HasScreens; static const char* m_ActionTypeNames[]; static const char* m_SwitchDirectionNames[]; static const char* m_LockCursorModeNames[]; }; typedef QList ActionList; QTextStream& operator<<(QTextStream& outStream, const Action& action); #endif synergy-1.8.8-stable/src/gui/src/ActionDialog.cpp000066400000000000000000000072671305627404700217270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ActionDialog.h" #include "Hotkey.h" #include "Action.h" #include "ServerConfig.h" #include "KeySequence.h" #include #include ActionDialog::ActionDialog(QWidget* parent, ServerConfig& config, Hotkey& hotkey, Action& action) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), Ui::ActionDialogBase(), m_ServerConfig(config), m_Hotkey(hotkey), m_Action(action), m_pButtonGroupType(new QButtonGroup(this)) { setupUi(this); // work around Qt Designer's lack of a QButtonGroup; we need it to get // at the button id of the checked radio button QRadioButton* const typeButtons[] = { m_pRadioPress, m_pRadioRelease, m_pRadioPressAndRelease, m_pRadioSwitchToScreen, m_pRadioSwitchInDirection, m_pRadioLockCursorToScreen }; for (unsigned int i = 0; i < sizeof(typeButtons) / sizeof(typeButtons[0]); i++) m_pButtonGroupType->addButton(typeButtons[i], i); m_pKeySequenceWidgetHotkey->setText(m_Action.keySequence().toString()); m_pKeySequenceWidgetHotkey->setKeySequence(m_Action.keySequence()); m_pButtonGroupType->button(m_Action.type())->setChecked(true); m_pComboSwitchInDirection->setCurrentIndex(m_Action.switchDirection()); m_pComboLockCursorToScreen->setCurrentIndex(m_Action.lockCursorMode()); if (m_Action.activeOnRelease()) m_pRadioHotkeyReleased->setChecked(true); else m_pRadioHotkeyPressed->setChecked(true); m_pGroupBoxScreens->setChecked(m_Action.haveScreens()); int idx = 0; foreach(const Screen& screen, serverConfig().screens()) if (!screen.isNull()) { QListWidgetItem *pListItem = new QListWidgetItem(screen.name()); m_pListScreens->addItem(pListItem); if (m_Action.typeScreenNames().indexOf(screen.name()) != -1) m_pListScreens->setCurrentItem(pListItem); m_pComboSwitchToScreen->addItem(screen.name()); if (screen.name() == m_Action.switchScreenName()) m_pComboSwitchToScreen->setCurrentIndex(idx); idx++; } } void ActionDialog::accept() { if (!sequenceWidget()->valid() && m_pButtonGroupType->checkedId() >= 0 && m_pButtonGroupType->checkedId() < 3) return; m_Action.setKeySequence(sequenceWidget()->keySequence()); m_Action.setType(m_pButtonGroupType->checkedId()); m_Action.setHaveScreens(m_pGroupBoxScreens->isChecked()); m_Action.typeScreenNames().clear(); foreach(const QListWidgetItem* pItem, m_pListScreens->selectedItems()) m_Action.typeScreenNames().append(pItem->text()); m_Action.setSwitchScreenName(m_pComboSwitchToScreen->currentText()); m_Action.setSwitchDirection(m_pComboSwitchInDirection->currentIndex()); m_Action.setLockCursorMode(m_pComboLockCursorToScreen->currentIndex()); m_Action.setActiveOnRelease(m_pRadioHotkeyReleased->isChecked()); QDialog::accept(); } void ActionDialog::on_m_pKeySequenceWidgetHotkey_keySequenceChanged() { if (sequenceWidget()->keySequence().isMouseButton()) { m_pGroupBoxScreens->setEnabled(false); m_pListScreens->setEnabled(false); } else { m_pGroupBoxScreens->setEnabled(true); m_pListScreens->setEnabled(true); } } synergy-1.8.8-stable/src/gui/src/ActionDialog.h000066400000000000000000000027541305627404700213700ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(ACTIONDIALOG_H) #define ACTIONDIALOG_H #include #include "ui_ActionDialogBase.h" class Hotkey; class Action; class QRadioButton; class QButtonGroup; class ServerConfig; class ActionDialog : public QDialog, public Ui::ActionDialogBase { Q_OBJECT public: ActionDialog(QWidget* parent, ServerConfig& config, Hotkey& hotkey, Action& action); protected slots: void accept(); void on_m_pKeySequenceWidgetHotkey_keySequenceChanged(); protected: const KeySequenceWidget* sequenceWidget() const { return m_pKeySequenceWidgetHotkey; } const ServerConfig& serverConfig() const { return m_ServerConfig; } private: const ServerConfig& m_ServerConfig; Hotkey& m_Hotkey; Action& m_Action; QButtonGroup* m_pButtonGroupType; }; #endif synergy-1.8.8-stable/src/gui/src/ActivationDialog.cpp000066400000000000000000000065671305627404700226150ustar00rootroot00000000000000#include "ActivationDialog.h" #include "ui_ActivationDialog.h" #include "CancelActivationDialog.h" #include "AppConfig.h" #include "WebClient.h" #include "EditionType.h" #include "ActivationNotifier.h" #include "MainWindow.h" #include "QUtility.h" #include "LicenseManager.h" #include "FailedLoginDialog.h" #include #include #include ActivationDialog::ActivationDialog(QWidget* parent, AppConfig& appConfig, LicenseManager& licenseManager) : QDialog(parent), ui(new Ui::ActivationDialog), m_appConfig(&appConfig), m_LicenseManager (&licenseManager) { ui->setupUi(this); refreshSerialKey(); time_t currentTime = ::time(0); if (!m_LicenseManager->serialKey().isExpired(currentTime)) { ui->m_trialWidget->hide(); } } void ActivationDialog::refreshSerialKey() { ui->m_pTextEditSerialKey->setText(m_appConfig->serialKey()); ui->m_pTextEditSerialKey->setFocus(); ui->m_pTextEditSerialKey->moveCursor(QTextCursor::End); ui->m_trialLabel->setText(tr("

Your trial has " "expired. Buy now!" "

") .arg (m_appConfig->serialKey())); } ActivationDialog::~ActivationDialog() { delete ui; } void ActivationDialog::reject() { if (m_LicenseManager->activeEdition() == kUnregistered) { CancelActivationDialog cancelActivationDialog(this); if (QDialog::Accepted == cancelActivationDialog.exec()) { m_LicenseManager->skipActivation(); m_appConfig->activationHasRun(true); m_appConfig->saveSettings(); } else { return; } } QDialog::reject(); } void ActivationDialog::accept() { QMessageBox message; m_appConfig->activationHasRun(true); m_appConfig->saveSettings(); std::pair result; try { SerialKey serialKey (ui->m_pTextEditSerialKey->toPlainText(). trimmed().toStdString()); result = m_LicenseManager->setSerialKey(serialKey); } catch (std::exception& e) { message.critical(this, "Unknown Error", tr("An error occurred while trying to activate Synergy. " "Please contact the helpdesk, and provide the " "following information:\n\n%1").arg(e.what())); refreshSerialKey(); return; } if (!result.first) { message.critical(this, "Activation failed", tr("%1").arg(result.second)); refreshSerialKey(); return; } m_LicenseManager->notifyActivation("serial:" + m_appConfig->serialKey()); Edition edition = m_LicenseManager->activeEdition(); time_t daysLeft = m_LicenseManager->serialKey().daysLeft(::time(0)); if (edition != kUnregistered) { QString thanksMessage = tr("Thanks for trying %1! %5\n\n%2 day%3 of " "your trial remain%4"). arg (m_LicenseManager->getEditionName(edition)). arg (daysLeft). arg ((daysLeft == 1) ? "" : "s"). arg ((daysLeft == 1) ? "s" : ""); if (edition == kPro) { thanksMessage = thanksMessage.arg("If you're using SSL, " "remember to activate all of your devices."); } else { thanksMessage = thanksMessage.arg(""); } if (m_LicenseManager->serialKey().isTrial()) { message.information(this, "Thanks!", thanksMessage); } else { message.information(this, "Activated!", tr("Thanks for activating %1!").arg (m_LicenseManager->getEditionName(edition))); } } QDialog::accept(); } synergy-1.8.8-stable/src/gui/src/ActivationDialog.h000066400000000000000000000010561305627404700222460ustar00rootroot00000000000000#ifndef ACTIVATIONDIALOG_H #define ACTIVATIONDIALOG_H #include #include namespace Ui { class ActivationDialog; } class AppConfig; class ActivationDialog : public QDialog { Q_OBJECT public: ActivationDialog(QWidget *parent, AppConfig& appConfig, LicenseManager& licenseManager); ~ActivationDialog(); public slots: void reject(); void accept(); protected: void refreshSerialKey(); private: Ui::ActivationDialog *ui; AppConfig* m_appConfig; LicenseManager* m_LicenseManager; }; #endif // ACTIVATIONDIALOG_H synergy-1.8.8-stable/src/gui/src/ActivationNotifier.cpp000066400000000000000000000027541305627404700231670ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015 Synergy Seamless Inc. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ActivationNotifier.h" #include "CoreInterface.h" ActivationNotifier::ActivationNotifier(QObject *parent) : QObject(parent) { } void ActivationNotifier::setIdentity(QString identity) { m_Identity = identity; } void ActivationNotifier::setUpdateInfo(QString const& fromVersion, QString const& toVersion, QString const& serialKey) { m_fromVersion = fromVersion; m_toVersion = toVersion; m_serialKey = serialKey; } void ActivationNotifier::notify() { CoreInterface coreInterface; try { coreInterface.notifyActivation(m_Identity); } catch (...) { // catch all exceptions and fails silently } } void ActivationNotifier::notifyUpdate() { try { CoreInterface coreInterface; coreInterface.notifyUpdate(m_fromVersion, m_toVersion, m_serialKey); } catch (...) { } } synergy-1.8.8-stable/src/gui/src/ActivationNotifier.h000066400000000000000000000023361305627404700226300ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015 Synergy Seamless Inc. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ACTIVATIONNOTIFIER_H #define ACTIVATIONNOTIFIER_H #include class ActivationNotifier : public QObject { Q_OBJECT public: explicit ActivationNotifier(QObject *parent = 0); void setIdentity(QString identity); void setUpdateInfo(QString const& fromVersion, QString const& toVersion, QString const& serialKey); public slots: void notify(); void notifyUpdate(); signals: void finished(); private: QString m_Identity; QString m_fromVersion; QString m_toVersion; QString m_serialKey; }; #endif // ACTIVATIONNOTIFIER_H synergy-1.8.8-stable/src/gui/src/AddClientDialog.cpp000066400000000000000000000070161305627404700223310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "AddClientDialog.h" #include "ui_AddClientDialogBase.h" #include #include AddClientDialog::AddClientDialog(const QString& clientName, QWidget* parent) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), Ui::AddClientDialog(), m_AddResult(kAddClientIgnore), m_IgnoreAutoConfigClient(false) { setupUi(this); m_pLabelHead->setText("A client wants to connect. " "Please choose a location for " + clientName + "."); QIcon icon(":res/icons/64x64/video-display.png"); QSize IconSize(32,32); m_pButtonLeft = new QPushButton(this); m_pButtonLeft->setIcon(icon); m_pButtonLeft->setIconSize(IconSize); gridLayout->addWidget(m_pButtonLeft, 2, 0, 1, 1, Qt::AlignCenter); connect(m_pButtonLeft, SIGNAL(clicked()), this, SLOT(handleButtonLeft())); m_pButtonUp = new QPushButton(this); m_pButtonUp->setIcon(icon); m_pButtonUp->setIconSize(IconSize); gridLayout->addWidget(m_pButtonUp, 1, 1, 1, 1, Qt::AlignCenter); connect(m_pButtonUp, SIGNAL(clicked()), this, SLOT(handleButtonUp())); m_pButtonRight = new QPushButton(this); m_pButtonRight->setIcon(icon); m_pButtonRight->setIconSize(IconSize); gridLayout->addWidget(m_pButtonRight, 2, 2, 1, 1, Qt::AlignCenter); connect(m_pButtonRight, SIGNAL(clicked()), this, SLOT(handleButtonRight())); m_pButtonDown = new QPushButton(this); m_pButtonDown->setIcon(icon); m_pButtonDown->setIconSize(IconSize); gridLayout->addWidget(m_pButtonDown, 3, 1, 1, 1, Qt::AlignCenter); connect(m_pButtonDown, SIGNAL(clicked()), this, SLOT(handleButtonDown())); m_pLabelCenter = new QLabel(this); m_pLabelCenter->setPixmap(QPixmap(":res/icons/64x64/video-display.png")); gridLayout->addWidget(m_pLabelCenter, 2, 1, 1, 1, Qt::AlignCenter); #if defined(Q_OS_MAC) m_pDialogButtonBox->setLayoutDirection(Qt::RightToLeft); #endif QPushButton* advanced = m_pDialogButtonBox->addButton("Advanced", QDialogButtonBox::HelpRole); connect(advanced, SIGNAL(clicked()), this, SLOT(handleButtonAdvanced())); } AddClientDialog::~AddClientDialog() { delete m_pButtonUp; delete m_pButtonDown; delete m_pButtonLeft; delete m_pButtonRight; delete m_pLabelCenter; } void AddClientDialog::changeEvent(QEvent *e) { QDialog::changeEvent(e); switch (e->type()) { case QEvent::LanguageChange: retranslateUi(this); break; default: break; } } void AddClientDialog::handleButtonLeft() { m_AddResult = kAddClientLeft; close(); } void AddClientDialog::handleButtonUp() { m_AddResult = kAddClientUp; close(); } void AddClientDialog::handleButtonRight() { m_AddResult = kAddClientRight; close(); } void AddClientDialog::handleButtonDown() { m_AddResult = kAddClientDown; close(); } void AddClientDialog::handleButtonAdvanced() { m_AddResult = kAddClientOther; close(); } void AddClientDialog::on_m_pCheckBoxIgnoreClient_toggled(bool checked) { m_IgnoreAutoConfigClient = checked; } synergy-1.8.8-stable/src/gui/src/AddClientDialog.h000066400000000000000000000032601305627404700217730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ADDCLIENTDIALOG_H #define ADDCLIENTDIALOG_H #include "ui_AddClientDialogBase.h" #include class QPushButton; class QLabel; enum { kAddClientRight, kAddClientLeft, kAddClientUp, kAddClientDown, kAddClientOther, kAddClientIgnore }; class AddClientDialog : public QDialog, public Ui::AddClientDialog { Q_OBJECT public: AddClientDialog(const QString& clientName, QWidget* parent = 0); ~AddClientDialog(); int addResult() { return m_AddResult; } bool ignoreAutoConfigClient() { return m_IgnoreAutoConfigClient; } protected: void changeEvent(QEvent *e); private slots: void on_m_pCheckBoxIgnoreClient_toggled(bool checked); void handleButtonLeft(); void handleButtonUp(); void handleButtonRight(); void handleButtonDown(); void handleButtonAdvanced(); private: QPushButton* m_pButtonLeft; QPushButton* m_pButtonUp; QPushButton* m_pButtonRight; QPushButton* m_pButtonDown; QLabel* m_pLabelCenter; int m_AddResult; bool m_IgnoreAutoConfigClient; }; #endif // ADDCLIENTDIALOG_H synergy-1.8.8-stable/src/gui/src/AppConfig.cpp000066400000000000000000000207661305627404700212370ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "AppConfig.h" #include "EditionType.h" #include "QUtility.h" #include #include #if defined(Q_OS_WIN) const char AppConfig::m_SynergysName[] = "synergys.exe"; const char AppConfig::m_SynergycName[] = "synergyc.exe"; const char AppConfig::m_SynergyLogDir[] = "log/"; #define DEFAULT_PROCESS_MODE Service #else const char AppConfig::m_SynergysName[] = "synergys"; const char AppConfig::m_SynergycName[] = "synergyc"; const char AppConfig::m_SynergyLogDir[] = "/var/log/"; #define DEFAULT_PROCESS_MODE Desktop #endif const ElevateMode defaultElevateMode = ElevateAsNeeded; static const char* logLevelNames[] = { "ERROR", "WARNING", "NOTE", "INFO", "DEBUG", "DEBUG1", "DEBUG2" }; AppConfig::AppConfig(QSettings* settings) : m_pSettings(settings), m_ScreenName(), m_Port(24800), m_Interface(), m_LogLevel(0), m_WizardLastRun(0), m_ProcessMode(DEFAULT_PROCESS_MODE), m_AutoConfig(true), m_ElevateMode(defaultElevateMode), m_AutoConfigPrompted(false), m_CryptoEnabled(false), m_AutoHide(false), m_LastExpiringWarningTime(0) { Q_ASSERT(m_pSettings); loadSettings(); } AppConfig::~AppConfig() { saveSettings(); } const QString &AppConfig::screenName() const { return m_ScreenName; } int AppConfig::port() const { return m_Port; } const QString &AppConfig::interface() const { return m_Interface; } int AppConfig::logLevel() const { return m_LogLevel; } bool AppConfig::logToFile() const { return m_LogToFile; } const QString &AppConfig::logFilename() const { return m_LogFilename; } QString AppConfig::synergyLogDir() const { #if defined(Q_OS_WIN) // on windows, we want to log to program files return synergyProgramDir() + "log/"; #else // on unix, we'll log to the standard log dir return "/var/log/"; #endif } QString AppConfig::synergyProgramDir() const { // synergy binaries should be in the same dir. return QCoreApplication::applicationDirPath() + "/"; } void AppConfig::persistLogDir() { QDir dir = synergyLogDir(); // persist the log directory if (!dir.exists()) { dir.mkpath(dir.path()); } } const QString AppConfig::logFilenameCmd() const { QString filename = m_LogFilename; #if defined(Q_OS_WIN) // wrap in quotes in case username contains spaces. filename = QString("\"%1\"").arg(filename); #endif return filename; } QString AppConfig::logLevelText() const { return logLevelNames[logLevel()]; } ProcessMode AppConfig::processMode() const { return m_ProcessMode; } bool AppConfig::wizardShouldRun() const { return m_WizardLastRun < kWizardVersion; } const QString &AppConfig::language() const { return m_Language; } bool AppConfig::startedBefore() const { return m_StartedBefore; } bool AppConfig::autoConfig() const { return m_AutoConfig; } void AppConfig::loadSettings() { m_ScreenName = settings().value("screenName", QHostInfo::localHostName()).toString(); m_Port = settings().value("port", 24800).toInt(); m_Interface = settings().value("interface").toString(); m_LogLevel = settings().value("logLevel", 3).toInt(); // level 3: INFO m_LogToFile = settings().value("logToFile", false).toBool(); m_LogFilename = settings().value("logFilename", synergyLogDir() + "synergy.log").toString(); m_WizardLastRun = settings().value("wizardLastRun", 0).toInt(); m_Language = settings().value("language", QLocale::system().name()).toString(); m_StartedBefore = settings().value("startedBefore", false).toBool(); m_AutoConfig = settings().value("autoConfig", true).toBool(); QVariant elevateMode = settings().value("elevateModeEnum"); if (!elevateMode.isValid()) { elevateMode = settings().value ("elevateMode", QVariant(static_cast(defaultElevateMode))); } m_ElevateMode = static_cast(elevateMode.toInt()); m_AutoConfigPrompted = settings().value("autoConfigPrompted", false).toBool(); m_Edition = static_cast(settings().value("edition", kUnregistered).toInt()); m_ActivateEmail = settings().value("activateEmail", "").toString(); m_CryptoEnabled = settings().value("cryptoEnabled", true).toBool(); m_AutoHide = settings().value("autoHide", false).toBool(); m_Serialkey = settings().value("serialKey", "").toString().trimmed(); m_lastVersion = settings().value("lastVersion", "Unknown").toString(); m_LastExpiringWarningTime = settings().value("lastExpiringWarningTime", 0).toInt(); m_ActivationHasRun = settings().value("activationHasRun", false).toBool(); } void AppConfig::saveSettings() { settings().setValue("screenName", m_ScreenName); settings().setValue("port", m_Port); settings().setValue("interface", m_Interface); settings().setValue("logLevel", m_LogLevel); settings().setValue("logToFile", m_LogToFile); settings().setValue("logFilename", m_LogFilename); settings().setValue("wizardLastRun", kWizardVersion); settings().setValue("language", m_Language); settings().setValue("startedBefore", m_StartedBefore); settings().setValue("autoConfig", m_AutoConfig); // Refer to enum ElevateMode declaration for insight in to why this // flag is mapped this way settings().setValue("elevateMode", m_ElevateMode == ElevateAlways); settings().setValue("elevateModeEnum", static_cast(m_ElevateMode)); settings().setValue("autoConfigPrompted", m_AutoConfigPrompted); settings().setValue("edition", m_Edition); settings().setValue("cryptoEnabled", m_CryptoEnabled); settings().setValue("autoHide", m_AutoHide); settings().setValue("serialKey", m_Serialkey); settings().setValue("lastVersion", m_lastVersion); settings().setValue("lastExpiringWarningTime", m_LastExpiringWarningTime); settings().setValue("activationHasRun", m_ActivationHasRun); settings().sync(); } bool AppConfig::activationHasRun() const { return m_ActivationHasRun; } AppConfig& AppConfig::activationHasRun(bool value) { m_ActivationHasRun = value; return *this; } QString AppConfig::lastVersion() const { return m_lastVersion; } void AppConfig::setLastVersion(QString version) { m_lastVersion = version; } QSettings &AppConfig::settings() { return *m_pSettings; } void AppConfig::setScreenName(const QString &s) { m_ScreenName = s; } void AppConfig::setPort(int i) { m_Port = i; } void AppConfig::setInterface(const QString &s) { m_Interface = s; } void AppConfig::setLogLevel(int i) { m_LogLevel = i; } void AppConfig::setLogToFile(bool b) { m_LogToFile = b; } void AppConfig::setLogFilename(const QString &s) { m_LogFilename = s; } void AppConfig::setWizardHasRun() { m_WizardLastRun = kWizardVersion; } void AppConfig::setLanguage(const QString language) { m_Language = language; } void AppConfig::setStartedBefore(bool b) { m_StartedBefore = b; } void AppConfig::setElevateMode(ElevateMode em) { m_ElevateMode = em; } void AppConfig::setAutoConfig(bool autoConfig) { m_AutoConfig = autoConfig; } bool AppConfig::autoConfigPrompted() { return m_AutoConfigPrompted; } void AppConfig::setAutoConfigPrompted(bool prompted) { m_AutoConfigPrompted = prompted; } void AppConfig::setEdition(Edition e) { m_Edition = e; } Edition AppConfig::edition() const { return m_Edition; } QString AppConfig::setSerialKey(QString serial) { using std::swap; swap (serial, m_Serialkey); return serial; } void AppConfig::clearSerialKey() { m_Serialkey.clear(); } QString AppConfig::serialKey() { return m_Serialkey; } int AppConfig::lastExpiringWarningTime() const { return m_LastExpiringWarningTime; } void AppConfig::setLastExpiringWarningTime(int t) { m_LastExpiringWarningTime = t; } QString AppConfig::synergysName() const { return m_SynergysName; } QString AppConfig::synergycName() const { return m_SynergycName; } ElevateMode AppConfig::elevateMode() { return m_ElevateMode; } void AppConfig::setCryptoEnabled(bool e) { m_CryptoEnabled = e; emit sslToggled(e); } bool AppConfig::getCryptoEnabled() const { return (edition() == kPro) && m_CryptoEnabled; } void AppConfig::setAutoHide(bool b) { m_AutoHide = b; } bool AppConfig::getAutoHide() { return m_AutoHide; } synergy-1.8.8-stable/src/gui/src/AppConfig.h000066400000000000000000000077471305627404700207100ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(APPCONFIG_H) #define APPCONFIG_H #include #include #include "ElevateMode.h" #include // this should be incremented each time a new page is added. this is // saved to settings when the user finishes running the wizard. if // the saved wizard version is lower than this number, the wizard // will be displayed. each version incrememnt should be described // here... // // 1: first version // 2: added language page // 3: added premium page and removed // 4: ssl plugin 'ns' v1.0 // 5: ssl plugin 'ns' v1.1 // 6: ssl plugin 'ns' v1.2 // 7: serial key activation // const int kWizardVersion = 7; class QSettings; class SettingsDialog; enum ProcessMode { Service, Desktop }; class AppConfig: public QObject { Q_OBJECT friend class SettingsDialog; friend class MainWindow; friend class SetupWizard; public: AppConfig(QSettings* settings); ~AppConfig(); public: const QString& screenName() const; int port() const; const QString& interface() const; int logLevel() const; bool logToFile() const; const QString& logFilename() const; const QString logFilenameCmd() const; QString logLevelText() const; ProcessMode processMode() const; bool wizardShouldRun() const; const QString& language() const; bool startedBefore() const; bool autoConfig() const; void setAutoConfig(bool autoConfig); bool autoConfigPrompted(); void setAutoConfigPrompted(bool prompted); void setEdition(Edition); Edition edition() const; QString setSerialKey(QString serial); void clearSerialKey(); QString serialKey(); int lastExpiringWarningTime() const; void setLastExpiringWarningTime(int t); QString synergysName() const; QString synergycName() const; QString synergyProgramDir() const; QString synergyLogDir() const; bool detectPath(const QString& name, QString& path); void persistLogDir(); ElevateMode elevateMode(); void setCryptoEnabled(bool e); bool getCryptoEnabled() const; void setAutoHide(bool b); bool getAutoHide(); bool activationHasRun() const; AppConfig& activationHasRun(bool value); QString lastVersion() const; void saveSettings(); void setLastVersion(QString version); protected: QSettings& settings(); void setScreenName(const QString& s); void setPort(int i); void setInterface(const QString& s); void setLogLevel(int i); void setLogToFile(bool b); void setLogFilename(const QString& s); void setWizardHasRun(); void setLanguage(const QString language); void setStartedBefore(bool b); void setElevateMode(ElevateMode em); void loadSettings(); private: QSettings* m_pSettings; QString m_ScreenName; int m_Port; QString m_Interface; int m_LogLevel; bool m_LogToFile; QString m_LogFilename; int m_WizardLastRun; ProcessMode m_ProcessMode; QString m_Language; bool m_StartedBefore; bool m_AutoConfig; ElevateMode m_ElevateMode; bool m_AutoConfigPrompted; Edition m_Edition; QString m_ActivateEmail; bool m_CryptoEnabled; bool m_AutoHide; QString m_Serialkey; QString m_lastVersion; int m_LastExpiringWarningTime; bool m_ActivationHasRun; static const char m_SynergysName[]; static const char m_SynergycName[]; static const char m_SynergyLogDir[]; signals: void sslToggled(bool enabled); }; #endif synergy-1.8.8-stable/src/gui/src/BaseConfig.cpp000066400000000000000000000021441305627404700213570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "BaseConfig.h" const char* BaseConfig::m_ModifierNames[] = { "shift", "ctrl", "alt", "meta", "super", "none" }; const char* BaseConfig::m_FixNames[] = { "halfDuplexCapsLock", "halfDuplexNumLock", "halfDuplexScrollLock", "xtestIsXineramaUnaware" }; const char* BaseConfig::m_SwitchCornerNames[] = { "top-left", "top-right", "bottom-left", "bottom-right" }; synergy-1.8.8-stable/src/gui/src/BaseConfig.h000066400000000000000000000052401305627404700210240ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(BASECONFIG_H) #define BASECONFIG_H #include #include #include class BaseConfig { public: enum Modifier { DefaultMod = -1, Shift, Ctrl, Alt, Meta, Super, None, NumModifiers }; enum SwitchCorner { TopLeft, TopRight, BottomLeft, BottomRight, NumSwitchCorners }; enum Fix { CapsLock, NumLock, ScrollLock, XTest, NumFixes }; protected: BaseConfig() {} virtual ~BaseConfig() {} protected: template void readSettings(QSettings& settings, T1& array, const QString& arrayName, const T2& deflt) { int entries = settings.beginReadArray(arrayName + "Array"); array.clear(); for (int i = 0; i < entries; i++) { settings.setArrayIndex(i); QVariant v = settings.value(arrayName, deflt); array.append(v.value()); } settings.endArray(); } template void readSettings(QSettings& settings, T1& array, const QString& arrayName, const T2& deflt, int entries) { Q_ASSERT(array.size() >= entries); settings.beginReadArray(arrayName + "Array"); for (int i = 0; i < entries; i++) { settings.setArrayIndex(i); QVariant v = settings.value(arrayName, deflt); array[i] = v.value(); } settings.endArray(); } template void writeSettings(QSettings& settings, const T& array, const QString& arrayName) const { settings.beginWriteArray(arrayName + "Array"); for (int i = 0; i < array.size(); i++) { settings.setArrayIndex(i); settings.setValue(arrayName, array[i]); } settings.endArray(); } public: static const char* modifierName(int idx) { return m_ModifierNames[idx]; } static const char* fixName(int idx) { return m_FixNames[idx]; } static const char* switchCornerName(int idx) { return m_SwitchCornerNames[idx]; } private: static const char* m_ModifierNames[]; static const char* m_FixNames[]; static const char* m_SwitchCornerNames[]; }; #endif synergy-1.8.8-stable/src/gui/src/CancelActivationDialog.cpp000066400000000000000000000004371305627404700237110ustar00rootroot00000000000000#include "CancelActivationDialog.h" #include "ui_CancelActivationDialog.h" CancelActivationDialog::CancelActivationDialog(QWidget *parent) : QDialog(parent), ui(new Ui::CancelActivationDialog) { ui->setupUi(this); } CancelActivationDialog::~CancelActivationDialog() { delete ui; } synergy-1.8.8-stable/src/gui/src/CancelActivationDialog.h000066400000000000000000000005611305627404700233540ustar00rootroot00000000000000#ifndef CANCELACTIVATIONDIALOG_H #define CANCELACTIVATIONDIALOG_H #include namespace Ui { class CancelActivationDialog; } class CancelActivationDialog : public QDialog { Q_OBJECT public: explicit CancelActivationDialog(QWidget *parent = 0); ~CancelActivationDialog(); private: Ui::CancelActivationDialog *ui; }; #endif // CANCELACTIVATIONDIALOG_H synergy-1.8.8-stable/src/gui/src/CommandProcess.cpp000066400000000000000000000031621305627404700222750ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "CommandProcess.h" #include #include CommandProcess::CommandProcess(QString cmd, QStringList arguments, QString input) : m_Command(cmd), m_Arguments(arguments), m_Input(input) { } QString CommandProcess::run() { QProcess process; process.setReadChannel(QProcess::StandardOutput); process.start(m_Command, m_Arguments); bool success = process.waitForStarted(); QString output, error; if (success) { if (!m_Input.isEmpty()) { process.write(m_Input.toStdString().c_str()); } if (process.waitForFinished()) { output = process.readAllStandardOutput().trimmed(); error = process.readAllStandardError().trimmed(); } } int code = process.exitCode(); if (!error.isEmpty() || !success || code != 0) { throw std::runtime_error( QString("Code: %1\nError: %2") .arg(process.exitCode()) .arg(error.isEmpty() ? "Unknown" : error) .toStdString()); } emit finished(); return output; } synergy-1.8.8-stable/src/gui/src/CommandProcess.h000066400000000000000000000020661305627404700217440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef COMMANDTHREAD_H #define COMMANDTHREAD_H #include #include class CommandProcess : public QObject { Q_OBJECT public: CommandProcess(QString cmd, QStringList arguments, QString input = ""); signals: void finished(); public slots: QString run(); private: QString m_Command; QStringList m_Arguments; QString m_Input; }; #endif // COMMANDTHREAD_H synergy-1.8.8-stable/src/gui/src/CoreInterface.cpp000066400000000000000000000045461305627404700221000ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "CoreInterface.h" #include "CommandProcess.h" #include "QUtility.h" #include #include #include #include #include static const char kCoreBinary[] = "syntool"; #ifdef Q_WS_WIN static const char kSerialKeyFilename[] = "Synergy.subkey"; #else static const char kSerialKeyFilename[] = ".synergy.subkey"; #endif CoreInterface::CoreInterface() { } QString CoreInterface::getProfileDir() { QStringList args("--get-profile-dir"); return run(args); } QString CoreInterface::getInstalledDir() { QStringList args("--get-installed-dir"); return run(args); } QString CoreInterface::getArch() { QStringList args("--get-arch"); return run(args); } QString CoreInterface::getSerialKeyFilePath() { QString filename = getProfileDir() + QDir::separator() + kSerialKeyFilename; return filename; } QString CoreInterface::notifyUpdate (QString const& fromVersion, QString const& toVersion, QString const& serialKey) { QStringList args("--notify-update"); QString input(fromVersion + ":" + toVersion + ":" + serialKey); input.append("\n"); return run(args, input); } QString CoreInterface::notifyActivation(const QString& identity) { QStringList args("--notify-activation"); QString input(identity + ":" + hash(getFirstMacAddress())); QString os= getOSInformation(); if (!os.isEmpty()) { input.append(":").append(os); } input.append("\n"); return run(args, input); } QString CoreInterface::run(const QStringList& args, const QString& input) { QString program( QCoreApplication::applicationDirPath() + "/" + kCoreBinary); CommandProcess commandProcess(program, args, input); return commandProcess.run(); } synergy-1.8.8-stable/src/gui/src/CoreInterface.h000066400000000000000000000021441305627404700215350ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include class CoreInterface { public: CoreInterface(); QString getProfileDir(); QString getInstalledDir(); QString getArch(); QString getSerialKeyFilePath(); QString notifyActivation(const QString& identity); QString notifyUpdate (QString const& fromVersion, QString const& toVersion, QString const& serialKey); QString run(const QStringList& args, const QString& input = ""); }; synergy-1.8.8-stable/src/gui/src/DataDownloader.cpp000066400000000000000000000025261305627404700222530ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "DataDownloader.h" DataDownloader::DataDownloader(QObject* parent) : QObject(parent), m_IsFinished(false) { connect(&m_NetworkManager, SIGNAL(finished(QNetworkReply*)), SLOT(complete(QNetworkReply*))); } DataDownloader::~DataDownloader() { } void DataDownloader::complete(QNetworkReply* reply) { m_Data = reply->readAll(); reply->deleteLater(); if (!m_Data.isEmpty()) { m_IsFinished = true; emit isComplete(); } } QByteArray DataDownloader::data() const { return m_Data; } void DataDownloader::cancel() { m_pReply->abort(); } void DataDownloader::download(QUrl url) { QNetworkRequest request(url); m_pReply = m_NetworkManager.get(request); } synergy-1.8.8-stable/src/gui/src/DataDownloader.h000066400000000000000000000025121305627404700217130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef DATADOWNLOADER_H #define DATADOWNLOADER_H #include #include #include #include #include class DataDownloader : public QObject { Q_OBJECT public: explicit DataDownloader(QObject* parent = 0); virtual ~DataDownloader(); QByteArray data() const; void cancel(); void download(QUrl url); bool isFinished() const { return m_IsFinished; } signals: void isComplete(); private slots: void complete(QNetworkReply* reply); private: QNetworkAccessManager m_NetworkManager; QByteArray m_Data; QNetworkReply* m_pReply; bool m_IsFinished; }; #endif // DATADOWNLOADER_H synergy-1.8.8-stable/src/gui/src/ElevateMode.h000066400000000000000000000030641305627404700212200ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once // The elevate mode tristate determines two behaviours on Windows. // The first, switch-on-desk-switch (SodS), passed through synergyd as a // command line argument to synergy core, determines if the server restarts // when switching Windows desktops (e.g. when Windows UAC dialog pops up). // The second, passed as a boolean flag to Synergyd over the IPC inside // kIpcCommandMessage, determines whether Synergy should be started with // elevated privileges. // // The matrix for these two behaviours is as follows: // SodS Elevate // ___________________________ // ElevateAsNeeded | true | false // ElevateAlways | false | true // ElevateNever | false | false // enum ElevateMode { ElevateAsNeeded = 0, ElevateAlways = 1, ElevateNever = 2 }; extern const ElevateMode defaultElevateMode; synergy-1.8.8-stable/src/gui/src/FailedLoginDialog.cpp000066400000000000000000000005171305627404700226560ustar00rootroot00000000000000#include "FailedLoginDialog.h" #include "ui_FailedLoginDialog.h" FailedLoginDialog::FailedLoginDialog(QWidget *parent, QString message): QDialog(parent), ui(new Ui::FailedLoginDialog) { ui->setupUi(this); ui->messageLabel->setText(ui->messageLabel->text().arg(message)); } FailedLoginDialog::~FailedLoginDialog() { delete ui; } synergy-1.8.8-stable/src/gui/src/FailedLoginDialog.h000066400000000000000000000005621305627404700223230ustar00rootroot00000000000000#ifndef FAILEDLOGINDIALOG_H #define FAILEDLOGINDIALOG_H #include #include namespace Ui { class FailedLoginDialog; } class FailedLoginDialog : public QDialog { Q_OBJECT public: explicit FailedLoginDialog(QWidget *parent = 0, QString message = ""); ~FailedLoginDialog(); private: Ui::FailedLoginDialog *ui; }; #endif // FAILEDLOGINDIALOG_H synergy-1.8.8-stable/src/gui/src/Fingerprint.cpp000066400000000000000000000060361305627404700216520ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Fingerprint.h" #include "CoreInterface.h" #include #include static const char kDirName[] = "SSL/Fingerprints"; static const char kLocalFilename[] = "Local.txt"; static const char kTrustedServersFilename[] = "TrustedServers.txt"; static const char kTrustedClientsFilename[] = "TrustedClients.txt"; Fingerprint::Fingerprint(const QString& filename) { m_Filename = filename; } void Fingerprint::trust(const QString& fingerprintText, bool append) { Fingerprint::persistDirectory(); QIODevice::OpenMode openMode; if (append) { openMode = QIODevice::Append; } else { openMode = QIODevice::WriteOnly; } QFile file(filePath()); if (file.open(openMode)) { QTextStream out(&file); out << fingerprintText << "\n"; file.close(); } } bool Fingerprint::fileExists() const { QString dirName = Fingerprint::directoryPath(); if (!QDir(dirName).exists()) { return false; } QFile file(filePath()); return file.exists(); } bool Fingerprint::isTrusted(const QString& fingerprintText) { QStringList list = readList(); foreach (QString trusted, list) { if (trusted == fingerprintText) { return true; } } return false; } QStringList Fingerprint::readList(const int readTo) { QStringList list; QString dirName = Fingerprint::directoryPath(); if (!QDir(dirName).exists()) { return list; } QFile file(filePath()); if (file.open(QIODevice::ReadOnly)) { QTextStream in(&file); while (!in.atEnd()) { list.append(in.readLine()); if (list.size() == readTo) { break; } } file.close(); } return list; } QString Fingerprint::readFirst() { QStringList list = readList(1); return list.at(0); } QString Fingerprint::filePath() const { QString dir = Fingerprint::directoryPath(); return QString("%1/%2").arg(dir).arg(m_Filename); } void Fingerprint::persistDirectory() { QDir dir(Fingerprint::directoryPath()); if (!dir.exists()) { dir.mkpath("."); } } QString Fingerprint::directoryPath() { CoreInterface coreInterface; QString profileDir = coreInterface.getProfileDir(); return QString("%1/%2") .arg(profileDir) .arg(kDirName); } Fingerprint Fingerprint::local() { return Fingerprint(kLocalFilename); } Fingerprint Fingerprint::trustedServers() { return Fingerprint(kTrustedServersFilename); } Fingerprint Fingerprint::trustedClients() { return Fingerprint(kTrustedClientsFilename); } synergy-1.8.8-stable/src/gui/src/Fingerprint.h000066400000000000000000000024561305627404700213210ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include class Fingerprint { private: Fingerprint(const QString& filename); public: void trust(const QString& fingerprintText, bool append = true); bool isTrusted(const QString& fingerprintText); QStringList readList(const int readTo = -1); QString readFirst(); QString filePath() const; bool fileExists() const; public: static Fingerprint local(); static Fingerprint trustedServers(); static Fingerprint trustedClients(); static QString directoryPath(); static QString localFingerprint(); static bool localFingerprintExists(); static void persistDirectory(); private: QString m_Filename; }; synergy-1.8.8-stable/src/gui/src/Hotkey.cpp000066400000000000000000000034541305627404700206270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Hotkey.h" #include Hotkey::Hotkey() : m_KeySequence(), m_Actions() { } QString Hotkey::text() const { QString text = keySequence().toString(); if (keySequence().isMouseButton()) return "mousebutton(" + text + ")"; return "keystroke(" + text + ")"; } void Hotkey::loadSettings(QSettings& settings) { keySequence().loadSettings(settings); actions().clear(); int num = settings.beginReadArray("actions"); for (int i = 0; i < num; i++) { settings.setArrayIndex(i); Action a; a.loadSettings(settings); actions().append(a); } settings.endArray(); } void Hotkey::saveSettings(QSettings& settings) const { keySequence().saveSettings(settings); settings.beginWriteArray("actions"); for (int i = 0; i < actions().size(); i++) { settings.setArrayIndex(i); actions()[i].saveSettings(settings); } settings.endArray(); } QTextStream& operator<<(QTextStream& outStream, const Hotkey& hotkey) { for (int i = 0; i < hotkey.actions().size(); i++) outStream << "\t" << hotkey.text() << " = " << hotkey.actions()[i] << endl; return outStream; } synergy-1.8.8-stable/src/gui/src/Hotkey.h000066400000000000000000000033251305627404700202710ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(HOTKEY_H) #define HOTKEY_H #include #include #include #include "Action.h" #include "KeySequence.h" class HotkeyDialog; class ServerConfigDialog; class QSettings; class Hotkey { friend class HotkeyDialog; friend class ServerConfigDialog; friend QTextStream& operator<<(QTextStream& outStream, const Hotkey& hotkey); public: Hotkey(); public: QString text() const; const KeySequence& keySequence() const { return m_KeySequence; } const ActionList& actions() const { return m_Actions; } void loadSettings(QSettings& settings); void saveSettings(QSettings& settings) const; protected: KeySequence& keySequence() { return m_KeySequence; } void setKeySequence(const KeySequence& seq) { m_KeySequence = seq; } ActionList& actions() { return m_Actions; } private: KeySequence m_KeySequence; ActionList m_Actions; }; typedef QList HotkeyList; QTextStream& operator<<(QTextStream& outStream, const Hotkey& hotkey); #endif synergy-1.8.8-stable/src/gui/src/HotkeyDialog.cpp000066400000000000000000000022701305627404700217420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "HotkeyDialog.h" #include #include HotkeyDialog::HotkeyDialog (QWidget* parent, Hotkey& hotkey) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), Ui::HotkeyDialogBase(), m_Hotkey(hotkey) { setupUi(this); m_pKeySequenceWidgetHotkey->setText(m_Hotkey.text()); } void HotkeyDialog::accept() { if (!sequenceWidget()->valid()) return; hotkey().setKeySequence(sequenceWidget()->keySequence()); QDialog::accept(); } synergy-1.8.8-stable/src/gui/src/HotkeyDialog.h000066400000000000000000000024071305627404700214110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(HOTKEYDIALOG_H) #define HOTKEYDIALOG_H #include "ui_HotkeyDialogBase.h" #include "Hotkey.h" #include class HotkeyDialog : public QDialog, public Ui::HotkeyDialogBase { Q_OBJECT public: HotkeyDialog(QWidget* parent, Hotkey& hotkey); public: const Hotkey& hotkey() const { return m_Hotkey; } protected slots: void accept(); protected: const KeySequenceWidget* sequenceWidget() const { return m_pKeySequenceWidgetHotkey; } Hotkey& hotkey() { return m_Hotkey; } private: Hotkey& m_Hotkey; }; #endif synergy-1.8.8-stable/src/gui/src/Ipc.cpp000066400000000000000000000017121305627404700200720ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // this class is a duplicate of /src/lib/ipc/Ipc.cpp #include "Ipc.h" const char* kIpcMsgHello = "IHEL%1i"; const char* kIpcMsgLogLine = "ILOG%s"; const char* kIpcMsgCommand = "ICMD%s%1i"; const char* kIpcMsgShutdown = "ISDN"; synergy-1.8.8-stable/src/gui/src/Ipc.h000066400000000000000000000021741305627404700175420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // this class is a duplicate of /src/lib/ipc/Ipc.h #pragma once #define IPC_HOST "127.0.0.1" #define IPC_PORT 24801 enum qIpcMessageType { kIpcHello, kIpcLogLine, kIpcCommand, kIpcShutdown, }; enum qIpcClientType { kIpcClientUnknown, kIpcClientGui, kIpcClientNode, }; extern const char* kIpcMsgHello; extern const char* kIpcMsgLogLine; extern const char* kIpcMsgCommand; extern const char* kIpcMsgShutdown; synergy-1.8.8-stable/src/gui/src/IpcClient.cpp000066400000000000000000000070341305627404700212340ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "IpcClient.h" #include #include #include #include #include "IpcReader.h" #include "Ipc.h" #include IpcClient::IpcClient() : m_ReaderStarted(false), m_Enabled(false) { m_Socket = new QTcpSocket(this); connect(m_Socket, SIGNAL(connected()), this, SLOT(connected())); connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(error(QAbstractSocket::SocketError))); m_Reader = new IpcReader(m_Socket); connect(m_Reader, SIGNAL(readLogLine(const QString&)), this, SLOT(handleReadLogLine(const QString&))); } IpcClient::~IpcClient() { } void IpcClient::connected() { sendHello(); infoMessage("connection established"); } void IpcClient::connectToHost() { m_Enabled = true; infoMessage("connecting to service..."); m_Socket->connectToHost(QHostAddress(QHostAddress::LocalHost), IPC_PORT); if (!m_ReaderStarted) { m_Reader->start(); m_ReaderStarted = true; } } void IpcClient::disconnectFromHost() { infoMessage("service disconnect"); m_Reader->stop(); m_Socket->close(); } void IpcClient::error(QAbstractSocket::SocketError error) { QString text; switch (error) { case 0: text = "connection refused"; break; case 1: text = "remote host closed"; break; default: text = QString("code=%1").arg(error); break; } errorMessage(QString("ipc connection error, %1").arg(text)); QTimer::singleShot(1000, this, SLOT(retryConnect())); } void IpcClient::retryConnect() { if (m_Enabled) { connectToHost(); } } void IpcClient::sendHello() { QDataStream stream(m_Socket); stream.writeRawData(kIpcMsgHello, 4); char typeBuf[1]; typeBuf[0] = kIpcClientGui; stream.writeRawData(typeBuf, 1); } void IpcClient::sendCommand(const QString& command, ElevateMode const elevate) { QDataStream stream(m_Socket); stream.writeRawData(kIpcMsgCommand, 4); std::string stdStringCommand = command.toStdString(); const char* charCommand = stdStringCommand.c_str(); int length = strlen(charCommand); char lenBuf[4]; intToBytes(length, lenBuf, 4); stream.writeRawData(lenBuf, 4); stream.writeRawData(charCommand, length); char elevateBuf[1]; // Refer to enum ElevateMode documentation for why this flag is mapped this way elevateBuf[0] = (elevate == ElevateAlways) ? 1 : 0; stream.writeRawData(elevateBuf, 1); } void IpcClient::handleReadLogLine(const QString& text) { readLogLine(text); } // TODO: qt must have a built in way of converting int to bytes. void IpcClient::intToBytes(int value, char *buffer, int size) { if (size == 1) { buffer[0] = value & 0xff; } else if (size == 2) { buffer[0] = (value >> 8) & 0xff; buffer[1] = value & 0xff; } else if (size == 4) { buffer[0] = (value >> 24) & 0xff; buffer[1] = (value >> 16) & 0xff; buffer[2] = (value >> 8) & 0xff; buffer[3] = value & 0xff; } else { // TODO: other sizes, if needed. } } synergy-1.8.8-stable/src/gui/src/IpcClient.h000066400000000000000000000027761305627404700207110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include #include "ElevateMode.h" class QTcpSocket; class IpcReader; class IpcClient : public QObject { Q_OBJECT public: IpcClient(); virtual ~IpcClient(); void sendHello(); void sendCommand(const QString& command, ElevateMode elevate); void connectToHost(); void disconnectFromHost(); public slots: void retryConnect(); private: void intToBytes(int value, char* buffer, int size); private slots: void connected(); void error(QAbstractSocket::SocketError error); void handleReadLogLine(const QString& text); signals: void readLogLine(const QString& text); void infoMessage(const QString& text); void errorMessage(const QString& text); private: QTcpSocket* m_Socket; IpcReader* m_Reader; bool m_ReaderStarted; bool m_Enabled; }; synergy-1.8.8-stable/src/gui/src/IpcReader.cpp000066400000000000000000000056661305627404700212310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "IpcReader.h" #include #include "Ipc.h" #include #include #include IpcReader::IpcReader(QTcpSocket* socket) : m_Socket(socket) { } IpcReader::~IpcReader() { } void IpcReader::start() { connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read())); } void IpcReader::stop() { disconnect(m_Socket, SIGNAL(readyRead()), this, SLOT(read())); } void IpcReader::read() { QMutexLocker locker(&m_Mutex); std::cout << "ready read" << std::endl; while (m_Socket->bytesAvailable()) { std::cout << "bytes available" << std::endl; char codeBuf[5]; readStream(codeBuf, 4); codeBuf[4] = 0; std::cout << "ipc read: " << codeBuf << std::endl; if (memcmp(codeBuf, kIpcMsgLogLine, 4) == 0) { std::cout << "reading log line" << std::endl; char lenBuf[4]; readStream(lenBuf, 4); int len = bytesToInt(lenBuf, 4); char* data = new char[len]; readStream(data, len); QString line = QString::fromUtf8(data, len); delete[] data; readLogLine(line); } else { std::cerr << "aborting, message invalid" << std::endl; return; } } std::cout << "read done" << std::endl; } bool IpcReader::readStream(char* buffer, int length) { std::cout << "reading stream" << std::endl; int read = 0; while (read < length) { int ask = length - read; if (m_Socket->bytesAvailable() < ask) { std::cout << "buffer too short, waiting" << std::endl; m_Socket->waitForReadyRead(-1); } int got = m_Socket->read(buffer, ask); read += got; std::cout << "> ask=" << ask << " got=" << got << " read=" << read << std::endl; if (got == -1) { std::cout << "socket ended, aborting" << std::endl; return false; } else if (length - read > 0) { std::cout << "more remains, seek to " << got << std::endl; buffer += got; } } return true; } int IpcReader::bytesToInt(const char *buffer, int size) { if (size == 1) { return (unsigned char)buffer[0]; } else if (size == 2) { return (((unsigned char)buffer[0]) << 8) + (unsigned char)buffer[1]; } else if (size == 4) { return (((unsigned char)buffer[0]) << 24) + (((unsigned char)buffer[1]) << 16) + (((unsigned char)buffer[2]) << 8) + (unsigned char)buffer[3]; } else { return 0; } } synergy-1.8.8-stable/src/gui/src/IpcReader.h000066400000000000000000000022211305627404700206560ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include class QTcpSocket; class IpcReader : public QObject { Q_OBJECT; public: IpcReader(QTcpSocket* socket); virtual ~IpcReader(); void start(); void stop(); signals: void readLogLine(const QString& text); private: bool readStream(char* buffer, int length); int bytesToInt(const char* buffer, int size); private slots: void read(); private: QTcpSocket* m_Socket; QMutex m_Mutex; }; synergy-1.8.8-stable/src/gui/src/KeySequence.cpp000066400000000000000000000131111305627404700215740ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "KeySequence.h" #include #include // this table originally comes from Qt sources (gui/kernel/qkeysequence.cpp) // and is heavily modified for QSynergy static const struct { int key; const char* name; } keyname[] = { { Qt::Key_Space, "Space" }, { Qt::Key_Escape, "Escape" }, { Qt::Key_Tab, "Tab" }, { Qt::Key_Backtab, "LeftTab" }, { Qt::Key_Backspace, "BackSpace" }, { Qt::Key_Return, "Return" }, { Qt::Key_Insert, "Insert" }, { Qt::Key_Delete, "Delete" }, { Qt::Key_Pause, "Pause" }, { Qt::Key_Print, "Print" }, { Qt::Key_SysReq, "SysReq" }, { Qt::Key_Home, "Home" }, { Qt::Key_End, "End" }, { Qt::Key_Left, "Left" }, { Qt::Key_Up, "Up" }, { Qt::Key_Right, "Right" }, { Qt::Key_Down, "Down" }, { Qt::Key_PageUp, "PageUp" }, { Qt::Key_PageDown, "PageDown" }, { Qt::Key_CapsLock, "CapsLock" }, { Qt::Key_NumLock, "NumLock" }, { Qt::Key_ScrollLock, "ScrollLock" }, { Qt::Key_Menu, "Menu" }, { Qt::Key_Help, "Help" }, { Qt::Key_Enter, "KP_Enter" }, { Qt::Key_Clear, "Clear" }, { Qt::Key_Back, "WWWBack" }, { Qt::Key_Forward, "WWWForward" }, { Qt::Key_Stop, "WWWStop" }, { Qt::Key_Refresh, "WWWRefresh" }, { Qt::Key_VolumeDown, "AudioDown" }, { Qt::Key_VolumeMute, "AudioMute" }, { Qt::Key_VolumeUp, "AudioUp" }, { Qt::Key_MediaPlay, "AudioPlay" }, { Qt::Key_MediaStop, "AudioStop" }, { Qt::Key_MediaPrevious,"AudioPrev" }, { Qt::Key_MediaNext, "AudioNext" }, { Qt::Key_HomePage, "WWWHome" }, { Qt::Key_Favorites, "WWWFavorites" }, { Qt::Key_Search, "WWWSearch" }, { Qt::Key_Standby, "Sleep" }, { Qt::Key_LaunchMail, "AppMail" }, { Qt::Key_LaunchMedia, "AppMedia" }, { Qt::Key_Launch0, "AppUser1" }, { Qt::Key_Launch1, "AppUser2" }, { Qt::Key_Select, "Select" }, { 0, 0 } }; KeySequence::KeySequence() : m_Sequence(), m_Modifiers(0), m_IsValid(false) { } bool KeySequence::isMouseButton() const { return !m_Sequence.isEmpty() && m_Sequence.last() < Qt::Key_Space; } QString KeySequence::toString() const { QString result; for (int i = 0; i < m_Sequence.size(); i++) { result += keyToString(m_Sequence[i]); if (i != m_Sequence.size() - 1) result += "+"; } return result; } bool KeySequence::appendMouseButton(int button) { return appendKey(button, 0); } bool KeySequence::appendKey(int key, int modifiers) { if (m_Sequence.size() == 4) return true; switch(key) { case Qt::Key_AltGr: return false; case Qt::Key_Control: case Qt::Key_Alt: case Qt::Key_Shift: case Qt::Key_Meta: case Qt::Key_Menu: { int mod = modifiers & (~m_Modifiers); if (mod) { m_Sequence.append(mod); m_Modifiers |= mod; } } break; default: // see if we can handle this key, if not, don't accept it if (keyToString(key).isEmpty()) break; m_Sequence.append(key); setValid(true); return true; } return false; } void KeySequence::loadSettings(QSettings& settings) { sequence().clear(); int num = settings.beginReadArray("keys"); for (int i = 0; i < num; i++) { settings.setArrayIndex(i); sequence().append(settings.value("key", 0).toInt()); } settings.endArray(); setModifiers(0); setValid(true); } void KeySequence::saveSettings(QSettings& settings) const { settings.beginWriteArray("keys"); for (int i = 0; i < sequence().size(); i++) { settings.setArrayIndex(i); settings.setValue("key", sequence()[i]); } settings.endArray(); } QString KeySequence::keyToString(int key) { // nothing there? if (key == 0) return ""; // a hack to handle mouse buttons as if they were keys if (key < Qt::Key_Space) { switch(key) { case Qt::LeftButton: return "1"; case Qt::RightButton: return "2"; case Qt::MidButton: return "3"; } return "4"; // qt only knows three mouse buttons, so assume it's an unknown fourth one } // modifiers? if (key & Qt::ShiftModifier) return "Shift"; if (key & Qt::ControlModifier) return "Control"; if (key & Qt::AltModifier) return "Alt"; if (key & Qt::MetaModifier) return "Meta"; // treat key pad like normal keys (FIXME: we should have another lookup table for keypad keys instead) key &= ~Qt::KeypadModifier; // a printable 7 bit character? if (key < 0x80 && key != Qt::Key_Space) return QChar(key & 0x7f).toLower(); // a function key? if (key >= Qt::Key_F1 && key <= Qt::Key_F35) return QString::fromUtf8("F%1").arg(key - Qt::Key_F1 + 1); // a special key? int i=0; while (keyname[i].name) { if (key == keyname[i].key) return QString::fromUtf8(keyname[i].name); i++; } // representable in ucs2? if (key < 0x10000) return QString("\\u%1").arg(QChar(key).toLower().unicode(), 4, 16, QChar('0')); // give up, synergy probably won't handle this return ""; } synergy-1.8.8-stable/src/gui/src/KeySequence.h000066400000000000000000000030261305627404700212450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(KEYSEQUENCE_H) #define KEYSEQUENCE_H #include #include class QSettings; class KeySequence { public: KeySequence(); public: QString toString() const; bool appendKey(int modifiers, int key); bool appendMouseButton(int button); bool isMouseButton() const; bool valid() const { return m_IsValid; } int modifiers() const { return m_Modifiers; } void saveSettings(QSettings& settings) const; void loadSettings(QSettings& settings); const QList& sequence() const { return m_Sequence; } private: void setValid(bool b) { m_IsValid = b; } void setModifiers(int i) { m_Modifiers = i; } QList& sequence() { return m_Sequence; } private: QList m_Sequence; int m_Modifiers; bool m_IsValid; static QString keyToString(int key); }; #endif synergy-1.8.8-stable/src/gui/src/KeySequenceWidget.cpp000066400000000000000000000055741305627404700227560ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "KeySequenceWidget.h" #include #include KeySequenceWidget::KeySequenceWidget(QWidget* parent, const KeySequence& seq) : QPushButton(parent), m_KeySequence(seq), m_BackupSequence(seq), m_Status(Stopped), m_MousePrefix("mousebutton("), m_MousePostfix(")"), m_KeyPrefix("keystroke("), m_KeyPostfix(")") { setFocusPolicy(Qt::NoFocus); updateOutput(); } void KeySequenceWidget::setKeySequence(const KeySequence& seq) { keySequence() = seq; backupSequence() = seq; setStatus(Stopped); updateOutput(); } void KeySequenceWidget::mousePressEvent(QMouseEvent* event) { event->accept(); if (status() == Stopped) { startRecording(); return; } if (m_KeySequence.appendMouseButton(event->button())) stopRecording(); updateOutput(); } void KeySequenceWidget::startRecording() { keySequence() = KeySequence(); setDown(true); setFocus(); grabKeyboard(); setStatus(Recording); } void KeySequenceWidget::stopRecording() { if (!keySequence().valid()) { keySequence() = backupSequence(); updateOutput(); } setDown(false); focusNextChild(); releaseKeyboard(); setStatus(Stopped); emit keySequenceChanged(); } bool KeySequenceWidget::event(QEvent* event) { if (status() == Recording) { switch(event->type()) { case QEvent::KeyPress: keyPressEvent(static_cast(event)); return true; case QEvent::MouseButtonRelease: event->accept(); return true; case QEvent::ShortcutOverride: event->accept(); return true; case QEvent::FocusOut: stopRecording(); if (!valid()) { keySequence() = backupSequence(); updateOutput(); } break; default: break; } } return QPushButton::event(event); } void KeySequenceWidget::keyPressEvent(QKeyEvent* event) { event->accept(); if (status() == Stopped) return; if (m_KeySequence.appendKey(event->key(), event->modifiers())) stopRecording(); updateOutput(); } void KeySequenceWidget::updateOutput() { QString s; if (m_KeySequence.isMouseButton()) s = mousePrefix() + m_KeySequence.toString() + mousePostfix(); else s = keyPrefix() + m_KeySequence.toString() + keyPostfix(); setText(s); } synergy-1.8.8-stable/src/gui/src/KeySequenceWidget.h000066400000000000000000000046451305627404700224210ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(KEYSEQUENCEWIDGET__H) #define KEYSEQUENCEWIDGET__H #include #include "KeySequence.h" class KeySequenceWidget : public QPushButton { Q_OBJECT public: KeySequenceWidget(QWidget* parent, const KeySequence& seq = KeySequence()); signals: void keySequenceChanged(); public: const QString& mousePrefix() const { return m_MousePrefix; } const QString& mousePostfix() const { return m_MousePostfix; } const QString& keyPrefix() const { return m_KeyPrefix; } const QString& keyPostfix() const { return m_KeyPostfix; } void setMousePrefix(const QString& s) { m_MousePrefix = s; } void setMousePostfix(const QString& s) { m_MousePostfix = s; } void setKeyPrefix(const QString& s) { m_KeyPrefix = s; } void setKeyPostfix(const QString& s) { m_KeyPostfix = s; } const KeySequence& keySequence() const { return m_KeySequence; } const KeySequence& backupSequence() const { return m_BackupSequence; } void setKeySequence(const KeySequence& seq); bool valid() const { return keySequence().valid(); } protected: void mousePressEvent(QMouseEvent*); void keyPressEvent(QKeyEvent*); bool event(QEvent* event); void appendToSequence(int key); void updateOutput(); void startRecording(); void stopRecording(); KeySequence& keySequence() { return m_KeySequence; } KeySequence& backupSequence() { return m_BackupSequence; } private: enum Status { Stopped, Recording }; void setStatus(Status s) { m_Status = s; } Status status() const { return m_Status; } private: KeySequence m_KeySequence; KeySequence m_BackupSequence; Status m_Status; QString m_MousePrefix; QString m_MousePostfix; QString m_KeyPrefix; QString m_KeyPostfix; }; #endif synergy-1.8.8-stable/src/gui/src/LicenseManager.cpp000066400000000000000000000102501305627404700222310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015 Synergy Seamless Inc. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "LicenseManager.h" #include "EditionType.h" #include "AppConfig.h" #include #include #include #include LicenseManager::LicenseManager(AppConfig* appConfig) : m_AppConfig(appConfig), m_serialKey(appConfig->edition()) { } std::pair LicenseManager::setSerialKey(SerialKey serialKey, bool acceptExpired) { std::pair ret (true, ""); time_t currentTime = ::time(0); if (!acceptExpired && serialKey.isExpired(currentTime)) { ret.first = false; ret.second = "Serial key expired"; return ret; } if (serialKey != m_serialKey) { using std::swap; swap (serialKey, m_serialKey); m_AppConfig->setSerialKey(QString::fromStdString (m_serialKey.toString())); emit serialKeyChanged(m_serialKey); if (serialKey.isTrial()) { emit endTrial(false); } if (m_serialKey.edition() != serialKey.edition()) { m_AppConfig->setEdition(m_serialKey.edition()); emit editionChanged(m_serialKey.edition()); } if (m_serialKey.isTrial()) { if (m_serialKey.isExpired(currentTime)) { emit endTrial(true); } else { emit beginTrial(m_serialKey.isExpiring(currentTime)); } } m_AppConfig->saveSettings(); } return ret; } void LicenseManager::notifyUpdate(QString fromVersion, QString toVersion) { if ((fromVersion == "Unknown") && (m_serialKey == SerialKey(kUnregistered))) { return; } ActivationNotifier* notifier = new ActivationNotifier(); notifier->setUpdateInfo (fromVersion, toVersion, QString::fromStdString(m_serialKey.toString())); QThread* thread = new QThread(); connect(notifier, SIGNAL(finished()), thread, SLOT(quit())); connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); notifier->moveToThread(thread); thread->start(); QMetaObject::invokeMethod(notifier, "notifyUpdate", Qt::QueuedConnection); } Edition LicenseManager::activeEdition() const { return m_serialKey.edition(); } QString LicenseManager::activeEditionName() const { return getEditionName(activeEdition(), m_serialKey.isTrial()); } SerialKey LicenseManager::serialKey() const { return m_serialKey; } void LicenseManager::refresh() { if (!m_AppConfig->serialKey().isEmpty()) { try { SerialKey serialKey (m_AppConfig->serialKey().toStdString()); setSerialKey(serialKey, true); } catch (...) { m_AppConfig->clearSerialKey(); m_AppConfig->saveSettings(); } } if (m_serialKey.isExpired(::time(0))) { emit endTrial(true); } } void LicenseManager::skipActivation() { notifyActivation ("skip:unknown"); } QString LicenseManager::getEditionName(Edition const edition, bool trial) { std::string name ("Synergy"); switch (edition) { case kUnregistered: name += " (UNREGISTERED)"; return QString::fromUtf8 (name.c_str(), name.size()); case kBasic: name += " Basic"; break; default: name += " Pro"; } if (trial) { name += " (Trial)"; } return QString::fromUtf8 (name.c_str(), name.size()); } void LicenseManager::notifyActivation(QString identity) { ActivationNotifier* notifier = new ActivationNotifier(); notifier->setIdentity(identity); QThread* thread = new QThread(); connect(notifier, SIGNAL(finished()), thread, SLOT(quit())); connect(notifier, SIGNAL(finished()), notifier, SLOT(deleteLater())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); notifier->moveToThread(thread); thread->start(); QMetaObject::invokeMethod(notifier, "notify", Qt::QueuedConnection); } synergy-1.8.8-stable/src/gui/src/LicenseManager.h000066400000000000000000000030261305627404700217010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015 Synergy Seamless Inc. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include #include #include class AppConfig; class LicenseManager: public QObject { Q_OBJECT public: LicenseManager(AppConfig* appConfig); std::pair setSerialKey(SerialKey serialKey, bool acceptExpired = false); void refresh(); Edition activeEdition() const; QString activeEditionName() const; SerialKey serialKey() const; void skipActivation(); void notifyUpdate(QString fromVersion, QString toVersion); static QString getEditionName(Edition edition, bool trial = false); void notifyActivation(QString identity); private: AppConfig* m_AppConfig; SerialKey m_serialKey; signals: void serialKeyChanged (SerialKey) const; void editionChanged (Edition) const; void beginTrial (bool expiring) const; void endTrial (bool expired) const; }; synergy-1.8.8-stable/src/gui/src/MainWindow.cpp000066400000000000000000001136411305627404700214400ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define DOWNLOAD_URL "http://symless.com/?source=gui" #include #include "MainWindow.h" #include "Fingerprint.h" #include "AboutDialog.h" #include "ServerConfigDialog.h" #include "SettingsDialog.h" #include "ActivationDialog.h" #include "ZeroconfService.h" #include "DataDownloader.h" #include "CommandProcess.h" #include "LicenseManager.h" #include "EditionType.h" #include "QUtility.h" #include "ProcessorArch.h" #include "SslCertificate.h" #include #include #include #include #include #include #include #include #include #if defined(Q_OS_MAC) #include #endif #if defined(Q_OS_WIN) #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #include #endif #if defined(Q_OS_WIN) static const char synergyConfigName[] = "synergy.sgc"; static const QString synergyConfigFilter(QObject::tr("Synergy Configurations (*.sgc);;All files (*.*)")); static QString bonjourBaseUrl = "http://symless.com/bonjour/"; static const char bonjourFilename32[] = "Bonjour.msi"; static const char bonjourFilename64[] = "Bonjour64.msi"; static const char bonjourTargetFilename[] = "Bonjour.msi"; #else static const char synergyConfigName[] = "synergy.conf"; static const QString synergyConfigFilter(QObject::tr("Synergy Configurations (*.conf);;All files (*.*)")); #endif static const char* synergyIconFiles[] = { ":/res/icons/16x16/synergy-disconnected.png", ":/res/icons/16x16/synergy-disconnected.png", ":/res/icons/16x16/synergy-connected.png", ":/res/icons/16x16/synergy-transfering.png" }; MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig, LicenseManager& licenseManager) : m_Settings(settings), m_AppConfig(&appConfig), m_LicenseManager(&licenseManager), m_pSynergy(NULL), m_SynergyState(synergyDisconnected), m_ServerConfig(&m_Settings, 5, 3, m_AppConfig->screenName(), this), m_pTempConfigFile(NULL), m_pTrayIcon(NULL), m_pTrayIconMenu(NULL), m_AlreadyHidden(false), m_pMenuBar(NULL), m_pMenuFile(NULL), m_pMenuEdit(NULL), m_pMenuWindow(NULL), m_pMenuHelp(NULL), m_pZeroconfService(NULL), m_pDataDownloader(NULL), m_DownloadMessageBox(NULL), m_pCancelButton(NULL), m_SuppressAutoConfigWarning(false), m_BonjourInstall(NULL), m_SuppressEmptyServerWarning(false), m_ExpectedRunningState(kStopped), m_pSslCertificate(NULL), m_ActivationDialogRunning(false) { setupUi(this); createMenuBar(); loadSettings(); initConnections(); m_pWidgetUpdate->hide(); m_VersionChecker.setApp(appPath(appConfig.synergycName())); m_pLabelScreenName->setText(getScreenName()); m_pLabelIpAddresses->setText(getIPAddresses()); #if defined(Q_OS_WIN) // ipc must always be enabled, so that we can disable command when switching to desktop mode. connect(&m_IpcClient, SIGNAL(readLogLine(const QString&)), this, SLOT(appendLogRaw(const QString&))); connect(&m_IpcClient, SIGNAL(errorMessage(const QString&)), this, SLOT(appendLogError(const QString&))); connect(&m_IpcClient, SIGNAL(infoMessage(const QString&)), this, SLOT(appendLogNote(const QString&))); m_IpcClient.connectToHost(); #endif // change default size based on os #if defined(Q_OS_MAC) resize(720, 550); setMinimumSize(size()); #elif defined(Q_OS_LINUX) resize(700, 530); setMinimumSize(size()); #endif m_SuppressAutoConfigWarning = true; m_pCheckBoxAutoConfig->setChecked(appConfig.autoConfig()); m_SuppressAutoConfigWarning = false; m_pComboServerList->hide(); m_pLabelPadlock->hide(); m_trialWidget->hide(); connect (this, SIGNAL(windowShown()), this, SLOT(on_windowShown()), Qt::QueuedConnection); connect (m_LicenseManager, SIGNAL(editionChanged(Edition)), this, SLOT(setEdition(Edition)), Qt::QueuedConnection); connect (m_LicenseManager, SIGNAL(beginTrial(bool)), this, SLOT(beginTrial(bool)), Qt::QueuedConnection); connect (m_LicenseManager, SIGNAL(endTrial(bool)), this, SLOT(endTrial(bool)), Qt::QueuedConnection); connect (m_AppConfig, SIGNAL(sslToggled(bool)), this, SLOT(sslToggled(bool)), Qt::QueuedConnection); setWindowTitle (m_LicenseManager->activeEditionName()); m_LicenseManager->refresh(); QString lastVersion = m_AppConfig->lastVersion(); QString currentVersion = m_VersionChecker.getVersion(); if (lastVersion != currentVersion) { m_AppConfig->setLastVersion (currentVersion); m_AppConfig->saveSettings(); m_LicenseManager->notifyUpdate (lastVersion, currentVersion); } } MainWindow::~MainWindow() { if (appConfig().processMode() == Desktop) { m_ExpectedRunningState = kStopped; stopDesktop(); } saveSettings(); delete m_pZeroconfService; if (m_DownloadMessageBox != NULL) { delete m_DownloadMessageBox; } if (m_BonjourInstall != NULL) { delete m_BonjourInstall; } delete m_pSslCertificate; } void MainWindow::open() { createTrayIcon(); if (!autoHide()) { showNormal(); } m_VersionChecker.checkLatest(); if (!appConfig().autoConfigPrompted()) { promptAutoConfig(); } // only start if user has previously started. this stops the gui from // auto hiding before the user has configured synergy (which of course // confuses first time users, who think synergy has crashed). if (appConfig().startedBefore() && appConfig().processMode() == Desktop) { m_SuppressEmptyServerWarning = true; startSynergy(); m_SuppressEmptyServerWarning = false; } } void MainWindow::onModeChanged(bool startDesktop, bool applyService) { if (appConfig().processMode() == Service) { // ensure that the apply button actually does something, since desktop // mode screws around with connecting/disconnecting the action. disconnect(m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger())); connect(m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger())); if (applyService) { stopDesktop(); startSynergy(); } } else if ((appConfig().processMode() == Desktop) && startDesktop) { stopService(); startSynergy(); } } void MainWindow::setStatus(const QString &status) { m_pStatusLabel->setText(status); } void MainWindow::createTrayIcon() { m_pTrayIconMenu = new QMenu(this); m_pTrayIconMenu->addAction(m_pActionStartSynergy); m_pTrayIconMenu->addAction(m_pActionStopSynergy); m_pTrayIconMenu->addSeparator(); m_pTrayIconMenu->addAction(m_pActionMinimize); m_pTrayIconMenu->addAction(m_pActionRestore); m_pTrayIconMenu->addSeparator(); m_pTrayIconMenu->addAction(m_pActionQuit); m_pTrayIcon = new QSystemTrayIcon(this); m_pTrayIcon->setContextMenu(m_pTrayIconMenu); connect(m_pTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason))); setIcon(synergyDisconnected); m_pTrayIcon->show(); } void MainWindow::retranslateMenuBar() { m_pMenuFile->setTitle(tr("&File")); m_pMenuEdit->setTitle(tr("&Edit")); m_pMenuWindow->setTitle(tr("&Window")); m_pMenuHelp->setTitle(tr("&Help")); } void MainWindow::createMenuBar() { m_pMenuBar = new QMenuBar(this); m_pMenuFile = new QMenu("", m_pMenuBar); m_pMenuEdit = new QMenu("", m_pMenuBar); m_pMenuWindow = new QMenu("", m_pMenuBar); m_pMenuHelp = new QMenu("", m_pMenuBar); retranslateMenuBar(); m_pMenuBar->addAction(m_pMenuFile->menuAction()); m_pMenuBar->addAction(m_pMenuEdit->menuAction()); #if !defined(Q_OS_MAC) m_pMenuBar->addAction(m_pMenuWindow->menuAction()); #endif m_pMenuBar->addAction(m_pMenuHelp->menuAction()); m_pMenuFile->addAction(m_pActionStartSynergy); m_pMenuFile->addAction(m_pActionStopSynergy); m_pMenuFile->addSeparator(); m_pMenuFile->addAction(m_pActivate); m_pMenuFile->addSeparator(); m_pMenuFile->addAction(m_pActionSave); m_pMenuFile->addSeparator(); m_pMenuFile->addAction(m_pActionQuit); m_pMenuEdit->addAction(m_pActionSettings); m_pMenuWindow->addAction(m_pActionMinimize); m_pMenuWindow->addAction(m_pActionRestore); m_pMenuHelp->addAction(m_pActionAbout); setMenuBar(m_pMenuBar); } void MainWindow::loadSettings() { // the next two must come BEFORE loading groupServerChecked and groupClientChecked or // disabling and/or enabling the right widgets won't automatically work m_pRadioExternalConfig->setChecked(settings().value("useExternalConfig", false).toBool()); m_pRadioInternalConfig->setChecked(settings().value("useInternalConfig", true).toBool()); m_pGroupServer->setChecked(settings().value("groupServerChecked", false).toBool()); m_pLineEditConfigFile->setText(settings().value("configFile", QDir::homePath() + "/" + synergyConfigName).toString()); m_pGroupClient->setChecked(settings().value("groupClientChecked", true).toBool()); m_pLineEditHostname->setText(settings().value("serverHostname").toString()); } void MainWindow::initConnections() { connect(m_pActionMinimize, SIGNAL(triggered()), this, SLOT(hide())); connect(m_pActionRestore, SIGNAL(triggered()), this, SLOT(showNormal())); connect(m_pActionStartSynergy, SIGNAL(triggered()), this, SLOT(startSynergy())); connect(m_pActionStopSynergy, SIGNAL(triggered()), this, SLOT(stopSynergy())); connect(m_pActionQuit, SIGNAL(triggered()), qApp, SLOT(quit())); connect(&m_VersionChecker, SIGNAL(updateFound(const QString&)), this, SLOT(updateFound(const QString&))); } void MainWindow::saveSettings() { // program settings settings().setValue("groupServerChecked", m_pGroupServer->isChecked()); settings().setValue("useExternalConfig", m_pRadioExternalConfig->isChecked()); settings().setValue("configFile", m_pLineEditConfigFile->text()); settings().setValue("useInternalConfig", m_pRadioInternalConfig->isChecked()); settings().setValue("groupClientChecked", m_pGroupClient->isChecked()); settings().setValue("serverHostname", m_pLineEditHostname->text()); settings().sync(); } void MainWindow::setIcon(qSynergyState state) { QIcon icon; icon.addFile(synergyIconFiles[state]); if (m_pTrayIcon) m_pTrayIcon->setIcon(icon); } void MainWindow::trayActivated(QSystemTrayIcon::ActivationReason reason) { #ifndef Q_OS_WIN if (reason == QSystemTrayIcon::DoubleClick) { if (isVisible()) { hide(); } else { showNormal(); activateWindow(); } } #endif } void MainWindow::logOutput() { if (m_pSynergy) { QString text(m_pSynergy->readAllStandardOutput()); foreach(QString line, text.split(QRegExp("\r|\n|\r\n"))) { if (!line.isEmpty()) { appendLogRaw(line); } } } } void MainWindow::logError() { if (m_pSynergy) { appendLogRaw(m_pSynergy->readAllStandardError()); } } void MainWindow::updateFound(const QString &version) { m_pWidgetUpdate->show(); m_pLabelUpdate->setText( tr("

Your version of Synergy is out of date. " "Version %1 is now available to " "download.

") .arg(version).arg(DOWNLOAD_URL)); } void MainWindow::appendLogInfo(const QString& text) { appendLogRaw(getTimeStamp() + " INFO: " + text); } void MainWindow::appendLogDebug(const QString& text) { if (appConfig().logLevel() >= 4) { appendLogRaw(getTimeStamp() + " DEBUG: " + text); } } void MainWindow::appendLogError(const QString& text) { appendLogRaw(getTimeStamp() + " ERROR: " + text); } void MainWindow::appendLogRaw(const QString& text) { foreach(QString line, text.split(QRegExp("\r|\n|\r\n"))) { if (!line.isEmpty()) { m_pLogOutput->append(line); updateFromLogLine(line); } } } void MainWindow::updateFromLogLine(const QString &line) { // TODO: this code makes Andrew cry checkConnected(line); checkFingerprint(line); checkLicense(line); } void MainWindow::checkConnected(const QString& line) { // TODO: implement ipc connection state messages to replace this hack. if (line.contains("started server") || line.contains("connected to server") || line.contains("watchdog status: ok")) { setSynergyState(synergyConnected); if (!appConfig().startedBefore() && isVisible()) { QMessageBox::information( this, "Synergy", tr("Synergy is now connected. You can close the " "config window and Synergy will remain connected in " "the background.")); appConfig().setStartedBefore(true); appConfig().saveSettings(); } } } void MainWindow::checkLicense(const QString &line) { if (line.contains("trial has expired")) { licenseManager().refresh(); raiseActivationDialog(); } } void MainWindow::checkFingerprint(const QString& line) { QRegExp fingerprintRegex(".*server fingerprint: ([A-F0-9:]+)"); if (!fingerprintRegex.exactMatch(line)) { return; } QString fingerprint = fingerprintRegex.cap(1); if (Fingerprint::trustedServers().isTrusted(fingerprint)) { return; } static bool messageBoxAlreadyShown = false; if (!messageBoxAlreadyShown) { stopSynergy(); messageBoxAlreadyShown = true; QMessageBox::StandardButton fingerprintReply = QMessageBox::information( this, tr("Security question"), tr("Do you trust this fingerprint?\n\n" "%1\n\n" "This is a server fingerprint. You should compare this " "fingerprint to the one on your server's screen. If the " "two don't match exactly, then it's probably not the server " "you're expecting (it could be a malicious user).\n\n" "To automatically trust this fingerprint for future " "connections, click Yes. To reject this fingerprint and " "disconnect from the server, click No.") .arg(fingerprint), QMessageBox::Yes | QMessageBox::No); if (fingerprintReply == QMessageBox::Yes) { // restart core process after trusting fingerprint. Fingerprint::trustedServers().trust(fingerprint); startSynergy(); } messageBoxAlreadyShown = false; } } bool MainWindow::autoHide() { if ((appConfig().processMode() == Desktop) && appConfig().getAutoHide()) { hide(); return true; } return false; } QString MainWindow::getTimeStamp() { QDateTime current = QDateTime::currentDateTime(); return '[' + current.toString(Qt::ISODate) + ']'; } void MainWindow::restartSynergy() { stopSynergy(); startSynergy(); } void MainWindow::proofreadInfo() { setEdition(m_AppConfig->edition()); // Why is this here? int oldState = m_SynergyState; m_SynergyState = synergyDisconnected; setSynergyState((qSynergyState)oldState); } void MainWindow::showEvent(QShowEvent* event) { QMainWindow::showEvent(event); emit windowShown(); } void MainWindow::clearLog() { m_pLogOutput->clear(); } void MainWindow::startSynergy() { SerialKey serialKey = m_LicenseManager->serialKey(); time_t currentTime = ::time(0); if (serialKey.isExpired(currentTime)) { if (QDialog::Rejected == raiseActivationDialog()) { return; } } bool desktopMode = appConfig().processMode() == Desktop; bool serviceMode = appConfig().processMode() == Service; appendLogDebug("starting process"); m_ExpectedRunningState = kStarted; setSynergyState(synergyConnecting); QString app; QStringList args; args << "-f" << "--no-tray" << "--debug" << appConfig().logLevelText(); args << "--name" << getScreenName(); if (desktopMode) { setSynergyProcess(new QProcess(this)); } else { // tell client/server to talk to daemon through ipc. args << "--ipc"; #if defined(Q_OS_WIN) // tell the client/server to shut down when a ms windows desk // is switched; this is because we may need to elevate or not // based on which desk the user is in (login always needs // elevation, where as default desk does not). // Note that this is only enabled when synergy is set to elevate // 'as needed' (e.g. on a UAC dialog popup) in order to prevent // unnecessary restarts when synergy was started elevated or // when it is not allowed to elevate. In these cases restarting // the server is fruitless. if (appConfig().elevateMode() == ElevateAsNeeded) { args << "--stop-on-desk-switch"; } #endif } #ifndef Q_OS_LINUX if (m_ServerConfig.enableDragAndDrop()) { args << "--enable-drag-drop"; } #endif if (m_AppConfig->getCryptoEnabled()) { args << "--enable-crypto"; } #if defined(Q_OS_WIN) // on windows, the profile directory changes depending on the user that // launched the process (e.g. when launched with elevation). setting the // profile dir on launch ensures it uses the same profile dir is used // no matter how its relaunched. args << "--profile-dir" << getProfileRootForArg(); #endif if ((synergyType() == synergyClient && !clientArgs(args, app)) || (synergyType() == synergyServer && !serverArgs(args, app))) { stopSynergy(); return; } if (desktopMode) { connect(synergyProcess(), SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(synergyFinished(int, QProcess::ExitStatus))); connect(synergyProcess(), SIGNAL(readyReadStandardOutput()), this, SLOT(logOutput())); connect(synergyProcess(), SIGNAL(readyReadStandardError()), this, SLOT(logError())); } // put a space between last log output and new instance. if (!m_pLogOutput->toPlainText().isEmpty()) appendLogRaw(""); appendLogInfo("starting " + QString(synergyType() == synergyServer ? "server" : "client")); qDebug() << args; // show command if debug log level... if (appConfig().logLevel() >= 4) { appendLogInfo(QString("command: %1 %2").arg(app, args.join(" "))); } appendLogInfo("config file: " + configFilename()); appendLogInfo("log level: " + appConfig().logLevelText()); if (appConfig().logToFile()) appendLogInfo("log file: " + appConfig().logFilename()); if (desktopMode) { synergyProcess()->start(app, args); if (!synergyProcess()->waitForStarted()) { show(); QMessageBox::warning(this, tr("Program can not be started"), QString(tr("The executable

%1

could not be successfully started, although it does exist. Please check if you have sufficient permissions to run this program.").arg(app))); return; } } if (serviceMode) { QString command(app + " " + args.join(" ")); m_IpcClient.sendCommand(command, appConfig().elevateMode()); } } void MainWindow::sslToggled (bool enabled) { if (enabled) { m_pSslCertificate = new SslCertificate(this); m_pSslCertificate->generateCertificate(); } updateLocalFingerprint(); } bool MainWindow::clientArgs(QStringList& args, QString& app) { app = appPath(appConfig().synergycName()); if (!QFile::exists(app)) { show(); QMessageBox::warning(this, tr("Synergy client not found"), tr("The executable for the synergy client does not exist.")); return false; } #if defined(Q_OS_WIN) // wrap in quotes so a malicious user can't start \Program.exe as admin. app = QString("\"%1\"").arg(app); #endif if (appConfig().logToFile()) { appConfig().persistLogDir(); args << "--log" << appConfig().logFilenameCmd(); } // check auto config first, if it is disabled or no server detected, // use line edit host name if it is not empty if (m_pCheckBoxAutoConfig->isChecked()) { if (m_pComboServerList->count() != 0) { QString serverIp = m_pComboServerList->currentText(); args << serverIp + ":" + QString::number(appConfig().port()); return true; } } if (m_pLineEditHostname->text().isEmpty()) { show(); if (!m_SuppressEmptyServerWarning) { QMessageBox::warning(this, tr("Hostname is empty"), tr("Please fill in a hostname for the synergy client to connect to.")); } return false; } args << m_pLineEditHostname->text() + ":" + QString::number(appConfig().port()); return true; } QString MainWindow::configFilename() { QString filename; if (m_pRadioInternalConfig->isChecked()) { // TODO: no need to use a temporary file, since we need it to // be permenant (since it'll be used for Windows services, etc). m_pTempConfigFile = new QTemporaryFile(); if (!m_pTempConfigFile->open()) { QMessageBox::critical(this, tr("Cannot write configuration file"), tr("The temporary configuration file required to start synergy can not be written.")); return ""; } serverConfig().save(*m_pTempConfigFile); filename = m_pTempConfigFile->fileName(); m_pTempConfigFile->close(); } else { if (!QFile::exists(m_pLineEditConfigFile->text())) { if (QMessageBox::warning(this, tr("Configuration filename invalid"), tr("You have not filled in a valid configuration file for the synergy server. " "Do you want to browse for the configuration file now?"), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes || !on_m_pButtonBrowseConfigFile_clicked()) return ""; } filename = m_pLineEditConfigFile->text(); } return filename; } QString MainWindow::address() { QString i = appConfig().interface(); return (!i.isEmpty() ? i : "") + ":" + QString::number(appConfig().port()); } QString MainWindow::appPath(const QString& name) { return appConfig().synergyProgramDir() + name; } bool MainWindow::serverArgs(QStringList& args, QString& app) { app = appPath(appConfig().synergysName()); if (!QFile::exists(app)) { QMessageBox::warning(this, tr("Synergy server not found"), tr("The executable for the synergy server does not exist.")); return false; } #if defined(Q_OS_WIN) // wrap in quotes so a malicious user can't start \Program.exe as admin. app = QString("\"%1\"").arg(app); #endif if (appConfig().logToFile()) { appConfig().persistLogDir(); args << "--log" << appConfig().logFilenameCmd(); } QString configFilename = this->configFilename(); #if defined(Q_OS_WIN) // wrap in quotes in case username contains spaces. configFilename = QString("\"%1\"").arg(configFilename); #endif args << "-c" << configFilename << "--address" << address(); if (!appConfig().serialKey().isEmpty()) { args << "--serial-key" << appConfig().serialKey(); } return true; } void MainWindow::stopSynergy() { appendLogDebug("stopping process"); m_ExpectedRunningState = kStopped; if (appConfig().processMode() == Service) { stopService(); } else if (appConfig().processMode() == Desktop) { stopDesktop(); } setSynergyState(synergyDisconnected); // HACK: deleting the object deletes the physical file, which is // bad, since it could be in use by the Windows service! //delete m_pTempConfigFile; m_pTempConfigFile = NULL; // reset so that new connects cause auto-hide. m_AlreadyHidden = false; } void MainWindow::stopService() { // send empty command to stop service from laucning anything. m_IpcClient.sendCommand("", appConfig().elevateMode()); } void MainWindow::stopDesktop() { QMutexLocker locker(&m_StopDesktopMutex); if (!synergyProcess()) { return; } appendLogInfo("stopping synergy desktop process"); if (synergyProcess()->isOpen()) { synergyProcess()->close(); } delete synergyProcess(); setSynergyProcess(NULL); } void MainWindow::synergyFinished(int exitCode, QProcess::ExitStatus) { if (exitCode == 0) { appendLogInfo(QString("process exited normally")); } else { appendLogError(QString("process exited with error code: %1").arg(exitCode)); } if (m_ExpectedRunningState == kStarted) { QTimer::singleShot(1000, this, SLOT(startSynergy())); appendLogInfo(QString("detected process not running, auto restarting")); } else { setSynergyState(synergyDisconnected); } } void MainWindow::setSynergyState(qSynergyState state) { if (synergyState() == state) return; if (state == synergyConnected || state == synergyConnecting) { disconnect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger())); connect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, SLOT(trigger())); m_pButtonToggleStart->setText(tr("&Stop")); m_pButtonApply->setEnabled(true); } else if (state == synergyDisconnected) { disconnect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStopSynergy, SLOT(trigger())); connect (m_pButtonToggleStart, SIGNAL(clicked()), m_pActionStartSynergy, SLOT(trigger())); m_pButtonToggleStart->setText(tr("&Start")); m_pButtonApply->setEnabled(false); } bool connected = false; if (state == synergyConnected || state == synergyTransfering) { connected = true; } m_pActionStartSynergy->setEnabled(!connected); m_pActionStopSynergy->setEnabled(connected); switch (state) { case synergyConnected: { if (m_AppConfig->getCryptoEnabled()) { m_pLabelPadlock->show(); } else { m_pLabelPadlock->hide(); } setStatus(tr("Synergy is running.")); break; } case synergyConnecting: m_pLabelPadlock->hide(); setStatus(tr("Synergy is starting.")); break; case synergyDisconnected: m_pLabelPadlock->hide(); setStatus(tr("Synergy is not running.")); break; case synergyTransfering: break; } setIcon(state); m_SynergyState = state; } void MainWindow::setVisible(bool visible) { QMainWindow::setVisible(visible); m_pActionMinimize->setEnabled(visible); m_pActionRestore->setEnabled(!visible); #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 // lion // dock hide only supported on lion :( ProcessSerialNumber psn = { 0, kCurrentProcess }; GetCurrentProcess(&psn); if (visible) TransformProcessType(&psn, kProcessTransformToForegroundApplication); else TransformProcessType(&psn, kProcessTransformToBackgroundApplication); #endif } QString MainWindow::getIPAddresses() { QList addresses = QNetworkInterface::allAddresses(); bool hinted = false; QString result; for (int i = 0; i < addresses.size(); i++) { if (addresses[i].protocol() == QAbstractSocket::IPv4Protocol && addresses[i] != QHostAddress(QHostAddress::LocalHost)) { QString address = addresses[i].toString(); QString format = "%1, "; // usually 192.168.x.x is a useful ip for the user, so indicate // this by making it bold. if (!hinted && address.startsWith("192.168")) { hinted = true; format = "%1, "; } result += format.arg(address); } } if (result == "") { return tr("Unknown"); } // remove trailing comma. result.chop(2); return result; } QString MainWindow::getScreenName() { if (appConfig().screenName() == "") { return QHostInfo::localHostName(); } else { return appConfig().screenName(); } } void MainWindow::changeEvent(QEvent* event) { if (event != 0) { switch (event->type()) { case QEvent::LanguageChange: { retranslateUi(this); retranslateMenuBar(); proofreadInfo(); break; } default: QMainWindow::changeEvent(event); } } } void MainWindow::updateZeroconfService() { QMutexLocker locker(&m_UpdateZeroconfMutex); if (isBonjourRunning()) { if (!m_AppConfig->wizardShouldRun()) { if (m_pZeroconfService) { delete m_pZeroconfService; m_pZeroconfService = NULL; } if (m_AppConfig->autoConfig() || synergyType() == synergyServer) { m_pZeroconfService = new ZeroconfService(this); } } } } void MainWindow::serverDetected(const QString name) { if (m_pComboServerList->findText(name) == -1) { // Note: the first added item triggers startSynergy m_pComboServerList->addItem(name); } if (m_pComboServerList->count() > 1) { m_pComboServerList->show(); } } void MainWindow::setEdition(Edition edition) { setWindowTitle(m_LicenseManager->getEditionName (edition)); if (m_AppConfig->getCryptoEnabled()) { m_pSslCertificate = new SslCertificate(this); m_pSslCertificate->generateCertificate(); } updateLocalFingerprint(); saveSettings(); } void MainWindow::beginTrial(bool isExpiring) { //Hack //if (isExpiring) { time_t daysLeft = m_LicenseManager->serialKey().daysLeft(::time(0)); QString expiringNotice ("

%1 day%3 of " "your %2 trial remain%5. " "Buy now!" "

"); expiringNotice = expiringNotice .arg (daysLeft) .arg (LicenseManager::getEditionName (m_LicenseManager->activeEdition())) .arg ((daysLeft == 1) ? "" : "s") .arg (QString::fromStdString (m_LicenseManager->serialKey().toString())) .arg ((daysLeft == 1) ? "s" : ""); this->m_trialLabel->setText(expiringNotice); this->m_trialWidget->show(); //} setWindowTitle (m_LicenseManager->activeEditionName()); } void MainWindow::endTrial(bool isExpired) { if (isExpired) { QString expiredNotice ( "

Your %1 trial has expired. " "" "Buy now!

" ); expiredNotice = expiredNotice .arg(LicenseManager::getEditionName (m_LicenseManager->activeEdition())) .arg(QString::fromStdString (m_LicenseManager->serialKey().toString())); this->m_trialLabel->setText(expiredNotice); this->m_trialWidget->show(); stopSynergy(); m_AppConfig->activationHasRun(false); } else { this->m_trialWidget->hide(); } setWindowTitle (m_LicenseManager->activeEditionName()); } void MainWindow::updateLocalFingerprint() { if (m_AppConfig->getCryptoEnabled() && Fingerprint::local().fileExists()) { m_pLabelFingerprint->setVisible(true); m_pLabelLocalFingerprint->setVisible(true); m_pLabelLocalFingerprint->setText(Fingerprint::local().readFirst()); } else { m_pLabelFingerprint->setVisible(false); m_pLabelLocalFingerprint->setVisible(false); } } LicenseManager& MainWindow::licenseManager() const { return *m_LicenseManager; } void MainWindow::on_m_pGroupClient_toggled(bool on) { m_pGroupServer->setChecked(!on); if (on) { updateZeroconfService(); } } void MainWindow::on_m_pGroupServer_toggled(bool on) { m_pGroupClient->setChecked(!on); if (on) { updateZeroconfService(); } } bool MainWindow::on_m_pButtonBrowseConfigFile_clicked() { QString fileName = QFileDialog::getOpenFileName(this, tr("Browse for a synergys config file"), QString(), synergyConfigFilter); if (!fileName.isEmpty()) { m_pLineEditConfigFile->setText(fileName); return true; } return false; } bool MainWindow::on_m_pActionSave_triggered() { QString fileName = QFileDialog::getSaveFileName(this, tr("Save configuration as...")); if (!fileName.isEmpty() && !serverConfig().save(fileName)) { QMessageBox::warning(this, tr("Save failed"), tr("Could not save configuration to file.")); return true; } return false; } void MainWindow::on_m_pActionAbout_triggered() { AboutDialog dlg(this, appPath(appConfig().synergycName())); dlg.exec(); } void MainWindow::on_m_pActionSettings_triggered() { ProcessMode lastProcessMode = appConfig().processMode(); SettingsDialog dlg(this, appConfig()); dlg.exec(); if (lastProcessMode != appConfig().processMode()) { onModeChanged(true, true); } } void MainWindow::autoAddScreen(const QString name) { if (!m_ServerConfig.ignoreAutoConfigClient()) { if (m_ActivationDialogRunning) { // TODO: refactor this code // add this screen to the pending list and check this list until // users finish activation dialog m_PendingClientNames.append(name); return; } int r = m_ServerConfig.autoAddScreen(name); if (r != kAutoAddScreenOk) { switch (r) { case kAutoAddScreenManualServer: showConfigureServer( tr("Please add the server (%1) to the grid.") .arg(appConfig().screenName())); break; case kAutoAddScreenManualClient: showConfigureServer( tr("Please drag the new client screen (%1) " "to the desired position on the grid.") .arg(name)); break; } } else { restartSynergy(); } } } void MainWindow::showConfigureServer(const QString& message) { ServerConfigDialog dlg(this, serverConfig(), appConfig().screenName()); dlg.message(message); dlg.exec(); } void MainWindow::on_m_pButtonConfigureServer_clicked() { showConfigureServer(); } void MainWindow::on_m_pActivate_triggered() { raiseActivationDialog(); } void MainWindow::on_m_pButtonApply_clicked() { restartSynergy(); } #if defined(Q_OS_WIN) bool MainWindow::isServiceRunning(QString name) { SC_HANDLE hSCManager; hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (hSCManager == NULL) { appendLogError("failed to open a service controller manager, error: " + GetLastError()); return false; } SC_HANDLE hService; int length = name.length(); wchar_t* array = new wchar_t[length + 1]; name.toWCharArray(array); array[length] = '\0'; hService = OpenService(hSCManager, array, SERVICE_QUERY_STATUS); delete[] array; if (hService == NULL) { appendLogDebug("failed to open service: " + name); return false; } SERVICE_STATUS status; if (QueryServiceStatus(hService, &status)) { if (status.dwCurrentState == SERVICE_RUNNING) { return true; } } #else bool MainWindow::isServiceRunning() { #endif return false; } bool MainWindow::isBonjourRunning() { bool result = false; #if defined(Q_OS_WIN) result = isServiceRunning("Bonjour Service"); #else result = true; #endif return result; } void MainWindow::downloadBonjour() { #if defined(Q_OS_WIN) QUrl url; int arch = getProcessorArch(); if (arch == kProcessorArchWin32) { url.setUrl(bonjourBaseUrl + bonjourFilename32); appendLogInfo("downloading 32-bit Bonjour"); } else if (arch == kProcessorArchWin64) { url.setUrl(bonjourBaseUrl + bonjourFilename64); appendLogInfo("downloading 64-bit Bonjour"); } else { QMessageBox::critical( this, tr("Synergy"), tr("Failed to detect system architecture.")); return; } if (m_pDataDownloader == NULL) { m_pDataDownloader = new DataDownloader(this); connect(m_pDataDownloader, SIGNAL(isComplete()), SLOT(installBonjour())); } m_pDataDownloader->download(url); if (m_DownloadMessageBox == NULL) { m_DownloadMessageBox = new QMessageBox(this); m_DownloadMessageBox->setWindowTitle("Synergy"); m_DownloadMessageBox->setIcon(QMessageBox::Information); m_DownloadMessageBox->setText("Installing Bonjour, please wait..."); m_DownloadMessageBox->setStandardButtons(0); m_pCancelButton = m_DownloadMessageBox->addButton( tr("Cancel"), QMessageBox::RejectRole); } m_DownloadMessageBox->exec(); if (m_DownloadMessageBox->clickedButton() == m_pCancelButton) { m_pDataDownloader->cancel(); } #endif } void MainWindow::installBonjour() { #if defined(Q_OS_WIN) QString tempLocation = QDesktopServices::storageLocation( QDesktopServices::TempLocation); QString filename = tempLocation; filename.append("\\").append(bonjourTargetFilename); QFile file(filename); if (!file.open(QIODevice::WriteOnly)) { m_DownloadMessageBox->hide(); QMessageBox::warning( this, "Synergy", tr("Failed to download Bonjour installer to location: %1") .arg(tempLocation)); return; } file.write(m_pDataDownloader->data()); file.close(); QStringList arguments; arguments.append("/i"); QString winFilename = QDir::toNativeSeparators(filename); arguments.append(winFilename); arguments.append("/passive"); if (m_BonjourInstall == NULL) { m_BonjourInstall = new CommandProcess("msiexec", arguments); } QThread* thread = new QThread; connect(m_BonjourInstall, SIGNAL(finished()), this, SLOT(bonjourInstallFinished())); connect(m_BonjourInstall, SIGNAL(finished()), thread, SLOT(quit())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); m_BonjourInstall->moveToThread(thread); thread->start(); QMetaObject::invokeMethod(m_BonjourInstall, "run", Qt::QueuedConnection); m_DownloadMessageBox->hide(); #endif } void MainWindow::promptAutoConfig() { if (!isBonjourRunning()) { int r = QMessageBox::question( this, tr("Synergy"), tr("Do you want to enable auto config and install Bonjour?\n\n" "This feature helps you establish the connection."), QMessageBox::Yes | QMessageBox::No); if (r == QMessageBox::Yes) { m_AppConfig->setAutoConfig(true); downloadBonjour(); } else { m_AppConfig->setAutoConfig(false); m_pCheckBoxAutoConfig->setChecked(false); } } m_AppConfig->setAutoConfigPrompted(true); } void MainWindow::on_m_pComboServerList_currentIndexChanged(QString ) { if (m_pComboServerList->count() != 0) { restartSynergy(); } } void MainWindow::on_m_pCheckBoxAutoConfig_toggled(bool checked) { if (!isBonjourRunning() && checked) { if (!m_SuppressAutoConfigWarning) { int r = QMessageBox::information( this, tr("Synergy"), tr("Auto config feature requires Bonjour.\n\n" "Do you want to install Bonjour?"), QMessageBox::Yes | QMessageBox::No); if (r == QMessageBox::Yes) { downloadBonjour(); } } m_pCheckBoxAutoConfig->setChecked(false); return; } m_pLineEditHostname->setDisabled(checked); appConfig().setAutoConfig(checked); updateZeroconfService(); if (!checked) { m_pComboServerList->clear(); m_pComboServerList->hide(); } } void MainWindow::bonjourInstallFinished() { appendLogInfo("Bonjour install finished"); m_pCheckBoxAutoConfig->setChecked(true); } int MainWindow::raiseActivationDialog() { if (m_ActivationDialogRunning) { return QDialog::Rejected; } ActivationDialog activationDialog (this, appConfig(), licenseManager()); m_ActivationDialogRunning = true; connect (&activationDialog, SIGNAL(finished(int)), this, SLOT(on_activationDialogFinish()), Qt::QueuedConnection); int result = activationDialog.exec(); m_ActivationDialogRunning = false; if (!m_PendingClientNames.empty()) { foreach (const QString& name, m_PendingClientNames) { autoAddScreen(name); } m_PendingClientNames.clear(); } if (result == QDialog::Accepted) { restartSynergy(); } return result; } void MainWindow::on_windowShown() { time_t currentTime = ::time(0); if (!m_AppConfig->activationHasRun() && ((m_AppConfig->edition() == kUnregistered) || (m_LicenseManager->serialKey().isExpired(currentTime)))) { raiseActivationDialog(); } } QString MainWindow::getProfileRootForArg() { CoreInterface coreInterface; QString dir = coreInterface.getProfileDir(); // HACK: strip our app name since we're returning the root dir. #if defined(Q_OS_WIN) dir.replace("\\Synergy", ""); #else dir.replace("/.synergy", ""); #endif return QString("\"%1\"").arg(dir); } synergy-1.8.8-stable/src/gui/src/MainWindow.h000066400000000000000000000146611305627404700211070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(MAINWINDOW__H) #define MAINWINDOW__H #include #include #include #include #include #include "ui_MainWindowBase.h" #include "ServerConfig.h" #include "AppConfig.h" #include "VersionChecker.h" #include "IpcClient.h" #include "Ipc.h" #include "ActivationDialog.h" #include class QAction; class QMenu; class QLineEdit; class QGroupBox; class QPushButton; class QTextEdit; class QComboBox; class QTabWidget; class QCheckBox; class QRadioButton; class QTemporaryFile; class QMessageBox; class QAbstractButton; class LogDialog; class QSynergyApplication; class SetupWizard; class ZeroconfService; class DataDownloader; class CommandProcess; class SslCertificate; class LicenseManager; class MainWindow : public QMainWindow, public Ui::MainWindowBase { Q_OBJECT friend class QSynergyApplication; friend class SetupWizard; friend class ActivationDialog; friend class SettingsDialog; public: enum qSynergyState { synergyDisconnected, synergyConnecting, synergyConnected, synergyTransfering }; enum qSynergyType { synergyClient, synergyServer }; enum qLevel { Error, Info }; enum qRuningState { kStarted, kStopped }; public: MainWindow(QSettings& settings, AppConfig& appConfig, LicenseManager& licenseManager); ~MainWindow(); public: void setVisible(bool visible); int synergyType() const { return m_pGroupClient->isChecked() ? synergyClient : synergyServer; } int synergyState() const { return m_SynergyState; } QString hostname() const { return m_pLineEditHostname->text(); } QString configFilename(); QString address(); QString appPath(const QString& name); void open(); void clearLog(); VersionChecker& versionChecker() { return m_VersionChecker; } QString getScreenName(); ServerConfig& serverConfig() { return m_ServerConfig; } void showConfigureServer(const QString& message); void showConfigureServer() { showConfigureServer(""); } void autoAddScreen(const QString name); void updateZeroconfService(); void serverDetected(const QString name); void updateLocalFingerprint(); LicenseManager& licenseManager() const; int raiseActivationDialog(); public slots: void setEdition(Edition edition); void beginTrial(bool isExpiring); void endTrial(bool isExpired); void appendLogRaw(const QString& text); void appendLogInfo(const QString& text); void appendLogDebug(const QString& text); void appendLogError(const QString& text); void startSynergy(); protected slots: void sslToggled(bool enabled); void on_m_pGroupClient_toggled(bool on); void on_m_pGroupServer_toggled(bool on); bool on_m_pButtonBrowseConfigFile_clicked(); void on_m_pButtonConfigureServer_clicked(); bool on_m_pActionSave_triggered(); void on_m_pActionAbout_triggered(); void on_m_pActionSettings_triggered(); void on_m_pActivate_triggered(); void synergyFinished(int exitCode, QProcess::ExitStatus); void trayActivated(QSystemTrayIcon::ActivationReason reason); void stopSynergy(); void logOutput(); void logError(); void updateFound(const QString& version); void bonjourInstallFinished(); protected: QSettings& settings() { return m_Settings; } AppConfig& appConfig() { return *m_AppConfig; } QProcess* synergyProcess() { return m_pSynergy; } void setSynergyProcess(QProcess* p) { m_pSynergy = p; } void initConnections(); void createMenuBar(); void createStatusBar(); void createTrayIcon(); void loadSettings(); void saveSettings(); void setIcon(qSynergyState state); void setSynergyState(qSynergyState state); bool checkForApp(int which, QString& app); bool clientArgs(QStringList& args, QString& app); bool serverArgs(QStringList& args, QString& app); void setStatus(const QString& status); void sendIpcMessage(qIpcMessageType type, const char* buffer, bool showErrors); void onModeChanged(bool startDesktop, bool applyService); void updateFromLogLine(const QString& line); QString getIPAddresses(); void stopService(); void stopDesktop(); void changeEvent(QEvent* event); void retranslateMenuBar(); #if defined(Q_OS_WIN) bool isServiceRunning(QString name); #else bool isServiceRunning(); #endif bool isBonjourRunning(); void downloadBonjour(); void promptAutoConfig(); QString getProfileRootForArg(); void checkConnected(const QString& line); void checkLicense(const QString& line); void checkFingerprint(const QString& line); bool autoHide(); QString getTimeStamp(); void restartSynergy(); void proofreadInfo(); void showEvent (QShowEvent*); private: QSettings& m_Settings; AppConfig* m_AppConfig; LicenseManager* m_LicenseManager; QProcess* m_pSynergy; int m_SynergyState; ServerConfig m_ServerConfig; QTemporaryFile* m_pTempConfigFile; QSystemTrayIcon* m_pTrayIcon; QMenu* m_pTrayIconMenu; bool m_AlreadyHidden; VersionChecker m_VersionChecker; IpcClient m_IpcClient; QMenuBar* m_pMenuBar; QMenu* m_pMenuFile; QMenu* m_pMenuEdit; QMenu* m_pMenuWindow; QMenu* m_pMenuHelp; ZeroconfService* m_pZeroconfService; DataDownloader* m_pDataDownloader; QMessageBox* m_DownloadMessageBox; QAbstractButton* m_pCancelButton; QMutex m_UpdateZeroconfMutex; bool m_SuppressAutoConfigWarning; CommandProcess* m_BonjourInstall; bool m_SuppressEmptyServerWarning; qRuningState m_ExpectedRunningState; QMutex m_StopDesktopMutex; SslCertificate* m_pSslCertificate; bool m_ActivationDialogRunning; QStringList m_PendingClientNames; private slots: void on_m_pCheckBoxAutoConfig_toggled(bool checked); void on_m_pComboServerList_currentIndexChanged(QString ); void on_m_pButtonApply_clicked(); void installBonjour(); void on_windowShown(); signals: void windowShown(); }; #endif synergy-1.8.8-stable/src/gui/src/NewScreenWidget.cpp000066400000000000000000000025741305627404700224230ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "NewScreenWidget.h" #include "ScreenSetupModel.h" #include #include NewScreenWidget::NewScreenWidget(QWidget* parent) : QLabel(parent) { } void NewScreenWidget::mousePressEvent(QMouseEvent* event) { Screen newScreen(tr("Unnamed")); QByteArray itemData; QDataStream dataStream(&itemData, QIODevice::WriteOnly); dataStream << -1 << -1 << newScreen; QMimeData* pMimeData = new QMimeData; pMimeData->setData(ScreenSetupModel::mimeType(), itemData); QDrag* pDrag = new QDrag(this); pDrag->setMimeData(pMimeData); pDrag->setPixmap(*pixmap()); pDrag->setHotSpot(event->pos()); pDrag->exec(Qt::CopyAction, Qt::CopyAction); } synergy-1.8.8-stable/src/gui/src/NewScreenWidget.h000066400000000000000000000017761305627404700220730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(NEWSCREENWIDGET__H) #define NEWSCREENWIDGET__H #include class QMouseEvent; class QWidget; class NewScreenWidget : public QLabel { Q_OBJECT public: NewScreenWidget(QWidget* parent); protected: void mousePressEvent(QMouseEvent* event); }; #endif synergy-1.8.8-stable/src/gui/src/PremiumAuth.cpp000066400000000000000000000000001305627404700216040ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/src/PremiumAuth.h000066400000000000000000000000001305627404700212510ustar00rootroot00000000000000synergy-1.8.8-stable/src/gui/src/ProcessorArch.h000066400000000000000000000015711305627404700216040ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once enum qProcessorArch { kProcessorArchWin32, kProcessorArchWin64, kProcessorArchMac32, kProcessorArchMac64, kProcessorArchLinux32, kProcessorArchLinux64, kProcessorArchUnknown }; synergy-1.8.8-stable/src/gui/src/QSynergyApplication.cpp000066400000000000000000000035131305627404700233250ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "QSynergyApplication.h" #include "MainWindow.h" #include #include QSynergyApplication* QSynergyApplication::s_Instance = NULL; QSynergyApplication::QSynergyApplication(int& argc, char** argv) : QApplication(argc, argv), m_Translator(NULL) { s_Instance = this; } QSynergyApplication::~QSynergyApplication() { delete m_Translator; } void QSynergyApplication::commitData(QSessionManager&) { foreach(QWidget* widget, topLevelWidgets()) { MainWindow* mainWindow = qobject_cast(widget); if (mainWindow) mainWindow->saveSettings(); } } QSynergyApplication* QSynergyApplication::getInstance() { return s_Instance; } void QSynergyApplication::switchTranslator(QString lang) { if (m_Translator != NULL) { removeTranslator(m_Translator); delete m_Translator; } QResource locale(":/res/lang/gui_" + lang + ".qm"); m_Translator = new QTranslator(); m_Translator->load(locale.data(), locale.size()); installTranslator(m_Translator); } void QSynergyApplication::setTranslator(QTranslator* translator) { m_Translator = translator; installTranslator(m_Translator); } synergy-1.8.8-stable/src/gui/src/QSynergyApplication.h000066400000000000000000000023721305627404700227740ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(QSYNERGYAPPLICATION__H) #define QSYNERGYAPPLICATION__H #include class QSessionManager; class QSynergyApplication : public QApplication { public: QSynergyApplication(int& argc, char** argv); ~QSynergyApplication(); public: void commitData(QSessionManager& manager); void switchTranslator(QString lang); void setTranslator(QTranslator* translator); static QSynergyApplication* getInstance(); private: QTranslator* m_Translator; static QSynergyApplication* s_Instance; }; #endif synergy-1.8.8-stable/src/gui/src/QUtility.cpp000066400000000000000000000050031305627404700211400ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "QUtility.h" #include "ProcessorArch.h" #include "CommandProcess.h" #include "EditionType.h" #if defined(Q_OS_LINUX) #include #endif #if defined(Q_OS_WIN) #define _WIN32_WINNT 0x0501 #define WIN32_LEAN_AND_MEAN #include #endif void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData) { for (int i = 0; i < comboBox->count(); ++i) { if (comboBox->itemData(i) == itemData) { comboBox->setCurrentIndex(i); return; } } } QString hash(const QString& string) { QByteArray data = string.toUtf8(); QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Md5); return hash.toHex(); } QString getFirstMacAddress() { QString mac; foreach (const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) { mac = interface.hardwareAddress(); if (mac.size() != 0) { break; } } return mac; } qProcessorArch getProcessorArch() { #if defined(Q_OS_WIN) SYSTEM_INFO systemInfo; GetNativeSystemInfo(&systemInfo); switch (systemInfo.wProcessorArchitecture) { case PROCESSOR_ARCHITECTURE_INTEL: return kProcessorArchWin32; case PROCESSOR_ARCHITECTURE_IA64: return kProcessorArchWin64; case PROCESSOR_ARCHITECTURE_AMD64: return kProcessorArchWin64; default: return kProcessorArchUnknown; } #endif #if defined(Q_OS_LINUX) #ifdef __i386__ return kProcessorArchLinux32; #else return kProcessorArchLinux64; #endif #endif return kProcessorArchUnknown; } QString getOSInformation() { QString result; #if defined(Q_OS_LINUX) result = "Linux"; try { QStringList arguments; arguments.append("/etc/os-release"); CommandProcess cp("/bin/cat", arguments); QString output = cp.run(); QRegExp resultRegex(".*PRETTY_NAME=\"([^\"]+)\".*"); if (resultRegex.exactMatch(output)) { result = resultRegex.cap(1); } } catch (...) { } #endif return result; } synergy-1.8.8-stable/src/gui/src/QUtility.h000066400000000000000000000020161305627404700206060ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "ProcessorArch.h" #include #include #include #include void setIndexFromItemData(QComboBox* comboBox, const QVariant& itemData); QString hash(const QString& string); QString getFirstMacAddress(); qProcessorArch getProcessorArch(); QString getOSInformation(); synergy-1.8.8-stable/src/gui/src/Screen.cpp000066400000000000000000000074551305627404700206100ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "Screen.h" #include #include Screen::Screen() : m_Pixmap(QPixmap(":res/icons/64x64/video-display.png")), m_Swapped(false) { init(); } Screen::Screen(const QString& name) : m_Pixmap(QPixmap(":res/icons/64x64/video-display.png")), m_Swapped(false) { init(); setName(name); } void Screen::init() { name().clear(); aliases().clear(); modifiers().clear(); switchCorners().clear(); fixes().clear(); setSwitchCornerSize(0); // m_Modifiers, m_SwitchCorners and m_Fixes are QLists we use like fixed-size arrays, // thus we need to make sure to fill them with the required number of elements. for (int i = 0; i < NumModifiers; i++) modifiers() << i; for (int i = 0; i < NumSwitchCorners; i++) switchCorners() << false; for (int i = 0; i < NumFixes; i++) fixes() << false; } void Screen::loadSettings(QSettings& settings) { setName(settings.value("name").toString()); if (name().isEmpty()) return; setSwitchCornerSize(settings.value("switchCornerSize").toInt()); readSettings(settings, aliases(), "alias", QString("")); readSettings(settings, modifiers(), "modifier", static_cast(DefaultMod), NumModifiers); readSettings(settings, switchCorners(), "switchCorner", false, NumSwitchCorners); readSettings(settings, fixes(), "fix", false, NumFixes); } void Screen::saveSettings(QSettings& settings) const { settings.setValue("name", name()); if (name().isEmpty()) return; settings.setValue("switchCornerSize", switchCornerSize()); writeSettings(settings, aliases(), "alias"); writeSettings(settings, modifiers(), "modifier"); writeSettings(settings, switchCorners(), "switchCorner"); writeSettings(settings, fixes(), "fix"); } QTextStream& Screen::writeScreensSection(QTextStream& outStream) const { outStream << "\t" << name() << ":" << endl; for (int i = 0; i < modifiers().size(); i++) if (modifier(i) != i) outStream << "\t\t" << modifierName(i) << " = " << modifierName(modifier(i)) << endl; for (int i = 0; i < fixes().size(); i++) outStream << "\t\t" << fixName(i) << " = " << (fixes()[i] ? "true" : "false") << endl; outStream << "\t\t" << "switchCorners = none "; for (int i = 0; i < switchCorners().size(); i++) if (switchCorners()[i]) outStream << "+" << switchCornerName(i) << " "; outStream << endl; outStream << "\t\t" << "switchCornerSize = " << switchCornerSize() << endl; return outStream; } QTextStream& Screen::writeAliasesSection(QTextStream& outStream) const { if (!aliases().isEmpty()) { outStream << "\t" << name() << ":" << endl; foreach (const QString& alias, aliases()) outStream << "\t\t" << alias << endl; } return outStream; } QDataStream& operator<<(QDataStream& outStream, const Screen& screen) { return outStream << screen.name() << screen.switchCornerSize() << screen.aliases() << screen.modifiers() << screen.switchCorners() << screen.fixes() ; } QDataStream& operator>>(QDataStream& inStream, Screen& screen) { return inStream >> screen.m_Name >> screen.m_SwitchCornerSize >> screen.m_Aliases >> screen.m_Modifiers >> screen.m_SwitchCorners >> screen.m_Fixes ; } synergy-1.8.8-stable/src/gui/src/Screen.h000066400000000000000000000065111305627404700202450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SCREEN__H) #define SCREEN__H #include #include #include #include #include "BaseConfig.h" class QSettings; class QTextStream; class ScreenSettingsDialog; class Screen : public BaseConfig { friend QDataStream& operator<<(QDataStream& outStream, const Screen& screen); friend QDataStream& operator>>(QDataStream& inStream, Screen& screen); friend class ScreenSettingsDialog; friend class ScreenSetupModel; friend class ScreenSetupView; public: Screen(); Screen(const QString& name); public: const QPixmap* pixmap() const { return &m_Pixmap; } const QString& name() const { return m_Name; } const QStringList& aliases() const { return m_Aliases; } bool isNull() const { return m_Name.isEmpty(); } int modifier(int m) const { return m_Modifiers[m] == DefaultMod ? m : m_Modifiers[m]; } const QList& modifiers() const { return m_Modifiers; } bool switchCorner(int c) const { return m_SwitchCorners[c]; } const QList& switchCorners() const { return m_SwitchCorners; } int switchCornerSize() const { return m_SwitchCornerSize; } bool fix(Fix f) const { return m_Fixes[f]; } const QList& fixes() const { return m_Fixes; } void loadSettings(QSettings& settings); void saveSettings(QSettings& settings) const; QTextStream& writeScreensSection(QTextStream& outStream) const; QTextStream& writeAliasesSection(QTextStream& outStream) const; bool swapped() const { return m_Swapped; } QString& name() { return m_Name; } void setName(const QString& name) { m_Name = name; } protected: void init(); QPixmap* pixmap() { return &m_Pixmap; } void setPixmap(const QPixmap& pixmap) { m_Pixmap = pixmap; } QStringList& aliases() { return m_Aliases; } void setModifier(int m, int n) { m_Modifiers[m] = n; } QList& modifiers() { return m_Modifiers; } void addAlias(const QString& alias) { m_Aliases.append(alias); } void setSwitchCorner(int c, bool on) { m_SwitchCorners[c] = on; } QList& switchCorners() { return m_SwitchCorners; } void setSwitchCornerSize(int val) { m_SwitchCornerSize = val; } void setFix(int f, bool on) { m_Fixes[f] = on; } QList& fixes() { return m_Fixes; } void setSwapped(bool on) { m_Swapped = on; } private: QPixmap m_Pixmap; QString m_Name; QStringList m_Aliases; QList m_Modifiers; QList m_SwitchCorners; int m_SwitchCornerSize; QList m_Fixes; bool m_Swapped; }; typedef QList ScreenList; QDataStream& operator<<(QDataStream& outStream, const Screen& screen); QDataStream& operator>>(QDataStream& inStream, Screen& screen); #endif synergy-1.8.8-stable/src/gui/src/ScreenSettingsDialog.cpp000066400000000000000000000120311305627404700234330ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ScreenSettingsDialog.h" #include "Screen.h" #include #include #include ScreenSettingsDialog::ScreenSettingsDialog(QWidget* parent, Screen* pScreen) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), Ui::ScreenSettingsDialogBase(), m_pScreen(pScreen) { setupUi(this); QRegExp validScreenName("[a-z0-9\\._-]{,255}", Qt::CaseInsensitive); m_pLineEditName->setText(m_pScreen->name()); m_pLineEditName->setValidator(new QRegExpValidator(validScreenName, m_pLineEditName)); m_pLineEditName->selectAll(); m_pLineEditAlias->setValidator(new QRegExpValidator(validScreenName, m_pLineEditName)); for (int i = 0; i < m_pScreen->aliases().count(); i++) new QListWidgetItem(m_pScreen->aliases()[i], m_pListAliases); m_pComboBoxShift->setCurrentIndex(m_pScreen->modifier(Screen::Shift)); m_pComboBoxCtrl->setCurrentIndex(m_pScreen->modifier(Screen::Ctrl)); m_pComboBoxAlt->setCurrentIndex(m_pScreen->modifier(Screen::Alt)); m_pComboBoxMeta->setCurrentIndex(m_pScreen->modifier(Screen::Meta)); m_pComboBoxSuper->setCurrentIndex(m_pScreen->modifier(Screen::Super)); m_pCheckBoxCornerTopLeft->setChecked(m_pScreen->switchCorner(Screen::TopLeft)); m_pCheckBoxCornerTopRight->setChecked(m_pScreen->switchCorner(Screen::TopRight)); m_pCheckBoxCornerBottomLeft->setChecked(m_pScreen->switchCorner(Screen::BottomLeft)); m_pCheckBoxCornerBottomRight->setChecked(m_pScreen->switchCorner(Screen::BottomRight)); m_pSpinBoxSwitchCornerSize->setValue(m_pScreen->switchCornerSize()); m_pCheckBoxCapsLock->setChecked(m_pScreen->fix(Screen::CapsLock)); m_pCheckBoxNumLock->setChecked(m_pScreen->fix(Screen::NumLock)); m_pCheckBoxScrollLock->setChecked(m_pScreen->fix(Screen::ScrollLock)); m_pCheckBoxXTest->setChecked(m_pScreen->fix(Screen::XTest)); } void ScreenSettingsDialog::accept() { if (m_pLineEditName->text().isEmpty()) { QMessageBox::warning( this, tr("Screen name is empty"), tr("The screen name cannot be empty. " "Please either fill in a name or cancel the dialog.")); return; } m_pScreen->init(); m_pScreen->setName(m_pLineEditName->text()); for (int i = 0; i < m_pListAliases->count(); i++) { QString alias(m_pListAliases->item(i)->text()); if (alias == m_pLineEditName->text()) { QMessageBox::warning( this, tr("Screen name matches alias"), tr("The screen name cannot be the same as an alias. " "Please either remove the alias or change the screen name.")); return; } m_pScreen->addAlias(alias); } m_pScreen->setModifier(Screen::Shift, m_pComboBoxShift->currentIndex()); m_pScreen->setModifier(Screen::Ctrl, m_pComboBoxCtrl->currentIndex()); m_pScreen->setModifier(Screen::Alt, m_pComboBoxAlt->currentIndex()); m_pScreen->setModifier(Screen::Meta, m_pComboBoxMeta->currentIndex()); m_pScreen->setModifier(Screen::Super, m_pComboBoxSuper->currentIndex()); m_pScreen->setSwitchCorner(Screen::TopLeft, m_pCheckBoxCornerTopLeft->isChecked()); m_pScreen->setSwitchCorner(Screen::TopRight, m_pCheckBoxCornerTopRight->isChecked()); m_pScreen->setSwitchCorner(Screen::BottomLeft, m_pCheckBoxCornerBottomLeft->isChecked()); m_pScreen->setSwitchCorner(Screen::BottomRight, m_pCheckBoxCornerBottomRight->isChecked()); m_pScreen->setSwitchCornerSize(m_pSpinBoxSwitchCornerSize->value()); m_pScreen->setFix(Screen::CapsLock, m_pCheckBoxCapsLock->isChecked()); m_pScreen->setFix(Screen::NumLock, m_pCheckBoxNumLock->isChecked()); m_pScreen->setFix(Screen::ScrollLock, m_pCheckBoxScrollLock->isChecked()); m_pScreen->setFix(Screen::XTest, m_pCheckBoxXTest->isChecked()); QDialog::accept(); } void ScreenSettingsDialog::on_m_pButtonAddAlias_clicked() { if (!m_pLineEditAlias->text().isEmpty() && m_pListAliases->findItems(m_pLineEditAlias->text(), Qt::MatchFixedString).isEmpty()) { new QListWidgetItem(m_pLineEditAlias->text(), m_pListAliases); m_pLineEditAlias->clear(); } } void ScreenSettingsDialog::on_m_pLineEditAlias_textChanged(const QString& text) { m_pButtonAddAlias->setEnabled(!text.isEmpty()); } void ScreenSettingsDialog::on_m_pButtonRemoveAlias_clicked() { QList items = m_pListAliases->selectedItems(); for (int i = 0; i < items.count(); i++) delete items[i]; } void ScreenSettingsDialog::on_m_pListAliases_itemSelectionChanged() { m_pButtonRemoveAlias->setEnabled(!m_pListAliases->selectedItems().isEmpty()); } synergy-1.8.8-stable/src/gui/src/ScreenSettingsDialog.h000066400000000000000000000025361305627404700231110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SCREENSETTINGSDIALOG__H) #define SCREENSETTINGSDIALOG__H #include #include "ui_ScreenSettingsDialogBase.h" class QWidget; class QString; class Screen; class ScreenSettingsDialog : public QDialog, public Ui::ScreenSettingsDialogBase { Q_OBJECT public: ScreenSettingsDialog(QWidget* parent, Screen* pScreen = NULL); public slots: void accept(); private slots: void on_m_pButtonAddAlias_clicked(); void on_m_pButtonRemoveAlias_clicked(); void on_m_pLineEditAlias_textChanged(const QString& text); void on_m_pListAliases_itemSelectionChanged(); private: Screen* m_pScreen; }; #endif synergy-1.8.8-stable/src/gui/src/ScreenSetupModel.cpp000066400000000000000000000075701305627404700226100ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ScreenSetupModel.h" #include "Screen.h" #include #include const QString ScreenSetupModel::m_MimeType = "application/x-qsynergy-screen"; ScreenSetupModel::ScreenSetupModel(ScreenList& screens, int numColumns, int numRows) : QAbstractTableModel(NULL), m_Screens(screens), m_NumColumns(numColumns), m_NumRows(numRows) { if (m_NumColumns * m_NumRows > screens.size()) qFatal("Not enough elements (%u) in screens QList for %d columns and %d rows", screens.size(), m_NumColumns, m_NumRows); } QVariant ScreenSetupModel::data(const QModelIndex& index, int role) const { if (index.isValid() && index.row() < m_NumRows && index.column() < m_NumColumns) { switch(role) { case Qt::DecorationRole: if (screen(index).isNull()) break; return QIcon(*screen(index).pixmap()); case Qt::ToolTipRole: if (screen(index).isNull()) break; return QString(tr( "
Screen: %1
" "
Double click to edit settings" "
Drag screen to the trashcan to remove it")).arg(screen(index).name()); case Qt::DisplayRole: if (screen(index).isNull()) break; return screen(index).name(); } } return QVariant(); } Qt::ItemFlags ScreenSetupModel::flags(const QModelIndex& index) const { if (!index.isValid() || index.row() >= m_NumRows || index.column() >= m_NumColumns) return 0; if (!screen(index).isNull()) return Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsSelectable | Qt::ItemIsDropEnabled; return Qt::ItemIsDropEnabled; } Qt::DropActions ScreenSetupModel::supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction; } QStringList ScreenSetupModel::mimeTypes() const { return QStringList() << m_MimeType; } QMimeData* ScreenSetupModel::mimeData(const QModelIndexList& indexes) const { QMimeData* pMimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); foreach (const QModelIndex& index, indexes) if (index.isValid()) stream << index.column() << index.row() << screen(index); pMimeData->setData(m_MimeType, encodedData); return pMimeData; } bool ScreenSetupModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) { if (action == Qt::IgnoreAction) return true; if (!data->hasFormat(m_MimeType)) return false; if (!parent.isValid() || row != -1 || column != -1) return false; QByteArray encodedData = data->data(m_MimeType); QDataStream stream(&encodedData, QIODevice::ReadOnly); int sourceColumn = -1; int sourceRow = -1; stream >> sourceColumn; stream >> sourceRow; // don't drop screen onto itself if (sourceColumn == parent.column() && sourceRow == parent.row()) return false; Screen droppedScreen; stream >> droppedScreen; Screen oldScreen = screen(parent.column(), parent.row()); if (!oldScreen.isNull() && sourceColumn != -1 && sourceRow != -1) { // mark the screen so it isn't deleted after the dragndrop succeeded // see ScreenSetupView::startDrag() oldScreen.setSwapped(true); screen(sourceColumn, sourceRow) = oldScreen; } screen(parent.column(), parent.row()) = droppedScreen; return true; } synergy-1.8.8-stable/src/gui/src/ScreenSetupModel.h000066400000000000000000000045321305627404700222500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SCREENSETUPMODEL__H) #define SCREENSETUPMODEL__H #include #include #include #include #include "Screen.h" class ScreenSetupView; class ServerConfigDialog; class ScreenSetupModel : public QAbstractTableModel { Q_OBJECT friend class ScreenSetupView; friend class ServerConfigDialog; public: ScreenSetupModel(ScreenList& screens, int numColumns, int numRows); public: static const QString& mimeType() { return m_MimeType; } QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const; int rowCount() const { return m_NumRows; } int columnCount() const { return m_NumColumns; } int rowCount(const QModelIndex&) const { return rowCount(); } int columnCount(const QModelIndex&) const { return columnCount(); } Qt::DropActions supportedDropActions() const; Qt::ItemFlags flags(const QModelIndex& index) const; QStringList mimeTypes() const; QMimeData* mimeData(const QModelIndexList& indexes) const; protected: bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent); const Screen& screen(const QModelIndex& index) const { return screen(index.column(), index.row()); } Screen& screen(const QModelIndex& index) { return screen(index.column(), index.row()); } const Screen& screen(int column, int row) const { return m_Screens[row * m_NumColumns + column]; } Screen& screen(int column, int row) { return m_Screens[row * m_NumColumns + column]; } private: ScreenList& m_Screens; const int m_NumColumns; const int m_NumRows; static const QString m_MimeType; }; #endif synergy-1.8.8-stable/src/gui/src/ScreenSetupView.cpp000066400000000000000000000103131305627404700224470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ScreenSetupView.h" #include "ScreenSetupModel.h" #include "ScreenSettingsDialog.h" #include #include ScreenSetupView::ScreenSetupView(QWidget* parent) : QTableView(parent) { setDropIndicatorShown(true); setDragDropMode(DragDrop); setSelectionMode(SingleSelection); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setIconSize(QSize(64, 64)); horizontalHeader()->hide(); verticalHeader()->hide(); } void ScreenSetupView::setModel(ScreenSetupModel* model) { QTableView::setModel(model); setTableSize(); } ScreenSetupModel* ScreenSetupView::model() const { return qobject_cast(QTableView::model()); } void ScreenSetupView::setTableSize() { for (int i = 0; i < model()->columnCount(); i++) setColumnWidth(i, width() / model()->columnCount()); for (int i = 0; i < model()->rowCount(); i++) setRowHeight(i, height() / model()->rowCount()); } void ScreenSetupView::resizeEvent(QResizeEvent* event) { setTableSize(); event->ignore(); } void ScreenSetupView::mouseDoubleClickEvent(QMouseEvent* event) { if (event->buttons() & Qt::LeftButton) { int col = columnAt(event->pos().x()); int row = rowAt(event->pos().y()); if (!model()->screen(col, row).isNull()) { ScreenSettingsDialog dlg(this, &model()->screen(col, row)); dlg.exec(); } } else event->ignore(); } void ScreenSetupView::dragEnterEvent(QDragEnterEvent* event) { // we accept anything that enters us by a drag as long as the // mime type is okay. anything else is dealt with in dragMoveEvent() if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) event->accept(); else event->ignore(); } void ScreenSetupView::dragMoveEvent(QDragMoveEvent* event) { if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) { // where does the event come from? myself or someone else? if (event->source() == this) { // myself is ok, but then it must be a move action, never a copy event->setDropAction(Qt::MoveAction); event->accept(); } else { int col = columnAt(event->pos().x()); int row = rowAt(event->pos().y()); // a drop from outside is not allowed if there's a screen already there. if (!model()->screen(col, row).isNull()) event->ignore(); else event->acceptProposedAction(); } } else event->ignore(); } // this is reimplemented from QAbstractItemView::startDrag() void ScreenSetupView::startDrag(Qt::DropActions) { QModelIndexList indexes = selectedIndexes(); if (indexes.count() != 1) return; QMimeData* pData = model()->mimeData(indexes); if (pData == NULL) return; QPixmap pixmap = *model()->screen(indexes[0]).pixmap(); QDrag* pDrag = new QDrag(this); pDrag->setPixmap(pixmap); pDrag->setMimeData(pData); pDrag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2)); if (pDrag->exec(Qt::MoveAction, Qt::MoveAction) == Qt::MoveAction) { selectionModel()->clear(); // make sure to only delete the drag source if screens weren't swapped // see ScreenSetupModel::dropMimeData if (!model()->screen(indexes[0]).swapped()) model()->screen(indexes[0]) = Screen(); else model()->screen(indexes[0]).setSwapped(false); } } QStyleOptionViewItem ScreenSetupView::viewOptions() const { QStyleOptionViewItem option = QTableView::viewOptions(); option.showDecorationSelected = true; option.decorationPosition = QStyleOptionViewItem::Top; option.displayAlignment = Qt::AlignCenter; option.textElideMode = Qt::ElideMiddle; return option; } synergy-1.8.8-stable/src/gui/src/ScreenSetupView.h000066400000000000000000000027601305627404700221230ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SCREENSETUPVIEW__H) #define SCREENSETUPVIEW__H #include #include #include "Screen.h" class QWidget; class QMouseEvent; class QResizeEvent; class QDragEnterEvent; class ScreenSetupModel; class ScreenSetupView : public QTableView { Q_OBJECT public: ScreenSetupView(QWidget* parent); public: void setModel(ScreenSetupModel* model); ScreenSetupModel* model() const; protected: void mouseDoubleClickEvent(QMouseEvent*); void setTableSize(); void resizeEvent(QResizeEvent*); void dragEnterEvent(QDragEnterEvent* event); void dragMoveEvent(QDragMoveEvent* event); void startDrag(Qt::DropActions supportedActions); QStyleOptionViewItem viewOptions() const; void scrollTo(const QModelIndex&, ScrollHint) {} }; #endif synergy-1.8.8-stable/src/gui/src/ServerConfig.cpp000066400000000000000000000251131305627404700217540ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ServerConfig.h" #include "Hotkey.h" #include "MainWindow.h" #include "AddClientDialog.h" #include #include #include #include static const struct { int x; int y; const char* name; } neighbourDirs[] = { { 1, 0, "right" }, { -1, 0, "left" }, { 0, -1, "up" }, { 0, 1, "down" }, }; const int serverDefaultIndex = 7; ServerConfig::ServerConfig(QSettings* settings, int numColumns, int numRows , QString serverName, MainWindow* mainWindow) : m_pSettings(settings), m_Screens(), m_NumColumns(numColumns), m_NumRows(numRows), m_ServerName(serverName), m_IgnoreAutoConfigClient(false), m_EnableDragAndDrop(false), m_ClipboardSharing(true), m_pMainWindow(mainWindow) { Q_ASSERT(m_pSettings); loadSettings(); } ServerConfig::~ServerConfig() { saveSettings(); } bool ServerConfig::save(const QString& fileName) const { QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) return false; save(file); file.close(); return true; } void ServerConfig::save(QFile& file) const { QTextStream outStream(&file); outStream << *this; } void ServerConfig::init() { switchCorners().clear(); screens().clear(); // m_NumSwitchCorners is used as a fixed size array. See Screen::init() for (int i = 0; i < NumSwitchCorners; i++) switchCorners() << false; // There must always be screen objects for each cell in the screens QList. Unused screens // are identified by having an empty name. for (int i = 0; i < numColumns() * numRows(); i++) addScreen(Screen()); } void ServerConfig::saveSettings() { settings().beginGroup("internalConfig"); settings().remove(""); settings().setValue("numColumns", numColumns()); settings().setValue("numRows", numRows()); settings().setValue("hasHeartbeat", hasHeartbeat()); settings().setValue("heartbeat", heartbeat()); settings().setValue("relativeMouseMoves", relativeMouseMoves()); settings().setValue("screenSaverSync", screenSaverSync()); settings().setValue("win32KeepForeground", win32KeepForeground()); settings().setValue("hasSwitchDelay", hasSwitchDelay()); settings().setValue("switchDelay", switchDelay()); settings().setValue("hasSwitchDoubleTap", hasSwitchDoubleTap()); settings().setValue("switchDoubleTap", switchDoubleTap()); settings().setValue("switchCornerSize", switchCornerSize()); settings().setValue("ignoreAutoConfigClient", ignoreAutoConfigClient()); settings().setValue("enableDragAndDrop", enableDragAndDrop()); writeSettings(settings(), switchCorners(), "switchCorner"); settings().beginWriteArray("screens"); for (int i = 0; i < screens().size(); i++) { settings().setArrayIndex(i); screens()[i].saveSettings(settings()); } settings().endArray(); settings().beginWriteArray("hotkeys"); for (int i = 0; i < hotkeys().size(); i++) { settings().setArrayIndex(i); hotkeys()[i].saveSettings(settings()); } settings().endArray(); settings().endGroup(); } void ServerConfig::loadSettings() { settings().beginGroup("internalConfig"); setNumColumns(settings().value("numColumns", 5).toInt()); setNumRows(settings().value("numRows", 3).toInt()); // we need to know the number of columns and rows before we can set up ourselves init(); haveHeartbeat(settings().value("hasHeartbeat", false).toBool()); setHeartbeat(settings().value("heartbeat", 5000).toInt()); setRelativeMouseMoves(settings().value("relativeMouseMoves", false).toBool()); setScreenSaverSync(settings().value("screenSaverSync", true).toBool()); setWin32KeepForeground(settings().value("win32KeepForeground", false).toBool()); haveSwitchDelay(settings().value("hasSwitchDelay", false).toBool()); setSwitchDelay(settings().value("switchDelay", 250).toInt()); haveSwitchDoubleTap(settings().value("hasSwitchDoubleTap", false).toBool()); setSwitchDoubleTap(settings().value("switchDoubleTap", 250).toInt()); setSwitchCornerSize(settings().value("switchCornerSize").toInt()); setIgnoreAutoConfigClient(settings().value("ignoreAutoConfigClient").toBool()); setEnableDragAndDrop(settings().value("enableDragAndDrop", true).toBool()); readSettings(settings(), switchCorners(), "switchCorner", false, NumSwitchCorners); int numScreens = settings().beginReadArray("screens"); Q_ASSERT(numScreens <= screens().size()); for (int i = 0; i < numScreens; i++) { settings().setArrayIndex(i); screens()[i].loadSettings(settings()); } settings().endArray(); int numHotkeys = settings().beginReadArray("hotkeys"); for (int i = 0; i < numHotkeys; i++) { settings().setArrayIndex(i); Hotkey h; h.loadSettings(settings()); hotkeys().append(h); } settings().endArray(); settings().endGroup(); } int ServerConfig::adjacentScreenIndex(int idx, int deltaColumn, int deltaRow) const { if (screens()[idx].isNull()) return -1; // if we're at the left or right end of the table, don't find results going further left or right if ((deltaColumn > 0 && (idx+1) % numColumns() == 0) || (deltaColumn < 0 && idx % numColumns() == 0)) return -1; int arrayPos = idx + deltaColumn + deltaRow * numColumns(); if (arrayPos >= screens().size() || arrayPos < 0) return -1; return arrayPos; } QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config) { outStream << "section: screens" << endl; foreach (const Screen& s, config.screens()) if (!s.isNull()) s.writeScreensSection(outStream); outStream << "end" << endl << endl; outStream << "section: aliases" << endl; foreach (const Screen& s, config.screens()) if (!s.isNull()) s.writeAliasesSection(outStream); outStream << "end" << endl << endl; outStream << "section: links" << endl; for (int i = 0; i < config.screens().size(); i++) if (!config.screens()[i].isNull()) { outStream << "\t" << config.screens()[i].name() << ":" << endl; for (unsigned int j = 0; j < sizeof(neighbourDirs) / sizeof(neighbourDirs[0]); j++) { int idx = config.adjacentScreenIndex(i, neighbourDirs[j].x, neighbourDirs[j].y); if (idx != -1 && !config.screens()[idx].isNull()) outStream << "\t\t" << neighbourDirs[j].name << " = " << config.screens()[idx].name() << endl; } } outStream << "end" << endl << endl; outStream << "section: options" << endl; if (config.hasHeartbeat()) outStream << "\t" << "heartbeat = " << config.heartbeat() << endl; outStream << "\t" << "relativeMouseMoves = " << (config.relativeMouseMoves() ? "true" : "false") << endl; outStream << "\t" << "screenSaverSync = " << (config.screenSaverSync() ? "true" : "false") << endl; outStream << "\t" << "win32KeepForeground = " << (config.win32KeepForeground() ? "true" : "false") << endl; outStream << "\t" << "clipboardSharing = " << (config.clipboardSharing() ? "true" : "false") << endl; if (config.hasSwitchDelay()) outStream << "\t" << "switchDelay = " << config.switchDelay() << endl; if (config.hasSwitchDoubleTap()) outStream << "\t" << "switchDoubleTap = " << config.switchDoubleTap() << endl; outStream << "\t" << "switchCorners = none "; for (int i = 0; i < config.switchCorners().size(); i++) if (config.switchCorners()[i]) outStream << "+" << config.switchCornerName(i) << " "; outStream << endl; outStream << "\t" << "switchCornerSize = " << config.switchCornerSize() << endl; foreach(const Hotkey& hotkey, config.hotkeys()) outStream << hotkey; outStream << "end" << endl << endl; return outStream; } int ServerConfig::numScreens() const { int rval = 0; foreach(const Screen& s, screens()) if (!s.isNull()) rval++; return rval; } int ServerConfig::autoAddScreen(const QString name) { int serverIndex = -1; int targetIndex = -1; if (!findScreenName(m_ServerName, serverIndex)) { if (!fixNoServer(m_ServerName, serverIndex)) { return kAutoAddScreenManualServer; } } if (findScreenName(name, targetIndex)) { // already exists. return kAutoAddScreenIgnore; } int result = showAddClientDialog(name); if (result == kAddClientIgnore) { return kAutoAddScreenIgnore; } if (result == kAddClientOther) { addToFirstEmptyGrid(name); return kAutoAddScreenManualClient; } bool success = false; int startIndex = serverIndex; int offset = 1; int dirIndex = 0; if (result == kAddClientLeft) { offset = -1; dirIndex = 1; } else if (result == kAddClientUp) { offset = -5; dirIndex = 2; } else if (result == kAddClientDown) { offset = 5; dirIndex = 3; } int idx = adjacentScreenIndex(startIndex, neighbourDirs[dirIndex].x, neighbourDirs[dirIndex].y); while (idx != -1) { if (screens()[idx].isNull()) { m_Screens[idx].setName(name); success = true; break; } startIndex += offset; idx = adjacentScreenIndex(startIndex, neighbourDirs[dirIndex].x, neighbourDirs[dirIndex].y); } if (!success) { addToFirstEmptyGrid(name); return kAutoAddScreenManualClient; } saveSettings(); return kAutoAddScreenOk; } bool ServerConfig::findScreenName(const QString& name, int& index) { bool found = false; for (int i = 0; i < screens().size(); i++) { if (!screens()[i].isNull() && screens()[i].name().compare(name) == 0) { index = i; found = true; break; } } return found; } bool ServerConfig::fixNoServer(const QString& name, int& index) { bool fixed = false; if (screens()[serverDefaultIndex].isNull()) { m_Screens[serverDefaultIndex].setName(name); index = serverDefaultIndex; fixed = true; } return fixed; } int ServerConfig::showAddClientDialog(const QString& clientName) { int result = kAddClientIgnore; if (!m_pMainWindow->isActiveWindow()) { m_pMainWindow->showNormal(); m_pMainWindow->activateWindow(); } AddClientDialog addClientDialog(clientName, m_pMainWindow); addClientDialog.exec(); result = addClientDialog.addResult(); m_IgnoreAutoConfigClient = addClientDialog.ignoreAutoConfigClient(); return result; } void::ServerConfig::addToFirstEmptyGrid(const QString &clientName) { for (int i = 0; i < screens().size(); i++) { if (screens()[i].isNull()) { m_Screens[i].setName(clientName); break; } } } synergy-1.8.8-stable/src/gui/src/ServerConfig.h000066400000000000000000000116711305627404700214250ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SERVERCONFIG__H) #define SERVERCONFIG__H #include #include "Screen.h" #include "BaseConfig.h" #include "Hotkey.h" class QTextStream; class QSettings; class QString; class QFile; class ServerConfigDialog; class MainWindow; class ServerConfig : public BaseConfig { friend class ServerConfigDialog; friend QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config); public: ServerConfig(QSettings* settings, int numColumns, int numRows, QString serverName, MainWindow* mainWindow); ~ServerConfig(); public: const ScreenList& screens() const { return m_Screens; } int numColumns() const { return m_NumColumns; } int numRows() const { return m_NumRows; } bool hasHeartbeat() const { return m_HasHeartbeat; } int heartbeat() const { return m_Heartbeat; } bool relativeMouseMoves() const { return m_RelativeMouseMoves; } bool screenSaverSync() const { return m_ScreenSaverSync; } bool win32KeepForeground() const { return m_Win32KeepForeground; } bool hasSwitchDelay() const { return m_HasSwitchDelay; } int switchDelay() const { return m_SwitchDelay; } bool hasSwitchDoubleTap() const { return m_HasSwitchDoubleTap; } int switchDoubleTap() const { return m_SwitchDoubleTap; } bool switchCorner(int c) const { return m_SwitchCorners[c]; } int switchCornerSize() const { return m_SwitchCornerSize; } const QList& switchCorners() const { return m_SwitchCorners; } const HotkeyList& hotkeys() const { return m_Hotkeys; } bool ignoreAutoConfigClient() const { return m_IgnoreAutoConfigClient; } bool enableDragAndDrop() const { return m_EnableDragAndDrop; } bool clipboardSharing() const { return m_ClipboardSharing; } void saveSettings(); void loadSettings(); bool save(const QString& fileName) const; void save(QFile& file) const; int numScreens() const; int autoAddScreen(const QString name); protected: QSettings& settings() { return *m_pSettings; } ScreenList& screens() { return m_Screens; } void setScreens(const ScreenList& screens) { m_Screens = screens; } void addScreen(const Screen& screen) { m_Screens.append(screen); } void setNumColumns(int n) { m_NumColumns = n; } void setNumRows(int n) { m_NumRows = n; } void haveHeartbeat(bool on) { m_HasHeartbeat = on; } void setHeartbeat(int val) { m_Heartbeat = val; } void setRelativeMouseMoves(bool on) { m_RelativeMouseMoves = on; } void setScreenSaverSync(bool on) { m_ScreenSaverSync = on; } void setWin32KeepForeground(bool on) { m_Win32KeepForeground = on; } void haveSwitchDelay(bool on) { m_HasSwitchDelay = on; } void setSwitchDelay(int val) { m_SwitchDelay = val; } void haveSwitchDoubleTap(bool on) { m_HasSwitchDoubleTap = on; } void setSwitchDoubleTap(int val) { m_SwitchDoubleTap = val; } void setSwitchCorner(int c, bool on) { m_SwitchCorners[c] = on; } void setSwitchCornerSize(int val) { m_SwitchCornerSize = val; } void setIgnoreAutoConfigClient(bool on) { m_IgnoreAutoConfigClient = on; } void setEnableDragAndDrop(bool on) { m_EnableDragAndDrop = on; } void setClipboardSharing(bool on) { m_ClipboardSharing = on; } QList& switchCorners() { return m_SwitchCorners; } HotkeyList& hotkeys() { return m_Hotkeys; } void init(); int adjacentScreenIndex(int idx, int deltaColumn, int deltaRow) const; private: bool findScreenName(const QString& name, int& index); bool fixNoServer(const QString& name, int& index); int showAddClientDialog(const QString& clientName); void addToFirstEmptyGrid(const QString& clientName); private: QSettings* m_pSettings; ScreenList m_Screens; int m_NumColumns; int m_NumRows; bool m_HasHeartbeat; int m_Heartbeat; bool m_RelativeMouseMoves; bool m_ScreenSaverSync; bool m_Win32KeepForeground; bool m_HasSwitchDelay; int m_SwitchDelay; bool m_HasSwitchDoubleTap; int m_SwitchDoubleTap; int m_SwitchCornerSize; QList m_SwitchCorners; HotkeyList m_Hotkeys; QString m_ServerName; bool m_IgnoreAutoConfigClient; bool m_EnableDragAndDrop; bool m_ClipboardSharing; MainWindow* m_pMainWindow; }; QTextStream& operator<<(QTextStream& outStream, const ServerConfig& config); enum { kAutoAddScreenOk, kAutoAddScreenManualServer, kAutoAddScreenManualClient, kAutoAddScreenIgnore }; #endif synergy-1.8.8-stable/src/gui/src/ServerConfigDialog.cpp000066400000000000000000000203561305627404700231000ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ServerConfigDialog.h" #include "ServerConfig.h" #include "HotkeyDialog.h" #include "ActionDialog.h" #include #include #include ServerConfigDialog::ServerConfigDialog(QWidget* parent, ServerConfig& config, const QString& defaultScreenName) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), Ui::ServerConfigDialogBase(), m_OrigServerConfig(config), m_ServerConfig(config), m_ScreenSetupModel(serverConfig().screens(), serverConfig().numColumns(), serverConfig().numRows()), m_Message("") { setupUi(this); m_pCheckBoxHeartbeat->setChecked(serverConfig().hasHeartbeat()); m_pSpinBoxHeartbeat->setValue(serverConfig().heartbeat()); m_pCheckBoxRelativeMouseMoves->setChecked(serverConfig().relativeMouseMoves()); m_pCheckBoxScreenSaverSync->setChecked(serverConfig().screenSaverSync()); m_pCheckBoxWin32KeepForeground->setChecked(serverConfig().win32KeepForeground()); m_pCheckBoxSwitchDelay->setChecked(serverConfig().hasSwitchDelay()); m_pSpinBoxSwitchDelay->setValue(serverConfig().switchDelay()); m_pCheckBoxSwitchDoubleTap->setChecked(serverConfig().hasSwitchDoubleTap()); m_pSpinBoxSwitchDoubleTap->setValue(serverConfig().switchDoubleTap()); m_pCheckBoxCornerTopLeft->setChecked(serverConfig().switchCorner(BaseConfig::TopLeft)); m_pCheckBoxCornerTopRight->setChecked(serverConfig().switchCorner(BaseConfig::TopRight)); m_pCheckBoxCornerBottomLeft->setChecked(serverConfig().switchCorner(BaseConfig::BottomLeft)); m_pCheckBoxCornerBottomRight->setChecked(serverConfig().switchCorner(BaseConfig::BottomRight)); m_pSpinBoxSwitchCornerSize->setValue(serverConfig().switchCornerSize()); m_pCheckBoxIgnoreAutoConfigClient->setChecked(serverConfig().ignoreAutoConfigClient()); m_pCheckBoxEnableDragAndDrop->setChecked(serverConfig().enableDragAndDrop()); m_pCheckBoxEnableClipboard->setChecked(serverConfig().clipboardSharing()); foreach(const Hotkey& hotkey, serverConfig().hotkeys()) m_pListHotkeys->addItem(hotkey.text()); m_pScreenSetupView->setModel(&m_ScreenSetupModel); if (serverConfig().numScreens() == 0) model().screen(serverConfig().numColumns() / 2, serverConfig().numRows() / 2) = Screen(defaultScreenName); } void ServerConfigDialog::showEvent(QShowEvent* event) { QDialog::show(); if (!m_Message.isEmpty()) { // TODO: ideally this massage box should pop up after the dialog is shown QMessageBox::information(this, tr("Configure server"), m_Message); } } void ServerConfigDialog::accept() { serverConfig().haveHeartbeat(m_pCheckBoxHeartbeat->isChecked()); serverConfig().setHeartbeat(m_pSpinBoxHeartbeat->value()); serverConfig().setRelativeMouseMoves(m_pCheckBoxRelativeMouseMoves->isChecked()); serverConfig().setScreenSaverSync(m_pCheckBoxScreenSaverSync->isChecked()); serverConfig().setWin32KeepForeground(m_pCheckBoxWin32KeepForeground->isChecked()); serverConfig().haveSwitchDelay(m_pCheckBoxSwitchDelay->isChecked()); serverConfig().setSwitchDelay(m_pSpinBoxSwitchDelay->value()); serverConfig().haveSwitchDoubleTap(m_pCheckBoxSwitchDoubleTap->isChecked()); serverConfig().setSwitchDoubleTap(m_pSpinBoxSwitchDoubleTap->value()); serverConfig().setSwitchCorner(BaseConfig::TopLeft, m_pCheckBoxCornerTopLeft->isChecked()); serverConfig().setSwitchCorner(BaseConfig::TopRight, m_pCheckBoxCornerTopRight->isChecked()); serverConfig().setSwitchCorner(BaseConfig::BottomLeft, m_pCheckBoxCornerBottomLeft->isChecked()); serverConfig().setSwitchCorner(BaseConfig::BottomRight, m_pCheckBoxCornerBottomRight->isChecked()); serverConfig().setSwitchCornerSize(m_pSpinBoxSwitchCornerSize->value()); serverConfig().setIgnoreAutoConfigClient(m_pCheckBoxIgnoreAutoConfigClient->isChecked()); serverConfig().setEnableDragAndDrop(m_pCheckBoxEnableDragAndDrop->isChecked()); serverConfig().setClipboardSharing(m_pCheckBoxEnableClipboard->isChecked()); // now that the dialog has been accepted, copy the new server config to the original one, // which is a reference to the one in MainWindow. setOrigServerConfig(serverConfig()); QDialog::accept(); } void ServerConfigDialog::on_m_pButtonNewHotkey_clicked() { Hotkey hotkey; HotkeyDialog dlg(this, hotkey); if (dlg.exec() == QDialog::Accepted) { serverConfig().hotkeys().append(hotkey); m_pListHotkeys->addItem(hotkey.text()); } } void ServerConfigDialog::on_m_pButtonEditHotkey_clicked() { int idx = m_pListHotkeys->currentRow(); Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); Hotkey& hotkey = serverConfig().hotkeys()[idx]; HotkeyDialog dlg(this, hotkey); if (dlg.exec() == QDialog::Accepted) m_pListHotkeys->currentItem()->setText(hotkey.text()); } void ServerConfigDialog::on_m_pButtonRemoveHotkey_clicked() { int idx = m_pListHotkeys->currentRow(); Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); serverConfig().hotkeys().removeAt(idx); m_pListActions->clear(); delete m_pListHotkeys->item(idx); } void ServerConfigDialog::on_m_pListHotkeys_itemSelectionChanged() { bool itemsSelected = !m_pListHotkeys->selectedItems().isEmpty(); m_pButtonEditHotkey->setEnabled(itemsSelected); m_pButtonRemoveHotkey->setEnabled(itemsSelected); m_pButtonNewAction->setEnabled(itemsSelected); if (itemsSelected && serverConfig().hotkeys().size() > 0) { m_pListActions->clear(); int idx = m_pListHotkeys->row(m_pListHotkeys->selectedItems()[0]); // There's a bug somewhere around here: We get idx == 1 right after we deleted the next to last item, so idx can // only possibly be 0. GDB shows we got called indirectly from the delete line in // on_m_pButtonRemoveHotkey_clicked() above, but the delete is of course necessary and seems correct. // The while() is a generalized workaround for all that and shouldn't be required. while (idx >= 0 && idx >= serverConfig().hotkeys().size()) idx--; Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); const Hotkey& hotkey = serverConfig().hotkeys()[idx]; foreach(const Action& action, hotkey.actions()) m_pListActions->addItem(action.text()); } } void ServerConfigDialog::on_m_pButtonNewAction_clicked() { int idx = m_pListHotkeys->currentRow(); Q_ASSERT(idx >= 0 && idx < serverConfig().hotkeys().size()); Hotkey& hotkey = serverConfig().hotkeys()[idx]; Action action; ActionDialog dlg(this, serverConfig(), hotkey, action); if (dlg.exec() == QDialog::Accepted) { hotkey.actions().append(action); m_pListActions->addItem(action.text()); } } void ServerConfigDialog::on_m_pButtonEditAction_clicked() { int idxHotkey = m_pListHotkeys->currentRow(); Q_ASSERT(idxHotkey >= 0 && idxHotkey < serverConfig().hotkeys().size()); Hotkey& hotkey = serverConfig().hotkeys()[idxHotkey]; int idxAction = m_pListActions->currentRow(); Q_ASSERT(idxAction >= 0 && idxAction < hotkey.actions().size()); Action& action = hotkey.actions()[idxAction]; ActionDialog dlg(this, serverConfig(), hotkey, action); if (dlg.exec() == QDialog::Accepted) m_pListActions->currentItem()->setText(action.text()); } void ServerConfigDialog::on_m_pButtonRemoveAction_clicked() { int idxHotkey = m_pListHotkeys->currentRow(); Q_ASSERT(idxHotkey >= 0 && idxHotkey < serverConfig().hotkeys().size()); Hotkey& hotkey = serverConfig().hotkeys()[idxHotkey]; int idxAction = m_pListActions->currentRow(); Q_ASSERT(idxAction >= 0 && idxAction < hotkey.actions().size()); hotkey.actions().removeAt(idxAction); delete m_pListActions->currentItem(); } void ServerConfigDialog::on_m_pListActions_itemSelectionChanged() { m_pButtonEditAction->setEnabled(!m_pListActions->selectedItems().isEmpty()); m_pButtonRemoveAction->setEnabled(!m_pListActions->selectedItems().isEmpty()); } synergy-1.8.8-stable/src/gui/src/ServerConfigDialog.h000066400000000000000000000036721305627404700225470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SERVERCONFIGDIALOG__H) #define SERVERCONFIGDIALOG__H #include "ScreenSetupModel.h" #include "ServerConfig.h" #include "ui_ServerConfigDialogBase.h" #include class ServerConfigDialog : public QDialog, public Ui::ServerConfigDialogBase { Q_OBJECT public: ServerConfigDialog(QWidget* parent, ServerConfig& config, const QString& defaultScreenName); public slots: void accept(); void showEvent(QShowEvent* event); void message(const QString& message) { m_Message = message; } protected slots: void on_m_pButtonNewHotkey_clicked(); void on_m_pListHotkeys_itemSelectionChanged(); void on_m_pButtonEditHotkey_clicked(); void on_m_pButtonRemoveHotkey_clicked(); void on_m_pButtonNewAction_clicked(); void on_m_pListActions_itemSelectionChanged(); void on_m_pButtonEditAction_clicked(); void on_m_pButtonRemoveAction_clicked(); protected: ServerConfig& serverConfig() { return m_ServerConfig; } void setOrigServerConfig(const ServerConfig& s) { m_OrigServerConfig = s; } ScreenSetupModel& model() { return m_ScreenSetupModel; } private: ServerConfig& m_OrigServerConfig; ServerConfig m_ServerConfig; ScreenSetupModel m_ScreenSetupModel; QString m_Message; }; #endif synergy-1.8.8-stable/src/gui/src/SettingsDialog.cpp000066400000000000000000000110211305627404700222710ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "SettingsDialog.h" #include "CoreInterface.h" #include "SynergyLocale.h" #include "QSynergyApplication.h" #include "QUtility.h" #include "AppConfig.h" #include "EditionType.h" #include "SslCertificate.h" #include "MainWindow.h" #include #include #include #include #include static const char networkSecurity[] = "ns"; SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) : QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint), Ui::SettingsDialogBase(), m_appConfig(config) { setupUi(this); m_Locale.fillLanguageComboBox(m_pComboLanguage); m_pLineEditScreenName->setText(appConfig().screenName()); m_pSpinBoxPort->setValue(appConfig().port()); m_pLineEditInterface->setText(appConfig().interface()); m_pComboLogLevel->setCurrentIndex(appConfig().logLevel()); m_pCheckBoxLogToFile->setChecked(appConfig().logToFile()); m_pLineEditLogFilename->setText(appConfig().logFilename()); setIndexFromItemData(m_pComboLanguage, appConfig().language()); m_pCheckBoxAutoHide->setChecked(appConfig().getAutoHide()); #if defined(Q_OS_WIN) m_pComboElevate->setCurrentIndex(static_cast(appConfig().elevateMode())); m_pCheckBoxAutoHide->hide(); #else // elevate checkbox is only useful on ms windows. m_pLabelElevate->hide(); m_pComboElevate->hide(); #endif m_pCheckBoxEnableCrypto->setChecked(m_appConfig.getCryptoEnabled()); m_pCheckBoxEnableCrypto->setEnabled(m_appConfig.edition() == kPro); } void SettingsDialog::accept() { appConfig().setScreenName(m_pLineEditScreenName->text()); appConfig().setPort(m_pSpinBoxPort->value()); appConfig().setInterface(m_pLineEditInterface->text()); appConfig().setLogLevel(m_pComboLogLevel->currentIndex()); appConfig().setLogToFile(m_pCheckBoxLogToFile->isChecked()); appConfig().setLogFilename(m_pLineEditLogFilename->text()); appConfig().setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString()); appConfig().setElevateMode(static_cast(m_pComboElevate->currentIndex())); appConfig().setAutoHide(m_pCheckBoxAutoHide->isChecked()); appConfig().saveSettings(); QDialog::accept(); } void SettingsDialog::reject() { if (appConfig().language() != m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString()) { QSynergyApplication::getInstance()->switchTranslator(appConfig().language()); } QDialog::reject(); } void SettingsDialog::changeEvent(QEvent* event) { if (event != 0) { switch (event->type()) { case QEvent::LanguageChange: { int logLevelIndex = m_pComboLogLevel->currentIndex(); m_pComboLanguage->blockSignals(true); retranslateUi(this); m_pComboLanguage->blockSignals(false); m_pComboLogLevel->setCurrentIndex(logLevelIndex); break; } default: QDialog::changeEvent(event); } } } void SettingsDialog::on_m_pCheckBoxLogToFile_stateChanged(int i) { bool checked = i == 2; m_pLineEditLogFilename->setEnabled(checked); m_pButtonBrowseLog->setEnabled(checked); } void SettingsDialog::on_m_pButtonBrowseLog_clicked() { QString fileName = QFileDialog::getSaveFileName( this, tr("Save log file to..."), m_pLineEditLogFilename->text(), "Logs (*.log *.txt)"); if (!fileName.isEmpty()) { m_pLineEditLogFilename->setText(fileName); } } void SettingsDialog::on_m_pComboLanguage_currentIndexChanged(int index) { QString ietfCode = m_pComboLanguage->itemData(index).toString(); QSynergyApplication::getInstance()->switchTranslator(ietfCode); } void SettingsDialog::on_m_pCheckBoxEnableCrypto_toggled(bool checked) { m_appConfig.setCryptoEnabled(checked); m_appConfig.saveSettings(); if (checked) { SslCertificate sslCertificate; sslCertificate.generateCertificate(); MainWindow& mainWindow = dynamic_cast (*this->parent()); mainWindow.updateLocalFingerprint(); } } synergy-1.8.8-stable/src/gui/src/SettingsDialog.h000066400000000000000000000033271305627404700217500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(SETTINGSDIALOG_H) #define SETTINGSDIALOG_H #include #include "ui_SettingsDialogBase.h" #include "SynergyLocale.h" #include "CoreInterface.h" class AppConfig; class SettingsDialog : public QDialog, public Ui::SettingsDialogBase { Q_OBJECT public: SettingsDialog(QWidget* parent, AppConfig& config); static QString browseForSynergyc(QWidget* parent, const QString& programDir, const QString& synergycName); static QString browseForSynergys(QWidget* parent, const QString& programDir, const QString& synergysName); protected: void accept(); void reject(); void changeEvent(QEvent* event); AppConfig& appConfig() { return m_appConfig; } private: AppConfig& m_appConfig; SynergyLocale m_Locale; CoreInterface m_CoreInterface; private slots: void on_m_pCheckBoxEnableCrypto_toggled(bool checked); void on_m_pComboLanguage_currentIndexChanged(int index); void on_m_pCheckBoxLogToFile_stateChanged(int ); void on_m_pButtonBrowseLog_clicked(); }; #endif synergy-1.8.8-stable/src/gui/src/SetupWizard.cpp000066400000000000000000000072471305627404700216510ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "SetupWizard.h" #include "MainWindow.h" #include "WebClient.h" #include "ActivationNotifier.h" #include "LicenseManager.h" #include "EditionType.h" #include "QSynergyApplication.h" #include "QUtility.h" #include SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) : m_MainWindow(mainWindow), m_StartMain(startMain) { setupUi(this); #if defined(Q_OS_MAC) // the mac style needs a little more room because of the // graphic on the left. resize(600, 500); setMinimumSize(size()); #elif defined(Q_OS_WIN) // when areo is disabled on windows, the next/back buttons // are hidden (must be a qt bug) -- resizing the window // to +1 of the original height seems to fix this. // NOTE: calling setMinimumSize after this will break // it again, so don't do that. resize(size().width(), size().height() + 1); #endif connect(m_pServerRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupServer, SLOT(setChecked(bool))); connect(m_pClientRadioButton, SIGNAL(toggled(bool)), m_MainWindow.m_pGroupClient, SLOT(setChecked(bool))); m_Locale.fillLanguageComboBox(m_pComboLanguage); setIndexFromItemData(m_pComboLanguage, m_MainWindow.appConfig().language()); } SetupWizard::~SetupWizard() { } bool SetupWizard::validateCurrentPage() { QMessageBox message; message.setWindowTitle(tr("Setup Synergy")); message.setIcon(QMessageBox::Information); if (currentPage() == m_pNodePage) { bool result = m_pClientRadioButton->isChecked() || m_pServerRadioButton->isChecked(); if (!result) { message.setText(tr("Please select an option.")); message.exec(); return false; } } return true; } void SetupWizard::changeEvent(QEvent* event) { if (event != 0) { switch (event->type()) { case QEvent::LanguageChange: { m_pComboLanguage->blockSignals(true); retranslateUi(this); m_pComboLanguage->blockSignals(false); break; } default: QWizard::changeEvent(event); } } } void SetupWizard::accept() { AppConfig& appConfig = m_MainWindow.appConfig(); appConfig.setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString()); appConfig.setWizardHasRun(); appConfig.saveSettings(); QSettings& settings = m_MainWindow.settings(); if (m_pServerRadioButton->isChecked()) { settings.setValue("groupServerChecked", true); settings.setValue("groupClientChecked", false); } if (m_pClientRadioButton->isChecked()) { settings.setValue("groupClientChecked", true); settings.setValue("groupServerChecked", false); } QWizard::accept(); if (m_StartMain) { m_MainWindow.updateZeroconfService(); m_MainWindow.open(); } } void SetupWizard::reject() { QSynergyApplication::getInstance()->switchTranslator(m_MainWindow.appConfig().language()); if (m_StartMain) { m_MainWindow.open(); } QWizard::reject(); } void SetupWizard::on_m_pComboLanguage_currentIndexChanged(int index) { QString ietfCode = m_pComboLanguage->itemData(index).toString(); QSynergyApplication::getInstance()->switchTranslator(ietfCode); } synergy-1.8.8-stable/src/gui/src/SetupWizard.h000066400000000000000000000024431305627404700213070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "ui_SetupWizardBase.h" #include "SynergyLocale.h" #include #include class MainWindow; class SetupWizard : public QWizard, public Ui::SetupWizardBase { Q_OBJECT public: enum { kMaximiumLoginAttemps = 3 }; public: SetupWizard(MainWindow& mainWindow, bool startMain); virtual ~SetupWizard(); bool validateCurrentPage(); protected: void changeEvent(QEvent* event); void accept(); void reject(); private: MainWindow& m_MainWindow; bool m_StartMain; SynergyLocale m_Locale; private slots: void on_m_pComboLanguage_currentIndexChanged(int index); }; synergy-1.8.8-stable/src/gui/src/SslCertificate.cpp000066400000000000000000000103211305627404700222570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "SslCertificate.h" #include "Fingerprint.h" #include #include #include static const char kCertificateLifetime[] = "365"; static const char kCertificateSubjectInfo[] = "/CN=Synergy"; static const char kCertificateFilename[] = "Synergy.pem"; static const char kSslDir[] = "SSL"; static const char kUnixOpenSslCommand[] = "openssl"; #if defined(Q_OS_WIN) static const char kWinOpenSslBinary[] = "OpenSSL\\openssl.exe"; static const char kConfigFile[] = "OpenSSL\\synergy.conf"; #endif SslCertificate::SslCertificate(QObject *parent) : QObject(parent) { m_ProfileDir = m_CoreInterface.getProfileDir(); if (m_ProfileDir.isEmpty()) { emit error(tr("Failed to get profile directory.")); } } bool SslCertificate::runTool(const QStringList& args) { QString program; #if defined(Q_OS_WIN) program = QCoreApplication::applicationDirPath(); program.append("\\").append(kWinOpenSslBinary); #else program = kUnixOpenSslCommand; #endif QStringList environment; #if defined(Q_OS_WIN) environment << QString("OPENSSL_CONF=%1\\%2") .arg(QCoreApplication::applicationDirPath()) .arg(kConfigFile); #endif QProcess process; process.setEnvironment(environment); process.start(program, args); bool success = process.waitForStarted(); QString standardError; if (success && process.waitForFinished()) { m_ToolOutput = process.readAllStandardOutput().trimmed(); standardError = process.readAllStandardError().trimmed(); } int code = process.exitCode(); if (!success || code != 0) { emit error( QString("SSL tool failed: %1\n\nCode: %2\nError: %3") .arg(program) .arg(process.exitCode()) .arg(standardError.isEmpty() ? "Unknown" : standardError)); return false; } return true; } void SslCertificate::generateCertificate() { QString sslDirPath = QString("%1%2%3") .arg(m_ProfileDir) .arg(QDir::separator()) .arg(kSslDir); QString filename = QString("%1%2%3") .arg(sslDirPath) .arg(QDir::separator()) .arg(kCertificateFilename); QFile file(filename); if (!file.exists()) { QStringList arguments; // self signed certificate arguments.append("req"); arguments.append("-x509"); arguments.append("-nodes"); // valide duration arguments.append("-days"); arguments.append(kCertificateLifetime); // subject information arguments.append("-subj"); QString subInfo(kCertificateSubjectInfo); arguments.append(subInfo); // private key arguments.append("-newkey"); arguments.append("rsa:1024"); QDir sslDir(sslDirPath); if (!sslDir.exists()) { sslDir.mkpath("."); } // key output filename arguments.append("-keyout"); arguments.append(filename); // certificate output filename arguments.append("-out"); arguments.append(filename); if (!runTool(arguments)) { return; } emit info(tr("SSL certificate generated.")); } generateFingerprint(filename); emit generateFinished(); } void SslCertificate::generateFingerprint(const QString& certificateFilename) { QStringList arguments; arguments.append("x509"); arguments.append("-fingerprint"); arguments.append("-sha1"); arguments.append("-noout"); arguments.append("-in"); arguments.append(certificateFilename); if (!runTool(arguments)) { return; } // find the fingerprint from the tool output int i = m_ToolOutput.indexOf("="); if (i != -1) { i++; QString fingerprint = m_ToolOutput.mid( i, m_ToolOutput.size() - i); Fingerprint::local().trust(fingerprint, false); emit info(tr("SSL fingerprint generated.")); } else { emit error(tr("Failed to find SSL fingerprint.")); } } synergy-1.8.8-stable/src/gui/src/SslCertificate.h000066400000000000000000000022451305627404700217320ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "CoreInterface.h" #include class SslCertificate : public QObject { Q_OBJECT public: explicit SslCertificate(QObject *parent = 0); public slots: void generateCertificate(); signals: void error(QString e); void info(QString i); void generateFinished(); private: bool runTool(const QStringList& args); void generateFingerprint(const QString& certificateFilename); private: QString m_ProfileDir; QString m_ToolOutput; CoreInterface m_CoreInterface; }; synergy-1.8.8-stable/src/gui/src/SynergyLocale.cpp000066400000000000000000000035661305627404700221500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see */ #include "SynergyLocale.h" #include #include #include SynergyLocale::SynergyLocale() { loadLanguages(); } void SynergyLocale::loadLanguages() { QResource resource(":/res/lang/Languages.xml"); QByteArray bytes(reinterpret_cast(resource.data()), resource.size()); QXmlStreamReader xml(bytes); while (!xml.atEnd()) { QXmlStreamReader::TokenType token = xml.readNext(); if (xml.hasError()) { qCritical() << xml.errorString(); throw std::exception(); } if (xml.name() == "language" && token == QXmlStreamReader::StartElement) { QXmlStreamAttributes attributes = xml.attributes(); addLanguage( attributes.value("ietfCode").toString(), attributes.value("name").toString()); } } } void SynergyLocale::addLanguage(const QString& ietfCode, const QString& name) { m_Languages.push_back(SynergyLocale::Language(ietfCode, name)); } void SynergyLocale::fillLanguageComboBox(QComboBox* comboBox) { comboBox->blockSignals(true); QVector::iterator it; for (it = m_Languages.begin(); it != m_Languages.end(); ++it) { comboBox->addItem((*it).m_Name, (*it).m_IetfCode); } comboBox->blockSignals(false); } synergy-1.8.8-stable/src/gui/src/SynergyLocale.h000066400000000000000000000022661305627404700216110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include #include class SynergyLocale { class Language { public: Language() { } Language(const QString& IetfCode, const QString& name) : m_IetfCode(IetfCode), m_Name(name) { } public: QString m_IetfCode; QString m_Name; }; public: SynergyLocale(); void fillLanguageComboBox(QComboBox* comboBox); private: void loadLanguages(); void addLanguage(const QString& IetfCode, const QString& name); private: QVector m_Languages; }; synergy-1.8.8-stable/src/gui/src/TcpSocketReader.cpp000066400000000000000000000016431305627404700224040ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "TcpSocketReader.h" #include IpcReader::IpcReader(QTcpSocket& socket) : m_Socket(socket) { connect(m_Socket, SIGNAL(readyRead()), this, SLOT(read())); } IpcReader::~IpcReader() { } synergy-1.8.8-stable/src/gui/src/TrashScreenWidget.cpp000066400000000000000000000023331305627404700227440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "TrashScreenWidget.h" #include "ScreenSetupModel.h" #include #include void TrashScreenWidget::dragEnterEvent(QDragEnterEvent* event) { if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) { event->setDropAction(Qt::MoveAction); event->accept(); } else event->ignore(); } void TrashScreenWidget::dropEvent(QDropEvent* event) { if (event->mimeData()->hasFormat(ScreenSetupModel::mimeType())) event->acceptProposedAction(); else event->ignore(); } synergy-1.8.8-stable/src/gui/src/TrashScreenWidget.h000066400000000000000000000021241305627404700224070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if !defined(TRASHSCREENWIDGET__H) #define TRASHSCREENWIDGET__H #include class QWidget; class QDragEnterEvent; class QDropEvent; class TrashScreenWidget : public QLabel { Q_OBJECT public: TrashScreenWidget(QWidget* parent) : QLabel(parent) {} public: void dragEnterEvent(QDragEnterEvent* event); void dropEvent(QDropEvent* event); }; #endif synergy-1.8.8-stable/src/gui/src/VersionChecker.cpp000066400000000000000000000055041305627404700222740ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "VersionChecker.h" #include #include #include #include #include #define VERSION_REGEX "(\\d+\\.\\d+\\.\\d+)" #define VERSION_URL "http://symless.com/version/" VersionChecker::VersionChecker() { m_manager = new QNetworkAccessManager(this); connect(m_manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); } VersionChecker::~VersionChecker() { delete m_manager; } void VersionChecker::checkLatest() { m_manager->get(QNetworkRequest(QUrl(VERSION_URL))); } void VersionChecker::replyFinished(QNetworkReply* reply) { QString newestVersion = QString(reply->readAll()); if (!newestVersion.isEmpty()) { QString currentVersion = getVersion(); if (currentVersion != "Unknown") { if (compareVersions(currentVersion, newestVersion) > 0) emit updateFound(newestVersion); } } } int VersionChecker::compareVersions(const QString& left, const QString& right) { if (left.compare(right) == 0) return 0; // versions are same. QStringList leftSplit = left.split(QRegExp("\\.")); if (leftSplit.size() != 3) return 1; // assume right wins. QStringList rightSplit = right.split(QRegExp("\\.")); if (rightSplit.size() != 3) return -1; // assume left wins. int leftMajor = leftSplit.at(0).toInt(); int leftMinor = leftSplit.at(1).toInt(); int leftRev = leftSplit.at(2).toInt(); int rightMajor = rightSplit.at(0).toInt(); int rightMinor = rightSplit.at(1).toInt(); int rightRev = rightSplit.at(2).toInt(); bool rightWins = (rightMajor > leftMajor) || ((rightMajor >= leftMajor) && (rightMinor > leftMinor)) || ((rightMajor >= leftMajor) && (rightMinor >= leftMinor) && (rightRev > leftRev)); return rightWins ? 1 : -1; } QString VersionChecker::getVersion() { QProcess process; process.start(m_app, QStringList() << "--version"); process.setReadChannel(QProcess::StandardOutput); if (process.waitForStarted() && process.waitForFinished()) { QRegExp rx(VERSION_REGEX); QString text = process.readLine(); if (rx.indexIn(text) != -1) { return rx.cap(1); } } return tr("Unknown"); } synergy-1.8.8-stable/src/gui/src/VersionChecker.h000066400000000000000000000023611305627404700217370ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include class QNetworkAccessManager; class QNetworkReply; class VersionChecker : public QObject { Q_OBJECT public: VersionChecker(); virtual ~VersionChecker(); void checkLatest(); QString getVersion(); void setApp(const QString& app) { m_app = app; } int compareVersions(const QString& left, const QString& right); public slots: void replyFinished(QNetworkReply* reply); signals: void updateFound(const QString& version); private: QNetworkAccessManager* m_manager; QString m_app; }; synergy-1.8.8-stable/src/gui/src/WebClient.cpp000066400000000000000000000044721305627404700212410ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "WebClient.h" #include "EditionType.h" #include "QUtility.h" #include #include #include #include bool WebClient::getEdition (int& edition, QString& errorOut) { QString responseJson = request(); /* TODO: This is horrible and should be ripped out as soon as we move * to Qt 5. See issue #5630 */ QRegExp resultRegex(".*\"result\".*:.*(true|false).*"); if (resultRegex.exactMatch (responseJson)) { QString boolString = resultRegex.cap(1); if (boolString == "true") { QRegExp editionRegex(".*\"edition\".*:.*\"([^\"]+)\".*"); if (editionRegex.exactMatch(responseJson)) { QString e = editionRegex.cap(1); edition = e.toInt(); return true; } else { throw std::runtime_error ("Unrecognised server response."); } } else { errorOut = tr("Login failed. Invalid email address or password."); return false; } } else { QRegExp errorRegex(".*\"error\".*:.*\"([^\"]+)\".*"); if (errorRegex.exactMatch (responseJson)) { errorOut = errorRegex.cap(1).replace("\\n", "\n"); return false; } else { throw std::runtime_error ("Unrecognised server response."); } } } bool WebClient::setEmail (QString email, QString& errorOut) { if (email.isEmpty()) { errorOut = tr("Your email address cannot be left blank."); return false; } m_Email = email; return true; } bool WebClient::setPassword (QString password, QString&) { m_Password = password; return true; } QString WebClient::request() { QStringList args("--login-auth"); QString credentials (m_Email + ":" + hash(m_Password) + "\n"); return m_CoreInterface.run (args, credentials); } synergy-1.8.8-stable/src/gui/src/WebClient.h000066400000000000000000000023151305627404700207000ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef WEBCLIENT_H #define WEBCLIENT_H #include #include #include "CoreInterface.h" class QMessageBox; class QWidget; class QStringList; class WebClient : public QObject { Q_OBJECT public: bool getEdition (int& edition, QString& errorOut); bool setEmail (QString email, QString& errorOut); bool setPassword (QString password, QString& errorOut); signals: void error(QString e); private: QString request(); QString m_Email; QString m_Password; CoreInterface m_CoreInterface; }; #endif // WEBCLIENT_H synergy-1.8.8-stable/src/gui/src/ZeroconfBrowser.cpp000066400000000000000000000050161305627404700225110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ZeroconfBrowser.h" #include ZeroconfBrowser::ZeroconfBrowser(QObject* parent) : QObject(parent), m_DnsServiceRef(0), m_pSocket(0) { } ZeroconfBrowser::~ZeroconfBrowser() { if (m_pSocket) { delete m_pSocket; } if (m_DnsServiceRef) { DNSServiceRefDeallocate(m_DnsServiceRef); m_DnsServiceRef = 0; } } void ZeroconfBrowser::browseForType(const QString& type) { DNSServiceErrorType err = DNSServiceBrowse(&m_DnsServiceRef, 0, 0, type.toUtf8().constData(), 0, browseReply, this); if (err != kDNSServiceErr_NoError) { emit error(err); } else { int sockFD = DNSServiceRefSockFD(m_DnsServiceRef); if (sockFD == -1) { emit error(kDNSServiceErr_Invalid); } else { m_pSocket = new QSocketNotifier(sockFD, QSocketNotifier::Read, this); connect(m_pSocket, SIGNAL(activated(int)), this, SLOT(socketReadyRead())); } } } void ZeroconfBrowser::socketReadyRead() { DNSServiceErrorType err = DNSServiceProcessResult(m_DnsServiceRef); if (err != kDNSServiceErr_NoError) { emit error(err); } } void ZeroconfBrowser::browseReply(DNSServiceRef, DNSServiceFlags flags, quint32, DNSServiceErrorType errorCode, const char* serviceName, const char* regType, const char* replyDomain, void* context) { ZeroconfBrowser* browser = static_cast(context); if (errorCode != kDNSServiceErr_NoError) { emit browser->error(errorCode); } else { ZeroconfRecord record(serviceName, regType, replyDomain); if (flags & kDNSServiceFlagsAdd) { if (!browser->m_Records.contains(record)) { browser->m_Records.append(record); } } else { browser->m_Records.removeAll(record); } if (!(flags & kDNSServiceFlagsMoreComing)) { emit browser->currentRecordsChanged(browser->m_Records); } } } synergy-1.8.8-stable/src/gui/src/ZeroconfBrowser.h000066400000000000000000000032521305627404700221560ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "ZeroconfRecord.h" #include #define _MSL_STDINT_H #include #include class QSocketNotifier; class ZeroconfBrowser : public QObject { Q_OBJECT public: ZeroconfBrowser(QObject* parent = 0); ~ZeroconfBrowser(); void browseForType(const QString& type); inline QList currentRecords() const { return m_Records; } inline QString serviceType() const { return m_BrowsingType; } signals: void currentRecordsChanged(const QList& list); void error(DNSServiceErrorType err); private slots: void socketReadyRead(); private: static void DNSSD_API browseReply(DNSServiceRef, DNSServiceFlags flags, quint32, DNSServiceErrorType errorCode, const char* serviceName, const char* regType, const char* replyDomain, void* context); private: DNSServiceRef m_DnsServiceRef; QSocketNotifier* m_pSocket; QList m_Records; QString m_BrowsingType; }; synergy-1.8.8-stable/src/gui/src/ZeroconfRecord.h000066400000000000000000000030031305627404700217430ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include class ZeroconfRecord { public: ZeroconfRecord() {} ZeroconfRecord(const QString& name, const QString& regType, const QString& domain) : serviceName(name), registeredType(regType), replyDomain(domain) {} ZeroconfRecord(const char* name, const char* regType, const char* domain) { serviceName = QString::fromUtf8(name); registeredType = QString::fromUtf8(regType); replyDomain = QString::fromUtf8(domain); } bool operator==(const ZeroconfRecord& other) const { return serviceName == other.serviceName && registeredType == other.registeredType && replyDomain == other.replyDomain; } public: QString serviceName; QString registeredType; QString replyDomain; }; Q_DECLARE_METATYPE(ZeroconfRecord) synergy-1.8.8-stable/src/gui/src/ZeroconfRegister.cpp000066400000000000000000000052251305627404700226540ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ZeroconfRegister.h" #include ZeroconfRegister::ZeroconfRegister(QObject* parent) : QObject(parent), m_DnsServiceRef(0), m_pSocket(0) { } ZeroconfRegister::~ZeroconfRegister() { if (m_pSocket) { delete m_pSocket; } if (m_DnsServiceRef) { DNSServiceRefDeallocate(m_DnsServiceRef); m_DnsServiceRef = 0; } } void ZeroconfRegister::registerService(const ZeroconfRecord& record, quint16 servicePort) { if (m_DnsServiceRef) { qWarning("Warning: Already registered a service for this object"); return; } quint16 bigEndianPort = servicePort; #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN { bigEndianPort = 0 | ((servicePort & 0x00ff) << 8) | ((servicePort & 0xff00) >> 8); } #endif DNSServiceErrorType err = DNSServiceRegister(&m_DnsServiceRef, kDNSServiceFlagsNoAutoRename, 0, record.serviceName.toUtf8().constData(), record.registeredType.toUtf8().constData(), record.replyDomain.isEmpty() ? 0 : record.replyDomain.toUtf8().constData(), 0, bigEndianPort, 0, 0, registerService, this); if (err != kDNSServiceErr_NoError) { emit error(err); } else { int sockfd = DNSServiceRefSockFD(m_DnsServiceRef); if (sockfd == -1) { emit error(kDNSServiceErr_Invalid); } else { m_pSocket = new QSocketNotifier(sockfd, QSocketNotifier::Read, this); connect(m_pSocket, SIGNAL(activated(int)), this, SLOT(socketReadyRead())); } } } void ZeroconfRegister::socketReadyRead() { DNSServiceErrorType err = DNSServiceProcessResult(m_DnsServiceRef); if (err != kDNSServiceErr_NoError) { emit error(err); } } void ZeroconfRegister::registerService(DNSServiceRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char* name, const char* regtype, const char* domain, void* data) { ZeroconfRegister* serviceRegister = static_cast(data); if (errorCode != kDNSServiceErr_NoError) { emit serviceRegister->error(errorCode); } } synergy-1.8.8-stable/src/gui/src/ZeroconfRegister.h000066400000000000000000000032431305627404700223170ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include "ZeroconfRecord.h" class QSocketNotifier; // Bonjour flags #define _MSL_STDINT_H #include #if defined(Q_OS_WIN) #define WIN32_LEAN_AND_MEAN #endif #include class ZeroconfRegister : public QObject { Q_OBJECT public: ZeroconfRegister(QObject* parent = 0); ~ZeroconfRegister(); void registerService(const ZeroconfRecord& record, quint16 servicePort); inline ZeroconfRecord registeredRecord() const { return finalRecord; } signals: void error(DNSServiceErrorType error); void serviceRegistered(const ZeroconfRecord& record); private slots: void socketReadyRead(); private: static void DNSSD_API registerService(DNSServiceRef sdRef, DNSServiceFlags, DNSServiceErrorType errorCode, const char* name, const char* regtype, const char* domain, void* context); private: DNSServiceRef m_DnsServiceRef; QSocketNotifier* m_pSocket; ZeroconfRecord finalRecord; }; synergy-1.8.8-stable/src/gui/src/ZeroconfServer.cpp000066400000000000000000000021121305627404700223260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ZeroconfServer.h" #include "ZeroconfThread.h" #include ZeroconfServer::ZeroconfServer(QObject* parent) : QTcpServer(parent) { } void ZeroconfServer::incomingConnection(int socketDescriptor) { ZeroconfThread* thread = new ZeroconfThread(socketDescriptor, this); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); thread->start(); } synergy-1.8.8-stable/src/gui/src/ZeroconfServer.h000066400000000000000000000017611305627404700220040ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include class ZeroconfRegister; class ZeroconfServer : public QTcpServer { Q_OBJECT public: ZeroconfServer(QObject* parent = 0); protected: void incomingConnection(int socketDescriptor); private: QStringList fortunes; }; synergy-1.8.8-stable/src/gui/src/ZeroconfService.cpp000066400000000000000000000113701305627404700224660ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ZeroconfService.h" #include "MainWindow.h" #include "ZeroconfRegister.h" #include "ZeroconfBrowser.h" #include #include #define _MSL_STDINT_H #include #include static const QStringList preferedIPAddress( QStringList() << "192.168." << "10." << "172."); const char* ZeroconfService:: m_ServerServiceName = "_synergyServerZeroconf._tcp"; const char* ZeroconfService:: m_ClientServiceName = "_synergyClientZeroconf._tcp"; ZeroconfService::ZeroconfService(MainWindow* mainWindow) : m_pMainWindow(mainWindow), m_pZeroconfBrowser(0), m_pZeroconfRegister(0), m_ServiceRegistered(false) { if (m_pMainWindow->synergyType() == MainWindow::synergyServer) { if (registerService(true)) { m_pZeroconfBrowser = new ZeroconfBrowser(this); connect(m_pZeroconfBrowser, SIGNAL( currentRecordsChanged(const QList&)), this, SLOT(clientDetected(const QList&))); m_pZeroconfBrowser->browseForType( QLatin1String(m_ClientServiceName)); } } else { m_pZeroconfBrowser = new ZeroconfBrowser(this); connect(m_pZeroconfBrowser, SIGNAL( currentRecordsChanged(const QList&)), this, SLOT(serverDetected(const QList&))); m_pZeroconfBrowser->browseForType( QLatin1String(m_ServerServiceName)); } connect(m_pZeroconfBrowser, SIGNAL(error(DNSServiceErrorType)), this, SLOT(errorHandle(DNSServiceErrorType))); } ZeroconfService::~ZeroconfService() { if (m_pZeroconfBrowser) { delete m_pZeroconfBrowser; } if (m_pZeroconfRegister) { delete m_pZeroconfRegister; } } void ZeroconfService::serverDetected(const QList& list) { foreach (ZeroconfRecord record, list) { registerService(false); m_pMainWindow->appendLogInfo(tr("zeroconf server detected: %1").arg( record.serviceName)); m_pMainWindow->serverDetected(record.serviceName); } } void ZeroconfService::clientDetected(const QList& list) { foreach (ZeroconfRecord record, list) { m_pMainWindow->appendLogInfo(tr("zeroconf client detected: %1").arg( record.serviceName)); m_pMainWindow->autoAddScreen(record.serviceName); } } void ZeroconfService::errorHandle(DNSServiceErrorType errorCode) { QMessageBox::critical(0, tr("Zero configuration service"), tr("Error code: %1.").arg(errorCode)); } QString ZeroconfService::getLocalIPAddresses() { QStringList addresses; foreach (const QHostAddress& address, QNetworkInterface::allAddresses()) { if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress(QHostAddress::LocalHost)) { addresses.append(address.toString()); } } foreach (const QString& preferedIP, preferedIPAddress) { foreach (const QString& address, addresses) { if (address.startsWith(preferedIP)) { return address; } } } return ""; } bool ZeroconfService::registerService(bool server) { bool result = true; if (!m_ServiceRegistered) { if (!m_zeroconfServer.listen()) { QMessageBox::critical(0, tr("Zero configuration service"), tr("Unable to start the zeroconf: %1.") .arg(m_zeroconfServer.errorString())); result = false; } else { m_pZeroconfRegister = new ZeroconfRegister(this); if (server) { QString localIP = getLocalIPAddresses(); if (localIP.isEmpty()) { QMessageBox::warning(m_pMainWindow, tr("Synergy"), tr("Failed to get local IP address. " "Please manually type in server address " "on your clients")); } else { m_pZeroconfRegister->registerService( ZeroconfRecord(tr("%1").arg(localIP), QLatin1String(m_ServerServiceName), QString()), m_zeroconfServer.serverPort()); } } else { m_pZeroconfRegister->registerService( ZeroconfRecord(tr("%1").arg(m_pMainWindow->getScreenName()), QLatin1String(m_ClientServiceName), QString()), m_zeroconfServer.serverPort()); } m_ServiceRegistered = true; } } return result; } synergy-1.8.8-stable/src/gui/src/ZeroconfService.h000066400000000000000000000030731305627404700221340ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "ZeroconfServer.h" #include "ZeroconfRecord.h" #include typedef int32_t DNSServiceErrorType; class ZeroconfRegister; class ZeroconfBrowser; class MainWindow; class ZeroconfService : public QObject { Q_OBJECT public: ZeroconfService(MainWindow* mainWindow); ~ZeroconfService(); private slots: void serverDetected(const QList& list); void clientDetected(const QList& list); void errorHandle(DNSServiceErrorType errorCode); private: QString getLocalIPAddresses(); bool registerService(bool server); private: MainWindow* m_pMainWindow; ZeroconfServer m_zeroconfServer; ZeroconfBrowser* m_pZeroconfBrowser; ZeroconfRegister* m_pZeroconfRegister; bool m_ServiceRegistered; static const char* m_ServerServiceName; static const char* m_ClientServiceName; }; synergy-1.8.8-stable/src/gui/src/ZeroconfThread.cpp000066400000000000000000000021641305627404700222760ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ZeroconfThread.h" #include ZeroconfThread::ZeroconfThread(int socketDescriptor, QObject* parent) : QThread(parent), m_SocketDescriptor(socketDescriptor) { } void ZeroconfThread::run() { QTcpSocket tcpSocket; if (!tcpSocket.setSocketDescriptor(m_SocketDescriptor)) { emit error(tcpSocket.error()); return; } tcpSocket.disconnectFromHost(); tcpSocket.waitForDisconnected(); } synergy-1.8.8-stable/src/gui/src/ZeroconfThread.h000066400000000000000000000020051305627404700217350ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include class ZeroconfThread : public QThread { Q_OBJECT public: ZeroconfThread(int socketDescriptor, QObject* parent); void run(); signals: void error(QTcpSocket::SocketError socketError); private: int m_SocketDescriptor; QString m_Text; }; synergy-1.8.8-stable/src/gui/src/main.cpp000066400000000000000000000074671305627404700203200ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2008 Volker Lanz (vl@fidra.de) * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define TRAY_RETRY_COUNT 10 #define TRAY_RETRY_WAIT 2000 #include "QSynergyApplication.h" #include "LicenseManager.h" #include "MainWindow.h" #include "AppConfig.h" #include "SetupWizard.h" #include #include #include #include #if defined(Q_OS_MAC) #include #endif class QThreadImpl : public QThread { public: static void msleep(unsigned long msecs) { QThread::msleep(msecs); } }; int waitForTray(); #if defined(Q_OS_MAC) bool checkMacAssistiveDevices(); #endif int main(int argc, char* argv[]) { QCoreApplication::setOrganizationName("Synergy"); QCoreApplication::setOrganizationDomain("http://symless.com/"); QCoreApplication::setApplicationName("Synergy"); QSynergyApplication app(argc, argv); #if defined(Q_OS_MAC) if (app.applicationDirPath().startsWith("/Volumes/")) { QMessageBox::information( NULL, "Synergy", "Please drag Synergy to the Applications folder, and open it from there."); return 1; } if (!checkMacAssistiveDevices()) { return 1; } #endif if (!waitForTray()) { return -1; } #ifndef Q_OS_WIN QApplication::setQuitOnLastWindowClosed(false); #endif QSettings settings; AppConfig appConfig (&settings); qRegisterMetaType("Edition"); LicenseManager licenseManager (&appConfig); app.switchTranslator(appConfig.language()); MainWindow mainWindow(settings, appConfig, licenseManager); SetupWizard setupWizard(mainWindow, true); if (appConfig.wizardShouldRun()) { setupWizard.show(); } else { mainWindow.open(); } return app.exec(); } int waitForTray() { // on linux, the system tray may not be available immediately after logging in, // so keep retrying but give up after a short time. int trayAttempts = 0; while (true) { if (QSystemTrayIcon::isSystemTrayAvailable()) { break; } if (++trayAttempts > TRAY_RETRY_COUNT) { QMessageBox::critical(NULL, "Synergy", QObject::tr("System tray is unavailable, don't close your window.")); return true; } QThreadImpl::msleep(TRAY_RETRY_WAIT); } return true; } #if defined(Q_OS_MAC) bool checkMacAssistiveDevices() { #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 // mavericks // new in mavericks, applications are trusted individually // with use of the accessibility api. this call will show a // prompt which can show the security/privacy/accessibility // tab, with a list of allowed applications. synergy should // show up there automatically, but will be unchecked. if (AXIsProcessTrusted()) { return true; } const void* keys[] = { kAXTrustedCheckOptionPrompt }; const void* trueValue[] = { kCFBooleanTrue }; CFDictionaryRef options = CFDictionaryCreate(NULL, keys, trueValue, 1, NULL, NULL); bool result = AXIsProcessTrustedWithOptions(options); CFRelease(options); return result; #else // now deprecated in mavericks. bool result = AXAPIEnabled(); if (!result) { QMessageBox::information( NULL, "Synergy", "Please enable access to assistive devices " "System Preferences -> Security & Privacy -> " "Privacy -> Accessibility, then re-open Synergy."); } return result; #endif } #endif synergy-1.8.8-stable/src/lib/000077500000000000000000000000001305627404700160455ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/CMakeLists.txt000066400000000000000000000020161305627404700206040ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . add_subdirectory(arch) add_subdirectory(base) add_subdirectory(client) add_subdirectory(common) add_subdirectory(io) add_subdirectory(ipc) add_subdirectory(mt) add_subdirectory(net) add_subdirectory(platform) add_subdirectory(server) add_subdirectory(synergy) add_subdirectory(shared) if (WIN32) add_subdirectory(synwinhk) endif() synergy-1.8.8-stable/src/lib/arch/000077500000000000000000000000001305627404700167625ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/arch/Arch.cpp000066400000000000000000000022501305627404700203420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/Arch.h" // // Arch // Arch* Arch::s_instance = NULL; Arch::Arch() { assert(s_instance == NULL); s_instance = this; } Arch::Arch(Arch* arch) { s_instance = arch; } Arch::~Arch() { #if SYSAPI_WIN32 ArchMiscWindows::cleanup(); #endif } void Arch::init() { ARCH_NETWORK::init(); #if SYSAPI_WIN32 ARCH_TASKBAR::init(); ArchMiscWindows::init(); #endif } Arch* Arch::getInstance() { assert(s_instance != NULL); return s_instance; } synergy-1.8.8-stable/src/lib/arch/Arch.h000066400000000000000000000103321305627404700200070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // TODO: consider whether or not to use either encapsulation (as below) // or inheritance (as it is now) for the ARCH stuff. // // case for encapsulation: // pros: // - compiler errors for missing pv implementations are not absolutely bonkers. // - function names don't have to be so verbose. // - easier to understand and debug. // - ctors in IArch implementations can call other implementations. // cons: // - slightly more code for calls to ARCH. // - you'll have to modify each ARCH call. // // also, we may want to consider making each encapsulated // class lazy-loaded so that apps like the daemon don't load // stuff when they don't need it. #pragma once #include "common/common.h" #if SYSAPI_WIN32 # include "arch/win32/ArchConsoleWindows.h" # include "arch/win32/ArchDaemonWindows.h" # include "arch/win32/ArchFileWindows.h" # include "arch/win32/ArchLogWindows.h" # include "arch/win32/ArchMiscWindows.h" # include "arch/win32/ArchMultithreadWindows.h" # include "arch/win32/ArchNetworkWinsock.h" # include "arch/win32/ArchSleepWindows.h" # include "arch/win32/ArchStringWindows.h" # include "arch/win32/ArchSystemWindows.h" # include "arch/win32/ArchTaskBarWindows.h" # include "arch/win32/ArchTimeWindows.h" # include "arch/win32/ArchInternetWindows.h" #elif SYSAPI_UNIX # include "arch/unix/ArchConsoleUnix.h" # include "arch/unix/ArchDaemonUnix.h" # include "arch/unix/ArchFileUnix.h" # include "arch/unix/ArchLogUnix.h" # if HAVE_PTHREAD # include "arch/unix/ArchMultithreadPosix.h" # endif # include "arch/unix/ArchNetworkBSD.h" # include "arch/unix/ArchSleepUnix.h" # include "arch/unix/ArchStringUnix.h" # include "arch/unix/ArchSystemUnix.h" # include "arch/unix/ArchTaskBarXWindows.h" # include "arch/unix/ArchTimeUnix.h" # include "arch/unix/ArchInternetUnix.h" #endif /*! \def ARCH This macro evaluates to the singleton Arch object. */ #define ARCH (Arch::getInstance()) //! Delegating implementation of architecture dependent interfaces /*! This class is a centralized interface to all architecture dependent interface implementations (except miscellaneous functions). It instantiates an implementation of each interface and delegates calls to each method to those implementations. Clients should use the \c ARCH macro to access this object. Clients must also instantiate exactly one of these objects before attempting to call any method, typically at the beginning of \c main(). */ class Arch : public ARCH_CONSOLE, public ARCH_DAEMON, public ARCH_FILE, public ARCH_LOG, public ARCH_MULTITHREAD, public ARCH_NETWORK, public ARCH_SLEEP, public ARCH_STRING, public ARCH_SYSTEM, public ARCH_TASKBAR, public ARCH_TIME { public: Arch(); Arch(Arch* arch); virtual ~Arch(); //! Call init on other arch classes. /*! Some arch classes depend on others to exist first. When init is called these clases will have ARCH available for use. */ virtual void init(); // // accessors // //! Return the singleton instance /*! The client must have instantiated exactly once Arch object before calling this function. */ static Arch* getInstance(); static void setInstance(Arch* s) { s_instance = s; } ARCH_INTERNET& internet() const { return (ARCH_INTERNET&)m_internet; } private: static Arch* s_instance; ARCH_INTERNET m_internet; }; //! Convenience object to lock/unlock an arch mutex class ArchMutexLock { public: ArchMutexLock(ArchMutex mutex) : m_mutex(mutex) { ARCH->lockMutex(m_mutex); } ~ArchMutexLock() { ARCH->unlockMutex(m_mutex); } private: ArchMutex m_mutex; }; synergy-1.8.8-stable/src/lib/arch/ArchConsoleStd.cpp000066400000000000000000000017711305627404700223470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/ArchConsoleStd.h" #include "base/Log.h" #include void ArchConsoleStd::writeConsole(ELevel level, const char* str) { if ((level >= kFATAL) && (level <= kWARNING)) std::cerr << str << std::endl; else std::cout << str << std::endl; std::cout.flush(); }synergy-1.8.8-stable/src/lib/arch/ArchConsoleStd.h000066400000000000000000000021661305627404700220130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchConsole.h" //! Cross platform implementation of IArchConsole class ArchConsoleStd : public IArchConsole { public: ArchConsoleStd() { } virtual ~ArchConsoleStd() { } // IArchConsole overrides virtual void openConsole(const char* title) { } virtual void closeConsole() { } virtual void showConsole(bool) { } virtual void writeConsole(ELevel level, const char*); }; synergy-1.8.8-stable/src/lib/arch/ArchDaemonNone.cpp000066400000000000000000000030511305627404700223060ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/ArchDaemonNone.h" // // ArchDaemonNone // ArchDaemonNone::ArchDaemonNone() { // do nothing } ArchDaemonNone::~ArchDaemonNone() { // do nothing } void ArchDaemonNone::installDaemon(const char*, const char*, const char*, const char*, const char*) { // do nothing } void ArchDaemonNone::uninstallDaemon(const char*) { // do nothing } int ArchDaemonNone::daemonize(const char* name, DaemonFunc func) { // simply forward the call to func. obviously, this doesn't // do any daemonizing. return func(1, &name); } bool ArchDaemonNone::canInstallDaemon(const char*) { return false; } bool ArchDaemonNone::isDaemonInstalled(const char*) { return false; } void ArchDaemonNone::installDaemon() { } void ArchDaemonNone::uninstallDaemon() { } std::string ArchDaemonNone::commandLine() const { return ""; } synergy-1.8.8-stable/src/lib/arch/ArchDaemonNone.h000066400000000000000000000032711305627404700217570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchDaemon.h" #define ARCH_DAEMON ArchDaemonNone //! Dummy implementation of IArchDaemon /*! This class implements IArchDaemon for a platform that does not have daemons. The install and uninstall functions do nothing, the query functions return false, and \c daemonize() simply calls the passed function and returns its result. */ class ArchDaemonNone : public IArchDaemon { public: ArchDaemonNone(); virtual ~ArchDaemonNone(); // IArchDaemon overrides virtual void installDaemon(const char* name, const char* description, const char* pathname, const char* commandLine, const char* dependencies); virtual void uninstallDaemon(const char* name); virtual int daemonize(const char* name, DaemonFunc func); virtual bool canInstallDaemon(const char* name); virtual bool isDaemonInstalled(const char* name); virtual void installDaemon(); virtual void uninstallDaemon(); virtual std::string commandLine() const; }; synergy-1.8.8-stable/src/lib/arch/CMakeLists.txt000066400000000000000000000024711305627404700215260ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() # arch if (WIN32) file(GLOB arch_headers "win32/*.h") file(GLOB arch_sources "win32/*.cpp") elseif (UNIX) file(GLOB arch_headers "unix/*.h") file(GLOB arch_sources "unix/*.cpp") endif() list(APPEND sources ${arch_sources}) list(APPEND headers ${arch_headers}) if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ) if (UNIX) include_directories( ../../.. ) endif() add_library(arch STATIC ${sources}) if (UNIX) target_link_libraries(arch dl ${libs}) endif() synergy-1.8.8-stable/src/lib/arch/IArchConsole.h000066400000000000000000000040611305627404700214450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "base/ELevel.h" //! Interface for architecture dependent console output /*! This interface defines the console operations required by synergy. Each architecture must implement this interface. */ class IArchConsole : public IInterface { public: //! @name manipulators //@{ //! Open the console /*! Opens the console for writing. The console is opened automatically on the first write so calling this method is optional. Uses \c title for the console's title if appropriate for the architecture. Calling this method on an already open console must have no effect. */ virtual void openConsole(const char* title) = 0; //! Close the console /*! Close the console. Calling this method on an already closed console must have no effect. */ virtual void closeConsole() = 0; //! Show the console /*! Causes the console to become visible. This generally only makes sense for a console in a graphical user interface. Other implementations will do nothing. Iff \p showIfEmpty is \c false then the implementation may optionally only show the console if it's not empty. */ virtual void showConsole(bool showIfEmpty) = 0; //! Write to the console /*! Writes the given string to the console, opening it if necessary. */ virtual void writeConsole(ELevel, const char*) = 0; //@} }; synergy-1.8.8-stable/src/lib/arch/IArchDaemon.h000066400000000000000000000104321305627404700212450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "base/String.h" //! Interface for architecture dependent daemonizing /*! This interface defines the operations required by synergy for installing uninstalling daeamons and daemonizing a process. Each architecture must implement this interface. */ class IArchDaemon : public IInterface { public: typedef int (*DaemonFunc)(int argc, const char** argv); //! @name manipulators //@{ //! Install daemon /*! Install a daemon. \c name is the name of the daemon passed to the system and \c description is a short human readable description of the daemon. \c pathname is the path to the daemon executable. \c commandLine should \b not include the name of program as the first argument. If \c allUsers is true then the daemon will be installed to start at boot time, otherwise it will be installed to start when the current user logs in. If \p dependencies is not NULL then it's a concatenation of NUL terminated other daemon names followed by a NUL; the daemon will be configured to startup after the listed daemons. Throws an \c XArchDaemon exception on failure. */ virtual void installDaemon(const char* name, const char* description, const char* pathname, const char* commandLine, const char* dependencies) = 0; //! Uninstall daemon /*! Uninstall a daemon. Throws an \c XArchDaemon on failure. */ virtual void uninstallDaemon(const char* name) = 0; //! Install daemon /*! Installs the default daemon. */ virtual void installDaemon() = 0; //! Uninstall daemon /*! Uninstalls the default daemon. */ virtual void uninstallDaemon() = 0; //! Daemonize the process /*! Daemonize. Throw XArchDaemonFailed on error. \c name is the name of the daemon. Once daemonized, \c func is invoked and daemonize returns when and what it does. Exactly what happens when daemonizing depends on the platform.
  • unix: Detaches from terminal. \c func gets passed one argument, the name passed to daemonize().
  • win32: Becomes a service. Argument 0 is the name of the service and the rest are the arguments passed to StartService(). \c func is only called when the service is actually started. \c func must call \c ArchMiscWindows::runDaemon() to finally becoming a service. The \c runFunc function passed to \c runDaemon() must call \c ArchMiscWindows::daemonRunning(true) when it enters the main loop (i.e. after initialization) and \c ArchMiscWindows::daemonRunning(false) when it leaves the main loop. The \c stopFunc function passed to \c runDaemon() is called when the daemon must exit the main loop and it must cause \c runFunc to return. \c func should return what \c runDaemon() returns. \c func or \c runFunc can call \c ArchMiscWindows::daemonFailed() to indicate startup failure.
*/ virtual int daemonize(const char* name, DaemonFunc func) = 0; //! Check if user has permission to install the daemon /*! Returns true iff the caller has permission to install or uninstall the daemon. Note that even if this method returns true it's possible that installing/uninstalling the service may still fail. This method ignores whether or not the service is already installed. */ virtual bool canInstallDaemon(const char* name) = 0; //! Check if the daemon is installed /*! Returns true iff the daemon is installed. */ virtual bool isDaemonInstalled(const char* name) = 0; //@} //! Get the command line /*! Gets the command line with which the application was started. */ virtual std::string commandLine() const = 0; //@} }; synergy-1.8.8-stable/src/lib/arch/IArchFile.h000066400000000000000000000056311305627404700207260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "common/stdstring.h" #include "base/String.h" //! Interface for architecture dependent file system operations /*! This interface defines the file system operations required by synergy. Each architecture must implement this interface. */ class IArchFile : public IInterface { public: //! @name manipulators //@{ //! Extract base name /*! Find the base name in the given \c pathname. */ virtual const char* getBasename(const char* pathname) = 0; //! Get user's home directory /*! Returns the user's home directory. Returns the empty string if this cannot be determined. */ virtual std::string getUserDirectory() = 0; //! Get system directory /*! Returns the ussystem configuration file directory. */ virtual std::string getSystemDirectory() = 0; //! Get installed directory /*! Returns the directory in which Synergy is installed. */ virtual std::string getInstalledDirectory() = 0; //! Get log directory /*! Returns the log file directory. */ virtual std::string getLogDirectory() = 0; //! Get plugins directory /*! Returns the plugin files directory. If no plugin directory is set, this will return the plugin folder within the user's profile. */ virtual std::string getPluginDirectory() = 0; //! Get user's profile directory /*! Returns the user's profile directory. If no profile directory is set, this will return the user's profile according to the operating system, which will depend on which user launched the program. */ virtual std::string getProfileDirectory() = 0; //! Concatenate path components /*! Concatenate pathname components with a directory separator between them. This should not check if the resulting path is longer than allowed by the system; we'll rely on the system calls to tell us that. */ virtual std::string concatPath( const std::string& prefix, const std::string& suffix) = 0; //@} //! Set the user's profile directory /* Returns the user's profile directory. */ virtual void setProfileDirectory(const String& s) = 0; //@} //! Set the user's plugin directory /* Returns the user's plugin directory. */ virtual void setPluginDirectory(const String& s) = 0; }; synergy-1.8.8-stable/src/lib/arch/IArchLog.h000066400000000000000000000033431305627404700205660ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "base/ELevel.h" //! Interface for architecture dependent logging /*! This interface defines the logging operations required by synergy. Each architecture must implement this interface. */ class IArchLog : public IInterface { public: //! @name manipulators //@{ //! Open the log /*! Opens the log for writing. The log must be opened before being written to. */ virtual void openLog(const char* name) = 0; //! Close the log /*! Close the log. */ virtual void closeLog() = 0; //! Show the log /*! Causes the log to become visible. This generally only makes sense for a log in a graphical user interface. Other implementations will do nothing. Iff \p showIfEmpty is \c false then the implementation may optionally only show the log if it's not empty. */ virtual void showLog(bool showIfEmpty) = 0; //! Write to the log /*! Writes the given string to the log with the given level. */ virtual void writeLog(ELevel, const char*) = 0; //@} }; synergy-1.8.8-stable/src/lib/arch/IArchMultithread.h000066400000000000000000000165171305627404700223360ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" /*! \class ArchCondImpl \brief Internal condition variable data. An architecture dependent type holding the necessary data for a condition variable. */ class ArchCondImpl; /*! \var ArchCond \brief Opaque condition variable type. An opaque type representing a condition variable. */ typedef ArchCondImpl* ArchCond; /*! \class ArchMutexImpl \brief Internal mutex data. An architecture dependent type holding the necessary data for a mutex. */ class ArchMutexImpl; /*! \var ArchMutex \brief Opaque mutex type. An opaque type representing a mutex. */ typedef ArchMutexImpl* ArchMutex; /*! \class ArchThreadImpl \brief Internal thread data. An architecture dependent type holding the necessary data for a thread. */ class ArchThreadImpl; /*! \var ArchThread \brief Opaque thread type. An opaque type representing a thread. */ typedef ArchThreadImpl* ArchThread; //! Interface for architecture dependent multithreading /*! This interface defines the multithreading operations required by synergy. Each architecture must implement this interface. */ class IArchMultithread : public IInterface { public: //! Type of thread entry point typedef void* (*ThreadFunc)(void*); //! Type of thread identifier typedef unsigned int ThreadID; //! Types of signals /*! Not all platforms support all signals. Unsupported signals are ignored. */ enum ESignal { kINTERRUPT, //!< Interrupt (e.g. Ctrl+C) kTERMINATE, //!< Terminate (e.g. Ctrl+Break) kHANGUP, //!< Hangup (SIGHUP) kUSER, //!< User (SIGUSR2) kNUM_SIGNALS }; //! Type of signal handler function typedef void (*SignalFunc)(ESignal, void* userData); //! @name manipulators //@{ // // condition variable methods // //! Create a condition variable /*! The condition variable is an opaque data type. */ virtual ArchCond newCondVar() = 0; //! Destroy a condition variable virtual void closeCondVar(ArchCond) = 0; //! Signal a condition variable /*! Signalling a condition variable releases one waiting thread. */ virtual void signalCondVar(ArchCond) = 0; //! Broadcast a condition variable /*! Broadcasting a condition variable releases all waiting threads. */ virtual void broadcastCondVar(ArchCond) = 0; //! Wait on a condition variable /*! Wait on a conditation variable for up to \c timeout seconds. If \c timeout is < 0 then there is no timeout. The mutex must be locked when this method is called. The mutex is unlocked during the wait and locked again before returning. Returns true if the condition variable was signalled and false on timeout. (Cancellation point) */ virtual bool waitCondVar(ArchCond, ArchMutex, double timeout) = 0; // // mutex methods // //! Create a recursive mutex /*! Creates a recursive mutex. A thread may lock a recursive mutex when it already holds a lock on that mutex. The mutex is an opaque data type. */ virtual ArchMutex newMutex() = 0; //! Destroy a mutex virtual void closeMutex(ArchMutex) = 0; //! Lock a mutex virtual void lockMutex(ArchMutex) = 0; //! Unlock a mutex virtual void unlockMutex(ArchMutex) = 0; // // thread methods // //! Start a new thread /*! Creates and starts a new thread, using \c func as the entry point and passing it \c userData. The thread is an opaque data type. */ virtual ArchThread newThread(ThreadFunc func, void* userData) = 0; //! Get a reference to the calling thread /*! Returns a thread representing the current (i.e. calling) thread. */ virtual ArchThread newCurrentThread() = 0; //! Copy a thread object /*! Returns a reference to to thread referred to by \c thread. */ virtual ArchThread copyThread(ArchThread thread) = 0; //! Release a thread reference /*! Deletes the given thread object. This does not destroy the thread the object referred to, even if there are no remaining references. Use cancelThread() and waitThread() to stop a thread and wait for it to exit. */ virtual void closeThread(ArchThread) = 0; //! Force a thread to exit /*! Causes \c thread to exit when it next calls a cancellation point. A thread avoids cancellation as long as it nevers calls a cancellation point. Once it begins the cancellation process it must always let cancellation go to completion but may take as long as necessary to clean up. */ virtual void cancelThread(ArchThread thread) = 0; //! Change thread priority /*! Changes the priority of \c thread by \c n. If \c n is positive the thread has a lower priority and if negative a higher priority. Some architectures may not support either or both directions. */ virtual void setPriorityOfThread(ArchThread, int n) = 0; //! Cancellation point /*! This method does nothing but is a cancellation point. Clients can make their own functions cancellation points by calling this method at appropriate times. (Cancellation point) */ virtual void testCancelThread() = 0; //! Wait for a thread to exit /*! Waits for up to \c timeout seconds for \c thread to exit (normally or by cancellation). Waits forever if \c timeout < 0. Returns true if the thread exited, false otherwise. Waiting on the current thread returns immediately with false. (Cancellation point) */ virtual bool wait(ArchThread thread, double timeout) = 0; //! Compare threads /*! Returns true iff two thread objects refer to the same thread. Note that comparing thread objects directly is meaningless. */ virtual bool isSameThread(ArchThread, ArchThread) = 0; //! Test if thread exited /*! Returns true iff \c thread has exited. */ virtual bool isExitedThread(ArchThread thread) = 0; //! Returns the exit code of a thread /*! Waits indefinitely for \c thread to exit (if it hasn't yet) then returns the thread's exit code. (Cancellation point) */ virtual void* getResultOfThread(ArchThread thread) = 0; //! Returns an ID for a thread /*! Returns some ID number for \c thread. This is for logging purposes. All thread objects referring to the same thread return the same ID. However, clients should us isSameThread() to compare thread objects instead of comparing IDs. */ virtual ThreadID getIDOfThread(ArchThread thread) = 0; //! Set the interrupt handler /*! Sets the function to call on receipt of an external interrupt. By default and when \p func is NULL, the main thread is cancelled. */ virtual void setSignalHandler(ESignal, SignalFunc func, void* userData) = 0; //! Invoke the signal handler /*! Invokes the signal handler for \p signal, if any. If no handler cancels the main thread for \c kINTERRUPT and \c kTERMINATE and ignores the call otherwise. */ virtual void raiseSignal(ESignal signal) = 0; //@} }; synergy-1.8.8-stable/src/lib/arch/IArchNetwork.h000066400000000000000000000202111305627404700214670ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "common/stdstring.h" class ArchThreadImpl; typedef ArchThreadImpl* ArchThread; /*! \class ArchSocketImpl \brief Internal socket data. An architecture dependent type holding the necessary data for a socket. */ class ArchSocketImpl; /*! \var ArchSocket \brief Opaque socket type. An opaque type representing a socket. */ typedef ArchSocketImpl* ArchSocket; /*! \class ArchNetAddressImpl \brief Internal network address data. An architecture dependent type holding the necessary data for a network address. */ class ArchNetAddressImpl; /*! \var ArchNetAddress \brief Opaque network address type. An opaque type representing a network address. */ typedef ArchNetAddressImpl* ArchNetAddress; //! Interface for architecture dependent networking /*! This interface defines the networking operations required by synergy. Each architecture must implement this interface. */ class IArchNetwork : public IInterface { public: //! Supported address families enum EAddressFamily { kUNKNOWN, kINET, }; //! Supported socket types enum ESocketType { kDGRAM, kSTREAM }; //! Events for \c poll() /*! Events for \c poll() are bitmasks and can be combined using the bitwise operators. */ enum { kPOLLIN = 1, //!< Socket is readable kPOLLOUT = 2, //!< Socket is writable kPOLLERR = 4, //!< The socket is in an error state kPOLLNVAL = 8 //!< The socket is invalid }; //! A socket query for \c poll() class PollEntry { public: //! The socket to query ArchSocket m_socket; //! The events to query for /*! The events to query for can be any combination of kPOLLIN and kPOLLOUT. */ unsigned short m_events; //! The result events unsigned short m_revents; }; //! @name manipulators //@{ //! Create a new socket /*! The socket is an opaque data type. */ virtual ArchSocket newSocket(EAddressFamily, ESocketType) = 0; //! Copy a socket object /*! Returns a reference to to socket referred to by \c s. */ virtual ArchSocket copySocket(ArchSocket s) = 0; //! Release a socket reference /*! Deletes the given socket object. This does not destroy the socket the object referred to until there are no remaining references for the socket. */ virtual void closeSocket(ArchSocket s) = 0; //! Close socket for further reads /*! Calling this disallows future reads on socket \c s. */ virtual void closeSocketForRead(ArchSocket s) = 0; //! Close socket for further writes /*! Calling this disallows future writes on socket \c s. */ virtual void closeSocketForWrite(ArchSocket s) = 0; //! Bind socket to address /*! Binds socket \c s to the address \c addr. */ virtual void bindSocket(ArchSocket s, ArchNetAddress addr) = 0; //! Listen for connections on socket /*! Causes the socket \c s to begin listening for incoming connections. */ virtual void listenOnSocket(ArchSocket s) = 0; //! Accept connection on socket /*! Accepts a connection on socket \c s, returning a new socket for the connection and filling in \c addr with the address of the remote end. \c addr may be NULL if the remote address isn't required. The original socket \c s is unaffected and remains in the listening state. The new socket shares most of the properties of \c s except it's not in the listening state and it's connected. Returns NULL if there are no pending connection requests. */ virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress* addr) = 0; //! Connect socket /*! Connects the socket \c s to the remote address \c addr. Returns true if the connection succeed immediately, false if the connection is in progress, and throws if the connection failed immediately. If it returns false, \c pollSocket() can be used to wait on the socket for writing to detect when the connection finally succeeds or fails. */ virtual bool connectSocket(ArchSocket s, ArchNetAddress addr) = 0; //! Check socket state /*! Tests the state of \c num sockets for readability and/or writability. Waits up to \c timeout seconds for some socket to become readable and/or writable (or indefinitely if \c timeout < 0). Returns the number of sockets that were readable (if readability was being queried) or writable (if writablility was being queried) and sets the \c m_revents members of the entries. \c kPOLLERR and \c kPOLLNVAL are set in \c m_revents as appropriate. If a socket indicates \c kPOLLERR then \c throwErrorOnSocket() can be used to determine the type of error. Returns 0 immediately regardless of the \c timeout if no valid sockets are selected for testing. (Cancellation point) */ virtual int pollSocket(PollEntry[], int num, double timeout) = 0; //! Unblock thread in pollSocket() /*! Cause a thread that's in a pollSocket() call to return. This call may return before the thread is unblocked. If the thread is not in a pollSocket() call this call has no effect. */ virtual void unblockPollSocket(ArchThread thread) = 0; //! Read data from socket /*! Read up to \c len bytes from socket \c s in \c buf and return the number of bytes read. The number of bytes can be less than \c len if not enough data is available. Returns 0 if the remote end has disconnected and/or there is no more queued received data. */ virtual size_t readSocket(ArchSocket s, void* buf, size_t len) = 0; //! Write data from socket /*! Write up to \c len bytes to socket \c s from \c buf and return the number of bytes written. The number of bytes can be less than \c len if the remote end disconnected or the internal buffers fill up. */ virtual size_t writeSocket(ArchSocket s, const void* buf, size_t len) = 0; //! Check error on socket /*! If the socket \c s is in an error state then throws an appropriate XArchNetwork exception. */ virtual void throwErrorOnSocket(ArchSocket s) = 0; //! Turn Nagle algorithm on or off on socket /*! Set socket to send messages immediately (true) or to collect small messages into one packet (false). Returns the previous state. */ virtual bool setNoDelayOnSocket(ArchSocket, bool noDelay) = 0; //! Turn address reuse on or off on socket /*! Allows the address this socket is bound to to be reused while in the TIME_WAIT state. Returns the previous state. */ virtual bool setReuseAddrOnSocket(ArchSocket, bool reuse) = 0; //! Return local host's name virtual std::string getHostName() = 0; //! Create an "any" network address virtual ArchNetAddress newAnyAddr(EAddressFamily) = 0; //! Copy a network address virtual ArchNetAddress copyAddr(ArchNetAddress) = 0; //! Convert a name to a network address virtual ArchNetAddress nameToAddr(const std::string&) = 0; //! Destroy a network address virtual void closeAddr(ArchNetAddress) = 0; //! Convert an address to a host name virtual std::string addrToName(ArchNetAddress) = 0; //! Convert an address to a string virtual std::string addrToString(ArchNetAddress) = 0; //! Get an address's family virtual EAddressFamily getAddrFamily(ArchNetAddress) = 0; //! Set the port of an address virtual void setAddrPort(ArchNetAddress, int port) = 0; //! Get the port of an address virtual int getAddrPort(ArchNetAddress) = 0; //! Test addresses for equality virtual bool isEqualAddr(ArchNetAddress, ArchNetAddress) = 0; //! Test for the "any" address /*! Returns true if \c addr is the "any" address. \c newAnyAddr() returns an "any" address. */ virtual bool isAnyAddr(ArchNetAddress addr) = 0; //@} virtual void init() = 0; }; synergy-1.8.8-stable/src/lib/arch/IArchSleep.h000066400000000000000000000024161305627404700211150ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" //! Interface for architecture dependent sleeping /*! This interface defines the sleep operations required by synergy. Each architecture must implement this interface. */ class IArchSleep : public IInterface { public: //! @name manipulators //@{ //! Sleep /*! Blocks the calling thread for \c timeout seconds. If \c timeout < 0.0 then the call returns immediately. If \c timeout == 0.0 then the calling thread yields the CPU. (cancellation point) */ virtual void sleep(double timeout) = 0; //@} }; synergy-1.8.8-stable/src/lib/arch/IArchString.cpp000066400000000000000000000072571305627404700216560ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/IArchString.h" #include "arch/Arch.h" #include "common/common.h" #include #include #include static ArchMutex s_mutex = NULL; // // use C library non-reentrant multibyte conversion with mutex // IArchString::~IArchString() { if (s_mutex != NULL) { ARCH->closeMutex(s_mutex); s_mutex = NULL; } } int IArchString::convStringWCToMB(char* dst, const wchar_t* src, UInt32 n, bool* errors) { int len = 0; bool dummyErrors; if (errors == NULL) { errors = &dummyErrors; } if (s_mutex == NULL) { s_mutex = ARCH->newMutex(); } ARCH->lockMutex(s_mutex); if (dst == NULL) { char dummy[MB_LEN_MAX]; for (const wchar_t* scan = src; n > 0; ++scan, --n) { int mblen = wctomb(dummy, *scan); if (mblen == -1) { *errors = true; mblen = 1; } len += mblen; } int mblen = wctomb(dummy, L'\0'); if (mblen != -1) { len += mblen - 1; } } else { char* dst0 = dst; for (const wchar_t* scan = src; n > 0; ++scan, --n) { int mblen = wctomb(dst, *scan); if (mblen == -1) { *errors = true; *dst++ = '?'; } else { dst += mblen; } } int mblen = wctomb(dst, L'\0'); if (mblen != -1) { // don't include nul terminator dst += mblen - 1; } len = (int)(dst - dst0); } ARCH->unlockMutex(s_mutex); return len; } int IArchString::convStringMBToWC(wchar_t* dst, const char* src, UInt32 n, bool* errors) { int len = 0; wchar_t dummy; bool dummyErrors; if (errors == NULL) { errors = &dummyErrors; } if (s_mutex == NULL) { s_mutex = ARCH->newMutex(); } ARCH->lockMutex(s_mutex); if (dst == NULL) { for (const char* scan = src; n > 0; ) { int mblen = mbtowc(&dummy, scan, n); switch (mblen) { case -2: // incomplete last character. convert to unknown character. *errors = true; len += 1; n = 0; break; case -1: // invalid character. count one unknown character and // start at the next byte. *errors = true; len += 1; scan += 1; n -= 1; break; case 0: len += 1; scan += 1; n -= 1; break; default: // normal character len += 1; scan += mblen; n -= mblen; break; } } } else { wchar_t* dst0 = dst; for (const char* scan = src; n > 0; ++dst) { int mblen = mbtowc(dst, scan, n); switch (mblen) { case -2: // incomplete character. convert to unknown character. *errors = true; *dst = (wchar_t)0xfffd; n = 0; break; case -1: // invalid character. count one unknown character and // start at the next byte. *errors = true; *dst = (wchar_t)0xfffd; scan += 1; n -= 1; break; case 0: *dst = (wchar_t)0x0000; scan += 1; n -= 1; break; default: // normal character scan += mblen; n -= mblen; break; } } len = (int)(dst - dst0); } ARCH->unlockMutex(s_mutex); return len; } synergy-1.8.8-stable/src/lib/arch/IArchString.h000066400000000000000000000041401305627404700213070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "common/basic_types.h" #include //! Interface for architecture dependent string operations /*! This interface defines the string operations required by synergy. Each architecture must implement this interface. */ class IArchString : public IInterface { public: virtual ~IArchString(); //! Wide character encodings /*! The known wide character encodings */ enum EWideCharEncoding { kUCS2, //!< The UCS-2 encoding kUCS4, //!< The UCS-4 encoding kUTF16, //!< The UTF-16 encoding kUTF32 //!< The UTF-32 encoding }; //! @name manipulators //@{ //! printf() to limited size buffer with va_list /*! This method is equivalent to vsprintf() except it will not write more than \c n bytes to the buffer, returning -1 if the output was truncated and the number of bytes written not including the trailing NUL otherwise. */ virtual int vsnprintf(char* str, int size, const char* fmt, va_list ap); //! Convert multibyte string to wide character string virtual int convStringMBToWC(wchar_t*, const char*, UInt32 n, bool* errors); //! Convert wide character string to multibyte string virtual int convStringWCToMB(char*, const wchar_t*, UInt32 n, bool* errors); //! Return the architecture's native wide character encoding virtual EWideCharEncoding getWideCharEncoding() = 0; //@} }; synergy-1.8.8-stable/src/lib/arch/IArchSystem.h000066400000000000000000000034741305627404700213360ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "common/stdstring.h" //! Interface for architecture dependent system queries /*! This interface defines operations for querying system info. */ class IArchSystem : public IInterface { public: //! @name accessors //@{ //! Identify the OS /*! Returns a string identifying the operating system. */ virtual std::string getOSName() const = 0; //! Identify the platform /*! Returns a string identifying the platform this OS is running on. */ virtual std::string getPlatformName() const = 0; //@} //! Get a Synergy setting /*! Reads a Synergy setting from the system. */ virtual std::string setting(const std::string& valueName) const = 0; //@} //! Set a Synergy setting /*! Writes a Synergy setting from the system. */ virtual void setting(const std::string& valueName, const std::string& valueString) const = 0; //@} //! Get the pathnames of the libraries used by Synergy /* Returns a string containing the full path names of all loaded libraries at the point it is called. */ virtual std::string getLibsUsed(void) const = 0; //@} }; synergy-1.8.8-stable/src/lib/arch/IArchTaskBar.h000066400000000000000000000035131305627404700213730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" class IArchTaskBarReceiver; //! Interface for architecture dependent task bar control /*! This interface defines the task bar icon operations required by synergy. Each architecture must implement this interface though each operation can be a no-op. */ class IArchTaskBar : public IInterface { public: //! @name manipulators //@{ //! Add a receiver /*! Add a receiver object to be notified of user and application events. This should be called before other methods. When the receiver is added to the task bar, its icon appears on the task bar. */ virtual void addReceiver(IArchTaskBarReceiver*) = 0; //! Remove a receiver /*! Remove a receiver object from the task bar. This removes the icon from the task bar. */ virtual void removeReceiver(IArchTaskBarReceiver*) = 0; //! Update a receiver /*! Updates the display of the receiver on the task bar. This should be called when the receiver appearance may have changed (e.g. it's icon or tool tip has changed). */ virtual void updateReceiver(IArchTaskBarReceiver*) = 0; //@} virtual void init() = 0; }; synergy-1.8.8-stable/src/lib/arch/IArchTaskBarReceiver.h000066400000000000000000000050351305627404700230610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" #include "common/IInterface.h" class IScreen; class INode; //! Interface for architecture dependent task bar event handling /*! This interface defines the task bar icon event handlers required by synergy. Each architecture must implement this interface though each operation can be a no-op. */ class IArchTaskBarReceiver : public IInterface { public: // Icon data is architecture dependent typedef void* Icon; //! @name manipulators //@{ //! Show status window /*! Open a window displaying current status. This should return immediately without waiting for the window to be closed. */ virtual void showStatus() = 0; //! Popup menu /*! Popup a menu of operations at or around \c x,y and perform the chosen operation. */ virtual void runMenu(int x, int y) = 0; //! Perform primary action /*! Perform the primary (default) action. */ virtual void primaryAction() = 0; //@} //! @name accessors //@{ //! Lock receiver /*! Locks the receiver from changing state. The receiver should be locked when querying it's state to ensure consistent results. Each call to \c lock() must have a matching \c unlock() and locks cannot be nested. */ virtual void lock() const = 0; //! Unlock receiver virtual void unlock() const = 0; //! Get icon /*! Returns the icon to display in the task bar. The interface to set the icon is left to subclasses. Getting and setting the icon must be thread safe. */ virtual const Icon getIcon() const = 0; //! Get tooltip /*! Returns the tool tip to display in the task bar. The interface to set the tooltip is left to sublclasses. Getting and setting the icon must be thread safe. */ virtual std::string getToolTip() const = 0; virtual void updateStatus(INode*, const String& errorMsg) = 0; virtual void cleanup() {} //@} }; synergy-1.8.8-stable/src/lib/arch/IArchTime.h000066400000000000000000000023151305627404700207410ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" //! Interface for architecture dependent time operations /*! This interface defines the time operations required by synergy. Each architecture must implement this interface. */ class IArchTime : public IInterface { public: //! @name manipulators //@{ //! Get the current time /*! Returns the number of seconds since some arbitrary starting time. This should return as high a precision as reasonable. */ virtual double time() = 0; //@} }; synergy-1.8.8-stable/src/lib/arch/XArch.h000066400000000000000000000116731305627404700201500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" #include "common/stdstring.h" #include "common/stdexcept.h" //! Generic thread exception /*! Exceptions derived from this class are used by the multithreading library to perform stack unwinding when a thread terminates. These exceptions must always be rethrown by clients when caught. */ class XThread { }; //! Thread exception to cancel /*! Thrown to cancel a thread. Clients must not throw this type, but must rethrow it if caught (by XThreadCancel, XThread, or ...). */ class XThreadCancel : public XThread { }; /*! \def RETHROW_XTHREAD Convenience macro to rethrow an XThread exception but ignore other exceptions. Put this in your catch (...) handler after necessary cleanup but before leaving or returning from the handler. */ #define RETHROW_XTHREAD \ try { throw; } catch (XThread&) { throw; } catch (...) { } //! Lazy error message string evaluation /*! This class encapsulates platform dependent error string lookup. Platforms subclass this type, taking an appropriate error code type in the c'tor and overriding eval() to return the error string for that error code. */ class XArchEval { public: XArchEval() { } virtual ~XArchEval() _NOEXCEPT { } virtual std::string eval() const = 0; }; //! Generic exception architecture dependent library class XArch : public std::runtime_error { public: XArch(XArchEval* adopted) : std::runtime_error(adopted->eval()) { delete adopted; } XArch(const std::string& msg) : std::runtime_error(msg) { } virtual ~XArch() _NOEXCEPT { } }; // Macro to declare XArch derived types #define XARCH_SUBCLASS(name_, super_) \ class name_ : public super_ { \ public: \ name_(XArchEval* adoptedEvaluator) : super_(adoptedEvaluator) { } \ name_(const std::string& msg) : super_(msg) { } \ } //! Generic network exception /*! Exceptions derived from this class are used by the networking library to indicate various errors. */ XARCH_SUBCLASS(XArchNetwork, XArch); //! Operation was interrupted XARCH_SUBCLASS(XArchNetworkInterrupted, XArchNetwork); //! Network insufficient permission XARCH_SUBCLASS(XArchNetworkAccess, XArchNetwork); //! Network insufficient resources XARCH_SUBCLASS(XArchNetworkResource, XArchNetwork); //! No support for requested network resource/service XARCH_SUBCLASS(XArchNetworkSupport, XArchNetwork); //! Network I/O error XARCH_SUBCLASS(XArchNetworkIO, XArchNetwork); //! Network address is unavailable or not local XARCH_SUBCLASS(XArchNetworkNoAddress, XArchNetwork); //! Network address in use XARCH_SUBCLASS(XArchNetworkAddressInUse, XArchNetwork); //! No route to address XARCH_SUBCLASS(XArchNetworkNoRoute, XArchNetwork); //! Socket not connected XARCH_SUBCLASS(XArchNetworkNotConnected, XArchNetwork); //! Remote read end of socket has closed XARCH_SUBCLASS(XArchNetworkShutdown, XArchNetwork); //! Remote end of socket has disconnected XARCH_SUBCLASS(XArchNetworkDisconnected, XArchNetwork); //! Remote end of socket refused connection XARCH_SUBCLASS(XArchNetworkConnectionRefused, XArchNetwork); //! Remote end of socket is not responding XARCH_SUBCLASS(XArchNetworkTimedOut, XArchNetwork); //! Generic network name lookup erros XARCH_SUBCLASS(XArchNetworkName, XArchNetwork); //! The named host is unknown XARCH_SUBCLASS(XArchNetworkNameUnknown, XArchNetworkName); //! The named host is known but has no address XARCH_SUBCLASS(XArchNetworkNameNoAddress, XArchNetworkName); //! Non-recoverable name server error XARCH_SUBCLASS(XArchNetworkNameFailure, XArchNetworkName); //! Temporary name server error XARCH_SUBCLASS(XArchNetworkNameUnavailable, XArchNetworkName); //! The named host is known but no supported address XARCH_SUBCLASS(XArchNetworkNameUnsupported, XArchNetworkName); //! Generic daemon exception /*! Exceptions derived from this class are used by the daemon library to indicate various errors. */ XARCH_SUBCLASS(XArchDaemon, XArch); //! Could not daemonize XARCH_SUBCLASS(XArchDaemonFailed, XArchDaemon); //! Could not install daemon XARCH_SUBCLASS(XArchDaemonInstallFailed, XArchDaemon); //! Could not uninstall daemon XARCH_SUBCLASS(XArchDaemonUninstallFailed, XArchDaemon); //! Attempted to uninstall a daemon that was not installed XARCH_SUBCLASS(XArchDaemonUninstallNotInstalled, XArchDaemonUninstallFailed); synergy-1.8.8-stable/src/lib/arch/multibyte.h000066400000000000000000000026161305627404700211560ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" #include "arch/Arch.h" #include #include #include #if HAVE_LOCALE_H # include #endif #if HAVE_WCHAR_H || defined(_MSC_VER) # include #elif __APPLE__ // wtf? Darwin puts mbtowc() et al. in stdlib # include #else // platform apparently has no wchar_t support. provide dummy // implementations. hopefully at least the C++ compiler has // a built-in wchar_t type. static inline int mbtowc(wchar_t* dst, const char* src, int n) { *dst = static_cast(*src); return 1; } static inline int wctomb(char* dst, wchar_t src) { *dst = static_cast(src); return 1; } #endif synergy-1.8.8-stable/src/lib/arch/unix/000077500000000000000000000000001305627404700177455ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/arch/unix/ArchConsoleUnix.cpp000066400000000000000000000015241305627404700235170ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchConsoleUnix.h" ArchConsoleUnix::ArchConsoleUnix() { } ArchConsoleUnix::~ArchConsoleUnix() { } synergy-1.8.8-stable/src/lib/arch/unix/ArchConsoleUnix.h000066400000000000000000000016361305627404700231700ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/ArchConsoleStd.h" #define ARCH_CONSOLE ArchConsoleUnix class ArchConsoleUnix : public ArchConsoleStd { public: ArchConsoleUnix(); virtual ~ArchConsoleUnix(); }; synergy-1.8.8-stable/src/lib/arch/unix/ArchDaemonUnix.cpp000066400000000000000000000056631305627404700233300ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchDaemonUnix.h" #include "arch/unix/XArchUnix.h" #include "base/Log.h" #include #include #include #include #include #include // // ArchDaemonUnix // ArchDaemonUnix::ArchDaemonUnix() { // do nothing } ArchDaemonUnix::~ArchDaemonUnix() { // do nothing } #ifdef __APPLE__ // In Mac OS X, fork()'d child processes can't use most APIs (the frameworks // that Synergy uses in fact prevent it and make the process just up and die), // so need to exec a copy of the program that doesn't fork so isn't limited. int execSelfNonDaemonized() { extern char** NXArgv; char** selfArgv = NXArgv; setenv("_SYNERGY_DAEMONIZED", "", 1); execvp(selfArgv[0], selfArgv); return 0; } bool alreadyDaemonized() { return getenv("_SYNERGY_DAEMONIZED") != NULL; } #endif int ArchDaemonUnix::daemonize(const char* name, DaemonFunc func) { #ifdef __APPLE__ if (alreadyDaemonized()) return func(1, &name); #endif // fork so shell thinks we're done and so we're not a process // group leader switch (fork()) { case -1: // failed throw XArchDaemonFailed(new XArchEvalUnix(errno)); case 0: // child break; default: // parent exits exit(0); } // become leader of a new session setsid(); #ifndef __APPLE__ // NB: don't run chdir on apple; causes strange behaviour. // chdir to root so we don't keep mounted filesystems points busy // TODO: this is a bit of a hack - can we find a better solution? int chdirErr = chdir("/"); if (chdirErr) // NB: file logging actually isn't working at this point! LOG((CLOG_ERR "chdir error: %i", chdirErr)); #endif // mask off permissions for any but owner umask(077); // close open files. we only expect stdin, stdout, stderr to be open. close(0); close(1); close(2); // attach file descriptors 0, 1, 2 to /dev/null so inadvertent use // of standard I/O safely goes in the bit bucket. open("/dev/null", O_RDONLY); open("/dev/null", O_RDWR); int dupErr = dup(1); if (dupErr < 0) { // NB: file logging actually isn't working at this point! LOG((CLOG_ERR "dup error: %i", dupErr)); } #ifdef __APPLE__ return execSelfNonDaemonized(); #endif // invoke function return func(1, &name); } synergy-1.8.8-stable/src/lib/arch/unix/ArchDaemonUnix.h000066400000000000000000000021351305627404700227640ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/ArchDaemonNone.h" #undef ARCH_DAEMON #define ARCH_DAEMON ArchDaemonUnix //! Unix implementation of IArchDaemon class ArchDaemonUnix : public ArchDaemonNone { public: ArchDaemonUnix(); virtual ~ArchDaemonUnix(); // IArchDaemon overrides virtual int daemonize(const char* name, DaemonFunc func); }; #define CONFIG_FILE "/etc/synergy/synergyd.conf" synergy-1.8.8-stable/src/lib/arch/unix/ArchFileUnix.cpp000066400000000000000000000060141305627404700227730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchFileUnix.h" #include #include #include #include #include // // ArchFileUnix // ArchFileUnix::ArchFileUnix() { // do nothing } ArchFileUnix::~ArchFileUnix() { // do nothing } const char* ArchFileUnix::getBasename(const char* pathname) { if (pathname == NULL) { return NULL; } const char* basename = strrchr(pathname, '/'); if (basename != NULL) { return basename + 1; } else { return pathname; } } std::string ArchFileUnix::getUserDirectory() { char* buffer = NULL; std::string dir; #if HAVE_GETPWUID_R struct passwd pwent; struct passwd* pwentp; #if defined(_SC_GETPW_R_SIZE_MAX) long size = sysconf(_SC_GETPW_R_SIZE_MAX); if (size == -1) { size = BUFSIZ; } #else long size = BUFSIZ; #endif buffer = new char[size]; getpwuid_r(getuid(), &pwent, buffer, size, &pwentp); #else struct passwd* pwentp = getpwuid(getuid()); #endif if (pwentp != NULL && pwentp->pw_dir != NULL) { dir = pwentp->pw_dir; } delete[] buffer; return dir; } std::string ArchFileUnix::getSystemDirectory() { return "/etc"; } std::string ArchFileUnix::getInstalledDirectory() { #if WINAPI_XWINDOWS return "/usr/bin"; #else return "/Applications/Synergy.app/Contents/MacOS"; #endif } std::string ArchFileUnix::getLogDirectory() { return "/var/log"; } std::string ArchFileUnix::getPluginDirectory() { if (!m_pluginDirectory.empty()) { return m_pluginDirectory; } #if WINAPI_XWINDOWS return getProfileDirectory().append("/plugins"); #else return getProfileDirectory().append("/Plugins"); #endif } std::string ArchFileUnix::getProfileDirectory() { String dir; if (!m_profileDirectory.empty()) { dir = m_profileDirectory; } else { #if WINAPI_XWINDOWS dir = getUserDirectory().append("/.synergy"); #else dir = getUserDirectory().append("/Library/Synergy"); #endif } return dir; } std::string ArchFileUnix::concatPath(const std::string& prefix, const std::string& suffix) { std::string path; path.reserve(prefix.size() + 1 + suffix.size()); path += prefix; if (path.size() == 0 || path[path.size() - 1] != '/') { path += '/'; } path += suffix; return path; } void ArchFileUnix::setProfileDirectory(const String& s) { m_profileDirectory = s; } void ArchFileUnix::setPluginDirectory(const String& s) { m_pluginDirectory = s; } synergy-1.8.8-stable/src/lib/arch/unix/ArchFileUnix.h000066400000000000000000000030121305627404700224330ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchFile.h" #define ARCH_FILE ArchFileUnix //! Unix implementation of IArchFile class ArchFileUnix : public IArchFile { public: ArchFileUnix(); virtual ~ArchFileUnix(); // IArchFile overrides virtual const char* getBasename(const char* pathname); virtual std::string getUserDirectory(); virtual std::string getSystemDirectory(); virtual std::string getInstalledDirectory(); virtual std::string getLogDirectory(); virtual std::string getPluginDirectory(); virtual std::string getProfileDirectory(); virtual std::string concatPath(const std::string& prefix, const std::string& suffix); virtual void setProfileDirectory(const String& s); virtual void setPluginDirectory(const String& s); private: String m_profileDirectory; String m_pluginDirectory; }; synergy-1.8.8-stable/src/lib/arch/unix/ArchInternetUnix.cpp000066400000000000000000000052001305627404700237000ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchInternetUnix.h" #include "arch/XArch.h" #include "common/Version.h" #include "base/Log.h" #include #include class CurlFacade { public: CurlFacade(); ~CurlFacade(); String get(const String& url); String urlEncode(const String& url); private: CURL* m_curl; }; // // ArchInternetUnix // String ArchInternetUnix::get(const String& url) { CurlFacade curl; return curl.get(url); } String ArchInternetUnix::urlEncode(const String& url) { CurlFacade curl; return curl.urlEncode(url); } // // CurlFacade // static size_t curlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp) { ((std::string*)userp)->append((char*)contents, size * nmemb); return size * nmemb; } CurlFacade::CurlFacade() : m_curl(NULL) { CURLcode init = curl_global_init(CURL_GLOBAL_ALL); if (init != CURLE_OK) { throw XArch("CURL global init failed."); } m_curl = curl_easy_init(); if (m_curl == NULL) { throw XArch("CURL easy init failed."); } } CurlFacade::~CurlFacade() { if (m_curl != NULL) { curl_easy_cleanup(m_curl); } curl_global_cleanup(); } String CurlFacade::get(const String& url) { curl_easy_setopt(m_curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, curlWriteCallback); std::stringstream userAgent; userAgent << "Synergy "; userAgent << kVersion; curl_easy_setopt(m_curl, CURLOPT_USERAGENT, userAgent.str().c_str()); std::string result; curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &result); CURLcode code = curl_easy_perform(m_curl); if (code != CURLE_OK) { LOG((CLOG_ERR "curl perform error: %s", curl_easy_strerror(code))); throw XArch("CURL perform failed."); } return result; } String CurlFacade::urlEncode(const String& url) { char* resultCStr = curl_easy_escape(m_curl, url.c_str(), 0); if (resultCStr == NULL) { throw XArch("CURL escape failed."); } std::string result(resultCStr); curl_free(resultCStr); return result; } synergy-1.8.8-stable/src/lib/arch/unix/ArchInternetUnix.h000066400000000000000000000015631305627404700233550ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #define ARCH_INTERNET ArchInternetUnix #include "base/String.h" class ArchInternetUnix { public: String get(const String& url); String urlEncode(const String& url); }; synergy-1.8.8-stable/src/lib/arch/unix/ArchLogUnix.cpp000066400000000000000000000027061305627404700226410ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchLogUnix.h" #include // // ArchLogUnix // ArchLogUnix::ArchLogUnix() { // do nothing } ArchLogUnix::~ArchLogUnix() { // do nothing } void ArchLogUnix::openLog(const char* name) { openlog(name, 0, LOG_DAEMON); } void ArchLogUnix::closeLog() { closelog(); } void ArchLogUnix::showLog(bool) { // do nothing } void ArchLogUnix::writeLog(ELevel level, const char* msg) { // convert level int priority; switch (level) { case kERROR: priority = LOG_ERR; break; case kWARNING: priority = LOG_WARNING; break; case kNOTE: priority = LOG_NOTICE; break; case kINFO: priority = LOG_INFO; break; default: priority = LOG_DEBUG; break; } // log it syslog(priority, "%s", msg); } synergy-1.8.8-stable/src/lib/arch/unix/ArchLogUnix.h000066400000000000000000000021131305627404700222760ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchLog.h" #define ARCH_LOG ArchLogUnix //! Unix implementation of IArchLog class ArchLogUnix : public IArchLog { public: ArchLogUnix(); virtual ~ArchLogUnix(); // IArchLog overrides virtual void openLog(const char* name); virtual void closeLog(); virtual void showLog(bool); virtual void writeLog(ELevel, const char*); }; synergy-1.8.8-stable/src/lib/arch/unix/ArchMultithreadPosix.cpp000066400000000000000000000431451305627404700245630ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchMultithreadPosix.h" #include "arch/Arch.h" #include "arch/XArch.h" #include #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #include #define SIGWAKEUP SIGUSR1 #if !HAVE_PTHREAD_SIGNAL // boy, is this platform broken. forget about pthread signal // handling and let signals through to every process. synergy // will not terminate cleanly when it gets SIGTERM or SIGINT. # define pthread_sigmask sigprocmask # define pthread_kill(tid_, sig_) kill(0, (sig_)) # define sigwait(set_, sig_) # undef HAVE_POSIX_SIGWAIT # define HAVE_POSIX_SIGWAIT 1 #endif static void setSignalSet(sigset_t* sigset) { sigemptyset(sigset); sigaddset(sigset, SIGHUP); sigaddset(sigset, SIGINT); sigaddset(sigset, SIGTERM); sigaddset(sigset, SIGUSR2); } // // ArchThreadImpl // class ArchThreadImpl { public: ArchThreadImpl(); public: int m_refCount; IArchMultithread::ThreadID m_id; pthread_t m_thread; IArchMultithread::ThreadFunc m_func; void* m_userData; bool m_cancel; bool m_cancelling; bool m_exited; void* m_result; void* m_networkData; }; ArchThreadImpl::ArchThreadImpl() : m_refCount(1), m_id(0), m_func(NULL), m_userData(NULL), m_cancel(false), m_cancelling(false), m_exited(false), m_result(NULL), m_networkData(NULL) { // do nothing } // // ArchMultithreadPosix // ArchMultithreadPosix* ArchMultithreadPosix::s_instance = NULL; ArchMultithreadPosix::ArchMultithreadPosix() : m_newThreadCalled(false), m_nextID(0) { assert(s_instance == NULL); s_instance = this; // no signal handlers for (size_t i = 0; i < kNUM_SIGNALS; ++i) { m_signalFunc[i] = NULL; m_signalUserData[i] = NULL; } // create mutex for thread list m_threadMutex = newMutex(); // create thread for calling (main) thread and add it to our // list. no need to lock the mutex since we're the only thread. m_mainThread = new ArchThreadImpl; m_mainThread->m_thread = pthread_self(); insert(m_mainThread); // install SIGWAKEUP handler. this causes SIGWAKEUP to interrupt // system calls. we use that when cancelling a thread to force it // to wake up immediately if it's blocked in a system call. we // won't need this until another thread is created but it's fine // to install it now. struct sigaction act; sigemptyset(&act.sa_mask); # if defined(SA_INTERRUPT) act.sa_flags = SA_INTERRUPT; # else act.sa_flags = 0; # endif act.sa_handler = &threadCancel; sigaction(SIGWAKEUP, &act, NULL); // set desired signal dispositions. let SIGWAKEUP through but // ignore SIGPIPE (we'll handle EPIPE). sigset_t sigset; sigemptyset(&sigset); sigaddset(&sigset, SIGWAKEUP); pthread_sigmask(SIG_UNBLOCK, &sigset, NULL); sigemptyset(&sigset); sigaddset(&sigset, SIGPIPE); pthread_sigmask(SIG_BLOCK, &sigset, NULL); } ArchMultithreadPosix::~ArchMultithreadPosix() { assert(s_instance != NULL); closeMutex(m_threadMutex); s_instance = NULL; } void ArchMultithreadPosix::setNetworkDataForCurrentThread(void* data) { lockMutex(m_threadMutex); ArchThreadImpl* thread = find(pthread_self()); thread->m_networkData = data; unlockMutex(m_threadMutex); } void* ArchMultithreadPosix::getNetworkDataForThread(ArchThread thread) { lockMutex(m_threadMutex); void* data = thread->m_networkData; unlockMutex(m_threadMutex); return data; } ArchMultithreadPosix* ArchMultithreadPosix::getInstance() { return s_instance; } ArchCond ArchMultithreadPosix::newCondVar() { ArchCondImpl* cond = new ArchCondImpl; int status = pthread_cond_init(&cond->m_cond, NULL); (void)status; assert(status == 0); return cond; } void ArchMultithreadPosix::closeCondVar(ArchCond cond) { int status = pthread_cond_destroy(&cond->m_cond); (void)status; assert(status == 0); delete cond; } void ArchMultithreadPosix::signalCondVar(ArchCond cond) { int status = pthread_cond_signal(&cond->m_cond); (void)status; assert(status == 0); } void ArchMultithreadPosix::broadcastCondVar(ArchCond cond) { int status = pthread_cond_broadcast(&cond->m_cond); (void)status; assert(status == 0); } bool ArchMultithreadPosix::waitCondVar(ArchCond cond, ArchMutex mutex, double timeout) { // we can't wait on a condition variable and also wake it up for // cancellation since we don't use posix cancellation. so we // must wake up periodically to check for cancellation. we // can't simply go back to waiting after the check since the // condition may have changed and we'll have lost the signal. // so we have to return to the caller. since the caller will // always check for spurious wakeups the only drawback here is // performance: we're waking up a lot more than desired. static const double maxCancellationLatency = 0.1; if (timeout < 0.0 || timeout > maxCancellationLatency) { timeout = maxCancellationLatency; } // see if we should cancel this thread testCancelThread(); // get final time struct timeval now; gettimeofday(&now, NULL); struct timespec finalTime; finalTime.tv_sec = now.tv_sec; finalTime.tv_nsec = now.tv_usec * 1000; long timeout_sec = (long)timeout; long timeout_nsec = (long)(1.0e+9 * (timeout - timeout_sec)); finalTime.tv_sec += timeout_sec; finalTime.tv_nsec += timeout_nsec; if (finalTime.tv_nsec >= 1000000000) { finalTime.tv_nsec -= 1000000000; finalTime.tv_sec += 1; } // wait int status = pthread_cond_timedwait(&cond->m_cond, &mutex->m_mutex, &finalTime); // check for cancel again testCancelThread(); switch (status) { case 0: // success return true; case ETIMEDOUT: return false; default: assert(0 && "condition variable wait error"); return false; } } ArchMutex ArchMultithreadPosix::newMutex() { pthread_mutexattr_t attr; int status = pthread_mutexattr_init(&attr); assert(status == 0); ArchMutexImpl* mutex = new ArchMutexImpl; status = pthread_mutex_init(&mutex->m_mutex, &attr); assert(status == 0); return mutex; } void ArchMultithreadPosix::closeMutex(ArchMutex mutex) { int status = pthread_mutex_destroy(&mutex->m_mutex); (void)status; assert(status == 0); delete mutex; } void ArchMultithreadPosix::lockMutex(ArchMutex mutex) { int status = pthread_mutex_lock(&mutex->m_mutex); switch (status) { case 0: // success return; case EDEADLK: assert(0 && "lock already owned"); break; case EAGAIN: assert(0 && "too many recursive locks"); break; default: assert(0 && "unexpected error"); break; } } void ArchMultithreadPosix::unlockMutex(ArchMutex mutex) { int status = pthread_mutex_unlock(&mutex->m_mutex); switch (status) { case 0: // success return; case EPERM: assert(0 && "thread doesn't own a lock"); break; default: assert(0 && "unexpected error"); break; } } ArchThread ArchMultithreadPosix::newThread(ThreadFunc func, void* data) { assert(func != NULL); // initialize signal handler. we do this here instead of the // constructor so we can avoid daemonizing (using fork()) // when there are multiple threads. clients can safely // use condition variables and mutexes before creating a // new thread and they can safely use the only thread // they have access to, the main thread, so they really // can't tell the difference. if (!m_newThreadCalled) { m_newThreadCalled = true; #if HAVE_PTHREAD_SIGNAL startSignalHandler(); #endif } lockMutex(m_threadMutex); // create thread impl for new thread ArchThreadImpl* thread = new ArchThreadImpl; thread->m_func = func; thread->m_userData = data; // create the thread. pthread_create() on RedHat 7.2 smp fails // if passed a NULL attr so use a default attr. pthread_attr_t attr; int status = pthread_attr_init(&attr); if (status == 0) { status = pthread_create(&thread->m_thread, &attr, &ArchMultithreadPosix::threadFunc, thread); pthread_attr_destroy(&attr); } // check if thread was started if (status != 0) { // failed to start thread so clean up delete thread; thread = NULL; } else { // add thread to list insert(thread); // increment ref count to account for the thread itself refThread(thread); } // note that the child thread will wait until we release this mutex unlockMutex(m_threadMutex); return thread; } ArchThread ArchMultithreadPosix::newCurrentThread() { lockMutex(m_threadMutex); ArchThreadImpl* thread = find(pthread_self()); unlockMutex(m_threadMutex); assert(thread != NULL); return thread; } void ArchMultithreadPosix::closeThread(ArchThread thread) { assert(thread != NULL); // decrement ref count and clean up thread if no more references if (--thread->m_refCount == 0) { // detach from thread (unless it's the main thread) if (thread->m_func != NULL) { pthread_detach(thread->m_thread); } // remove thread from list lockMutex(m_threadMutex); assert(findNoRef(thread->m_thread) == thread); erase(thread); unlockMutex(m_threadMutex); // done with thread delete thread; } } ArchThread ArchMultithreadPosix::copyThread(ArchThread thread) { refThread(thread); return thread; } void ArchMultithreadPosix::cancelThread(ArchThread thread) { assert(thread != NULL); // set cancel and wakeup flags if thread can be cancelled bool wakeup = false; lockMutex(m_threadMutex); if (!thread->m_exited && !thread->m_cancelling) { thread->m_cancel = true; wakeup = true; } unlockMutex(m_threadMutex); // force thread to exit system calls if wakeup is true if (wakeup) { pthread_kill(thread->m_thread, SIGWAKEUP); } } void ArchMultithreadPosix::setPriorityOfThread(ArchThread thread, int /*n*/) { assert(thread != NULL); // FIXME } void ArchMultithreadPosix::testCancelThread() { // find current thread lockMutex(m_threadMutex); ArchThreadImpl* thread = findNoRef(pthread_self()); unlockMutex(m_threadMutex); // test cancel on thread testCancelThreadImpl(thread); } bool ArchMultithreadPosix::wait(ArchThread target, double timeout) { assert(target != NULL); lockMutex(m_threadMutex); // find current thread ArchThreadImpl* self = findNoRef(pthread_self()); // ignore wait if trying to wait on ourself if (target == self) { unlockMutex(m_threadMutex); return false; } // ref the target so it can't go away while we're watching it refThread(target); unlockMutex(m_threadMutex); try { // do first test regardless of timeout testCancelThreadImpl(self); if (isExitedThread(target)) { closeThread(target); return true; } // wait and repeat test if there's a timeout if (timeout != 0.0) { const double start = ARCH->time(); do { // wait a little ARCH->sleep(0.05); // repeat test testCancelThreadImpl(self); if (isExitedThread(target)) { closeThread(target); return true; } // repeat wait and test until timed out } while (timeout < 0.0 || (ARCH->time() - start) <= timeout); } closeThread(target); return false; } catch (...) { closeThread(target); throw; } } bool ArchMultithreadPosix::isSameThread(ArchThread thread1, ArchThread thread2) { return (thread1 == thread2); } bool ArchMultithreadPosix::isExitedThread(ArchThread thread) { lockMutex(m_threadMutex); bool exited = thread->m_exited; unlockMutex(m_threadMutex); return exited; } void* ArchMultithreadPosix::getResultOfThread(ArchThread thread) { lockMutex(m_threadMutex); void* result = thread->m_result; unlockMutex(m_threadMutex); return result; } IArchMultithread::ThreadID ArchMultithreadPosix::getIDOfThread(ArchThread thread) { return thread->m_id; } void ArchMultithreadPosix::setSignalHandler( ESignal signal, SignalFunc func, void* userData) { lockMutex(m_threadMutex); m_signalFunc[signal] = func; m_signalUserData[signal] = userData; unlockMutex(m_threadMutex); } void ArchMultithreadPosix::raiseSignal(ESignal signal) { lockMutex(m_threadMutex); if (m_signalFunc[signal] != NULL) { m_signalFunc[signal](signal, m_signalUserData[signal]); pthread_kill(m_mainThread->m_thread, SIGWAKEUP); } else if (signal == kINTERRUPT || signal == kTERMINATE) { ARCH->cancelThread(m_mainThread); } unlockMutex(m_threadMutex); } void ArchMultithreadPosix::startSignalHandler() { // set signal mask. the main thread blocks these signals and // the signal handler thread will listen for them. sigset_t sigset, oldsigset; setSignalSet(&sigset); pthread_sigmask(SIG_BLOCK, &sigset, &oldsigset); // fire up the INT and TERM signal handler thread. we could // instead arrange to catch and handle these signals but // we'd be unable to cancel the main thread since no pthread // calls are allowed in a signal handler. pthread_attr_t attr; int status = pthread_attr_init(&attr); if (status == 0) { status = pthread_create(&m_signalThread, &attr, &ArchMultithreadPosix::threadSignalHandler, NULL); pthread_attr_destroy(&attr); } if (status != 0) { // can't create thread to wait for signal so don't block // the signals. pthread_sigmask(SIG_UNBLOCK, &oldsigset, NULL); } } ArchThreadImpl* ArchMultithreadPosix::find(pthread_t thread) { ArchThreadImpl* impl = findNoRef(thread); if (impl != NULL) { refThread(impl); } return impl; } ArchThreadImpl* ArchMultithreadPosix::findNoRef(pthread_t thread) { // linear search for (ThreadList::const_iterator index = m_threadList.begin(); index != m_threadList.end(); ++index) { if ((*index)->m_thread == thread) { return *index; } } return NULL; } void ArchMultithreadPosix::insert(ArchThreadImpl* thread) { assert(thread != NULL); // thread shouldn't already be on the list assert(findNoRef(thread->m_thread) == NULL); // set thread id. note that we don't worry about m_nextID // wrapping back to 0 and duplicating thread ID's since the // likelihood of synergy running that long is vanishingly // small. thread->m_id = ++m_nextID; // append to list m_threadList.push_back(thread); } void ArchMultithreadPosix::erase(ArchThreadImpl* thread) { for (ThreadList::iterator index = m_threadList.begin(); index != m_threadList.end(); ++index) { if (*index == thread) { m_threadList.erase(index); break; } } } void ArchMultithreadPosix::refThread(ArchThreadImpl* thread) { assert(thread != NULL); assert(findNoRef(thread->m_thread) != NULL); ++thread->m_refCount; } void ArchMultithreadPosix::testCancelThreadImpl(ArchThreadImpl* thread) { assert(thread != NULL); // update cancel state lockMutex(m_threadMutex); bool cancel = false; if (thread->m_cancel && !thread->m_cancelling) { thread->m_cancelling = true; thread->m_cancel = false; cancel = true; } unlockMutex(m_threadMutex); // unwind thread's stack if cancelling if (cancel) { throw XThreadCancel(); } } void* ArchMultithreadPosix::threadFunc(void* vrep) { // get the thread ArchThreadImpl* thread = static_cast(vrep); // setup pthreads pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL); // run thread s_instance->doThreadFunc(thread); // terminate the thread return NULL; } void ArchMultithreadPosix::doThreadFunc(ArchThread thread) { // default priority is slightly below normal setPriorityOfThread(thread, 1); // wait for parent to initialize this object lockMutex(m_threadMutex); unlockMutex(m_threadMutex); void* result = NULL; try { // go result = (*thread->m_func)(thread->m_userData); } catch (XThreadCancel&) { // client called cancel() } catch (...) { // note -- don't catch (...) to avoid masking bugs lockMutex(m_threadMutex); thread->m_exited = true; unlockMutex(m_threadMutex); closeThread(thread); throw; } // thread has exited lockMutex(m_threadMutex); thread->m_result = result; thread->m_exited = true; unlockMutex(m_threadMutex); // done with thread closeThread(thread); } void ArchMultithreadPosix::threadCancel(int) { // do nothing } void* ArchMultithreadPosix::threadSignalHandler(void*) { // detach pthread_detach(pthread_self()); // add signal to mask sigset_t sigset; setSignalSet(&sigset); // also wait on SIGABRT. on linux (others?) this thread (process) // will persist after all the other threads evaporate due to an // assert unless we wait on SIGABRT. that means our resources (like // the socket we're listening on) are not released and never will be // until the lingering thread is killed. i don't know why sigwait() // should protect the thread from being killed. note that sigwait() // doesn't actually return if we receive SIGABRT and, for some // reason, we don't have to block SIGABRT. sigaddset(&sigset, SIGABRT); // we exit the loop via thread cancellation in sigwait() for (;;) { // wait #if HAVE_POSIX_SIGWAIT int signal = 0; sigwait(&sigset, &signal); #else sigwait(&sigset); #endif // if we get here then the signal was raised switch (signal) { case SIGINT: ARCH->raiseSignal(kINTERRUPT); break; case SIGTERM: ARCH->raiseSignal(kTERMINATE); break; case SIGHUP: ARCH->raiseSignal(kHANGUP); break; case SIGUSR2: ARCH->raiseSignal(kUSER); break; default: // ignore break; } } return NULL; } synergy-1.8.8-stable/src/lib/arch/unix/ArchMultithreadPosix.h000066400000000000000000000062411305627404700242240ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchMultithread.h" #include "common/stdlist.h" #include #define ARCH_MULTITHREAD ArchMultithreadPosix class ArchCondImpl { public: pthread_cond_t m_cond; }; class ArchMutexImpl { public: pthread_mutex_t m_mutex; }; //! Posix implementation of IArchMultithread class ArchMultithreadPosix : public IArchMultithread { public: ArchMultithreadPosix(); virtual ~ArchMultithreadPosix(); //! @name manipulators //@{ void setNetworkDataForCurrentThread(void*); //@} //! @name accessors //@{ void* getNetworkDataForThread(ArchThread); static ArchMultithreadPosix* getInstance(); //@} // IArchMultithread overrides virtual ArchCond newCondVar(); virtual void closeCondVar(ArchCond); virtual void signalCondVar(ArchCond); virtual void broadcastCondVar(ArchCond); virtual bool waitCondVar(ArchCond, ArchMutex, double timeout); virtual ArchMutex newMutex(); virtual void closeMutex(ArchMutex); virtual void lockMutex(ArchMutex); virtual void unlockMutex(ArchMutex); virtual ArchThread newThread(ThreadFunc, void*); virtual ArchThread newCurrentThread(); virtual ArchThread copyThread(ArchThread); virtual void closeThread(ArchThread); virtual void cancelThread(ArchThread); virtual void setPriorityOfThread(ArchThread, int n); virtual void testCancelThread(); virtual bool wait(ArchThread, double timeout); virtual bool isSameThread(ArchThread, ArchThread); virtual bool isExitedThread(ArchThread); virtual void* getResultOfThread(ArchThread); virtual ThreadID getIDOfThread(ArchThread); virtual void setSignalHandler(ESignal, SignalFunc, void*); virtual void raiseSignal(ESignal); private: void startSignalHandler(); ArchThreadImpl* find(pthread_t thread); ArchThreadImpl* findNoRef(pthread_t thread); void insert(ArchThreadImpl* thread); void erase(ArchThreadImpl* thread); void refThread(ArchThreadImpl* rep); void testCancelThreadImpl(ArchThreadImpl* rep); void doThreadFunc(ArchThread thread); static void* threadFunc(void* vrep); static void threadCancel(int); static void* threadSignalHandler(void* vrep); private: typedef std::list ThreadList; static ArchMultithreadPosix* s_instance; bool m_newThreadCalled; ArchMutex m_threadMutex; ArchThread m_mainThread; ThreadList m_threadList; ThreadID m_nextID; pthread_t m_signalThread; SignalFunc m_signalFunc[kNUM_SIGNALS]; void* m_signalUserData[kNUM_SIGNALS]; }; synergy-1.8.8-stable/src/lib/arch/unix/ArchNetworkBSD.cpp000066400000000000000000000467511305627404700232460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchNetworkBSD.h" #include "arch/unix/ArchMultithreadPosix.h" #include "arch/unix/XArchUnix.h" #include "arch/Arch.h" #if HAVE_UNISTD_H # include #endif #include #include #if !defined(TCP_NODELAY) # include #endif #include #include #include #include #if HAVE_POLL # include #else # if HAVE_SYS_SELECT_H # include # endif # if HAVE_SYS_TIME_H # include # endif #endif #if !HAVE_INET_ATON # include #endif static const int s_family[] = { PF_UNSPEC, PF_INET }; static const int s_type[] = { SOCK_DGRAM, SOCK_STREAM }; #if !HAVE_INET_ATON // parse dotted quad addresses. we don't bother with the weird BSD'ism // of handling octal and hex and partial forms. static in_addr_t inet_aton(const char* cp, struct in_addr* inp) { unsigned int a, b, c, d; if (sscanf(cp, "%u.%u.%u.%u", &a, &b, &c, &d) != 4) { return 0; } if (a >= 256 || b >= 256 || c >= 256 || d >= 256) { return 0; } unsigned char* incp = (unsigned char*)inp; incp[0] = (unsigned char)(a & 0xffu); incp[1] = (unsigned char)(b & 0xffu); incp[2] = (unsigned char)(c & 0xffu); incp[3] = (unsigned char)(d & 0xffu); return inp->s_addr; } #endif // // ArchNetworkBSD // ArchNetworkBSD::ArchNetworkBSD() { } ArchNetworkBSD::~ArchNetworkBSD() { ARCH->closeMutex(m_mutex); } void ArchNetworkBSD::init() { // create mutex to make some calls thread safe m_mutex = ARCH->newMutex(); } ArchSocket ArchNetworkBSD::newSocket(EAddressFamily family, ESocketType type) { // create socket int fd = socket(s_family[family], s_type[type], 0); if (fd == -1) { throwError(errno); } try { setBlockingOnSocket(fd, false); } catch (...) { close(fd); throw; } // allocate socket object ArchSocketImpl* newSocket = new ArchSocketImpl; newSocket->m_fd = fd; newSocket->m_refCount = 1; return newSocket; } ArchSocket ArchNetworkBSD::copySocket(ArchSocket s) { assert(s != NULL); // ref the socket and return it ARCH->lockMutex(m_mutex); ++s->m_refCount; ARCH->unlockMutex(m_mutex); return s; } void ArchNetworkBSD::closeSocket(ArchSocket s) { assert(s != NULL); // unref the socket and note if it should be released ARCH->lockMutex(m_mutex); const bool doClose = (--s->m_refCount == 0); ARCH->unlockMutex(m_mutex); // close the socket if necessary if (doClose) { if (close(s->m_fd) == -1) { // close failed. restore the last ref and throw. int err = errno; ARCH->lockMutex(m_mutex); ++s->m_refCount; ARCH->unlockMutex(m_mutex); throwError(err); } delete s; } } void ArchNetworkBSD::closeSocketForRead(ArchSocket s) { assert(s != NULL); if (shutdown(s->m_fd, 0) == -1) { if (errno != ENOTCONN) { throwError(errno); } } } void ArchNetworkBSD::closeSocketForWrite(ArchSocket s) { assert(s != NULL); if (shutdown(s->m_fd, 1) == -1) { if (errno != ENOTCONN) { throwError(errno); } } } void ArchNetworkBSD::bindSocket(ArchSocket s, ArchNetAddress addr) { assert(s != NULL); assert(addr != NULL); if (bind(s->m_fd, &addr->m_addr, addr->m_len) == -1) { throwError(errno); } } void ArchNetworkBSD::listenOnSocket(ArchSocket s) { assert(s != NULL); // hardcoding backlog if (listen(s->m_fd, 3) == -1) { throwError(errno); } } ArchSocket ArchNetworkBSD::acceptSocket(ArchSocket s, ArchNetAddress* addr) { assert(s != NULL); // if user passed NULL in addr then use scratch space ArchNetAddress dummy; if (addr == NULL) { addr = &dummy; } // create new socket and address ArchSocketImpl* newSocket = new ArchSocketImpl; *addr = new ArchNetAddressImpl; // accept on socket ACCEPT_TYPE_ARG3 len = (ACCEPT_TYPE_ARG3)((*addr)->m_len); int fd = accept(s->m_fd, &(*addr)->m_addr, &len); (*addr)->m_len = (socklen_t)len; if (fd == -1) { int err = errno; delete newSocket; delete *addr; *addr = NULL; if (err == EAGAIN) { return NULL; } throwError(err); } try { setBlockingOnSocket(fd, false); } catch (...) { close(fd); delete newSocket; delete *addr; *addr = NULL; throw; } // initialize socket newSocket->m_fd = fd; newSocket->m_refCount = 1; // discard address if not requested if (addr == &dummy) { ARCH->closeAddr(dummy); } return newSocket; } bool ArchNetworkBSD::connectSocket(ArchSocket s, ArchNetAddress addr) { assert(s != NULL); assert(addr != NULL); if (connect(s->m_fd, &addr->m_addr, addr->m_len) == -1) { if (errno == EISCONN) { return true; } if (errno == EINPROGRESS) { return false; } throwError(errno); } return true; } #if HAVE_POLL int ArchNetworkBSD::pollSocket(PollEntry pe[], int num, double timeout) { assert(pe != NULL || num == 0); // return if nothing to do if (num == 0) { if (timeout > 0.0) { ARCH->sleep(timeout); } return 0; } // allocate space for translated query struct pollfd* pfd = new struct pollfd[1 + num]; // translate query for (int i = 0; i < num; ++i) { pfd[i].fd = (pe[i].m_socket == NULL) ? -1 : pe[i].m_socket->m_fd; pfd[i].events = 0; if ((pe[i].m_events & kPOLLIN) != 0) { pfd[i].events |= POLLIN; } if ((pe[i].m_events & kPOLLOUT) != 0) { pfd[i].events |= POLLOUT; } } int n = num; // add the unblock pipe const int* unblockPipe = getUnblockPipe(); if (unblockPipe != NULL) { pfd[n].fd = unblockPipe[0]; pfd[n].events = POLLIN; ++n; } // prepare timeout int t = (timeout < 0.0) ? -1 : static_cast(1000.0 * timeout); // do the poll n = poll(pfd, n, t); // reset the unblock pipe if (n > 0 && unblockPipe != NULL && (pfd[num].revents & POLLIN) != 0) { // the unblock event was signalled. flush the pipe. char dummy[100]; int ignore; do { ignore = read(unblockPipe[0], dummy, sizeof(dummy)); } while (errno != EAGAIN); // don't count this unblock pipe in return value --n; } // handle results if (n == -1) { if (errno == EINTR) { // interrupted system call ARCH->testCancelThread(); delete[] pfd; return 0; } delete[] pfd; throwError(errno); } // translate back for (int i = 0; i < num; ++i) { pe[i].m_revents = 0; if ((pfd[i].revents & POLLIN) != 0) { pe[i].m_revents |= kPOLLIN; } if ((pfd[i].revents & POLLOUT) != 0) { pe[i].m_revents |= kPOLLOUT; } if ((pfd[i].revents & POLLERR) != 0) { pe[i].m_revents |= kPOLLERR; } if ((pfd[i].revents & POLLNVAL) != 0) { pe[i].m_revents |= kPOLLNVAL; } } delete[] pfd; return n; } #else int ArchNetworkBSD::pollSocket(PollEntry pe[], int num, double timeout) { int i, n; // prepare sets for select n = 0; fd_set readSet, writeSet, errSet; fd_set* readSetP = NULL; fd_set* writeSetP = NULL; fd_set* errSetP = NULL; FD_ZERO(&readSet); FD_ZERO(&writeSet); FD_ZERO(&errSet); for (i = 0; i < num; ++i) { // reset return flags pe[i].m_revents = 0; // set invalid flag if socket is bogus then go to next socket if (pe[i].m_socket == NULL) { pe[i].m_revents |= kPOLLNVAL; continue; } int fdi = pe[i].m_socket->m_fd; if (pe[i].m_events & kPOLLIN) { FD_SET(pe[i].m_socket->m_fd, &readSet); readSetP = &readSet; if (fdi > n) { n = fdi; } } if (pe[i].m_events & kPOLLOUT) { FD_SET(pe[i].m_socket->m_fd, &writeSet); writeSetP = &writeSet; if (fdi > n) { n = fdi; } } if (true) { FD_SET(pe[i].m_socket->m_fd, &errSet); errSetP = &errSet; if (fdi > n) { n = fdi; } } } // add the unblock pipe const int* unblockPipe = getUnblockPipe(); if (unblockPipe != NULL) { FD_SET(unblockPipe[0], &readSet); readSetP = &readSet; if (unblockPipe[0] > n) { n = unblockPipe[0]; } } // if there are no sockets then don't block forever if (n == 0 && timeout < 0.0) { timeout = 0.0; } // prepare timeout for select struct timeval timeout2; struct timeval* timeout2P; if (timeout < 0.0) { timeout2P = NULL; } else { timeout2P = &timeout2; timeout2.tv_sec = static_cast(timeout); timeout2.tv_usec = static_cast(1.0e+6 * (timeout - timeout2.tv_sec)); } // do the select n = select((SELECT_TYPE_ARG1) n + 1, SELECT_TYPE_ARG234 readSetP, SELECT_TYPE_ARG234 writeSetP, SELECT_TYPE_ARG234 errSetP, SELECT_TYPE_ARG5 timeout2P); // reset the unblock pipe if (n > 0 && unblockPipe != NULL && FD_ISSET(unblockPipe[0], &readSet)) { // the unblock event was signalled. flush the pipe. char dummy[100]; do { read(unblockPipe[0], dummy, sizeof(dummy)); } while (errno != EAGAIN); } // handle results if (n == -1) { if (errno == EINTR) { // interrupted system call ARCH->testCancelThread(); return 0; } throwError(errno); } n = 0; for (i = 0; i < num; ++i) { if (pe[i].m_socket != NULL) { if (FD_ISSET(pe[i].m_socket->m_fd, &readSet)) { pe[i].m_revents |= kPOLLIN; } if (FD_ISSET(pe[i].m_socket->m_fd, &writeSet)) { pe[i].m_revents |= kPOLLOUT; } if (FD_ISSET(pe[i].m_socket->m_fd, &errSet)) { pe[i].m_revents |= kPOLLERR; } } if (pe[i].m_revents != 0) { ++n; } } return n; } #endif void ArchNetworkBSD::unblockPollSocket(ArchThread thread) { const int* unblockPipe = getUnblockPipeForThread(thread); if (unblockPipe != NULL) { char dummy = 0; int ignore; ignore = write(unblockPipe[1], &dummy, 1); } } size_t ArchNetworkBSD::readSocket(ArchSocket s, void* buf, size_t len) { assert(s != NULL); ssize_t n = read(s->m_fd, buf, len); if (n == -1) { if (errno == EINTR || errno == EAGAIN) { return 0; } throwError(errno); } return n; } size_t ArchNetworkBSD::writeSocket(ArchSocket s, const void* buf, size_t len) { assert(s != NULL); ssize_t n = write(s->m_fd, buf, len); if (n == -1) { if (errno == EINTR || errno == EAGAIN) { return 0; } throwError(errno); } return n; } void ArchNetworkBSD::throwErrorOnSocket(ArchSocket s) { assert(s != NULL); // get the error from the socket layer int err = 0; socklen_t size = (socklen_t)sizeof(err); if (getsockopt(s->m_fd, SOL_SOCKET, SO_ERROR, (optval_t*)&err, &size) == -1) { err = errno; } // throw if there's an error if (err != 0) { throwError(err); } } void ArchNetworkBSD::setBlockingOnSocket(int fd, bool blocking) { assert(fd != -1); int mode = fcntl(fd, F_GETFL, 0); if (mode == -1) { throwError(errno); } if (blocking) { mode &= ~O_NONBLOCK; } else { mode |= O_NONBLOCK; } if (fcntl(fd, F_SETFL, mode) == -1) { throwError(errno); } } bool ArchNetworkBSD::setNoDelayOnSocket(ArchSocket s, bool noDelay) { assert(s != NULL); // get old state int oflag; socklen_t size = (socklen_t)sizeof(oflag); if (getsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, (optval_t*)&oflag, &size) == -1) { throwError(errno); } int flag = noDelay ? 1 : 0; size = (socklen_t)sizeof(flag); if (setsockopt(s->m_fd, IPPROTO_TCP, TCP_NODELAY, (optval_t*)&flag, size) == -1) { throwError(errno); } return (oflag != 0); } bool ArchNetworkBSD::setReuseAddrOnSocket(ArchSocket s, bool reuse) { assert(s != NULL); // get old state int oflag; socklen_t size = (socklen_t)sizeof(oflag); if (getsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR, (optval_t*)&oflag, &size) == -1) { throwError(errno); } int flag = reuse ? 1 : 0; size = (socklen_t)sizeof(flag); if (setsockopt(s->m_fd, SOL_SOCKET, SO_REUSEADDR, (optval_t*)&flag, size) == -1) { throwError(errno); } return (oflag != 0); } std::string ArchNetworkBSD::getHostName() { char name[256]; if (gethostname(name, sizeof(name)) == -1) { name[0] = '\0'; } else { name[sizeof(name) - 1] = '\0'; } return name; } ArchNetAddress ArchNetworkBSD::newAnyAddr(EAddressFamily family) { // allocate address ArchNetAddressImpl* addr = new ArchNetAddressImpl; // fill it in switch (family) { case kINET: { struct sockaddr_in* ipAddr = reinterpret_cast(&addr->m_addr); ipAddr->sin_family = AF_INET; ipAddr->sin_port = 0; ipAddr->sin_addr.s_addr = INADDR_ANY; addr->m_len = (socklen_t)sizeof(struct sockaddr_in); break; } default: delete addr; assert(0 && "invalid family"); } return addr; } ArchNetAddress ArchNetworkBSD::copyAddr(ArchNetAddress addr) { assert(addr != NULL); // allocate and copy address return new ArchNetAddressImpl(*addr); } ArchNetAddress ArchNetworkBSD::nameToAddr(const std::string& name) { // allocate address ArchNetAddressImpl* addr = new ArchNetAddressImpl; // try to convert assuming an IPv4 dot notation address struct sockaddr_in inaddr; memset(&inaddr, 0, sizeof(inaddr)); if (inet_aton(name.c_str(), &inaddr.sin_addr) != 0) { // it's a dot notation address addr->m_len = (socklen_t)sizeof(struct sockaddr_in); inaddr.sin_family = AF_INET; inaddr.sin_port = 0; memcpy(&addr->m_addr, &inaddr, addr->m_len); } else { // mutexed address lookup (ugh) ARCH->lockMutex(m_mutex); struct hostent* info = gethostbyname(name.c_str()); if (info == NULL) { ARCH->unlockMutex(m_mutex); delete addr; throwNameError(h_errno); } // copy over address (only IPv4 currently supported) if (info->h_addrtype == AF_INET) { addr->m_len = (socklen_t)sizeof(struct sockaddr_in); inaddr.sin_family = info->h_addrtype; inaddr.sin_port = 0; memcpy(&inaddr.sin_addr, info->h_addr_list[0], sizeof(inaddr.sin_addr)); memcpy(&addr->m_addr, &inaddr, addr->m_len); } else { ARCH->unlockMutex(m_mutex); delete addr; throw XArchNetworkNameUnsupported( "The requested name is valid but " "does not have a supported address family"); } // done with static buffer ARCH->unlockMutex(m_mutex); } return addr; } void ArchNetworkBSD::closeAddr(ArchNetAddress addr) { assert(addr != NULL); delete addr; } std::string ArchNetworkBSD::addrToName(ArchNetAddress addr) { assert(addr != NULL); // mutexed name lookup (ugh) ARCH->lockMutex(m_mutex); struct hostent* info = gethostbyaddr(&addr->m_addr, addr->m_len, addr->m_addr.sa_family); if (info == NULL) { ARCH->unlockMutex(m_mutex); throwNameError(h_errno); } // save (primary) name std::string name = info->h_name; // done with static buffer ARCH->unlockMutex(m_mutex); return name; } std::string ArchNetworkBSD::addrToString(ArchNetAddress addr) { assert(addr != NULL); switch (getAddrFamily(addr)) { case kINET: { struct sockaddr_in* ipAddr = reinterpret_cast(&addr->m_addr); ARCH->lockMutex(m_mutex); std::string s = inet_ntoa(ipAddr->sin_addr); ARCH->unlockMutex(m_mutex); return s; } default: assert(0 && "unknown address family"); return ""; } } IArchNetwork::EAddressFamily ArchNetworkBSD::getAddrFamily(ArchNetAddress addr) { assert(addr != NULL); switch (addr->m_addr.sa_family) { case AF_INET: return kINET; default: return kUNKNOWN; } } void ArchNetworkBSD::setAddrPort(ArchNetAddress addr, int port) { assert(addr != NULL); switch (getAddrFamily(addr)) { case kINET: { struct sockaddr_in* ipAddr = reinterpret_cast(&addr->m_addr); ipAddr->sin_port = htons(port); break; } default: assert(0 && "unknown address family"); break; } } int ArchNetworkBSD::getAddrPort(ArchNetAddress addr) { assert(addr != NULL); switch (getAddrFamily(addr)) { case kINET: { struct sockaddr_in* ipAddr = reinterpret_cast(&addr->m_addr); return ntohs(ipAddr->sin_port); } default: assert(0 && "unknown address family"); return 0; } } bool ArchNetworkBSD::isAnyAddr(ArchNetAddress addr) { assert(addr != NULL); switch (getAddrFamily(addr)) { case kINET: { struct sockaddr_in* ipAddr = reinterpret_cast(&addr->m_addr); return (ipAddr->sin_addr.s_addr == INADDR_ANY && addr->m_len == (socklen_t)sizeof(struct sockaddr_in)); } default: assert(0 && "unknown address family"); return true; } } bool ArchNetworkBSD::isEqualAddr(ArchNetAddress a, ArchNetAddress b) { return (a->m_len == b->m_len && memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0); } const int* ArchNetworkBSD::getUnblockPipe() { ArchMultithreadPosix* mt = ArchMultithreadPosix::getInstance(); ArchThread thread = mt->newCurrentThread(); const int* p = getUnblockPipeForThread(thread); ARCH->closeThread(thread); return p; } const int* ArchNetworkBSD::getUnblockPipeForThread(ArchThread thread) { ArchMultithreadPosix* mt = ArchMultithreadPosix::getInstance(); int* unblockPipe = (int*)mt->getNetworkDataForThread(thread); if (unblockPipe == NULL) { unblockPipe = new int[2]; if (pipe(unblockPipe) != -1) { try { setBlockingOnSocket(unblockPipe[0], false); mt->setNetworkDataForCurrentThread(unblockPipe); } catch (...) { delete[] unblockPipe; unblockPipe = NULL; } } else { delete[] unblockPipe; unblockPipe = NULL; } } return unblockPipe; } void ArchNetworkBSD::throwError(int err) { switch (err) { case EINTR: ARCH->testCancelThread(); throw XArchNetworkInterrupted(new XArchEvalUnix(err)); case EACCES: case EPERM: throw XArchNetworkAccess(new XArchEvalUnix(err)); case ENFILE: case EMFILE: case ENODEV: case ENOBUFS: case ENOMEM: case ENETDOWN: #if defined(ENOSR) case ENOSR: #endif throw XArchNetworkResource(new XArchEvalUnix(err)); case EPROTOTYPE: case EPROTONOSUPPORT: case EAFNOSUPPORT: case EPFNOSUPPORT: case ESOCKTNOSUPPORT: case EINVAL: case ENOPROTOOPT: case EOPNOTSUPP: case ESHUTDOWN: #if defined(ENOPKG) case ENOPKG: #endif throw XArchNetworkSupport(new XArchEvalUnix(err)); case EIO: throw XArchNetworkIO(new XArchEvalUnix(err)); case EADDRNOTAVAIL: throw XArchNetworkNoAddress(new XArchEvalUnix(err)); case EADDRINUSE: throw XArchNetworkAddressInUse(new XArchEvalUnix(err)); case EHOSTUNREACH: case ENETUNREACH: throw XArchNetworkNoRoute(new XArchEvalUnix(err)); case ENOTCONN: throw XArchNetworkNotConnected(new XArchEvalUnix(err)); case EPIPE: throw XArchNetworkShutdown(new XArchEvalUnix(err)); case ECONNABORTED: case ECONNRESET: throw XArchNetworkDisconnected(new XArchEvalUnix(err)); case ECONNREFUSED: throw XArchNetworkConnectionRefused(new XArchEvalUnix(err)); case EHOSTDOWN: case ETIMEDOUT: throw XArchNetworkTimedOut(new XArchEvalUnix(err)); default: throw XArchNetwork(new XArchEvalUnix(err)); } } void ArchNetworkBSD::throwNameError(int err) { static const char* s_msg[] = { "The specified host is unknown", "The requested name is valid but does not have an IP address", "A non-recoverable name server error occurred", "A temporary error occurred on an authoritative name server", "An unknown name server error occurred" }; switch (err) { case HOST_NOT_FOUND: throw XArchNetworkNameUnknown(s_msg[0]); case NO_DATA: throw XArchNetworkNameNoAddress(s_msg[1]); case NO_RECOVERY: throw XArchNetworkNameFailure(s_msg[2]); case TRY_AGAIN: throw XArchNetworkNameUnavailable(s_msg[3]); default: throw XArchNetworkName(s_msg[4]); } } synergy-1.8.8-stable/src/lib/arch/unix/ArchNetworkBSD.h000066400000000000000000000064721305627404700227070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchNetwork.h" #include "arch/IArchMultithread.h" #if HAVE_SYS_TYPES_H # include #endif #if HAVE_SYS_SOCKET_H # include #endif #if !HAVE_SOCKLEN_T typedef int socklen_t; #endif // old systems may use char* for [gs]etsockopt()'s optval argument. // this should be void on modern systems but char is forwards // compatible so we always use it. typedef char optval_t; #define ARCH_NETWORK ArchNetworkBSD class ArchSocketImpl { public: int m_fd; int m_refCount; }; class ArchNetAddressImpl { public: ArchNetAddressImpl() : m_len(sizeof(m_addr)) { } public: struct sockaddr m_addr; socklen_t m_len; }; //! Berkeley (BSD) sockets implementation of IArchNetwork class ArchNetworkBSD : public IArchNetwork { public: ArchNetworkBSD(); virtual ~ArchNetworkBSD(); virtual void init(); // IArchNetwork overrides virtual ArchSocket newSocket(EAddressFamily, ESocketType); virtual ArchSocket copySocket(ArchSocket s); virtual void closeSocket(ArchSocket s); virtual void closeSocketForRead(ArchSocket s); virtual void closeSocketForWrite(ArchSocket s); virtual void bindSocket(ArchSocket s, ArchNetAddress addr); virtual void listenOnSocket(ArchSocket s); virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress* addr); virtual bool connectSocket(ArchSocket s, ArchNetAddress name); virtual int pollSocket(PollEntry[], int num, double timeout); virtual void unblockPollSocket(ArchThread thread); virtual size_t readSocket(ArchSocket s, void* buf, size_t len); virtual size_t writeSocket(ArchSocket s, const void* buf, size_t len); virtual void throwErrorOnSocket(ArchSocket); virtual bool setNoDelayOnSocket(ArchSocket, bool noDelay); virtual bool setReuseAddrOnSocket(ArchSocket, bool reuse); virtual std::string getHostName(); virtual ArchNetAddress newAnyAddr(EAddressFamily); virtual ArchNetAddress copyAddr(ArchNetAddress); virtual ArchNetAddress nameToAddr(const std::string&); virtual void closeAddr(ArchNetAddress); virtual std::string addrToName(ArchNetAddress); virtual std::string addrToString(ArchNetAddress); virtual EAddressFamily getAddrFamily(ArchNetAddress); virtual void setAddrPort(ArchNetAddress, int port); virtual int getAddrPort(ArchNetAddress); virtual bool isAnyAddr(ArchNetAddress); virtual bool isEqualAddr(ArchNetAddress, ArchNetAddress); private: const int* getUnblockPipe(); const int* getUnblockPipeForThread(ArchThread); void setBlockingOnSocket(int fd, bool blocking); void throwError(int); void throwNameError(int); private: ArchMutex m_mutex; }; synergy-1.8.8-stable/src/lib/arch/unix/ArchSleepUnix.cpp000066400000000000000000000041311305627404700231620ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchSleepUnix.h" #include "arch/Arch.h" #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if !HAVE_NANOSLEEP # if HAVE_SYS_SELECT_H # include # endif # if HAVE_SYS_TYPES_H # include # endif # if HAVE_UNISTD_H # include # endif #endif // // ArchSleepUnix // ArchSleepUnix::ArchSleepUnix() { // do nothing } ArchSleepUnix::~ArchSleepUnix() { // do nothing } void ArchSleepUnix::sleep(double timeout) { ARCH->testCancelThread(); if (timeout < 0.0) { return; } #if HAVE_NANOSLEEP // prep timeout struct timespec t; t.tv_sec = (long)timeout; t.tv_nsec = (long)(1.0e+9 * (timeout - (double)t.tv_sec)); // wait while (nanosleep(&t, &t) < 0) ARCH->testCancelThread(); #else /* emulate nanosleep() with select() */ double startTime = ARCH->time(); double timeLeft = timeout; while (timeLeft > 0.0) { struct timeval timeout2; timeout2.tv_sec = static_cast(timeLeft); timeout2.tv_usec = static_cast(1.0e+6 * (timeLeft - timeout2.tv_sec)); select((SELECT_TYPE_ARG1) 0, SELECT_TYPE_ARG234 NULL, SELECT_TYPE_ARG234 NULL, SELECT_TYPE_ARG234 NULL, SELECT_TYPE_ARG5 &timeout2); ARCH->testCancelThread(); timeLeft = timeout - (ARCH->time() - startTime); } #endif } synergy-1.8.8-stable/src/lib/arch/unix/ArchSleepUnix.h000066400000000000000000000017621305627404700226360ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchSleep.h" #define ARCH_SLEEP ArchSleepUnix //! Unix implementation of IArchSleep class ArchSleepUnix : public IArchSleep { public: ArchSleepUnix(); virtual ~ArchSleepUnix(); // IArchSleep overrides virtual void sleep(double timeout); }; synergy-1.8.8-stable/src/lib/arch/unix/ArchStringUnix.cpp000066400000000000000000000020161305627404700233600ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchStringUnix.h" #include // // ArchStringUnix // #include "arch/multibyte.h" #include "arch/vsnprintf.h" ArchStringUnix::ArchStringUnix() { } ArchStringUnix::~ArchStringUnix() { } IArchString::EWideCharEncoding ArchStringUnix::getWideCharEncoding() { return kUCS4; } synergy-1.8.8-stable/src/lib/arch/unix/ArchStringUnix.h000066400000000000000000000020151305627404700230240ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchString.h" #define ARCH_STRING ArchStringUnix //! Unix implementation of IArchString class ArchStringUnix : public IArchString { public: ArchStringUnix(); virtual ~ArchStringUnix(); // IArchString overrides virtual EWideCharEncoding getWideCharEncoding(); }; synergy-1.8.8-stable/src/lib/arch/unix/ArchSystemUnix.cpp000066400000000000000000000031531305627404700234010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchSystemUnix.h" #include // // ArchSystemUnix // ArchSystemUnix::ArchSystemUnix() { // do nothing } ArchSystemUnix::~ArchSystemUnix() { // do nothing } std::string ArchSystemUnix::getOSName() const { #if defined(HAVE_SYS_UTSNAME_H) struct utsname info; if (uname(&info) == 0) { std::string msg; msg += info.sysname; msg += " "; msg += info.release; return msg; } #endif return "Unix"; } std::string ArchSystemUnix::getPlatformName() const { #if defined(HAVE_SYS_UTSNAME_H) struct utsname info; if (uname(&info) == 0) { return std::string(info.machine); } #endif return "unknown"; } std::string ArchSystemUnix::setting(const std::string&) const { return ""; } void ArchSystemUnix::setting(const std::string&, const std::string&) const { } std::string ArchSystemUnix::getLibsUsed(void) const { return "not implemented.\nuse lsof on shell"; } synergy-1.8.8-stable/src/lib/arch/unix/ArchSystemUnix.h000066400000000000000000000023271305627404700230500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchSystem.h" #define ARCH_SYSTEM ArchSystemUnix //! Unix implementation of IArchString class ArchSystemUnix : public IArchSystem { public: ArchSystemUnix(); virtual ~ArchSystemUnix(); // IArchSystem overrides virtual std::string getOSName() const; virtual std::string getPlatformName() const; virtual std::string setting(const std::string&) const; virtual void setting(const std::string&, const std::string&) const; virtual std::string getLibsUsed(void) const; }; synergy-1.8.8-stable/src/lib/arch/unix/ArchTaskBarXWindows.cpp000066400000000000000000000023041305627404700243000ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchTaskBarXWindows.h" // // ArchTaskBarXWindows // ArchTaskBarXWindows::ArchTaskBarXWindows() { // do nothing } ArchTaskBarXWindows::~ArchTaskBarXWindows() { // do nothing } void ArchTaskBarXWindows::addReceiver(IArchTaskBarReceiver* /*receiver*/) { // do nothing } void ArchTaskBarXWindows::removeReceiver(IArchTaskBarReceiver* /*receiver*/) { // do nothing } void ArchTaskBarXWindows::updateReceiver(IArchTaskBarReceiver* /*receiver*/) { // do nothing } synergy-1.8.8-stable/src/lib/arch/unix/ArchTaskBarXWindows.h000066400000000000000000000022141305627404700237450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchTaskBar.h" #define ARCH_TASKBAR ArchTaskBarXWindows //! X11 implementation of IArchTaskBar class ArchTaskBarXWindows : public IArchTaskBar { public: ArchTaskBarXWindows(); virtual ~ArchTaskBarXWindows(); // IArchTaskBar overrides virtual void addReceiver(IArchTaskBarReceiver*); virtual void removeReceiver(IArchTaskBarReceiver*); virtual void updateReceiver(IArchTaskBarReceiver*); }; synergy-1.8.8-stable/src/lib/arch/unix/ArchTimeUnix.cpp000066400000000000000000000022351305627404700230130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/ArchTimeUnix.h" #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif // // ArchTimeUnix // ArchTimeUnix::ArchTimeUnix() { // do nothing } ArchTimeUnix::~ArchTimeUnix() { // do nothing } double ArchTimeUnix::time() { struct timeval t; gettimeofday(&t, NULL); return (double)t.tv_sec + 1.0e-6 * (double)t.tv_usec; } synergy-1.8.8-stable/src/lib/arch/unix/ArchTimeUnix.h000066400000000000000000000017441305627404700224640ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchTime.h" #define ARCH_TIME ArchTimeUnix //! Generic Unix implementation of IArchTime class ArchTimeUnix : public IArchTime { public: ArchTimeUnix(); virtual ~ArchTimeUnix(); // IArchTime overrides virtual double time(); }; synergy-1.8.8-stable/src/lib/arch/unix/XArchUnix.cpp000066400000000000000000000016161305627404700223260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/unix/XArchUnix.h" #include // // XArchEvalUnix // std::string XArchEvalUnix::eval() const { // FIXME -- not thread safe return strerror(m_error); } synergy-1.8.8-stable/src/lib/arch/unix/XArchUnix.h000066400000000000000000000020001305627404700217570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/XArch.h" //! Lazy error message string evaluation for unix class XArchEvalUnix : public XArchEval { public: XArchEvalUnix(int error) : m_error(error) { } virtual ~XArchEvalUnix() _NOEXCEPT { } virtual std::string eval() const; private: int m_error; }; synergy-1.8.8-stable/src/lib/arch/vsnprintf.h000066400000000000000000000031111305627404700211600ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/IArchString.h" #if HAVE_VSNPRINTF #if !defined(ARCH_VSNPRINTF) # define ARCH_VSNPRINTF vsnprintf #endif int IArchString::vsnprintf(char* str, int size, const char* fmt, va_list ap) { int n = ::ARCH_VSNPRINTF(str, size, fmt, ap); if (n > size) { n = -1; } return n; } #elif SYSAPI_UNIX // !HAVE_VSNPRINTF #include int IArchString::vsnprintf(char* str, int size, const char* fmt, va_list ap) { static FILE* bitbucket = fopen("/dev/null", "w"); if (bitbucket == NULL) { // uh oh if (size > 0) { str[0] = '\0'; } return 0; } else { // count the characters using the bitbucket int n = vfprintf(bitbucket, fmt, ap); if (n + 1 <= size) { // it'll fit so print it into str vsprintf(str, fmt, ap); } return n; } } #else // !HAVE_VSNPRINTF && !SYSAPI_UNIX #error vsnprintf not implemented #endif // !HAVE_VSNPRINTF synergy-1.8.8-stable/src/lib/arch/win32/000077500000000000000000000000001305627404700177245ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/arch/win32/ArchConsoleWindows.cpp000066400000000000000000000015441305627404700242070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchConsoleWindows.h" ArchConsoleWindows::ArchConsoleWindows() { } ArchConsoleWindows::~ArchConsoleWindows() { } synergy-1.8.8-stable/src/lib/arch/win32/ArchConsoleWindows.h000066400000000000000000000016521305627404700236540ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/ArchConsoleStd.h" #define ARCH_CONSOLE ArchConsoleWindows class ArchConsoleWindows : public ArchConsoleStd { public: ArchConsoleWindows(); virtual ~ArchConsoleWindows(); }; synergy-1.8.8-stable/src/lib/arch/win32/ArchDaemonWindows.cpp000066400000000000000000000417651305627404700240210ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchDaemonWindows.h" #include "arch/win32/ArchMiscWindows.h" #include "arch/win32/XArchWindows.h" #include "arch/Arch.h" #include "common/stdvector.h" #include // // ArchDaemonWindows // ArchDaemonWindows* ArchDaemonWindows::s_daemon = NULL; ArchDaemonWindows::ArchDaemonWindows() : m_daemonThreadID(0) { m_quitMessage = RegisterWindowMessage("SynergyDaemonExit"); } ArchDaemonWindows::~ArchDaemonWindows() { // do nothing } int ArchDaemonWindows::runDaemon(RunFunc runFunc) { assert(s_daemon != NULL); return s_daemon->doRunDaemon(runFunc); } void ArchDaemonWindows::daemonRunning(bool running) { if (s_daemon != NULL) { s_daemon->doDaemonRunning(running); } } UINT ArchDaemonWindows::getDaemonQuitMessage() { if (s_daemon != NULL) { return s_daemon->doGetDaemonQuitMessage(); } else { return 0; } } void ArchDaemonWindows::daemonFailed(int result) { assert(s_daemon != NULL); throw XArchDaemonRunFailed(result); } void ArchDaemonWindows::installDaemon(const char* name, const char* description, const char* pathname, const char* commandLine, const char* dependencies) { // open service manager SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); if (mgr == NULL) { // can't open service manager throw XArchDaemonInstallFailed(new XArchEvalWindows); } // create the service SC_HANDLE service = CreateService( mgr, name, name, 0, SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, pathname, NULL, NULL, dependencies, NULL, NULL); if (service == NULL) { // can't create service DWORD err = GetLastError(); if (err != ERROR_SERVICE_EXISTS) { CloseServiceHandle(mgr); throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); } } else { // done with service (but only try to close if not null) CloseServiceHandle(service); } // done with manager CloseServiceHandle(mgr); // open the registry key for this service HKEY key = openNTServicesKey(); key = ArchMiscWindows::addKey(key, name); if (key == NULL) { // can't open key DWORD err = GetLastError(); try { uninstallDaemon(name); } catch (...) { // ignore } throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); } // set the description ArchMiscWindows::setValue(key, _T("Description"), description); // set command line key = ArchMiscWindows::addKey(key, _T("Parameters")); if (key == NULL) { // can't open key DWORD err = GetLastError(); ArchMiscWindows::closeKey(key); try { uninstallDaemon(name); } catch (...) { // ignore } throw XArchDaemonInstallFailed(new XArchEvalWindows(err)); } ArchMiscWindows::setValue(key, _T("CommandLine"), commandLine); // done with registry ArchMiscWindows::closeKey(key); } void ArchDaemonWindows::uninstallDaemon(const char* name) { // remove parameters for this service. ignore failures. HKEY key = openNTServicesKey(); key = ArchMiscWindows::openKey(key, name); if (key != NULL) { ArchMiscWindows::deleteKey(key, _T("Parameters")); ArchMiscWindows::closeKey(key); } // open service manager SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); if (mgr == NULL) { // can't open service manager throw XArchDaemonUninstallFailed(new XArchEvalWindows); } // open the service. oddly, you must open a service to delete it. SC_HANDLE service = OpenService(mgr, name, DELETE | SERVICE_STOP); if (service == NULL) { DWORD err = GetLastError(); CloseServiceHandle(mgr); if (err != ERROR_SERVICE_DOES_NOT_EXIST) { throw XArchDaemonUninstallFailed(new XArchEvalWindows(err)); } throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err)); } // stop the service. we don't care if we fail. SERVICE_STATUS status; ControlService(service, SERVICE_CONTROL_STOP, &status); // delete the service const bool okay = (DeleteService(service) == 0); const DWORD err = GetLastError(); // clean up CloseServiceHandle(service); CloseServiceHandle(mgr); // give windows a chance to remove the service before // we check if it still exists. ARCH->sleep(1); // handle failure. ignore error if service isn't installed anymore. if (!okay && isDaemonInstalled(name)) { if (err == ERROR_SUCCESS) { // this seems to occur even though the uninstall was successful. // it could be a timing issue, i.e., isDaemonInstalled is // called too soon. i've added a sleep to try and stop this. return; } if (err == ERROR_IO_PENDING) { // this seems to be a spurious error return; } if (err != ERROR_SERVICE_MARKED_FOR_DELETE) { throw XArchDaemonUninstallFailed(new XArchEvalWindows(err)); } throw XArchDaemonUninstallNotInstalled(new XArchEvalWindows(err)); } } int ArchDaemonWindows::daemonize(const char* name, DaemonFunc func) { assert(name != NULL); assert(func != NULL); // save daemon function m_daemonFunc = func; // construct the service entry SERVICE_TABLE_ENTRY entry[2]; entry[0].lpServiceName = const_cast(name); entry[0].lpServiceProc = &ArchDaemonWindows::serviceMainEntry; entry[1].lpServiceName = NULL; entry[1].lpServiceProc = NULL; // hook us up to the service control manager. this won't return // (if successful) until the processes have terminated. s_daemon = this; if (StartServiceCtrlDispatcher(entry) == 0) { // StartServiceCtrlDispatcher failed s_daemon = NULL; throw XArchDaemonFailed(new XArchEvalWindows); } s_daemon = NULL; return m_daemonResult; } bool ArchDaemonWindows::canInstallDaemon(const char* /*name*/) { // check if we can open service manager for write SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); if (mgr == NULL) { return false; } CloseServiceHandle(mgr); // check if we can open the registry key HKEY key = openNTServicesKey(); ArchMiscWindows::closeKey(key); return (key != NULL); } bool ArchDaemonWindows::isDaemonInstalled(const char* name) { // open service manager SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); if (mgr == NULL) { return false; } // open the service SC_HANDLE service = OpenService(mgr, name, GENERIC_READ); // clean up if (service != NULL) { CloseServiceHandle(service); } CloseServiceHandle(mgr); return (service != NULL); } HKEY ArchDaemonWindows::openNTServicesKey() { static const char* s_keyNames[] = { _T("SYSTEM"), _T("CurrentControlSet"), _T("Services"), NULL }; return ArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_keyNames); } bool ArchDaemonWindows::isRunState(DWORD state) { switch (state) { case SERVICE_START_PENDING: case SERVICE_CONTINUE_PENDING: case SERVICE_RUNNING: return true; default: return false; } } int ArchDaemonWindows::doRunDaemon(RunFunc run) { // should only be called from DaemonFunc assert(m_serviceMutex != NULL); assert(run != NULL); // create message queue for this thread MSG dummy; PeekMessage(&dummy, NULL, 0, 0, PM_NOREMOVE); int result = 0; ARCH->lockMutex(m_serviceMutex); m_daemonThreadID = GetCurrentThreadId(); while (m_serviceState != SERVICE_STOPPED) { // wait until we're told to start while (!isRunState(m_serviceState) && m_serviceState != SERVICE_STOP_PENDING) { ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0); } // run unless told to stop if (m_serviceState != SERVICE_STOP_PENDING) { ARCH->unlockMutex(m_serviceMutex); try { result = run(); } catch (...) { ARCH->lockMutex(m_serviceMutex); setStatusError(0); m_serviceState = SERVICE_STOPPED; setStatus(m_serviceState); ARCH->broadcastCondVar(m_serviceCondVar); ARCH->unlockMutex(m_serviceMutex); throw; } ARCH->lockMutex(m_serviceMutex); } // notify of new state if (m_serviceState == SERVICE_PAUSE_PENDING) { m_serviceState = SERVICE_PAUSED; } else { m_serviceState = SERVICE_STOPPED; } setStatus(m_serviceState); ARCH->broadcastCondVar(m_serviceCondVar); } ARCH->unlockMutex(m_serviceMutex); return result; } void ArchDaemonWindows::doDaemonRunning(bool running) { ARCH->lockMutex(m_serviceMutex); if (running) { m_serviceState = SERVICE_RUNNING; setStatus(m_serviceState); ARCH->broadcastCondVar(m_serviceCondVar); } ARCH->unlockMutex(m_serviceMutex); } UINT ArchDaemonWindows::doGetDaemonQuitMessage() { return m_quitMessage; } void ArchDaemonWindows::setStatus(DWORD state) { setStatus(state, 0, 0); } void ArchDaemonWindows::setStatus(DWORD state, DWORD step, DWORD waitHint) { assert(s_daemon != NULL); SERVICE_STATUS status; status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS; status.dwCurrentState = state; status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN; status.dwWin32ExitCode = NO_ERROR; status.dwServiceSpecificExitCode = 0; status.dwCheckPoint = step; status.dwWaitHint = waitHint; SetServiceStatus(s_daemon->m_statusHandle, &status); } void ArchDaemonWindows::setStatusError(DWORD error) { assert(s_daemon != NULL); SERVICE_STATUS status; status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS; status.dwCurrentState = SERVICE_STOPPED; status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN; status.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; status.dwServiceSpecificExitCode = error; status.dwCheckPoint = 0; status.dwWaitHint = 0; SetServiceStatus(s_daemon->m_statusHandle, &status); } void ArchDaemonWindows::serviceMain(DWORD argc, LPTSTR* argvIn) { typedef std::vector ArgList; typedef std::vector Arguments; const char** argv = const_cast(argvIn); // create synchronization objects m_serviceMutex = ARCH->newMutex(); m_serviceCondVar = ARCH->newCondVar(); // register our service handler function m_statusHandle = RegisterServiceCtrlHandler(argv[0], &ArchDaemonWindows::serviceHandlerEntry); if (m_statusHandle == 0) { // cannot start as service m_daemonResult = -1; ARCH->closeCondVar(m_serviceCondVar); ARCH->closeMutex(m_serviceMutex); return; } // tell service control manager that we're starting m_serviceState = SERVICE_START_PENDING; setStatus(m_serviceState, 0, 10000); std::string commandLine; // if no arguments supplied then try getting them from the registry. // the first argument doesn't count because it's the service name. Arguments args; ArgList myArgv; if (argc <= 1) { // read command line HKEY key = openNTServicesKey(); key = ArchMiscWindows::openKey(key, argvIn[0]); key = ArchMiscWindows::openKey(key, _T("Parameters")); if (key != NULL) { commandLine = ArchMiscWindows::readValueString(key, _T("CommandLine")); } // if the command line isn't empty then parse and use it if (!commandLine.empty()) { // parse, honoring double quoted substrings std::string::size_type i = commandLine.find_first_not_of(" \t"); while (i != std::string::npos && i != commandLine.size()) { // find end of string std::string::size_type e; if (commandLine[i] == '\"') { // quoted. find closing quote. ++i; e = commandLine.find("\"", i); // whitespace must follow closing quote if (e == std::string::npos || (e + 1 != commandLine.size() && commandLine[e + 1] != ' ' && commandLine[e + 1] != '\t')) { args.clear(); break; } // extract args.push_back(commandLine.substr(i, e - i)); i = e + 1; } else { // unquoted. find next whitespace. e = commandLine.find_first_of(" \t", i); if (e == std::string::npos) { e = commandLine.size(); } // extract args.push_back(commandLine.substr(i, e - i)); i = e + 1; } // next argument i = commandLine.find_first_not_of(" \t", i); } // service name goes first myArgv.push_back(argv[0]); // get pointers for (size_t j = 0; j < args.size(); ++j) { myArgv.push_back(args[j].c_str()); } // adjust argc/argv argc = (DWORD)myArgv.size(); argv = &myArgv[0]; } } m_commandLine = commandLine; try { // invoke daemon function m_daemonResult = m_daemonFunc(static_cast(argc), argv); } catch (XArchDaemonRunFailed& e) { setStatusError(e.m_result); m_daemonResult = -1; } catch (...) { setStatusError(1); m_daemonResult = -1; } // clean up ARCH->closeCondVar(m_serviceCondVar); ARCH->closeMutex(m_serviceMutex); // we're going to exit now, so set status to stopped m_serviceState = SERVICE_STOPPED; setStatus(m_serviceState, 0, 10000); } void WINAPI ArchDaemonWindows::serviceMainEntry(DWORD argc, LPTSTR* argv) { s_daemon->serviceMain(argc, argv); } void ArchDaemonWindows::serviceHandler(DWORD ctrl) { assert(m_serviceMutex != NULL); assert(m_serviceCondVar != NULL); ARCH->lockMutex(m_serviceMutex); // ignore request if service is already stopped if (s_daemon == NULL || m_serviceState == SERVICE_STOPPED) { if (s_daemon != NULL) { setStatus(m_serviceState); } ARCH->unlockMutex(m_serviceMutex); return; } switch (ctrl) { case SERVICE_CONTROL_PAUSE: m_serviceState = SERVICE_PAUSE_PENDING; setStatus(m_serviceState, 0, 5000); PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0); while (isRunState(m_serviceState)) { ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0); } break; case SERVICE_CONTROL_CONTINUE: // FIXME -- maybe should flush quit messages from queue m_serviceState = SERVICE_CONTINUE_PENDING; setStatus(m_serviceState, 0, 5000); ARCH->broadcastCondVar(m_serviceCondVar); break; case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: m_serviceState = SERVICE_STOP_PENDING; setStatus(m_serviceState, 0, 5000); PostThreadMessage(m_daemonThreadID, m_quitMessage, 0, 0); ARCH->broadcastCondVar(m_serviceCondVar); while (isRunState(m_serviceState)) { ARCH->waitCondVar(m_serviceCondVar, m_serviceMutex, -1.0); } break; default: // unknown service command // fall through case SERVICE_CONTROL_INTERROGATE: setStatus(m_serviceState); break; } ARCH->unlockMutex(m_serviceMutex); } void WINAPI ArchDaemonWindows::serviceHandlerEntry(DWORD ctrl) { s_daemon->serviceHandler(ctrl); } void ArchDaemonWindows::start(const char* name) { // open service manager SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); if (mgr == NULL) { throw XArchDaemonFailed(new XArchEvalWindows()); } // open the service SC_HANDLE service = OpenService( mgr, name, SERVICE_START); if (service == NULL) { CloseServiceHandle(mgr); throw XArchDaemonFailed(new XArchEvalWindows()); } // start the service if (!StartService(service, 0, NULL)) { throw XArchDaemonFailed(new XArchEvalWindows()); } } void ArchDaemonWindows::stop(const char* name) { // open service manager SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); if (mgr == NULL) { throw XArchDaemonFailed(new XArchEvalWindows()); } // open the service SC_HANDLE service = OpenService( mgr, name, SERVICE_STOP | SERVICE_QUERY_STATUS); if (service == NULL) { CloseServiceHandle(mgr); throw XArchDaemonFailed(new XArchEvalWindows()); } // ask the service to stop, asynchronously SERVICE_STATUS ss; if (!ControlService(service, SERVICE_CONTROL_STOP, &ss)) { DWORD dwErrCode = GetLastError(); if (dwErrCode != ERROR_SERVICE_NOT_ACTIVE) { throw XArchDaemonFailed(new XArchEvalWindows()); } } } void ArchDaemonWindows::installDaemon() { // install default daemon if not already installed. if (!isDaemonInstalled(DEFAULT_DAEMON_NAME)) { char path[MAX_PATH]; GetModuleFileName(ArchMiscWindows::instanceWin32(), path, MAX_PATH); // wrap in quotes so a malicious user can't start \Program.exe as admin. std::stringstream ss; ss << '"'; ss << path; ss << '"'; installDaemon(DEFAULT_DAEMON_NAME, DEFAULT_DAEMON_INFO, ss.str().c_str(), "", ""); } start(DEFAULT_DAEMON_NAME); } void ArchDaemonWindows::uninstallDaemon() { // remove legacy services if installed. if (isDaemonInstalled(LEGACY_SERVER_DAEMON_NAME)) { uninstallDaemon(LEGACY_SERVER_DAEMON_NAME); } if (isDaemonInstalled(LEGACY_CLIENT_DAEMON_NAME)) { uninstallDaemon(LEGACY_CLIENT_DAEMON_NAME); } // remove new service if installed. if (isDaemonInstalled(DEFAULT_DAEMON_NAME)) { uninstallDaemon(DEFAULT_DAEMON_NAME); } } synergy-1.8.8-stable/src/lib/arch/win32/ArchDaemonWindows.h000066400000000000000000000107641305627404700234610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchDaemon.h" #include "arch/IArchMultithread.h" #include "common/stdstring.h" #define WIN32_LEAN_AND_MEAN #include #include #define ARCH_DAEMON ArchDaemonWindows //! Win32 implementation of IArchDaemon class ArchDaemonWindows : public IArchDaemon { public: typedef int (*RunFunc)(void); ArchDaemonWindows(); virtual ~ArchDaemonWindows(); //! Run the daemon /*! When the client calls \c daemonize(), the \c DaemonFunc should call this function after initialization and argument parsing to perform the daemon processing. The \c runFunc should perform the daemon's main loop, calling \c daemonRunning(true) when it enters the main loop (i.e. after initialization) and \c daemonRunning(false) when it leaves the main loop. The \c runFunc is called in a new thread and when the daemon must exit the main loop due to some external control the getDaemonQuitMessage() is posted to the thread. This function returns what \c runFunc returns. \c runFunc should call \c daemonFailed() if the daemon fails. */ static int runDaemon(RunFunc runFunc); //! Indicate daemon is in main loop /*! The \c runFunc passed to \c runDaemon() should call this function to indicate when it has entered (\c running is \c true) or exited (\c running is \c false) the main loop. */ static void daemonRunning(bool running); //! Indicate failure of running daemon /*! The \c runFunc passed to \c runDaemon() should call this function to indicate failure. \c result is returned by \c daemonize(). */ static void daemonFailed(int result); //! Get daemon quit message /*! The windows NT daemon tells daemon thread to exit by posting this message to it. The thread must, of course, have a message queue for this to work. */ static UINT getDaemonQuitMessage(); // IArchDaemon overrides virtual void installDaemon(const char* name, const char* description, const char* pathname, const char* commandLine, const char* dependencies); virtual void uninstallDaemon(const char* name); virtual void installDaemon(); virtual void uninstallDaemon(); virtual int daemonize(const char* name, DaemonFunc func); virtual bool canInstallDaemon(const char* name); virtual bool isDaemonInstalled(const char* name); std::string commandLine() const { return m_commandLine; } private: static HKEY openNTServicesKey(); int doRunDaemon(RunFunc runFunc); void doDaemonRunning(bool running); UINT doGetDaemonQuitMessage(); static void setStatus(DWORD state); static void setStatus(DWORD state, DWORD step, DWORD waitHint); static void setStatusError(DWORD error); static bool isRunState(DWORD state); void serviceMain(DWORD, LPTSTR*); static void WINAPI serviceMainEntry(DWORD, LPTSTR*); void serviceHandler(DWORD ctrl); static void WINAPI serviceHandlerEntry(DWORD ctrl); void start(const char* name); void stop(const char* name); private: class XArchDaemonRunFailed { public: XArchDaemonRunFailed(int result) : m_result(result) { } public: int m_result; }; private: static ArchDaemonWindows* s_daemon; ArchMutex m_serviceMutex; ArchCond m_serviceCondVar; DWORD m_serviceState; bool m_serviceHandlerWaiting; bool m_serviceRunning; DWORD m_daemonThreadID; DaemonFunc m_daemonFunc; int m_daemonResult; SERVICE_STATUS_HANDLE m_statusHandle; UINT m_quitMessage; std::string m_commandLine; }; #define DEFAULT_DAEMON_NAME _T("Synergy") #define DEFAULT_DAEMON_INFO _T("Manages the Synergy foreground processes.") #define LEGACY_SERVER_DAEMON_NAME _T("Synergy Server") #define LEGACY_CLIENT_DAEMON_NAME _T("Synergy Client") static const TCHAR* const g_daemonKeyPath[] = { _T("SOFTWARE"), _T("The Synergy Project"), _T("Synergy"), _T("Service"), NULL }; synergy-1.8.8-stable/src/lib/arch/win32/ArchFileWindows.cpp000066400000000000000000000103571305627404700234660ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchFileWindows.h" #define WIN32_LEAN_AND_MEAN #include #include #include #include // // ArchFileWindows // ArchFileWindows::ArchFileWindows() { // do nothing } ArchFileWindows::~ArchFileWindows() { // do nothing } const char* ArchFileWindows::getBasename(const char* pathname) { if (pathname == NULL) { return NULL; } // check for last slash const char* basename = strrchr(pathname, '/'); if (basename != NULL) { ++basename; } else { basename = pathname; } // check for last backslash const char* basename2 = strrchr(pathname, '\\'); if (basename2 != NULL && basename2 > basename) { basename = basename2 + 1; } return basename; } std::string ArchFileWindows::getUserDirectory() { // try %HOMEPATH% TCHAR dir[MAX_PATH]; DWORD size = sizeof(dir) / sizeof(TCHAR); DWORD result = GetEnvironmentVariable(_T("HOMEPATH"), dir, size); if (result != 0 && result <= size) { // sanity check -- if dir doesn't appear to start with a // drive letter and isn't a UNC name then don't use it // FIXME -- allow UNC names if (dir[0] != '\0' && (dir[1] == ':' || ((dir[0] == '\\' || dir[0] == '/') && (dir[1] == '\\' || dir[1] == '/')))) { return dir; } } // get the location of the personal files. that's as close to // a home directory as we're likely to find. ITEMIDLIST* idl; if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &idl))) { TCHAR* path = NULL; if (SHGetPathFromIDList(idl, dir)) { DWORD attr = GetFileAttributes(dir); if (attr != 0xffffffff && (attr & FILE_ATTRIBUTE_DIRECTORY) != 0) path = dir; } IMalloc* shalloc; if (SUCCEEDED(SHGetMalloc(&shalloc))) { shalloc->Free(idl); shalloc->Release(); } if (path != NULL) { return path; } } // use root of C drive as a default return "C:"; } std::string ArchFileWindows::getSystemDirectory() { // get windows directory char dir[MAX_PATH]; if (GetWindowsDirectory(dir, sizeof(dir)) != 0) { return dir; } else { // can't get it. use C:\ as a default. return "C:"; } } std::string ArchFileWindows::getInstalledDirectory() { char fileNameBuffer[MAX_PATH]; GetModuleFileName(NULL, fileNameBuffer, MAX_PATH); std::string fileName(fileNameBuffer); size_t lastSlash = fileName.find_last_of("\\"); fileName = fileName.substr(0, lastSlash); return fileName; } std::string ArchFileWindows::getLogDirectory() { return getInstalledDirectory(); } std::string ArchFileWindows::getPluginDirectory() { if (!m_pluginDirectory.empty()) { return m_pluginDirectory; } std::string dir = getProfileDirectory(); dir.append("\\Plugins"); return dir; } std::string ArchFileWindows::getProfileDirectory() { String dir; if (!m_profileDirectory.empty()) { dir = m_profileDirectory; } else { TCHAR result[MAX_PATH]; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, result))) { dir = result; } else { dir = getUserDirectory(); } } // HACK: append program name, this seems wrong. dir.append("\\Synergy"); return dir; } std::string ArchFileWindows::concatPath(const std::string& prefix, const std::string& suffix) { std::string path; path.reserve(prefix.size() + 1 + suffix.size()); path += prefix; if (path.size() == 0 || (path[path.size() - 1] != '\\' && path[path.size() - 1] != '/')) { path += '\\'; } path += suffix; return path; } void ArchFileWindows::setProfileDirectory(const String& s) { m_profileDirectory = s; } void ArchFileWindows::setPluginDirectory(const String& s) { m_pluginDirectory = s; } synergy-1.8.8-stable/src/lib/arch/win32/ArchFileWindows.h000066400000000000000000000030271305627404700231270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchFile.h" #define ARCH_FILE ArchFileWindows //! Win32 implementation of IArchFile class ArchFileWindows : public IArchFile { public: ArchFileWindows(); virtual ~ArchFileWindows(); // IArchFile overrides virtual const char* getBasename(const char* pathname); virtual std::string getUserDirectory(); virtual std::string getSystemDirectory(); virtual std::string getInstalledDirectory(); virtual std::string getLogDirectory(); virtual std::string getPluginDirectory(); virtual std::string getProfileDirectory(); virtual std::string concatPath(const std::string& prefix, const std::string& suffix); virtual void setProfileDirectory(const String& s); virtual void setPluginDirectory(const String& s); private: String m_profileDirectory; String m_pluginDirectory; }; synergy-1.8.8-stable/src/lib/arch/win32/ArchInternetWindows.cpp000066400000000000000000000110111305627404700243630ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchInternetWindows.h" #include "arch/win32/XArchWindows.h" #include "arch/Arch.h" #include "common/Version.h" #include #include #include struct WinINetUrl { String m_scheme; String m_host; String m_path; INTERNET_PORT m_port; DWORD m_flags; }; class WinINetRequest { public: WinINetRequest(const String& url); ~WinINetRequest(); String send(); void openSession(); void connect(); void openRequest(); private: HINTERNET m_session; HINTERNET m_connect; HINTERNET m_request; WinINetUrl m_url; bool m_used; }; // // ArchInternetWindows // String ArchInternetWindows::get(const String& url) { WinINetRequest request(url); return request.send(); } String ArchInternetWindows::urlEncode(const String& url) { TCHAR buffer[1024]; DWORD bufferSize = sizeof(buffer); if (UrlEscape(url.c_str(), buffer, &bufferSize, URL_ESCAPE_UNSAFE) != S_OK) { throw XArch(new XArchEvalWindows()); } String result(buffer); // the win32 url encoding funcitons are pretty useless (to us) and only // escape "unsafe" chars, but not + or =, so we need to replace these // manually (and probably many other chars). synergy::string::findReplaceAll(result, "+", "%2B"); synergy::string::findReplaceAll(result, "=", "%3D"); return result; } // // WinINetRequest // static WinINetUrl parseUrl(const String& url); WinINetRequest::WinINetRequest(const String& url) : m_session(NULL), m_connect(NULL), m_request(NULL), m_used(false), m_url(parseUrl(url)) { } WinINetRequest::~WinINetRequest() { if (m_request != NULL) { InternetCloseHandle(m_request); } if (m_connect != NULL) { InternetCloseHandle(m_connect); } if (m_session != NULL) { InternetCloseHandle(m_session); } } String WinINetRequest::send() { if (m_used) { throw XArch("class is one time use."); } m_used = true; openSession(); connect(); openRequest(); String headers("Content-Type: text/html"); if (!HttpSendRequest(m_request, headers.c_str(), (DWORD)headers.length(), NULL, NULL)) { throw XArch(new XArchEvalWindows()); } std::stringstream result; CHAR buffer[1025]; DWORD read = 0; while (InternetReadFile(m_request, buffer, sizeof(buffer) - 1, &read) && (read != 0)) { buffer[read] = 0; result << buffer; read = 0; } return result.str(); } void WinINetRequest::openSession() { std::stringstream userAgent; userAgent << "Synergy "; userAgent << kVersion; m_session = InternetOpen( userAgent.str().c_str(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, NULL); if (m_session == NULL) { throw XArch(new XArchEvalWindows()); } } void WinINetRequest::connect() { m_connect = InternetConnect( m_session, m_url.m_host.c_str(), m_url.m_port, NULL, NULL, INTERNET_SERVICE_HTTP, NULL, NULL); if (m_connect == NULL) { throw XArch(new XArchEvalWindows()); } } void WinINetRequest::openRequest() { m_request = HttpOpenRequest( m_connect, "GET", m_url.m_path.c_str(), HTTP_VERSION, NULL, NULL, m_url.m_flags, NULL); if (m_request == NULL) { throw XArch(new XArchEvalWindows()); } } // nb: i tried to use InternetCrackUrl here, but couldn't quite get that to // work. here's some (less robust) code to split the url into components. // this works fine with simple urls, but doesn't consider the full url spec. static WinINetUrl parseUrl(const String& url) { WinINetUrl parsed; size_t schemeEnd = url.find("://"); size_t hostEnd = url.find('/', schemeEnd + 3); parsed.m_scheme = url.substr(0, schemeEnd); parsed.m_host = url.substr(schemeEnd + 3, hostEnd - (schemeEnd + 3)); parsed.m_path = url.substr(hostEnd); parsed.m_port = INTERNET_DEFAULT_HTTP_PORT; parsed.m_flags = 0; if (parsed.m_scheme.find("https") != String::npos) { parsed.m_port = INTERNET_DEFAULT_HTTPS_PORT; parsed.m_flags = INTERNET_FLAG_SECURE; } return parsed; } synergy-1.8.8-stable/src/lib/arch/win32/ArchInternetWindows.h000066400000000000000000000015711305627404700240420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #define ARCH_INTERNET ArchInternetWindows #include "base/String.h" class ArchInternetWindows { public: String get(const String& url); String urlEncode(const String& url); }; synergy-1.8.8-stable/src/lib/arch/win32/ArchLogWindows.cpp000066400000000000000000000041431305627404700233240ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchLogWindows.h" #include "arch/win32/ArchMiscWindows.h" #include // // ArchLogWindows // ArchLogWindows::ArchLogWindows() : m_eventLog(NULL) { // do nothing } ArchLogWindows::~ArchLogWindows() { // do nothing } void ArchLogWindows::openLog(const char* name) { if (m_eventLog == NULL) { m_eventLog = RegisterEventSource(NULL, name); } } void ArchLogWindows::closeLog() { if (m_eventLog != NULL) { DeregisterEventSource(m_eventLog); m_eventLog = NULL; } } void ArchLogWindows::showLog(bool) { // do nothing } void ArchLogWindows::writeLog(ELevel level, const char* msg) { if (m_eventLog != NULL) { // convert priority WORD type; switch (level) { case kERROR: type = EVENTLOG_ERROR_TYPE; break; case kWARNING: type = EVENTLOG_WARNING_TYPE; break; default: type = EVENTLOG_INFORMATION_TYPE; break; } // log it // FIXME -- win32 wants to use a message table to look up event // strings. log messages aren't organized that way so we'll // just dump our string into the raw data section of the event // so users can at least see the message. note that we use our // level as the event category. ReportEvent(m_eventLog, type, static_cast(level), 0, // event ID NULL, 0, (DWORD)strlen(msg) + 1, // raw data size NULL, const_cast(msg));// raw data } } synergy-1.8.8-stable/src/lib/arch/win32/ArchLogWindows.h000066400000000000000000000022671305627404700227760ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchLog.h" #define WIN32_LEAN_AND_MEAN #include #define ARCH_LOG ArchLogWindows //! Win32 implementation of IArchLog class ArchLogWindows : public IArchLog { public: ArchLogWindows(); virtual ~ArchLogWindows(); // IArchLog overrides virtual void openLog(const char* name); virtual void closeLog(); virtual void showLog(bool showIfEmpty); virtual void writeLog(ELevel, const char*); private: HANDLE m_eventLog; }; synergy-1.8.8-stable/src/lib/arch/win32/ArchMiscWindows.cpp000066400000000000000000000260371305627404700235040ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchMiscWindows.h" #include "arch/win32/ArchDaemonWindows.h" #include "base/Log.h" #include "common/Version.h" #include #pragma warning(disable: 4099) #include #pragma warning(default: 4099) // parent process name for services in Vista #define SERVICE_LAUNCHER "services.exe" #ifndef ES_SYSTEM_REQUIRED #define ES_SYSTEM_REQUIRED ((DWORD)0x00000001) #endif #ifndef ES_DISPLAY_REQUIRED #define ES_DISPLAY_REQUIRED ((DWORD)0x00000002) #endif #ifndef ES_CONTINUOUS #define ES_CONTINUOUS ((DWORD)0x80000000) #endif typedef DWORD EXECUTION_STATE; // // ArchMiscWindows // ArchMiscWindows::Dialogs* ArchMiscWindows::s_dialogs = NULL; DWORD ArchMiscWindows::s_busyState = 0; ArchMiscWindows::STES_t ArchMiscWindows::s_stes = NULL; HICON ArchMiscWindows::s_largeIcon = NULL; HICON ArchMiscWindows::s_smallIcon = NULL; HINSTANCE ArchMiscWindows::s_instanceWin32 = NULL; void ArchMiscWindows::cleanup() { delete s_dialogs; } void ArchMiscWindows::init() { // stop windows system error dialogs from showing. SetErrorMode(SEM_FAILCRITICALERRORS); s_dialogs = new Dialogs; } void ArchMiscWindows::setIcons(HICON largeIcon, HICON smallIcon) { s_largeIcon = largeIcon; s_smallIcon = smallIcon; } void ArchMiscWindows::getIcons(HICON& largeIcon, HICON& smallIcon) { largeIcon = s_largeIcon; smallIcon = s_smallIcon; } int ArchMiscWindows::runDaemon(RunFunc runFunc) { return ArchDaemonWindows::runDaemon(runFunc); } void ArchMiscWindows::daemonRunning(bool running) { ArchDaemonWindows::daemonRunning(running); } void ArchMiscWindows::daemonFailed(int result) { ArchDaemonWindows::daemonFailed(result); } UINT ArchMiscWindows::getDaemonQuitMessage() { return ArchDaemonWindows::getDaemonQuitMessage(); } HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR* keyName) { return openKey(key, keyName, false); } HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR* const* keyNames) { return openKey(key, keyNames, false); } HKEY ArchMiscWindows::addKey(HKEY key, const TCHAR* keyName) { return openKey(key, keyName, true); } HKEY ArchMiscWindows::addKey(HKEY key, const TCHAR* const* keyNames) { return openKey(key, keyNames, true); } HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR* keyName, bool create) { // ignore if parent is NULL if (key == NULL) { return NULL; } // open next key HKEY newKey; LONG result = RegOpenKeyEx(key, keyName, 0, KEY_WRITE | KEY_QUERY_VALUE, &newKey); if (result != ERROR_SUCCESS && create) { DWORD disp; result = RegCreateKeyEx(key, keyName, 0, TEXT(""), 0, KEY_WRITE | KEY_QUERY_VALUE, NULL, &newKey, &disp); } if (result != ERROR_SUCCESS) { RegCloseKey(key); return NULL; } // switch to new key RegCloseKey(key); return newKey; } HKEY ArchMiscWindows::openKey(HKEY key, const TCHAR* const* keyNames, bool create) { for (size_t i = 0; key != NULL && keyNames[i] != NULL; ++i) { // open next key key = openKey(key, keyNames[i], create); } return key; } void ArchMiscWindows::closeKey(HKEY key) { assert(key != NULL); if (key==NULL) return; RegCloseKey(key); } void ArchMiscWindows::deleteKey(HKEY key, const TCHAR* name) { assert(key != NULL); assert(name != NULL); if (key==NULL || name==NULL) return; RegDeleteKey(key, name); } void ArchMiscWindows::deleteValue(HKEY key, const TCHAR* name) { assert(key != NULL); assert(name != NULL); if (key==NULL || name==NULL) return; RegDeleteValue(key, name); } bool ArchMiscWindows::hasValue(HKEY key, const TCHAR* name) { DWORD type; LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL); return (result == ERROR_SUCCESS && (type == REG_DWORD || type == REG_SZ)); } ArchMiscWindows::EValueType ArchMiscWindows::typeOfValue(HKEY key, const TCHAR* name) { DWORD type; LONG result = RegQueryValueEx(key, name, 0, &type, NULL, NULL); if (result != ERROR_SUCCESS) { return kNO_VALUE; } switch (type) { case REG_DWORD: return kUINT; case REG_SZ: return kSTRING; case REG_BINARY: return kBINARY; default: return kUNKNOWN; } } void ArchMiscWindows::setValue(HKEY key, const TCHAR* name, const std::string& value) { assert(key != NULL); if (key == NULL) { // TODO: throw exception return; } RegSetValueEx(key, name, 0, REG_SZ, reinterpret_cast(value.c_str()), (DWORD)value.size() + 1); } void ArchMiscWindows::setValue(HKEY key, const TCHAR* name, DWORD value) { assert(key != NULL); if (key == NULL) { // TODO: throw exception return; } RegSetValueEx(key, name, 0, REG_DWORD, reinterpret_cast(&value), sizeof(DWORD)); } void ArchMiscWindows::setValueBinary(HKEY key, const TCHAR* name, const std::string& value) { assert(key != NULL); assert(name != NULL); if (key == NULL || name == NULL) { // TODO: throw exception return; } RegSetValueEx(key, name, 0, REG_BINARY, reinterpret_cast(value.data()), (DWORD)value.size()); } std::string ArchMiscWindows::readBinaryOrString(HKEY key, const TCHAR* name, DWORD type) { // get the size of the string DWORD actualType; DWORD size = 0; LONG result = RegQueryValueEx(key, name, 0, &actualType, NULL, &size); if (result != ERROR_SUCCESS || actualType != type) { return std::string(); } // if zero size then return empty string if (size == 0) { return std::string(); } // allocate space char* buffer = new char[size]; // read it result = RegQueryValueEx(key, name, 0, &actualType, reinterpret_cast(buffer), &size); if (result != ERROR_SUCCESS || actualType != type) { delete[] buffer; return std::string(); } // clean up and return value if (type == REG_SZ && buffer[size - 1] == '\0') { // don't include terminating nul; std::string will add one. --size; } std::string value(buffer, size); delete[] buffer; return value; } std::string ArchMiscWindows::readValueString(HKEY key, const TCHAR* name) { return readBinaryOrString(key, name, REG_SZ); } std::string ArchMiscWindows::readValueBinary(HKEY key, const TCHAR* name) { return readBinaryOrString(key, name, REG_BINARY); } DWORD ArchMiscWindows::readValueInt(HKEY key, const TCHAR* name) { DWORD type; DWORD value; DWORD size = sizeof(value); LONG result = RegQueryValueEx(key, name, 0, &type, reinterpret_cast(&value), &size); if (result != ERROR_SUCCESS || type != REG_DWORD) { return 0; } return value; } void ArchMiscWindows::addDialog(HWND hwnd) { s_dialogs->insert(hwnd); } void ArchMiscWindows::removeDialog(HWND hwnd) { s_dialogs->erase(hwnd); } bool ArchMiscWindows::processDialog(MSG* msg) { for (Dialogs::const_iterator index = s_dialogs->begin(); index != s_dialogs->end(); ++index) { if (IsDialogMessage(*index, msg)) { return true; } } return false; } void ArchMiscWindows::addBusyState(DWORD busyModes) { s_busyState |= busyModes; setThreadExecutionState(s_busyState); } void ArchMiscWindows::removeBusyState(DWORD busyModes) { s_busyState &= ~busyModes; setThreadExecutionState(s_busyState); } void ArchMiscWindows::setThreadExecutionState(DWORD busyModes) { // look up function dynamically so we work on older systems if (s_stes == NULL) { HINSTANCE kernel = LoadLibrary("kernel32.dll"); if (kernel != NULL) { s_stes = reinterpret_cast(GetProcAddress(kernel, "SetThreadExecutionState")); } if (s_stes == NULL) { s_stes = &ArchMiscWindows::dummySetThreadExecutionState; } } // convert to STES form EXECUTION_STATE state = 0; if ((busyModes & kSYSTEM) != 0) { state |= ES_SYSTEM_REQUIRED; } if ((busyModes & kDISPLAY) != 0) { state |= ES_DISPLAY_REQUIRED; } if (state != 0) { state |= ES_CONTINUOUS; } // do it s_stes(state); } DWORD ArchMiscWindows::dummySetThreadExecutionState(DWORD) { // do nothing return 0; } void ArchMiscWindows::wakeupDisplay() { // We can't use ::setThreadExecutionState here because it sets // ES_CONTINUOUS, which we don't want. if (s_stes == NULL) { HINSTANCE kernel = LoadLibrary("kernel32.dll"); if (kernel != NULL) { s_stes = reinterpret_cast(GetProcAddress(kernel, "SetThreadExecutionState")); } if (s_stes == NULL) { s_stes = &ArchMiscWindows::dummySetThreadExecutionState; } } s_stes(ES_DISPLAY_REQUIRED); // restore the original execution states setThreadExecutionState(s_busyState); } bool ArchMiscWindows::wasLaunchedAsService() { String name; if (!getParentProcessName(name)) { LOG((CLOG_ERR "cannot determine if process was launched as service")); return false; } return (name == SERVICE_LAUNCHER); } bool ArchMiscWindows::getParentProcessName(String &name) { PROCESSENTRY32 parentEntry; if (!getParentProcessEntry(parentEntry)){ LOG((CLOG_ERR "could not get entry for parent process")); return false; } name = parentEntry.szExeFile; return true; } BOOL WINAPI ArchMiscWindows::getSelfProcessEntry(PROCESSENTRY32& entry) { // get entry from current PID return getProcessEntry(entry, GetCurrentProcessId()); } BOOL WINAPI ArchMiscWindows::getParentProcessEntry(PROCESSENTRY32& entry) { // get the current process, so we can get parent PID PROCESSENTRY32 selfEntry; if (!getSelfProcessEntry(selfEntry)) { return FALSE; } // get entry from parent PID return getProcessEntry(entry, selfEntry.th32ParentProcessID); } BOOL WINAPI ArchMiscWindows::getProcessEntry(PROCESSENTRY32& entry, DWORD processID) { // first we need to take a snapshot of the running processes HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snapshot == INVALID_HANDLE_VALUE) { LOG((CLOG_ERR "could not get process snapshot (error: %i)", GetLastError())); return FALSE; } entry.dwSize = sizeof(PROCESSENTRY32); // get the first process, and if we can't do that then it's // unlikely we can go any further BOOL gotEntry = Process32First(snapshot, &entry); if (!gotEntry) { LOG((CLOG_ERR "could not get first process entry (error: %i)", GetLastError())); return FALSE; } while(gotEntry) { if (entry.th32ProcessID == processID) { // found current process return TRUE; } // now move on to the next entry (when we reach end, loop will stop) gotEntry = Process32Next(snapshot, &entry); } return FALSE; } HINSTANCE ArchMiscWindows::instanceWin32() { assert(s_instanceWin32 != NULL); return s_instanceWin32; } void ArchMiscWindows::setInstanceWin32(HINSTANCE instance) { assert(instance != NULL); s_instanceWin32 = instance; }synergy-1.8.8-stable/src/lib/arch/win32/ArchMiscWindows.h000066400000000000000000000125611305627404700231460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" #include "common/stdstring.h" #include "common/stdset.h" #include "base/String.h" #define WIN32_LEAN_AND_MEAN #include #include //! Miscellaneous win32 functions. class ArchMiscWindows { public: enum EValueType { kUNKNOWN, kNO_VALUE, kUINT, kSTRING, kBINARY }; enum EBusyModes { kIDLE = 0x0000, kSYSTEM = 0x0001, kDISPLAY = 0x0002 }; typedef int (*RunFunc)(void); //! Initialize static void init(); //! Delete memory static void cleanup(); //! Set the application icons /*! Set the application icons. */ static void setIcons(HICON largeIcon, HICON smallIcon); //! Get the application icons /*! Get the application icons. */ static void getIcons(HICON& largeIcon, HICON& smallIcon); //! Run the daemon /*! Delegates to ArchDaemonWindows. */ static int runDaemon(RunFunc runFunc); //! Indicate daemon is in main loop /*! Delegates to ArchDaemonWindows. */ static void daemonRunning(bool running); //! Indicate failure of running daemon /*! Delegates to ArchDaemonWindows. */ static void daemonFailed(int result); //! Get daemon quit message /*! Delegates to ArchDaemonWindows. */ static UINT getDaemonQuitMessage(); //! Open and return a registry key, closing the parent key static HKEY openKey(HKEY parent, const TCHAR* child); //! Open and return a registry key, closing the parent key static HKEY openKey(HKEY parent, const TCHAR* const* keyPath); //! Open/create and return a registry key, closing the parent key static HKEY addKey(HKEY parent, const TCHAR* child); //! Open/create and return a registry key, closing the parent key static HKEY addKey(HKEY parent, const TCHAR* const* keyPath); //! Close a key static void closeKey(HKEY); //! Delete a key (which should have no subkeys) static void deleteKey(HKEY parent, const TCHAR* name); //! Delete a value static void deleteValue(HKEY parent, const TCHAR* name); //! Test if a value exists static bool hasValue(HKEY key, const TCHAR* name); //! Get type of value static EValueType typeOfValue(HKEY key, const TCHAR* name); //! Set a string value in the registry static void setValue(HKEY key, const TCHAR* name, const std::string& value); //! Set a DWORD value in the registry static void setValue(HKEY key, const TCHAR* name, DWORD value); //! Set a BINARY value in the registry /*! Sets the \p name value of \p key to \p value.data(). */ static void setValueBinary(HKEY key, const TCHAR* name, const std::string& value); //! Read a string value from the registry static std::string readValueString(HKEY, const TCHAR* name); //! Read a DWORD value from the registry static DWORD readValueInt(HKEY, const TCHAR* name); //! Read a BINARY value from the registry static std::string readValueBinary(HKEY, const TCHAR* name); //! Add a dialog static void addDialog(HWND); //! Remove a dialog static void removeDialog(HWND); //! Process dialog message /*! Checks if the message is destined for a dialog. If so the message is passed to the dialog and returns true, otherwise returns false. */ static bool processDialog(MSG*); //! Disable power saving static void addBusyState(DWORD busyModes); //! Enable power saving static void removeBusyState(DWORD busyModes); //! Briefly interrupt power saving static void wakeupDisplay(); //! Returns true if this process was launched via NT service host. static bool wasLaunchedAsService(); //! Returns true if we got the parent process name. static bool getParentProcessName(String &name); static HINSTANCE instanceWin32(); static void setInstanceWin32(HINSTANCE instance); static BOOL WINAPI getProcessEntry(PROCESSENTRY32& entry, DWORD processID); static BOOL WINAPI getSelfProcessEntry(PROCESSENTRY32& entry); static BOOL WINAPI getParentProcessEntry(PROCESSENTRY32& entry); private: //! Open and return a registry key, closing the parent key static HKEY openKey(HKEY parent, const TCHAR* child, bool create); //! Open and return a registry key, closing the parent key static HKEY openKey(HKEY parent, const TCHAR* const* keyPath, bool create); //! Read a string value from the registry static std::string readBinaryOrString(HKEY, const TCHAR* name, DWORD type); //! Set thread busy state static void setThreadExecutionState(DWORD); static DWORD WINAPI dummySetThreadExecutionState(DWORD); private: typedef std::set Dialogs; typedef DWORD (WINAPI *STES_t)(DWORD); static Dialogs* s_dialogs; static DWORD s_busyState; static STES_t s_stes; static HICON s_largeIcon; static HICON s_smallIcon; static HINSTANCE s_instanceWin32; }; synergy-1.8.8-stable/src/lib/arch/win32/ArchMultithreadWindows.cpp000066400000000000000000000411541305627404700250700ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if defined(_MSC_VER) && !defined(_MT) # error multithreading compile option is required #endif #include "arch/win32/ArchMultithreadWindows.h" #include "arch/Arch.h" #include "arch/XArch.h" #include // // note -- implementation of condition variable taken from: // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html // titled "Strategies for Implementing POSIX Condition Variables // on Win32." it also provides an implementation that doesn't // suffer from the incorrectness problem described in our // corresponding header but it is slower, still unfair, and // can cause busy waiting. // // // ArchThreadImpl // class ArchThreadImpl { public: ArchThreadImpl(); ~ArchThreadImpl(); public: int m_refCount; HANDLE m_thread; DWORD m_id; IArchMultithread::ThreadFunc m_func; void* m_userData; HANDLE m_cancel; bool m_cancelling; HANDLE m_exit; void* m_result; void* m_networkData; }; ArchThreadImpl::ArchThreadImpl() : m_refCount(1), m_thread(NULL), m_id(0), m_func(NULL), m_userData(NULL), m_cancelling(false), m_result(NULL), m_networkData(NULL) { m_exit = CreateEvent(NULL, TRUE, FALSE, NULL); m_cancel = CreateEvent(NULL, TRUE, FALSE, NULL); } ArchThreadImpl::~ArchThreadImpl() { CloseHandle(m_exit); CloseHandle(m_cancel); } // // ArchMultithreadWindows // ArchMultithreadWindows* ArchMultithreadWindows::s_instance = NULL; ArchMultithreadWindows::ArchMultithreadWindows() { assert(s_instance == NULL); s_instance = this; // no signal handlers for (size_t i = 0; i < kNUM_SIGNALS; ++i) { m_signalFunc[i] = NULL; m_signalUserData[i] = NULL; } // create mutex for thread list m_threadMutex = newMutex(); // create thread for calling (main) thread and add it to our // list. no need to lock the mutex since we're the only thread. m_mainThread = new ArchThreadImpl; m_mainThread->m_thread = NULL; m_mainThread->m_id = GetCurrentThreadId(); insert(m_mainThread); } ArchMultithreadWindows::~ArchMultithreadWindows() { s_instance = NULL; // clean up thread list for (ThreadList::iterator index = m_threadList.begin(); index != m_threadList.end(); ++index) { delete *index; } // done with mutex delete m_threadMutex; } void ArchMultithreadWindows::setNetworkDataForCurrentThread(void* data) { lockMutex(m_threadMutex); ArchThreadImpl* thread = findNoRef(GetCurrentThreadId()); thread->m_networkData = data; unlockMutex(m_threadMutex); } void* ArchMultithreadWindows::getNetworkDataForThread(ArchThread thread) { lockMutex(m_threadMutex); void* data = thread->m_networkData; unlockMutex(m_threadMutex); return data; } HANDLE ArchMultithreadWindows::getCancelEventForCurrentThread() { lockMutex(m_threadMutex); ArchThreadImpl* thread = findNoRef(GetCurrentThreadId()); unlockMutex(m_threadMutex); return thread->m_cancel; } ArchMultithreadWindows* ArchMultithreadWindows::getInstance() { return s_instance; } ArchCond ArchMultithreadWindows::newCondVar() { ArchCondImpl* cond = new ArchCondImpl; cond->m_events[ArchCondImpl::kSignal] = CreateEvent(NULL, FALSE, FALSE, NULL); cond->m_events[ArchCondImpl::kBroadcast] = CreateEvent(NULL, TRUE, FALSE, NULL); cond->m_waitCountMutex = newMutex(); cond->m_waitCount = 0; return cond; } void ArchMultithreadWindows::closeCondVar(ArchCond cond) { CloseHandle(cond->m_events[ArchCondImpl::kSignal]); CloseHandle(cond->m_events[ArchCondImpl::kBroadcast]); closeMutex(cond->m_waitCountMutex); delete cond; } void ArchMultithreadWindows::signalCondVar(ArchCond cond) { // is anybody waiting? lockMutex(cond->m_waitCountMutex); const bool hasWaiter = (cond->m_waitCount > 0); unlockMutex(cond->m_waitCountMutex); // wake one thread if anybody is waiting if (hasWaiter) { SetEvent(cond->m_events[ArchCondImpl::kSignal]); } } void ArchMultithreadWindows::broadcastCondVar(ArchCond cond) { // is anybody waiting? lockMutex(cond->m_waitCountMutex); const bool hasWaiter = (cond->m_waitCount > 0); unlockMutex(cond->m_waitCountMutex); // wake all threads if anybody is waiting if (hasWaiter) { SetEvent(cond->m_events[ArchCondImpl::kBroadcast]); } } bool ArchMultithreadWindows::waitCondVar(ArchCond cond, ArchMutex mutex, double timeout) { // prepare to wait const DWORD winTimeout = (timeout < 0.0) ? INFINITE : static_cast(1000.0 * timeout); // make a list of the condition variable events and the cancel event // for the current thread. HANDLE handles[4]; handles[0] = cond->m_events[ArchCondImpl::kSignal]; handles[1] = cond->m_events[ArchCondImpl::kBroadcast]; handles[2] = getCancelEventForCurrentThread(); // update waiter count lockMutex(cond->m_waitCountMutex); ++cond->m_waitCount; unlockMutex(cond->m_waitCountMutex); // release mutex. this should be atomic with the wait so that it's // impossible for another thread to signal us between the unlock and // the wait, which would lead to a lost signal on broadcasts. // however, we're using a manual reset event for broadcasts which // stays set until we reset it, so we don't lose the broadcast. unlockMutex(mutex); // wait for a signal or broadcast DWORD result = WaitForMultipleObjects(3, handles, FALSE, winTimeout); // cancel takes priority if (result != WAIT_OBJECT_0 + 2 && WaitForSingleObject(handles[2], 0) == WAIT_OBJECT_0) { result = WAIT_OBJECT_0 + 2; } // update the waiter count and check if we're the last waiter lockMutex(cond->m_waitCountMutex); --cond->m_waitCount; const bool last = (result == WAIT_OBJECT_0 + 1 && cond->m_waitCount == 0); unlockMutex(cond->m_waitCountMutex); // reset the broadcast event if we're the last waiter if (last) { ResetEvent(cond->m_events[ArchCondImpl::kBroadcast]); } // reacquire the mutex lockMutex(mutex); // cancel thread if necessary if (result == WAIT_OBJECT_0 + 2) { ARCH->testCancelThread(); } // return success or failure return (result == WAIT_OBJECT_0 + 0 || result == WAIT_OBJECT_0 + 1); } ArchMutex ArchMultithreadWindows::newMutex() { ArchMutexImpl* mutex = new ArchMutexImpl; InitializeCriticalSection(&mutex->m_mutex); return mutex; } void ArchMultithreadWindows::closeMutex(ArchMutex mutex) { DeleteCriticalSection(&mutex->m_mutex); delete mutex; } void ArchMultithreadWindows::lockMutex(ArchMutex mutex) { EnterCriticalSection(&mutex->m_mutex); } void ArchMultithreadWindows::unlockMutex(ArchMutex mutex) { LeaveCriticalSection(&mutex->m_mutex); } ArchThread ArchMultithreadWindows::newThread(ThreadFunc func, void* data) { lockMutex(m_threadMutex); // create thread impl for new thread ArchThreadImpl* thread = new ArchThreadImpl; thread->m_func = func; thread->m_userData = data; // create thread unsigned int id = 0; thread->m_thread = reinterpret_cast(_beginthreadex(NULL, 0, threadFunc, (void*)thread, 0, &id)); thread->m_id = static_cast(id); // check if thread was started if (thread->m_thread == 0) { // failed to start thread so clean up delete thread; thread = NULL; } else { // add thread to list insert(thread); // increment ref count to account for the thread itself refThread(thread); } // note that the child thread will wait until we release this mutex unlockMutex(m_threadMutex); return thread; } ArchThread ArchMultithreadWindows::newCurrentThread() { lockMutex(m_threadMutex); ArchThreadImpl* thread = find(GetCurrentThreadId()); unlockMutex(m_threadMutex); assert(thread != NULL); return thread; } void ArchMultithreadWindows::closeThread(ArchThread thread) { assert(thread != NULL); // decrement ref count and clean up thread if no more references if (--thread->m_refCount == 0) { // close the handle (main thread has a NULL handle) if (thread->m_thread != NULL) { CloseHandle(thread->m_thread); } // remove thread from list lockMutex(m_threadMutex); assert(findNoRefOrCreate(thread->m_id) == thread); erase(thread); unlockMutex(m_threadMutex); // done with thread delete thread; } } ArchThread ArchMultithreadWindows::copyThread(ArchThread thread) { refThread(thread); return thread; } void ArchMultithreadWindows::cancelThread(ArchThread thread) { assert(thread != NULL); // set cancel flag SetEvent(thread->m_cancel); } void ArchMultithreadWindows::setPriorityOfThread(ArchThread thread, int n) { struct PriorityInfo { public: DWORD m_class; int m_level; }; static const PriorityInfo s_pClass[] = { { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_IDLE }, { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST }, { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL }, { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL }, { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL }, { IDLE_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST }, { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST }, { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL }, { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL }, { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL }, { NORMAL_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST }, { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST }, { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL }, { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL }, { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL }, { HIGH_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST }, { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_IDLE }, { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_LOWEST }, { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_BELOW_NORMAL }, { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_NORMAL }, { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_ABOVE_NORMAL }, { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_HIGHEST }, { REALTIME_PRIORITY_CLASS, THREAD_PRIORITY_TIME_CRITICAL} }; #if defined(_DEBUG) // don't use really high priorities when debugging static const size_t s_pMax = 13; #else static const size_t s_pMax = sizeof(s_pClass) / sizeof(s_pClass[0]) - 1; #endif static const size_t s_pBase = 8; // index of normal priority assert(thread != NULL); size_t index; if (n > 0 && s_pBase < (size_t)n) { // lowest priority index = 0; } else { index = (size_t)((int)s_pBase - n); if (index > s_pMax) { // highest priority index = s_pMax; } } SetPriorityClass(GetCurrentProcess(), s_pClass[index].m_class); SetThreadPriority(thread->m_thread, s_pClass[index].m_level); } void ArchMultithreadWindows::testCancelThread() { // find current thread lockMutex(m_threadMutex); ArchThreadImpl* thread = findNoRef(GetCurrentThreadId()); unlockMutex(m_threadMutex); // test cancel on thread testCancelThreadImpl(thread); } bool ArchMultithreadWindows::wait(ArchThread target, double timeout) { assert(target != NULL); lockMutex(m_threadMutex); // find current thread ArchThreadImpl* self = findNoRef(GetCurrentThreadId()); // ignore wait if trying to wait on ourself if (target == self) { unlockMutex(m_threadMutex); return false; } // ref the target so it can't go away while we're watching it refThread(target); unlockMutex(m_threadMutex); // convert timeout DWORD t; if (timeout < 0.0) { t = INFINITE; } else { t = (DWORD)(1000.0 * timeout); } // wait for this thread to be cancelled or woken up or for the // target thread to terminate. HANDLE handles[2]; handles[0] = target->m_exit; handles[1] = self->m_cancel; DWORD result = WaitForMultipleObjects(2, handles, FALSE, t); // cancel takes priority if (result != WAIT_OBJECT_0 + 1 && WaitForSingleObject(handles[1], 0) == WAIT_OBJECT_0) { result = WAIT_OBJECT_0 + 1; } // release target closeThread(target); // handle result switch (result) { case WAIT_OBJECT_0 + 0: // target thread terminated return true; case WAIT_OBJECT_0 + 1: // this thread was cancelled. does not return. testCancelThreadImpl(self); default: // timeout or error return false; } } bool ArchMultithreadWindows::isSameThread(ArchThread thread1, ArchThread thread2) { return (thread1 == thread2); } bool ArchMultithreadWindows::isExitedThread(ArchThread thread) { // poll exit event return (WaitForSingleObject(thread->m_exit, 0) == WAIT_OBJECT_0); } void* ArchMultithreadWindows::getResultOfThread(ArchThread thread) { lockMutex(m_threadMutex); void* result = thread->m_result; unlockMutex(m_threadMutex); return result; } IArchMultithread::ThreadID ArchMultithreadWindows::getIDOfThread(ArchThread thread) { return static_cast(thread->m_id); } void ArchMultithreadWindows::setSignalHandler( ESignal signal, SignalFunc func, void* userData) { lockMutex(m_threadMutex); m_signalFunc[signal] = func; m_signalUserData[signal] = userData; unlockMutex(m_threadMutex); } void ArchMultithreadWindows::raiseSignal(ESignal signal) { lockMutex(m_threadMutex); if (m_signalFunc[signal] != NULL) { m_signalFunc[signal](signal, m_signalUserData[signal]); ARCH->unblockPollSocket(m_mainThread); } else if (signal == kINTERRUPT || signal == kTERMINATE) { ARCH->cancelThread(m_mainThread); } unlockMutex(m_threadMutex); } ArchThreadImpl* ArchMultithreadWindows::find(DWORD id) { ArchThreadImpl* impl = findNoRef(id); if (impl != NULL) { refThread(impl); } return impl; } ArchThreadImpl* ArchMultithreadWindows::findNoRef(DWORD id) { ArchThreadImpl* impl = findNoRefOrCreate(id); if (impl == NULL) { // create thread for calling thread which isn't in our list and // add it to the list. this won't normally happen but it can if // the system calls us under a new thread, like it does when we // run as a service. impl = new ArchThreadImpl; impl->m_thread = NULL; impl->m_id = GetCurrentThreadId(); insert(impl); } return impl; } ArchThreadImpl* ArchMultithreadWindows::findNoRefOrCreate(DWORD id) { // linear search for (ThreadList::const_iterator index = m_threadList.begin(); index != m_threadList.end(); ++index) { if ((*index)->m_id == id) { return *index; } } return NULL; } void ArchMultithreadWindows::insert(ArchThreadImpl* thread) { assert(thread != NULL); // thread shouldn't already be on the list assert(findNoRefOrCreate(thread->m_id) == NULL); // append to list m_threadList.push_back(thread); } void ArchMultithreadWindows::erase(ArchThreadImpl* thread) { for (ThreadList::iterator index = m_threadList.begin(); index != m_threadList.end(); ++index) { if (*index == thread) { m_threadList.erase(index); break; } } } void ArchMultithreadWindows::refThread(ArchThreadImpl* thread) { assert(thread != NULL); assert(findNoRefOrCreate(thread->m_id) != NULL); ++thread->m_refCount; } void ArchMultithreadWindows::testCancelThreadImpl(ArchThreadImpl* thread) { assert(thread != NULL); // poll cancel event. return if not set. const DWORD result = WaitForSingleObject(thread->m_cancel, 0); if (result != WAIT_OBJECT_0) { return; } // update cancel state lockMutex(m_threadMutex); bool cancel = !thread->m_cancelling; thread->m_cancelling = true; ResetEvent(thread->m_cancel); unlockMutex(m_threadMutex); // unwind thread's stack if cancelling if (cancel) { throw XThreadCancel(); } } unsigned int __stdcall ArchMultithreadWindows::threadFunc(void* vrep) { // get the thread ArchThreadImpl* thread = static_cast(vrep); // run thread s_instance->doThreadFunc(thread); // terminate the thread return 0; } void ArchMultithreadWindows::doThreadFunc(ArchThread thread) { // wait for parent to initialize this object lockMutex(m_threadMutex); unlockMutex(m_threadMutex); void* result = NULL; try { // go result = (*thread->m_func)(thread->m_userData); } catch (XThreadCancel&) { // client called cancel() } catch (...) { // note -- don't catch (...) to avoid masking bugs SetEvent(thread->m_exit); closeThread(thread); throw; } // thread has exited lockMutex(m_threadMutex); thread->m_result = result; unlockMutex(m_threadMutex); SetEvent(thread->m_exit); // done with thread closeThread(thread); } synergy-1.8.8-stable/src/lib/arch/win32/ArchMultithreadWindows.h000066400000000000000000000063021305627404700245310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchMultithread.h" #include "common/stdlist.h" #define WIN32_LEAN_AND_MEAN #include #define ARCH_MULTITHREAD ArchMultithreadWindows class ArchCondImpl { public: enum { kSignal = 0, kBroadcast }; HANDLE m_events[2]; mutable int m_waitCount; ArchMutex m_waitCountMutex; }; class ArchMutexImpl { public: CRITICAL_SECTION m_mutex; }; //! Win32 implementation of IArchMultithread class ArchMultithreadWindows : public IArchMultithread { public: ArchMultithreadWindows(); virtual ~ArchMultithreadWindows(); //! @name manipulators //@{ void setNetworkDataForCurrentThread(void*); //@} //! @name accessors //@{ HANDLE getCancelEventForCurrentThread(); void* getNetworkDataForThread(ArchThread); static ArchMultithreadWindows* getInstance(); //@} // IArchMultithread overrides virtual ArchCond newCondVar(); virtual void closeCondVar(ArchCond); virtual void signalCondVar(ArchCond); virtual void broadcastCondVar(ArchCond); virtual bool waitCondVar(ArchCond, ArchMutex, double timeout); virtual ArchMutex newMutex(); virtual void closeMutex(ArchMutex); virtual void lockMutex(ArchMutex); virtual void unlockMutex(ArchMutex); virtual ArchThread newThread(ThreadFunc, void*); virtual ArchThread newCurrentThread(); virtual ArchThread copyThread(ArchThread); virtual void closeThread(ArchThread); virtual void cancelThread(ArchThread); virtual void setPriorityOfThread(ArchThread, int n); virtual void testCancelThread(); virtual bool wait(ArchThread, double timeout); virtual bool isSameThread(ArchThread, ArchThread); virtual bool isExitedThread(ArchThread); virtual void* getResultOfThread(ArchThread); virtual ThreadID getIDOfThread(ArchThread); virtual void setSignalHandler(ESignal, SignalFunc, void*); virtual void raiseSignal(ESignal); private: ArchThreadImpl* find(DWORD id); ArchThreadImpl* findNoRef(DWORD id); ArchThreadImpl* findNoRefOrCreate(DWORD id); void insert(ArchThreadImpl* thread); void erase(ArchThreadImpl* thread); void refThread(ArchThreadImpl* rep); void testCancelThreadImpl(ArchThreadImpl* rep); void doThreadFunc(ArchThread thread); static unsigned int __stdcall threadFunc(void* vrep); private: typedef std::list ThreadList; static ArchMultithreadWindows* s_instance; ArchMutex m_threadMutex; ThreadList m_threadList; ArchThread m_mainThread; SignalFunc m_signalFunc[kNUM_SIGNALS]; void* m_signalUserData[kNUM_SIGNALS]; }; synergy-1.8.8-stable/src/lib/arch/win32/ArchNetworkWinsock.cpp000066400000000000000000000613661305627404700242310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchNetworkWinsock.h" #include "arch/win32/ArchMultithreadWindows.h" #include "arch/win32/XArchWindows.h" #include "arch/IArchMultithread.h" #include "arch/Arch.h" #include static const int s_family[] = { PF_UNSPEC, PF_INET }; static const int s_type[] = { SOCK_DGRAM, SOCK_STREAM }; static SOCKET (PASCAL FAR *accept_winsock)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen); static int (PASCAL FAR *bind_winsock)(SOCKET s, const struct sockaddr FAR *addr, int namelen); static int (PASCAL FAR *close_winsock)(SOCKET s); static int (PASCAL FAR *connect_winsock)(SOCKET s, const struct sockaddr FAR *name, int namelen); static int (PASCAL FAR *gethostname_winsock)(char FAR * name, int namelen); static int (PASCAL FAR *getsockerror_winsock)(void); static int (PASCAL FAR *getsockopt_winsock)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen); static u_short (PASCAL FAR *htons_winsock)(u_short v); static char FAR * (PASCAL FAR *inet_ntoa_winsock)(struct in_addr in); static unsigned long (PASCAL FAR *inet_addr_winsock)(const char FAR * cp); static int (PASCAL FAR *ioctl_winsock)(SOCKET s, int cmd, void FAR * data); static int (PASCAL FAR *listen_winsock)(SOCKET s, int backlog); static u_short (PASCAL FAR *ntohs_winsock)(u_short v); static int (PASCAL FAR *recv_winsock)(SOCKET s, void FAR * buf, int len, int flags); static int (PASCAL FAR *select_winsock)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout); static int (PASCAL FAR *send_winsock)(SOCKET s, const void FAR * buf, int len, int flags); static int (PASCAL FAR *setsockopt_winsock)(SOCKET s, int level, int optname, const void FAR * optval, int optlen); static int (PASCAL FAR *shutdown_winsock)(SOCKET s, int how); static SOCKET (PASCAL FAR *socket_winsock)(int af, int type, int protocol); static struct hostent FAR * (PASCAL FAR *gethostbyaddr_winsock)(const char FAR * addr, int len, int type); static struct hostent FAR * (PASCAL FAR *gethostbyname_winsock)(const char FAR * name); static int (PASCAL FAR *WSACleanup_winsock)(void); static int (PASCAL FAR *WSAFDIsSet_winsock)(SOCKET, fd_set FAR * fdset); static WSAEVENT (PASCAL FAR *WSACreateEvent_winsock)(void); static BOOL (PASCAL FAR *WSACloseEvent_winsock)(WSAEVENT); static BOOL (PASCAL FAR *WSASetEvent_winsock)(WSAEVENT); static BOOL (PASCAL FAR *WSAResetEvent_winsock)(WSAEVENT); static int (PASCAL FAR *WSAEventSelect_winsock)(SOCKET, WSAEVENT, long); static DWORD (PASCAL FAR *WSAWaitForMultipleEvents_winsock)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL); static int (PASCAL FAR *WSAEnumNetworkEvents_winsock)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS); #undef FD_ISSET #define FD_ISSET(fd, set) WSAFDIsSet_winsock((SOCKET)(fd), (fd_set FAR *)(set)) #define setfunc(var, name, type) var = (type)netGetProcAddress(module, #name) static HMODULE s_networkModule = NULL; static FARPROC netGetProcAddress(HMODULE module, LPCSTR name) { FARPROC func = ::GetProcAddress(module, name); if (!func) { throw XArchNetworkSupport(""); } return func; } ArchNetAddressImpl* ArchNetAddressImpl::alloc(size_t size) { size_t totalSize = size + ADDR_HDR_SIZE; ArchNetAddressImpl* addr = (ArchNetAddressImpl*)malloc(totalSize); addr->m_len = (int)size; return addr; } // // ArchNetworkWinsock // ArchNetworkWinsock::ArchNetworkWinsock() : m_mutex(NULL) { } ArchNetworkWinsock::~ArchNetworkWinsock() { if (s_networkModule != NULL) { WSACleanup_winsock(); ::FreeLibrary(s_networkModule); WSACleanup_winsock = NULL; s_networkModule = NULL; } if (m_mutex != NULL) { ARCH->closeMutex(m_mutex); } EventList::iterator it; for (it = m_unblockEvents.begin(); it != m_unblockEvents.end(); it++) { delete *it; } } void ArchNetworkWinsock::init() { static const char* s_library[] = { "ws2_32.dll" }; assert(WSACleanup_winsock == NULL); assert(s_networkModule == NULL); // try each winsock library for (size_t i = 0; i < sizeof(s_library) / sizeof(s_library[0]); ++i) { try { initModule((HMODULE)::LoadLibrary(s_library[i])); m_mutex = ARCH->newMutex(); return; } catch (XArchNetwork&) { // ignore } } // can't initialize any library throw XArchNetworkSupport("Cannot load winsock library"); } void ArchNetworkWinsock::initModule(HMODULE module) { if (module == NULL) { throw XArchNetworkSupport(""); } // get startup function address int (PASCAL FAR *startup)(WORD, LPWSADATA); setfunc(startup, WSAStartup, int(PASCAL FAR*)(WORD, LPWSADATA)); // startup network library WORD version = MAKEWORD(2 /*major*/, 0 /*minor*/); WSADATA data; int err = startup(version, &data); if (data.wVersion != version) { throw XArchNetworkSupport(new XArchEvalWinsock(err)); } if (err != 0) { // some other initialization error throwError(err); } // get function addresses setfunc(accept_winsock, accept, SOCKET (PASCAL FAR *)(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen)); setfunc(bind_winsock, bind, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *addr, int namelen)); setfunc(close_winsock, closesocket, int (PASCAL FAR *)(SOCKET s)); setfunc(connect_winsock, connect, int (PASCAL FAR *)(SOCKET s, const struct sockaddr FAR *name, int namelen)); setfunc(gethostname_winsock, gethostname, int (PASCAL FAR *)(char FAR * name, int namelen)); setfunc(getsockerror_winsock, WSAGetLastError, int (PASCAL FAR *)(void)); setfunc(getsockopt_winsock, getsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, void FAR * optval, int FAR *optlen)); setfunc(htons_winsock, htons, u_short (PASCAL FAR *)(u_short v)); setfunc(inet_ntoa_winsock, inet_ntoa, char FAR * (PASCAL FAR *)(struct in_addr in)); setfunc(inet_addr_winsock, inet_addr, unsigned long (PASCAL FAR *)(const char FAR * cp)); setfunc(ioctl_winsock, ioctlsocket, int (PASCAL FAR *)(SOCKET s, int cmd, void FAR *)); setfunc(listen_winsock, listen, int (PASCAL FAR *)(SOCKET s, int backlog)); setfunc(ntohs_winsock, ntohs, u_short (PASCAL FAR *)(u_short v)); setfunc(recv_winsock, recv, int (PASCAL FAR *)(SOCKET s, void FAR * buf, int len, int flags)); setfunc(select_winsock, select, int (PASCAL FAR *)(int nfds, fd_set FAR *readfds, fd_set FAR *writefds, fd_set FAR *exceptfds, const struct timeval FAR *timeout)); setfunc(send_winsock, send, int (PASCAL FAR *)(SOCKET s, const void FAR * buf, int len, int flags)); setfunc(setsockopt_winsock, setsockopt, int (PASCAL FAR *)(SOCKET s, int level, int optname, const void FAR * optval, int optlen)); setfunc(shutdown_winsock, shutdown, int (PASCAL FAR *)(SOCKET s, int how)); setfunc(socket_winsock, socket, SOCKET (PASCAL FAR *)(int af, int type, int protocol)); setfunc(gethostbyaddr_winsock, gethostbyaddr, struct hostent FAR * (PASCAL FAR *)(const char FAR * addr, int len, int type)); setfunc(gethostbyname_winsock, gethostbyname, struct hostent FAR * (PASCAL FAR *)(const char FAR * name)); setfunc(WSACleanup_winsock, WSACleanup, int (PASCAL FAR *)(void)); setfunc(WSAFDIsSet_winsock, __WSAFDIsSet, int (PASCAL FAR *)(SOCKET, fd_set FAR *)); setfunc(WSACreateEvent_winsock, WSACreateEvent, WSAEVENT (PASCAL FAR *)(void)); setfunc(WSACloseEvent_winsock, WSACloseEvent, BOOL (PASCAL FAR *)(WSAEVENT)); setfunc(WSASetEvent_winsock, WSASetEvent, BOOL (PASCAL FAR *)(WSAEVENT)); setfunc(WSAResetEvent_winsock, WSAResetEvent, BOOL (PASCAL FAR *)(WSAEVENT)); setfunc(WSAEventSelect_winsock, WSAEventSelect, int (PASCAL FAR *)(SOCKET, WSAEVENT, long)); setfunc(WSAWaitForMultipleEvents_winsock, WSAWaitForMultipleEvents, DWORD (PASCAL FAR *)(DWORD, const WSAEVENT FAR*, BOOL, DWORD, BOOL)); setfunc(WSAEnumNetworkEvents_winsock, WSAEnumNetworkEvents, int (PASCAL FAR *)(SOCKET, WSAEVENT, LPWSANETWORKEVENTS)); s_networkModule = module; } ArchSocket ArchNetworkWinsock::newSocket(EAddressFamily family, ESocketType type) { // create socket SOCKET fd = socket_winsock(s_family[family], s_type[type], 0); if (fd == INVALID_SOCKET) { throwError(getsockerror_winsock()); } try { setBlockingOnSocket(fd, false); } catch (...) { close_winsock(fd); throw; } // allocate socket object ArchSocketImpl* socket = new ArchSocketImpl; socket->m_socket = fd; socket->m_refCount = 1; socket->m_event = WSACreateEvent_winsock(); socket->m_pollWrite = true; return socket; } ArchSocket ArchNetworkWinsock::copySocket(ArchSocket s) { assert(s != NULL); // ref the socket and return it ARCH->lockMutex(m_mutex); ++s->m_refCount; ARCH->unlockMutex(m_mutex); return s; } void ArchNetworkWinsock::closeSocket(ArchSocket s) { assert(s != NULL); // unref the socket and note if it should be released ARCH->lockMutex(m_mutex); const bool doClose = (--s->m_refCount == 0); ARCH->unlockMutex(m_mutex); // close the socket if necessary if (doClose) { if (close_winsock(s->m_socket) == SOCKET_ERROR) { // close failed. restore the last ref and throw. int err = getsockerror_winsock(); ARCH->lockMutex(m_mutex); ++s->m_refCount; ARCH->unlockMutex(m_mutex); throwError(err); } WSACloseEvent_winsock(s->m_event); delete s; } } void ArchNetworkWinsock::closeSocketForRead(ArchSocket s) { assert(s != NULL); if (shutdown_winsock(s->m_socket, SD_RECEIVE) == SOCKET_ERROR) { if (getsockerror_winsock() != WSAENOTCONN) { throwError(getsockerror_winsock()); } } } void ArchNetworkWinsock::closeSocketForWrite(ArchSocket s) { assert(s != NULL); if (shutdown_winsock(s->m_socket, SD_SEND) == SOCKET_ERROR) { if (getsockerror_winsock() != WSAENOTCONN) { throwError(getsockerror_winsock()); } } } void ArchNetworkWinsock::bindSocket(ArchSocket s, ArchNetAddress addr) { assert(s != NULL); assert(addr != NULL); if (bind_winsock(s->m_socket, &addr->m_addr, addr->m_len) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } } void ArchNetworkWinsock::listenOnSocket(ArchSocket s) { assert(s != NULL); // hardcoding backlog if (listen_winsock(s->m_socket, 3) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } } ArchSocket ArchNetworkWinsock::acceptSocket(ArchSocket s, ArchNetAddress* addr) { assert(s != NULL); // create new socket and temporary address ArchSocketImpl* socket = new ArchSocketImpl; ArchNetAddress tmp = ArchNetAddressImpl::alloc(sizeof(struct sockaddr)); // accept on socket SOCKET fd = accept_winsock(s->m_socket, &tmp->m_addr, &tmp->m_len); if (fd == INVALID_SOCKET) { int err = getsockerror_winsock(); delete socket; free(tmp); *addr = NULL; if (err == WSAEWOULDBLOCK) { return NULL; } throwError(err); } try { setBlockingOnSocket(fd, false); } catch (...) { close_winsock(fd); delete socket; free(tmp); *addr = NULL; throw; } // initialize socket socket->m_socket = fd; socket->m_refCount = 1; socket->m_event = WSACreateEvent_winsock(); socket->m_pollWrite = true; // copy address if requested if (addr != NULL) { *addr = ARCH->copyAddr(tmp); } free(tmp); return socket; } bool ArchNetworkWinsock::connectSocket(ArchSocket s, ArchNetAddress addr) { assert(s != NULL); assert(addr != NULL); if (connect_winsock(s->m_socket, &addr->m_addr, addr->m_len) == SOCKET_ERROR) { if (getsockerror_winsock() == WSAEISCONN) { return true; } if (getsockerror_winsock() == WSAEWOULDBLOCK) { return false; } throwError(getsockerror_winsock()); } return true; } int ArchNetworkWinsock::pollSocket(PollEntry pe[], int num, double timeout) { int i; DWORD n; // prepare sockets and wait list bool canWrite = false; WSAEVENT* events = (WSAEVENT*)alloca((num + 1) * sizeof(WSAEVENT)); for (i = 0, n = 0; i < num; ++i) { // reset return flags pe[i].m_revents = 0; // set invalid flag if socket is bogus then go to next socket if (pe[i].m_socket == NULL) { pe[i].m_revents |= kPOLLNVAL; continue; } // select desired events long socketEvents = 0; if ((pe[i].m_events & kPOLLIN) != 0) { socketEvents |= FD_READ | FD_ACCEPT | FD_CLOSE; } if ((pe[i].m_events & kPOLLOUT) != 0) { socketEvents |= FD_WRITE | FD_CONNECT | FD_CLOSE; // if m_pollWrite is false then we assume the socket is // writable. winsock doesn't signal writability except // when the state changes from unwritable. if (!pe[i].m_socket->m_pollWrite) { canWrite = true; pe[i].m_revents |= kPOLLOUT; } } // if no events then ignore socket if (socketEvents == 0) { continue; } // select socket for desired events WSAEventSelect_winsock(pe[i].m_socket->m_socket, pe[i].m_socket->m_event, socketEvents); // add socket event to wait list events[n++] = pe[i].m_socket->m_event; } // if no sockets then return immediately if (n == 0) { return 0; } // add the unblock event ArchMultithreadWindows* mt = ArchMultithreadWindows::getInstance(); ArchThread thread = mt->newCurrentThread(); WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread); ARCH->closeThread(thread); if (unblockEvent == NULL) { unblockEvent = new WSAEVENT; m_unblockEvents.push_back(unblockEvent); *unblockEvent = WSACreateEvent_winsock(); mt->setNetworkDataForCurrentThread(unblockEvent); } events[n++] = *unblockEvent; // prepare timeout DWORD t = (timeout < 0.0) ? INFINITE : (DWORD)(1000.0 * timeout); if (canWrite) { // if we know we can write then don't block t = 0; } // wait DWORD result = WSAWaitForMultipleEvents_winsock(n, events, FALSE, t, FALSE); // reset the unblock event WSAResetEvent_winsock(*unblockEvent); // handle results if (result == WSA_WAIT_FAILED) { if (getsockerror_winsock() == WSAEINTR) { // interrupted system call ARCH->testCancelThread(); return 0; } throwError(getsockerror_winsock()); } if (result == WSA_WAIT_TIMEOUT && !canWrite) { return 0; } if (result == WSA_WAIT_EVENT_0 + n - 1) { // the unblock event was signalled return 0; } for (i = 0, n = 0; i < num; ++i) { // skip events we didn't check if (pe[i].m_socket == NULL || (pe[i].m_events & (kPOLLIN | kPOLLOUT)) == 0) { continue; } // get events WSANETWORKEVENTS info; if (WSAEnumNetworkEvents_winsock(pe[i].m_socket->m_socket, pe[i].m_socket->m_event, &info) == SOCKET_ERROR) { continue; } if ((info.lNetworkEvents & FD_READ) != 0) { pe[i].m_revents |= kPOLLIN; } if ((info.lNetworkEvents & FD_ACCEPT) != 0) { pe[i].m_revents |= kPOLLIN; } if ((info.lNetworkEvents & FD_WRITE) != 0) { pe[i].m_revents |= kPOLLOUT; // socket is now writable so don't bothing polling for // writable until it becomes unwritable. pe[i].m_socket->m_pollWrite = false; } if ((info.lNetworkEvents & FD_CONNECT) != 0) { if (info.iErrorCode[FD_CONNECT_BIT] != 0) { pe[i].m_revents |= kPOLLERR; } else { pe[i].m_revents |= kPOLLOUT; pe[i].m_socket->m_pollWrite = false; } } if ((info.lNetworkEvents & FD_CLOSE) != 0) { if (info.iErrorCode[FD_CLOSE_BIT] != 0) { pe[i].m_revents |= kPOLLERR; } else { if ((pe[i].m_events & kPOLLIN) != 0) { pe[i].m_revents |= kPOLLIN; } if ((pe[i].m_events & kPOLLOUT) != 0) { pe[i].m_revents |= kPOLLOUT; } } } if (pe[i].m_revents != 0) { ++n; } } return (int)n; } void ArchNetworkWinsock::unblockPollSocket(ArchThread thread) { // set the unblock event ArchMultithreadWindows* mt = ArchMultithreadWindows::getInstance(); WSAEVENT* unblockEvent = (WSAEVENT*)mt->getNetworkDataForThread(thread); if (unblockEvent != NULL) { WSASetEvent_winsock(*unblockEvent); } } size_t ArchNetworkWinsock::readSocket(ArchSocket s, void* buf, size_t len) { assert(s != NULL); int n = recv_winsock(s->m_socket, buf, (int)len, 0); if (n == SOCKET_ERROR) { int err = getsockerror_winsock(); if (err == WSAEINTR || err == WSAEWOULDBLOCK) { return 0; } throwError(err); } return static_cast(n); } size_t ArchNetworkWinsock::writeSocket(ArchSocket s, const void* buf, size_t len) { assert(s != NULL); int n = send_winsock(s->m_socket, buf, (int)len, 0); if (n == SOCKET_ERROR) { int err = getsockerror_winsock(); if (err == WSAEINTR) { return 0; } if (err == WSAEWOULDBLOCK) { s->m_pollWrite = true; return 0; } throwError(err); } return static_cast(n); } void ArchNetworkWinsock::throwErrorOnSocket(ArchSocket s) { assert(s != NULL); // get the error from the socket layer int err = 0; int size = sizeof(err); if (getsockopt_winsock(s->m_socket, SOL_SOCKET, SO_ERROR, &err, &size) == SOCKET_ERROR) { err = getsockerror_winsock(); } // throw if there's an error if (err != 0) { throwError(err); } } void ArchNetworkWinsock::setBlockingOnSocket(SOCKET s, bool blocking) { assert(s != 0); int flag = blocking ? 0 : 1; if (ioctl_winsock(s, FIONBIO, &flag) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } } bool ArchNetworkWinsock::setNoDelayOnSocket(ArchSocket s, bool noDelay) { assert(s != NULL); // get old state BOOL oflag; int size = sizeof(oflag); if (getsockopt_winsock(s->m_socket, IPPROTO_TCP, TCP_NODELAY, &oflag, &size) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } // set new state BOOL flag = noDelay ? 1 : 0; size = sizeof(flag); if (setsockopt_winsock(s->m_socket, IPPROTO_TCP, TCP_NODELAY, &flag, size) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } return (oflag != 0); } bool ArchNetworkWinsock::setReuseAddrOnSocket(ArchSocket s, bool reuse) { assert(s != NULL); // get old state BOOL oflag; int size = sizeof(oflag); if (getsockopt_winsock(s->m_socket, SOL_SOCKET, SO_REUSEADDR, &oflag, &size) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } // set new state BOOL flag = reuse ? 1 : 0; size = sizeof(flag); if (setsockopt_winsock(s->m_socket, SOL_SOCKET, SO_REUSEADDR, &flag, size) == SOCKET_ERROR) { throwError(getsockerror_winsock()); } return (oflag != 0); } std::string ArchNetworkWinsock::getHostName() { char name[256]; if (gethostname_winsock(name, sizeof(name)) == -1) { name[0] = '\0'; } else { name[sizeof(name) - 1] = '\0'; } return name; } ArchNetAddress ArchNetworkWinsock::newAnyAddr(EAddressFamily family) { ArchNetAddressImpl* addr = NULL; switch (family) { case kINET: { addr = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in)); struct sockaddr_in* ipAddr = TYPED_ADDR(struct sockaddr_in, addr); ipAddr->sin_family = AF_INET; ipAddr->sin_port = 0; ipAddr->sin_addr.s_addr = INADDR_ANY; break; } default: assert(0 && "invalid family"); } return addr; } ArchNetAddress ArchNetworkWinsock::copyAddr(ArchNetAddress addr) { assert(addr != NULL); ArchNetAddressImpl* copy = ArchNetAddressImpl::alloc(addr->m_len); memcpy(TYPED_ADDR(void, copy), TYPED_ADDR(void, addr), addr->m_len); return copy; } ArchNetAddress ArchNetworkWinsock::nameToAddr(const std::string& name) { // allocate address ArchNetAddressImpl* addr = NULL; // try to convert assuming an IPv4 dot notation address struct sockaddr_in inaddr; memset(&inaddr, 0, sizeof(inaddr)); inaddr.sin_family = AF_INET; inaddr.sin_port = 0; inaddr.sin_addr.s_addr = inet_addr_winsock(name.c_str()); if (inaddr.sin_addr.s_addr != INADDR_NONE) { // it's a dot notation address addr = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in)); memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len); } else { // address lookup struct hostent* info = gethostbyname_winsock(name.c_str()); if (info == NULL) { throwNameError(getsockerror_winsock()); } // copy over address (only IPv4 currently supported) if (info->h_addrtype == AF_INET) { addr = ArchNetAddressImpl::alloc(sizeof(struct sockaddr_in)); memcpy(&inaddr.sin_addr, info->h_addr_list[0], sizeof(inaddr.sin_addr)); memcpy(TYPED_ADDR(void, addr), &inaddr, addr->m_len); } else { throw XArchNetworkNameUnsupported( "The requested name is valid but " "does not have a supported address family"); } } return addr; } void ArchNetworkWinsock::closeAddr(ArchNetAddress addr) { assert(addr != NULL); free(addr); } std::string ArchNetworkWinsock::addrToName(ArchNetAddress addr) { assert(addr != NULL); // name lookup struct hostent* info = gethostbyaddr_winsock( reinterpret_cast(&addr->m_addr), addr->m_len, addr->m_addr.sa_family); if (info == NULL) { throwNameError(getsockerror_winsock()); } // return (primary) name return info->h_name; } std::string ArchNetworkWinsock::addrToString(ArchNetAddress addr) { assert(addr != NULL); switch (getAddrFamily(addr)) { case kINET: { struct sockaddr_in* ipAddr = reinterpret_cast(&addr->m_addr); return inet_ntoa_winsock(ipAddr->sin_addr); } default: assert(0 && "unknown address family"); return ""; } } IArchNetwork::EAddressFamily ArchNetworkWinsock::getAddrFamily(ArchNetAddress addr) { assert(addr != NULL); switch (addr->m_addr.sa_family) { case AF_INET: return kINET; default: return kUNKNOWN; } } void ArchNetworkWinsock::setAddrPort(ArchNetAddress addr, int port) { assert(addr != NULL); switch (getAddrFamily(addr)) { case kINET: { struct sockaddr_in* ipAddr = reinterpret_cast(&addr->m_addr); ipAddr->sin_port = htons_winsock(port); break; } default: assert(0 && "unknown address family"); break; } } int ArchNetworkWinsock::getAddrPort(ArchNetAddress addr) { assert(addr != NULL); switch (getAddrFamily(addr)) { case kINET: { struct sockaddr_in* ipAddr = reinterpret_cast(&addr->m_addr); return ntohs_winsock(ipAddr->sin_port); } default: assert(0 && "unknown address family"); return 0; } } bool ArchNetworkWinsock::isAnyAddr(ArchNetAddress addr) { assert(addr != NULL); switch (getAddrFamily(addr)) { case kINET: { struct sockaddr_in* ipAddr = reinterpret_cast(&addr->m_addr); return (addr->m_len == sizeof(struct sockaddr_in) && ipAddr->sin_addr.s_addr == INADDR_ANY); } default: assert(0 && "unknown address family"); return true; } } bool ArchNetworkWinsock::isEqualAddr(ArchNetAddress a, ArchNetAddress b) { return (a == b || (a->m_len == b->m_len && memcmp(&a->m_addr, &b->m_addr, a->m_len) == 0)); } void ArchNetworkWinsock::throwError(int err) { switch (err) { case WSAEACCES: throw XArchNetworkAccess(new XArchEvalWinsock(err)); case WSAEMFILE: case WSAENOBUFS: case WSAENETDOWN: throw XArchNetworkResource(new XArchEvalWinsock(err)); case WSAEPROTOTYPE: case WSAEPROTONOSUPPORT: case WSAEAFNOSUPPORT: case WSAEPFNOSUPPORT: case WSAESOCKTNOSUPPORT: case WSAEINVAL: case WSAENOPROTOOPT: case WSAEOPNOTSUPP: case WSAESHUTDOWN: case WSANOTINITIALISED: case WSAVERNOTSUPPORTED: case WSASYSNOTREADY: throw XArchNetworkSupport(new XArchEvalWinsock(err)); case WSAEADDRNOTAVAIL: throw XArchNetworkNoAddress(new XArchEvalWinsock(err)); case WSAEADDRINUSE: throw XArchNetworkAddressInUse(new XArchEvalWinsock(err)); case WSAEHOSTUNREACH: case WSAENETUNREACH: throw XArchNetworkNoRoute(new XArchEvalWinsock(err)); case WSAENOTCONN: throw XArchNetworkNotConnected(new XArchEvalWinsock(err)); case WSAEDISCON: throw XArchNetworkShutdown(new XArchEvalWinsock(err)); case WSAENETRESET: case WSAECONNABORTED: case WSAECONNRESET: throw XArchNetworkDisconnected(new XArchEvalWinsock(err)); case WSAECONNREFUSED: throw XArchNetworkConnectionRefused(new XArchEvalWinsock(err)); case WSAEHOSTDOWN: case WSAETIMEDOUT: throw XArchNetworkTimedOut(new XArchEvalWinsock(err)); case WSAHOST_NOT_FOUND: throw XArchNetworkNameUnknown(new XArchEvalWinsock(err)); case WSANO_DATA: throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err)); case WSANO_RECOVERY: throw XArchNetworkNameFailure(new XArchEvalWinsock(err)); case WSATRY_AGAIN: throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err)); default: throw XArchNetwork(new XArchEvalWinsock(err)); } } void ArchNetworkWinsock::throwNameError(int err) { switch (err) { case WSAHOST_NOT_FOUND: throw XArchNetworkNameUnknown(new XArchEvalWinsock(err)); case WSANO_DATA: throw XArchNetworkNameNoAddress(new XArchEvalWinsock(err)); case WSANO_RECOVERY: throw XArchNetworkNameFailure(new XArchEvalWinsock(err)); case WSATRY_AGAIN: throw XArchNetworkNameUnavailable(new XArchEvalWinsock(err)); default: throw XArchNetworkName(new XArchEvalWinsock(err)); } } synergy-1.8.8-stable/src/lib/arch/win32/ArchNetworkWinsock.h000066400000000000000000000065371305627404700236750ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once // declare no functions in winsock2 #define INCL_WINSOCK_API_PROTOTYPES 0 #define INCL_WINSOCK_API_TYPEDEFS 0 #include "arch/IArchNetwork.h" #include "arch/IArchMultithread.h" #include #define WIN32_LEAN_AND_MEAN #include #include #define ARCH_NETWORK ArchNetworkWinsock class ArchSocketImpl { public: SOCKET m_socket; int m_refCount; WSAEVENT m_event; bool m_pollWrite; }; class ArchNetAddressImpl { public: static ArchNetAddressImpl* alloc(size_t); public: int m_len; struct sockaddr m_addr; }; #define ADDR_HDR_SIZE offsetof(ArchNetAddressImpl, m_addr) #define TYPED_ADDR(type_, addr_) (reinterpret_cast(&addr_->m_addr)) //! Win32 implementation of IArchNetwork class ArchNetworkWinsock : public IArchNetwork { public: ArchNetworkWinsock(); virtual ~ArchNetworkWinsock(); virtual void init(); // IArchNetwork overrides virtual ArchSocket newSocket(EAddressFamily, ESocketType); virtual ArchSocket copySocket(ArchSocket s); virtual void closeSocket(ArchSocket s); virtual void closeSocketForRead(ArchSocket s); virtual void closeSocketForWrite(ArchSocket s); virtual void bindSocket(ArchSocket s, ArchNetAddress addr); virtual void listenOnSocket(ArchSocket s); virtual ArchSocket acceptSocket(ArchSocket s, ArchNetAddress* addr); virtual bool connectSocket(ArchSocket s, ArchNetAddress name); virtual int pollSocket(PollEntry[], int num, double timeout); virtual void unblockPollSocket(ArchThread thread); virtual size_t readSocket(ArchSocket s, void* buf, size_t len); virtual size_t writeSocket(ArchSocket s, const void* buf, size_t len); virtual void throwErrorOnSocket(ArchSocket); virtual bool setNoDelayOnSocket(ArchSocket, bool noDelay); virtual bool setReuseAddrOnSocket(ArchSocket, bool reuse); virtual std::string getHostName(); virtual ArchNetAddress newAnyAddr(EAddressFamily); virtual ArchNetAddress copyAddr(ArchNetAddress); virtual ArchNetAddress nameToAddr(const std::string&); virtual void closeAddr(ArchNetAddress); virtual std::string addrToName(ArchNetAddress); virtual std::string addrToString(ArchNetAddress); virtual EAddressFamily getAddrFamily(ArchNetAddress); virtual void setAddrPort(ArchNetAddress, int port); virtual int getAddrPort(ArchNetAddress); virtual bool isAnyAddr(ArchNetAddress); virtual bool isEqualAddr(ArchNetAddress, ArchNetAddress); private: void initModule(HMODULE); void setBlockingOnSocket(SOCKET, bool blocking); void throwError(int); void throwNameError(int); private: typedef std::list EventList; ArchMutex m_mutex; EventList m_unblockEvents; }; synergy-1.8.8-stable/src/lib/arch/win32/ArchSleepWindows.cpp000066400000000000000000000031561305627404700236560ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchSleepWindows.h" #include "arch/Arch.h" #include "arch/win32/ArchMultithreadWindows.h" // // ArchSleepWindows // ArchSleepWindows::ArchSleepWindows() { // do nothing } ArchSleepWindows::~ArchSleepWindows() { // do nothing } void ArchSleepWindows::sleep(double timeout) { ARCH->testCancelThread(); if (timeout < 0.0) { return; } // get the cancel event from the current thread. this only // works if we're using the windows multithread object but // this is windows so that's pretty certain; we'll get a // link error if we're not, though. ArchMultithreadWindows* mt = ArchMultithreadWindows::getInstance(); if (mt != NULL) { HANDLE cancelEvent = mt->getCancelEventForCurrentThread(); WaitForSingleObject(cancelEvent, (DWORD)(1000.0 * timeout)); if (timeout == 0.0) { Sleep(0); } } else { Sleep((DWORD)(1000.0 * timeout)); } ARCH->testCancelThread(); } synergy-1.8.8-stable/src/lib/arch/win32/ArchSleepWindows.h000066400000000000000000000017771305627404700233320ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchSleep.h" #define ARCH_SLEEP ArchSleepWindows //! Win32 implementation of IArchSleep class ArchSleepWindows : public IArchSleep { public: ArchSleepWindows(); virtual ~ArchSleepWindows(); // IArchSleep overrides virtual void sleep(double timeout); }; synergy-1.8.8-stable/src/lib/arch/win32/ArchStringWindows.cpp000066400000000000000000000022211305627404700240440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchStringWindows.h" #define WIN32_LEAN_AND_MEAN #include #include // // ArchStringWindows // #include "arch/multibyte.h" #define HAVE_VSNPRINTF 1 #define ARCH_VSNPRINTF _vsnprintf #include "arch/vsnprintf.h" ArchStringWindows::ArchStringWindows() { } ArchStringWindows::~ArchStringWindows() { } IArchString::EWideCharEncoding ArchStringWindows::getWideCharEncoding() { return kUTF16; } synergy-1.8.8-stable/src/lib/arch/win32/ArchStringWindows.h000066400000000000000000000020321305627404700235110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchString.h" #define ARCH_STRING ArchStringWindows //! Win32 implementation of IArchString class ArchStringWindows : public IArchString { public: ArchStringWindows(); virtual ~ArchStringWindows(); // IArchString overrides virtual EWideCharEncoding getWideCharEncoding(); }; synergy-1.8.8-stable/src/lib/arch/win32/ArchSystemWindows.cpp000066400000000000000000000111241305627404700240640ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchSystemWindows.h" #include "arch/win32/ArchMiscWindows.h" #include "arch/win32/XArchWindows.h" #include "tchar.h" #include #include #include static const char* s_settingsKeyNames[] = { _T("SOFTWARE"), _T("Synergy"), NULL }; // // ArchSystemWindows // ArchSystemWindows::ArchSystemWindows() { // do nothing } ArchSystemWindows::~ArchSystemWindows() { // do nothing } std::string ArchSystemWindows::getOSName() const { #if WINVER >= _WIN32_WINNT_WIN2K OSVERSIONINFOEX info; #else OSVERSIONINFO info; #endif info.dwOSVersionInfoSize = sizeof(info); if (GetVersionEx((OSVERSIONINFO*) &info)) { switch (info.dwPlatformId) { case VER_PLATFORM_WIN32_NT: #if WINVER >= _WIN32_WINNT_WIN2K if (info.dwMajorVersion == 6) { if (info.dwMinorVersion == 0) { if (info.wProductType == VER_NT_WORKSTATION) { return "Microsoft Windows Vista"; } else { return "Microsoft Windows Server 2008"; } } else if (info.dwMinorVersion == 1) { if (info.wProductType == VER_NT_WORKSTATION) { return "Microsoft Windows 7"; } else { return "Microsoft Windows Server 2008 R2"; } } } #endif if (info.dwMajorVersion == 5 && info.dwMinorVersion == 2) { return "Microsoft Windows Server 2003"; } if (info.dwMajorVersion == 5 && info.dwMinorVersion == 1) { return "Microsoft Windows XP"; } if (info.dwMajorVersion == 5 && info.dwMinorVersion == 0) { return "Microsoft Windows Server 2000"; } char buffer[100]; sprintf(buffer, "Microsoft Windows %d.%d", info.dwMajorVersion, info.dwMinorVersion); return buffer; default: break; } } return "Microsoft Windows "; } std::string ArchSystemWindows::getPlatformName() const { #ifdef _X86_ if (isWOW64()) return "x86 (WOW64)"; else return "x86"; #else #ifdef _AMD64_ return "x64"; #else return "Unknown"; #endif #endif } std::string ArchSystemWindows::setting(const std::string& valueName) const { HKEY key = ArchMiscWindows::openKey(HKEY_LOCAL_MACHINE, s_settingsKeyNames); if (key == NULL) return ""; return ArchMiscWindows::readValueString(key, valueName.c_str()); } void ArchSystemWindows::setting(const std::string& valueName, const std::string& valueString) const { HKEY key = ArchMiscWindows::addKey(HKEY_LOCAL_MACHINE, s_settingsKeyNames); if (key == NULL) throw XArch(std::string("could not access registry key: ") + valueName); ArchMiscWindows::setValue(key, valueName.c_str(), valueString.c_str()); } bool ArchSystemWindows::isWOW64() const { #if WINVER >= _WIN32_WINNT_WINXP typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); HMODULE hModule = GetModuleHandle(TEXT("kernel32")); if (!hModule) return FALSE; LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(hModule, "IsWow64Process"); BOOL bIsWow64 = FALSE; if (NULL != fnIsWow64Process && fnIsWow64Process(GetCurrentProcess(), &bIsWow64) && bIsWow64) { return true; } #endif return false; } #pragma comment(lib, "psapi") std::string ArchSystemWindows::getLibsUsed(void) const { HMODULE hMods[1024]; HANDLE hProcess; DWORD cbNeeded; unsigned int i; char hex[16]; DWORD pid = GetCurrentProcessId(); std::string msg = "pid:" + std::to_string((_ULonglong)pid) + "\n"; hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (NULL == hProcess) { return msg; } if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) { for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { TCHAR szModName[MAX_PATH]; if (GetModuleFileNameEx(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR))) { sprintf(hex,"(0x%08X)",hMods[i]); msg += szModName; msg.append(hex); msg.append("\n"); } } } CloseHandle(hProcess); return msg; } synergy-1.8.8-stable/src/lib/arch/win32/ArchSystemWindows.h000066400000000000000000000024331305627404700235340ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchSystem.h" #define ARCH_SYSTEM ArchSystemWindows //! Win32 implementation of IArchString class ArchSystemWindows : public IArchSystem { public: ArchSystemWindows(); virtual ~ArchSystemWindows(); // IArchSystem overrides virtual std::string getOSName() const; virtual std::string getPlatformName() const; virtual std::string setting(const std::string& valueName) const; virtual void setting(const std::string& valueName, const std::string& valueString) const; virtual std::string getLibsUsed(void) const; bool isWOW64() const; }; synergy-1.8.8-stable/src/lib/arch/win32/ArchTaskBarWindows.cpp000066400000000000000000000275251305627404700241430ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchTaskBarWindows.h" #include "arch/win32/ArchMiscWindows.h" #include "arch/IArchTaskBarReceiver.h" #include "arch/Arch.h" #include "arch/XArch.h" #include "synergy/win32/AppUtilWindows.h" #include #include static const UINT kAddReceiver = WM_USER + 10; static const UINT kRemoveReceiver = WM_USER + 11; static const UINT kUpdateReceiver = WM_USER + 12; static const UINT kNotifyReceiver = WM_USER + 13; static const UINT kFirstReceiverID = WM_USER + 14; // // ArchTaskBarWindows // ArchTaskBarWindows* ArchTaskBarWindows::s_instance = NULL; ArchTaskBarWindows::ArchTaskBarWindows() : m_nextID(kFirstReceiverID), m_thread(NULL), m_condVar(NULL), m_mutex(NULL) { // save the singleton instance s_instance = this; } ArchTaskBarWindows::~ArchTaskBarWindows() { if (m_thread != NULL) { PostMessage(m_hwnd, WM_QUIT, 0, 0); ARCH->wait(m_thread, -1.0); ARCH->closeThread(m_thread); } if (m_condVar != NULL) { ARCH->closeCondVar(m_condVar); } if (m_mutex != NULL) { ARCH->closeMutex(m_mutex); } s_instance = NULL; } void ArchTaskBarWindows::init() { // we need a mutex m_mutex = ARCH->newMutex(); // and a condition variable which uses the above mutex m_ready = false; m_condVar = ARCH->newCondVar(); // we're going to want to get a result from the thread we're // about to create to know if it initialized successfully. // so we lock the condition variable. ARCH->lockMutex(m_mutex); // open a window and run an event loop in a separate thread. // this has to happen in a separate thread because if we // create a window on the current desktop with the current // thread then the current thread won't be able to switch // desktops if it needs to. m_thread = ARCH->newThread(&ArchTaskBarWindows::threadEntry, this); // wait for child thread while (!m_ready) { ARCH->waitCondVar(m_condVar, m_mutex, -1.0); } // ready ARCH->unlockMutex(m_mutex); } void ArchTaskBarWindows::addDialog(HWND hwnd) { ArchMiscWindows::addDialog(hwnd); } void ArchTaskBarWindows::removeDialog(HWND hwnd) { ArchMiscWindows::removeDialog(hwnd); } void ArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver) { // ignore bogus receiver if (receiver == NULL) { return; } // add receiver if necessary ReceiverToInfoMap::iterator index = m_receivers.find(receiver); if (index == m_receivers.end()) { // add it, creating a new message ID for it ReceiverInfo info; info.m_id = getNextID(); index = m_receivers.insert(std::make_pair(receiver, info)).first; // add ID to receiver mapping m_idTable.insert(std::make_pair(info.m_id, index)); } // add receiver PostMessage(m_hwnd, kAddReceiver, index->second.m_id, 0); } void ArchTaskBarWindows::removeReceiver(IArchTaskBarReceiver* receiver) { // find receiver ReceiverToInfoMap::iterator index = m_receivers.find(receiver); if (index == m_receivers.end()) { return; } // remove icon. wait for this to finish before returning. SendMessage(m_hwnd, kRemoveReceiver, index->second.m_id, 0); // recycle the ID recycleID(index->second.m_id); // discard m_idTable.erase(index->second.m_id); m_receivers.erase(index); } void ArchTaskBarWindows::updateReceiver(IArchTaskBarReceiver* receiver) { // find receiver ReceiverToInfoMap::const_iterator index = m_receivers.find(receiver); if (index == m_receivers.end()) { return; } // update icon and tool tip PostMessage(m_hwnd, kUpdateReceiver, index->second.m_id, 0); } UINT ArchTaskBarWindows::getNextID() { if (m_oldIDs.empty()) { return m_nextID++; } UINT id = m_oldIDs.back(); m_oldIDs.pop_back(); return id; } void ArchTaskBarWindows::recycleID(UINT id) { m_oldIDs.push_back(id); } void ArchTaskBarWindows::addIcon(UINT id) { ARCH->lockMutex(m_mutex); CIDToReceiverMap::const_iterator index = m_idTable.find(id); if (index != m_idTable.end()) { modifyIconNoLock(index->second, NIM_ADD); } ARCH->unlockMutex(m_mutex); } void ArchTaskBarWindows::removeIcon(UINT id) { ARCH->lockMutex(m_mutex); removeIconNoLock(id); ARCH->unlockMutex(m_mutex); } void ArchTaskBarWindows::updateIcon(UINT id) { ARCH->lockMutex(m_mutex); CIDToReceiverMap::const_iterator index = m_idTable.find(id); if (index != m_idTable.end()) { modifyIconNoLock(index->second, NIM_MODIFY); } ARCH->unlockMutex(m_mutex); } void ArchTaskBarWindows::addAllIcons() { ARCH->lockMutex(m_mutex); for (ReceiverToInfoMap::const_iterator index = m_receivers.begin(); index != m_receivers.end(); ++index) { modifyIconNoLock(index, NIM_ADD); } ARCH->unlockMutex(m_mutex); } void ArchTaskBarWindows::removeAllIcons() { ARCH->lockMutex(m_mutex); for (ReceiverToInfoMap::const_iterator index = m_receivers.begin(); index != m_receivers.end(); ++index) { removeIconNoLock(index->second.m_id); } ARCH->unlockMutex(m_mutex); } void ArchTaskBarWindows::modifyIconNoLock( ReceiverToInfoMap::const_iterator index, DWORD taskBarMessage) { // get receiver UINT id = index->second.m_id; IArchTaskBarReceiver* receiver = index->first; // lock receiver so icon and tool tip are guaranteed to be consistent receiver->lock(); // get icon data HICON icon = static_cast( const_cast(receiver->getIcon())); // get tool tip std::string toolTip = receiver->getToolTip(); // done querying receiver->unlock(); // prepare to add icon NOTIFYICONDATA data; data.cbSize = sizeof(NOTIFYICONDATA); data.hWnd = m_hwnd; data.uID = id; data.uFlags = NIF_MESSAGE; data.uCallbackMessage = kNotifyReceiver; data.hIcon = icon; if (icon != NULL) { data.uFlags |= NIF_ICON; } if (!toolTip.empty()) { strncpy(data.szTip, toolTip.c_str(), sizeof(data.szTip)); data.szTip[sizeof(data.szTip) - 1] = '\0'; data.uFlags |= NIF_TIP; } else { data.szTip[0] = '\0'; } // add icon if (Shell_NotifyIcon(taskBarMessage, &data) == 0) { // failed } } void ArchTaskBarWindows::removeIconNoLock(UINT id) { NOTIFYICONDATA data; data.cbSize = sizeof(NOTIFYICONDATA); data.hWnd = m_hwnd; data.uID = id; if (Shell_NotifyIcon(NIM_DELETE, &data) == 0) { // failed } } void ArchTaskBarWindows::handleIconMessage( IArchTaskBarReceiver* receiver, LPARAM lParam) { // process message switch (lParam) { case WM_LBUTTONDOWN: receiver->showStatus(); break; case WM_LBUTTONDBLCLK: receiver->primaryAction(); break; case WM_RBUTTONUP: { POINT p; GetCursorPos(&p); receiver->runMenu(p.x, p.y); break; } case WM_MOUSEMOVE: // currently unused break; default: // unused break; } } bool ArchTaskBarWindows::processDialogs(MSG* msg) { // only one thread can be in this method on any particular object // at any given time. that's not a problem since only our event // loop calls this method and there's just one of those. ARCH->lockMutex(m_mutex); // remove removed dialogs m_dialogs.erase(false); // merge added dialogs into the dialog list for (Dialogs::const_iterator index = m_addedDialogs.begin(); index != m_addedDialogs.end(); ++index) { m_dialogs.insert(std::make_pair(index->first, index->second)); } m_addedDialogs.clear(); ARCH->unlockMutex(m_mutex); // check message against all dialogs until one handles it. // note that we don't hold a lock while checking because // the message is processed and may make calls to this // object. that's okay because addDialog() and // removeDialog() don't change the map itself (just the // values of some elements). ARCH->lockMutex(m_mutex); for (Dialogs::const_iterator index = m_dialogs.begin(); index != m_dialogs.end(); ++index) { if (index->second) { ARCH->unlockMutex(m_mutex); if (IsDialogMessage(index->first, msg)) { return true; } ARCH->lockMutex(m_mutex); } } ARCH->unlockMutex(m_mutex); return false; } LRESULT ArchTaskBarWindows::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case kNotifyReceiver: { // lookup receiver CIDToReceiverMap::const_iterator index = m_idTable.find((UINT)wParam); if (index != m_idTable.end()) { IArchTaskBarReceiver* receiver = index->second->first; handleIconMessage(receiver, lParam); return 0; } break; } case kAddReceiver: addIcon((UINT)wParam); break; case kRemoveReceiver: removeIcon((UINT)wParam); break; case kUpdateReceiver: updateIcon((UINT)wParam); break; default: if (msg == m_taskBarRestart) { // task bar was recreated so re-add our icons addAllIcons(); } break; } return DefWindowProc(hwnd, msg, wParam, lParam); } LRESULT CALLBACK ArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // if msg is WM_NCCREATE, extract the ArchTaskBarWindows* and put // it in the extra window data then forward the call. ArchTaskBarWindows* self = NULL; if (msg == WM_NCCREATE) { CREATESTRUCT* createInfo; createInfo = reinterpret_cast(lParam); self = static_cast( createInfo->lpCreateParams); SetWindowLongPtr(hwnd, 0, reinterpret_cast(createInfo->lpCreateParams)); } else { // get the extra window data and forward the call LONG_PTR data = GetWindowLongPtr(hwnd, 0); if (data != 0) { self = static_cast(reinterpret_cast(data)); } } // forward the message if (self != NULL) { return self->wndProc(hwnd, msg, wParam, lParam); } else { return DefWindowProc(hwnd, msg, wParam, lParam); } } void ArchTaskBarWindows::threadMainLoop() { // register the task bar restart message m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); // register a window class LPCTSTR className = TEXT("SynergyTaskBar"); WNDCLASSEX classInfo; classInfo.cbSize = sizeof(classInfo); classInfo.style = CS_NOCLOSE; classInfo.lpfnWndProc = &ArchTaskBarWindows::staticWndProc; classInfo.cbClsExtra = 0; classInfo.cbWndExtra = sizeof(ArchTaskBarWindows*); classInfo.hInstance = instanceWin32(); classInfo.hIcon = NULL; classInfo.hCursor = NULL; classInfo.hbrBackground = NULL; classInfo.lpszMenuName = NULL; classInfo.lpszClassName = className; classInfo.hIconSm = NULL; ATOM windowClass = RegisterClassEx(&classInfo); // create window m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, className, TEXT("Synergy Task Bar"), WS_POPUP, 0, 0, 1, 1, NULL, NULL, instanceWin32(), static_cast(this)); // signal ready ARCH->lockMutex(m_mutex); m_ready = true; ARCH->broadcastCondVar(m_condVar); ARCH->unlockMutex(m_mutex); // handle failure if (m_hwnd == NULL) { UnregisterClass(className, instanceWin32()); return; } // main loop MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { if (!processDialogs(&msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } // clean up removeAllIcons(); DestroyWindow(m_hwnd); UnregisterClass(className, instanceWin32()); } void* ArchTaskBarWindows::threadEntry(void* self) { static_cast(self)->threadMainLoop(); return NULL; } HINSTANCE ArchTaskBarWindows::instanceWin32() { return ArchMiscWindows::instanceWin32(); }synergy-1.8.8-stable/src/lib/arch/win32/ArchTaskBarWindows.h000066400000000000000000000057001305627404700235770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchTaskBar.h" #include "arch/IArchMultithread.h" #include "common/stdmap.h" #include "common/stdvector.h" #define WIN32_LEAN_AND_MEAN #include #define ARCH_TASKBAR ArchTaskBarWindows //! Win32 implementation of IArchTaskBar class ArchTaskBarWindows : public IArchTaskBar { public: ArchTaskBarWindows(); virtual ~ArchTaskBarWindows(); virtual void init(); //! Add a dialog window /*! Tell the task bar event loop about a dialog. Win32 annoyingly requires messages destined for modeless dialog boxes to be dispatched differently than other messages. */ static void addDialog(HWND); //! Remove a dialog window /*! Remove a dialog window added via \c addDialog(). */ static void removeDialog(HWND); // IArchTaskBar overrides virtual void addReceiver(IArchTaskBarReceiver*); virtual void removeReceiver(IArchTaskBarReceiver*); virtual void updateReceiver(IArchTaskBarReceiver*); private: class ReceiverInfo { public: UINT m_id; }; typedef std::map ReceiverToInfoMap; typedef std::map CIDToReceiverMap; typedef std::vector CIDStack; typedef std::map Dialogs; UINT getNextID(); void recycleID(UINT); void addIcon(UINT); void removeIcon(UINT); void updateIcon(UINT); void addAllIcons(); void removeAllIcons(); void modifyIconNoLock(ReceiverToInfoMap::const_iterator, DWORD taskBarMessage); void removeIconNoLock(UINT id); void handleIconMessage(IArchTaskBarReceiver*, LPARAM); bool processDialogs(MSG*); LRESULT wndProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK staticWndProc(HWND, UINT, WPARAM, LPARAM); void threadMainLoop(); static void* threadEntry(void*); HINSTANCE instanceWin32(); private: static ArchTaskBarWindows* s_instance; // multithread data ArchMutex m_mutex; ArchCond m_condVar; bool m_ready; int m_result; ArchThread m_thread; // child thread data HWND m_hwnd; UINT m_taskBarRestart; // shared data ReceiverToInfoMap m_receivers; CIDToReceiverMap m_idTable; CIDStack m_oldIDs; UINT m_nextID; // dialogs Dialogs m_dialogs; Dialogs m_addedDialogs; }; synergy-1.8.8-stable/src/lib/arch/win32/ArchTimeWindows.cpp000066400000000000000000000050201305627404700234740ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/ArchTimeWindows.h" #define WIN32_LEAN_AND_MEAN #include #define MMNODRV // Disable: Installable driver support #define MMNOSOUND // Disable: Sound support #define MMNOWAVE // Disable: Waveform support #define MMNOMIDI // Disable: MIDI support #define MMNOAUX // Disable: Auxiliary audio support #define MMNOMIXER // Disable: Mixer support #define MMNOJOY // Disable: Joystick support #define MMNOMCI // Disable: MCI support #define MMNOMMIO // Disable: Multimedia file I/O support #define MMNOMMSYSTEM // Disable: General MMSYSTEM functions #include typedef WINMMAPI DWORD (WINAPI *PTimeGetTime)(void); static double s_freq = 0.0; static HINSTANCE s_mmInstance = NULL; static PTimeGetTime s_tgt = NULL; // // ArchTimeWindows // ArchTimeWindows::ArchTimeWindows() { assert(s_freq == 0.0 || s_mmInstance == NULL); LARGE_INTEGER freq; if (QueryPerformanceFrequency(&freq) && freq.QuadPart != 0) { s_freq = 1.0 / static_cast(freq.QuadPart); } else { // load winmm.dll and get timeGetTime s_mmInstance = LoadLibrary("winmm"); if (s_mmInstance != NULL) { s_tgt = (PTimeGetTime)GetProcAddress(s_mmInstance, "timeGetTime"); } } } ArchTimeWindows::~ArchTimeWindows() { s_freq = 0.0; if (s_mmInstance == NULL) { FreeLibrary(static_cast(s_mmInstance)); s_tgt = NULL; s_mmInstance = NULL; } } double ArchTimeWindows::time() { // get time. we try three ways, in order of descending precision if (s_freq != 0.0) { LARGE_INTEGER c; QueryPerformanceCounter(&c); return s_freq * static_cast(c.QuadPart); } else if (s_tgt != NULL) { return 0.001 * static_cast(s_tgt()); } else { return 0.001 * static_cast(GetTickCount()); } } synergy-1.8.8-stable/src/lib/arch/win32/ArchTimeWindows.h000066400000000000000000000017511305627404700231500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchTime.h" #define ARCH_TIME ArchTimeWindows //! Win32 implementation of IArchTime class ArchTimeWindows : public IArchTime { public: ArchTimeWindows(); virtual ~ArchTimeWindows(); // IArchTime overrides virtual double time(); }; synergy-1.8.8-stable/src/lib/arch/win32/XArchWindows.cpp000066400000000000000000000135661305627404700230230ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/win32/XArchWindows.h" #include "arch/win32/ArchNetworkWinsock.h" #include "base/String.h" // // XArchEvalWindows // std::string XArchEvalWindows::eval() const throw() { char* cmsg; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, 0, m_error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&cmsg, 0, NULL) == 0) { cmsg = NULL; return synergy::string::sprintf("Unknown error, code %d", m_error); } std::string smsg(cmsg); LocalFree(cmsg); return smsg; } // // XArchEvalWinsock // std::string XArchEvalWinsock::eval() const throw() { // built-in windows function for looking up error message strings // may not look up network error messages correctly. we'll have // to do it ourself. static const struct { int m_code; const char* m_msg; } s_netErrorCodes[] = { /* 10004 */{WSAEINTR, "The (blocking) call was canceled via WSACancelBlockingCall"}, /* 10009 */{WSAEBADF, "Bad file handle"}, /* 10013 */{WSAEACCES, "The requested address is a broadcast address, but the appropriate flag was not set"}, /* 10014 */{WSAEFAULT, "WSAEFAULT"}, /* 10022 */{WSAEINVAL, "WSAEINVAL"}, /* 10024 */{WSAEMFILE, "No more file descriptors available"}, /* 10035 */{WSAEWOULDBLOCK, "Socket is marked as non-blocking and no connections are present or the receive operation would block"}, /* 10036 */{WSAEINPROGRESS, "A blocking Windows Sockets operation is in progress"}, /* 10037 */{WSAEALREADY, "The asynchronous routine being canceled has already completed"}, /* 10038 */{WSAENOTSOCK, "At least on descriptor is not a socket"}, /* 10039 */{WSAEDESTADDRREQ, "A destination address is required"}, /* 10040 */{WSAEMSGSIZE, "The datagram was too large to fit into the specified buffer and was truncated"}, /* 10041 */{WSAEPROTOTYPE, "The specified protocol is the wrong type for this socket"}, /* 10042 */{WSAENOPROTOOPT, "The option is unknown or unsupported"}, /* 10043 */{WSAEPROTONOSUPPORT,"The specified protocol is not supported"}, /* 10044 */{WSAESOCKTNOSUPPORT,"The specified socket type is not supported by this address family"}, /* 10045 */{WSAEOPNOTSUPP, "The referenced socket is not a type that supports that operation"}, /* 10046 */{WSAEPFNOSUPPORT, "BSD: Protocol family not supported"}, /* 10047 */{WSAEAFNOSUPPORT, "The specified address family is not supported"}, /* 10048 */{WSAEADDRINUSE, "The specified address is already in use"}, /* 10049 */{WSAEADDRNOTAVAIL, "The specified address is not available from the local machine"}, /* 10050 */{WSAENETDOWN, "The Windows Sockets implementation has detected that the network subsystem has failed"}, /* 10051 */{WSAENETUNREACH, "The network can't be reached from this host at this time"}, /* 10052 */{WSAENETRESET, "The connection must be reset because the Windows Sockets implementation dropped it"}, /* 10053 */{WSAECONNABORTED, "The virtual circuit was aborted due to timeout or other failure"}, /* 10054 */{WSAECONNRESET, "The virtual circuit was reset by the remote side"}, /* 10055 */{WSAENOBUFS, "No buffer space is available or a buffer deadlock has occured. The socket cannot be created"}, /* 10056 */{WSAEISCONN, "The socket is already connected"}, /* 10057 */{WSAENOTCONN, "The socket is not connected"}, /* 10058 */{WSAESHUTDOWN, "The socket has been shutdown"}, /* 10059 */{WSAETOOMANYREFS, "BSD: Too many references"}, /* 10060 */{WSAETIMEDOUT, "Attempt to connect timed out without establishing a connection"}, /* 10061 */{WSAECONNREFUSED, "Connection was refused"}, /* 10062 */{WSAELOOP, "Undocumented WinSock error code used in BSD"}, /* 10063 */{WSAENAMETOOLONG, "Undocumented WinSock error code used in BSD"}, /* 10064 */{WSAEHOSTDOWN, "Undocumented WinSock error code used in BSD"}, /* 10065 */{WSAEHOSTUNREACH, "No route to host"}, /* 10066 */{WSAENOTEMPTY, "Undocumented WinSock error code"}, /* 10067 */{WSAEPROCLIM, "Undocumented WinSock error code"}, /* 10068 */{WSAEUSERS, "Undocumented WinSock error code"}, /* 10069 */{WSAEDQUOT, "Undocumented WinSock error code"}, /* 10070 */{WSAESTALE, "Undocumented WinSock error code"}, /* 10071 */{WSAEREMOTE, "Undocumented WinSock error code"}, /* 10091 */{WSASYSNOTREADY, "Underlying network subsytem is not ready for network communication"}, /* 10092 */{WSAVERNOTSUPPORTED, "The version of WinSock API support requested is not provided in this implementation"}, /* 10093 */{WSANOTINITIALISED, "WinSock subsystem not properly initialized"}, /* 10101 */{WSAEDISCON, "Virtual circuit has gracefully terminated connection"}, /* 11001 */{WSAHOST_NOT_FOUND, "The specified host is unknown"}, /* 11002 */{WSATRY_AGAIN, "A temporary error occurred on an authoritative name server"}, /* 11003 */{WSANO_RECOVERY, "A non-recoverable name server error occurred"}, /* 11004 */{WSANO_DATA, "The requested name is valid but does not have an IP address"}, /* end */{0, NULL} }; for (unsigned int i = 0; s_netErrorCodes[i].m_code != 0; ++i) { if (s_netErrorCodes[i].m_code == m_error) { return s_netErrorCodes[i].m_msg; } } return "Unknown error"; } synergy-1.8.8-stable/src/lib/arch/win32/XArchWindows.h000066400000000000000000000025511305627404700224600ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/XArch.h" #define WIN32_LEAN_AND_MEAN #include //! Lazy error message string evaluation for windows class XArchEvalWindows : public XArchEval { public: XArchEvalWindows() : m_error(GetLastError()) { } XArchEvalWindows(DWORD error) : m_error(error) { } virtual ~XArchEvalWindows() { } virtual std::string eval() const; private: DWORD m_error; }; //! Lazy error message string evaluation for winsock class XArchEvalWinsock : public XArchEval { public: XArchEvalWinsock(int error) : m_error(error) { } virtual ~XArchEvalWinsock() { } virtual std::string eval() const; private: int m_error; }; synergy-1.8.8-stable/src/lib/base/000077500000000000000000000000001305627404700167575ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/base/CMakeLists.txt000066400000000000000000000017501305627404700215220ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ) if (UNIX) include_directories( ../../.. ) endif() add_library(base STATIC ${sources}) if (UNIX) target_link_libraries(base common) endif() synergy-1.8.8-stable/src/lib/base/ELevel.h000066400000000000000000000026141305627404700203070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once //! Log levels /*! The logging priority levels in order of highest to lowest priority. */ enum ELevel { kPRINT = -1, //!< For print only (no file or time) kFATAL, //!< For fatal errors kERROR, //!< For serious errors kWARNING, //!< For minor errors and warnings kNOTE, //!< For messages about notable events kINFO, //!< For informational messages kDEBUG, //!< For important debugging messages kDEBUG1, //!< For verbosity +1 debugging messages kDEBUG2, //!< For verbosity +2 debugging messages kDEBUG3, //!< For verbosity +3 debugging messages kDEBUG4, //!< For verbosity +4 debugging messages kDEBUG5 //!< For verbosity +5 debugging messages }; synergy-1.8.8-stable/src/lib/base/Event.cpp000066400000000000000000000033631305627404700205510ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "base/Event.h" #include "base/EventQueue.h" // // Event // Event::Event() : m_type(kUnknown), m_target(NULL), m_data(NULL), m_flags(0), m_dataObject(nullptr) { // do nothing } Event::Event(Type type, void* target, void* data, Flags flags) : m_type(type), m_target(target), m_data(data), m_flags(flags), m_dataObject(nullptr) { // do nothing } Event::Type Event::getType() const { return m_type; } void* Event::getTarget() const { return m_target; } void* Event::getData() const { return m_data; } EventData* Event::getDataObject() const { return m_dataObject; } Event::Flags Event::getFlags() const { return m_flags; } void Event::deleteData(const Event& event) { switch (event.getType()) { case kUnknown: case kQuit: case kSystem: case kTimer: break; default: if ((event.getFlags() & kDontFreeData) == 0) { free(event.getData()); delete event.getDataObject(); } break; } } void Event::setDataObject(EventData* dataObject) { assert(m_dataObject == nullptr); m_dataObject = dataObject; } synergy-1.8.8-stable/src/lib/base/Event.h000066400000000000000000000056621305627404700202220ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/basic_types.h" #include "common/stdmap.h" class EventData { public: EventData() { } virtual ~EventData() { } }; //! Event /*! A \c Event holds an event type and a pointer to event data. */ class Event { public: typedef UInt32 Type; enum { kUnknown, //!< The event type is unknown kQuit, //!< The quit event kSystem, //!< The data points to a system event type kTimer, //!< The data points to timer info kLast //!< Must be last }; typedef UInt32 Flags; enum { kNone = 0x00, //!< No flags kDeliverImmediately = 0x01, //!< Dispatch and free event immediately kDontFreeData = 0x02 //!< Don't free data in deleteData }; Event(); //! Create \c Event with data (POD) /*! The \p data must be POD (plain old data) allocated by malloc(), which means it cannot have a constructor, destructor or be composed of any types that do. For non-POD (normal C++ objects use \c setDataObject(). \p target is the intended recipient of the event. \p flags is any combination of \c Flags. */ Event(Type type, void* target = NULL, void* data = NULL, Flags flags = kNone); //! @name manipulators //@{ //! Release event data /*! Deletes event data for the given event (using free()). */ static void deleteData(const Event&); //! Set data (non-POD) /*! Set non-POD (non plain old data), where delete is called when the event is deleted, and the destructor is called. */ void setDataObject(EventData* dataObject); //@} //! @name accessors //@{ //! Get event type /*! Returns the event type. */ Type getType() const; //! Get the event target /*! Returns the event target. */ void* getTarget() const; //! Get the event data (POD). /*! Returns the event data (POD). */ void* getData() const; //! Get the event data (non-POD) /*! Returns the event data (non-POD). The difference between this and \c getData() is that when delete is called on this data, so non-POD (non plain old data) dtor is called. */ EventData* getDataObject() const; //! Get event flags /*! Returns the event flags. */ Flags getFlags() const; //@} private: Type m_type; void* m_target; void* m_data; Flags m_flags; EventData* m_dataObject; }; synergy-1.8.8-stable/src/lib/base/EventQueue.cpp000066400000000000000000000337051305627404700215610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "base/EventQueue.h" #include "mt/Mutex.h" #include "mt/Lock.h" #include "arch/Arch.h" #include "base/SimpleEventQueueBuffer.h" #include "base/Stopwatch.h" #include "base/IEventJob.h" #include "base/EventTypes.h" #include "base/Log.h" #include "base/XBase.h" EVENT_TYPE_ACCESSOR(Client) EVENT_TYPE_ACCESSOR(IStream) EVENT_TYPE_ACCESSOR(IpcClient) EVENT_TYPE_ACCESSOR(IpcClientProxy) EVENT_TYPE_ACCESSOR(IpcServer) EVENT_TYPE_ACCESSOR(IpcServerProxy) EVENT_TYPE_ACCESSOR(IDataSocket) EVENT_TYPE_ACCESSOR(IListenSocket) EVENT_TYPE_ACCESSOR(ISocket) EVENT_TYPE_ACCESSOR(OSXScreen) EVENT_TYPE_ACCESSOR(ClientListener) EVENT_TYPE_ACCESSOR(ClientProxy) EVENT_TYPE_ACCESSOR(ClientProxyUnknown) EVENT_TYPE_ACCESSOR(Server) EVENT_TYPE_ACCESSOR(ServerApp) EVENT_TYPE_ACCESSOR(IKeyState) EVENT_TYPE_ACCESSOR(IPrimaryScreen) EVENT_TYPE_ACCESSOR(IScreen) EVENT_TYPE_ACCESSOR(Clipboard) EVENT_TYPE_ACCESSOR(File) // interrupt handler. this just adds a quit event to the queue. static void interrupt(Arch::ESignal, void* data) { EventQueue* events = static_cast(data); events->addEvent(Event(Event::kQuit)); } // // EventQueue // EventQueue::EventQueue() : m_systemTarget(0), m_nextType(Event::kLast), m_typesForClient(NULL), m_typesForIStream(NULL), m_typesForIpcClient(NULL), m_typesForIpcClientProxy(NULL), m_typesForIpcServer(NULL), m_typesForIpcServerProxy(NULL), m_typesForIDataSocket(NULL), m_typesForIListenSocket(NULL), m_typesForISocket(NULL), m_typesForOSXScreen(NULL), m_typesForClientListener(NULL), m_typesForClientProxy(NULL), m_typesForClientProxyUnknown(NULL), m_typesForServer(NULL), m_typesForServerApp(NULL), m_typesForIKeyState(NULL), m_typesForIPrimaryScreen(NULL), m_typesForIScreen(NULL), m_typesForClipboard(NULL), m_typesForFile(NULL), m_readyMutex(new Mutex), m_readyCondVar(new CondVar(m_readyMutex, false)) { m_mutex = ARCH->newMutex(); ARCH->setSignalHandler(Arch::kINTERRUPT, &interrupt, this); ARCH->setSignalHandler(Arch::kTERMINATE, &interrupt, this); m_buffer = new SimpleEventQueueBuffer; } EventQueue::~EventQueue() { delete m_buffer; delete m_readyCondVar; delete m_readyMutex; ARCH->setSignalHandler(Arch::kINTERRUPT, NULL, NULL); ARCH->setSignalHandler(Arch::kTERMINATE, NULL, NULL); ARCH->closeMutex(m_mutex); } void EventQueue::loop() { m_buffer->init(); { Lock lock(m_readyMutex); *m_readyCondVar = true; m_readyCondVar->signal(); } LOG((CLOG_DEBUG "event queue is ready")); while (!m_pending.empty()) { LOG((CLOG_DEBUG "add pending events to buffer")); Event& event = m_pending.front(); addEventToBuffer(event); m_pending.pop(); } Event event; getEvent(event); while (event.getType() != Event::kQuit) { dispatchEvent(event); Event::deleteData(event); getEvent(event); } } Event::Type EventQueue::registerTypeOnce(Event::Type& type, const char* name) { ArchMutexLock lock(m_mutex); if (type == Event::kUnknown) { m_typeMap.insert(std::make_pair(m_nextType, name)); m_nameMap.insert(std::make_pair(name, m_nextType)); LOG((CLOG_DEBUG1 "registered event type %s as %d", name, m_nextType)); type = m_nextType++; } return type; } const char* EventQueue::getTypeName(Event::Type type) { switch (type) { case Event::kUnknown: return "nil"; case Event::kQuit: return "quit"; case Event::kSystem: return "system"; case Event::kTimer: return "timer"; default: TypeMap::const_iterator i = m_typeMap.find(type); if (i == m_typeMap.end()) { return ""; } else { return i->second; } } } void EventQueue::adoptBuffer(IEventQueueBuffer* buffer) { ArchMutexLock lock(m_mutex); LOG((CLOG_DEBUG "adopting new buffer")); if (m_events.size() != 0) { // this can come as a nasty surprise to programmers expecting // their events to be raised, only to have them deleted. LOG((CLOG_DEBUG "discarding %d event(s)", m_events.size())); } // discard old buffer and old events delete m_buffer; for (EventTable::iterator i = m_events.begin(); i != m_events.end(); ++i) { Event::deleteData(i->second); } m_events.clear(); m_oldEventIDs.clear(); // use new buffer m_buffer = buffer; if (m_buffer == NULL) { m_buffer = new SimpleEventQueueBuffer; } } bool EventQueue::getEvent(Event& event, double timeout) { Stopwatch timer(true); retry: // if no events are waiting then handle timers and then wait while (m_buffer->isEmpty()) { // handle timers first if (hasTimerExpired(event)) { return true; } // get time remaining in timeout double timeLeft = timeout - timer.getTime(); if (timeout >= 0.0 && timeLeft <= 0.0) { return false; } // get time until next timer expires. if there is a timer // and it'll expire before the client's timeout then use // that duration for our timeout instead. double timerTimeout = getNextTimerTimeout(); if (timeout < 0.0 || (timerTimeout >= 0.0 && timerTimeout < timeLeft)) { timeLeft = timerTimeout; } // wait for an event m_buffer->waitForEvent(timeLeft); } // get the event UInt32 dataID; IEventQueueBuffer::Type type = m_buffer->getEvent(event, dataID); switch (type) { case IEventQueueBuffer::kNone: if (timeout < 0.0 || timeout <= timer.getTime()) { // don't want to fail if client isn't expecting that // so if getEvent() fails with an infinite timeout // then just try getting another event. goto retry; } return false; case IEventQueueBuffer::kSystem: return true; case IEventQueueBuffer::kUser: { ArchMutexLock lock(m_mutex); event = removeEvent(dataID); return true; } default: assert(0 && "invalid event type"); return false; } } bool EventQueue::dispatchEvent(const Event& event) { void* target = event.getTarget(); IEventJob* job = getHandler(event.getType(), target); if (job == NULL) { job = getHandler(Event::kUnknown, target); } if (job != NULL) { job->run(event); return true; } return false; } void EventQueue::addEvent(const Event& event) { // discard bogus event types switch (event.getType()) { case Event::kUnknown: case Event::kSystem: case Event::kTimer: return; default: break; } if ((event.getFlags() & Event::kDeliverImmediately) != 0) { dispatchEvent(event); Event::deleteData(event); } else if (!(*m_readyCondVar)) { m_pending.push(event); } else { addEventToBuffer(event); } } void EventQueue::addEventToBuffer(const Event& event) { ArchMutexLock lock(m_mutex); // store the event's data locally UInt32 eventID = saveEvent(event); // add it if (!m_buffer->addEvent(eventID)) { // failed to send event removeEvent(eventID); Event::deleteData(event); } } EventQueueTimer* EventQueue::newTimer(double duration, void* target) { assert(duration > 0.0); EventQueueTimer* timer = m_buffer->newTimer(duration, false); if (target == NULL) { target = timer; } ArchMutexLock lock(m_mutex); m_timers.insert(timer); // initial duration is requested duration plus whatever's on // the clock currently because the latter will be subtracted // the next time we check for timers. m_timerQueue.push(Timer(timer, duration, duration + m_time.getTime(), target, false)); return timer; } EventQueueTimer* EventQueue::newOneShotTimer(double duration, void* target) { assert(duration > 0.0); EventQueueTimer* timer = m_buffer->newTimer(duration, true); if (target == NULL) { target = timer; } ArchMutexLock lock(m_mutex); m_timers.insert(timer); // initial duration is requested duration plus whatever's on // the clock currently because the latter will be subtracted // the next time we check for timers. m_timerQueue.push(Timer(timer, duration, duration + m_time.getTime(), target, true)); return timer; } void EventQueue::deleteTimer(EventQueueTimer* timer) { ArchMutexLock lock(m_mutex); for (TimerQueue::iterator index = m_timerQueue.begin(); index != m_timerQueue.end(); ++index) { if (index->getTimer() == timer) { m_timerQueue.erase(index); break; } } Timers::iterator index = m_timers.find(timer); if (index != m_timers.end()) { m_timers.erase(index); } m_buffer->deleteTimer(timer); } void EventQueue::adoptHandler(Event::Type type, void* target, IEventJob* handler) { ArchMutexLock lock(m_mutex); IEventJob*& job = m_handlers[target][type]; delete job; job = handler; } void EventQueue::removeHandler(Event::Type type, void* target) { IEventJob* handler = NULL; { ArchMutexLock lock(m_mutex); HandlerTable::iterator index = m_handlers.find(target); if (index != m_handlers.end()) { TypeHandlerTable& typeHandlers = index->second; TypeHandlerTable::iterator index2 = typeHandlers.find(type); if (index2 != typeHandlers.end()) { handler = index2->second; typeHandlers.erase(index2); } } } delete handler; } void EventQueue::removeHandlers(void* target) { std::vector handlers; { ArchMutexLock lock(m_mutex); HandlerTable::iterator index = m_handlers.find(target); if (index != m_handlers.end()) { // copy to handlers array and clear table for target TypeHandlerTable& typeHandlers = index->second; for (TypeHandlerTable::iterator index2 = typeHandlers.begin(); index2 != typeHandlers.end(); ++index2) { handlers.push_back(index2->second); } typeHandlers.clear(); } } // delete handlers for (std::vector::iterator index = handlers.begin(); index != handlers.end(); ++index) { delete *index; } } bool EventQueue::isEmpty() const { return (m_buffer->isEmpty() && getNextTimerTimeout() != 0.0); } IEventJob* EventQueue::getHandler(Event::Type type, void* target) const { ArchMutexLock lock(m_mutex); HandlerTable::const_iterator index = m_handlers.find(target); if (index != m_handlers.end()) { const TypeHandlerTable& typeHandlers = index->second; TypeHandlerTable::const_iterator index2 = typeHandlers.find(type); if (index2 != typeHandlers.end()) { return index2->second; } } return NULL; } UInt32 EventQueue::saveEvent(const Event& event) { // choose id UInt32 id; if (!m_oldEventIDs.empty()) { // reuse an id id = m_oldEventIDs.back(); m_oldEventIDs.pop_back(); } else { // make a new id id = static_cast(m_events.size()); } // save data m_events[id] = event; return id; } Event EventQueue::removeEvent(UInt32 eventID) { // look up id EventTable::iterator index = m_events.find(eventID); if (index == m_events.end()) { return Event(); } // get data Event event = index->second; m_events.erase(index); // save old id for reuse m_oldEventIDs.push_back(eventID); return event; } bool EventQueue::hasTimerExpired(Event& event) { // return true if there's a timer in the timer priority queue that // has expired. if returning true then fill in event appropriately // and reset and reinsert the timer. if (m_timerQueue.empty()) { return false; } // get time elapsed since last check const double time = m_time.getTime(); m_time.reset(); // countdown elapsed time for (TimerQueue::iterator index = m_timerQueue.begin(); index != m_timerQueue.end(); ++index) { (*index) -= time; } // done if no timers are expired if (m_timerQueue.top() > 0.0) { return false; } // remove timer from queue Timer timer = m_timerQueue.top(); m_timerQueue.pop(); // prepare event and reset the timer's clock timer.fillEvent(m_timerEvent); event = Event(Event::kTimer, timer.getTarget(), &m_timerEvent); timer.reset(); // reinsert timer into queue if it's not a one-shot if (!timer.isOneShot()) { m_timerQueue.push(timer); } return true; } double EventQueue::getNextTimerTimeout() const { // return -1 if no timers, 0 if the top timer has expired, otherwise // the time until the top timer in the timer priority queue will // expire. if (m_timerQueue.empty()) { return -1.0; } if (m_timerQueue.top() <= 0.0) { return 0.0; } return m_timerQueue.top(); } Event::Type EventQueue::getRegisteredType(const String& name) const { NameMap::const_iterator found = m_nameMap.find(name); if (found != m_nameMap.end()) return found->second; return Event::kUnknown; } void* EventQueue::getSystemTarget() { // any unique arbitrary pointer will do return &m_systemTarget; } void EventQueue::waitForReady() const { double timeout = ARCH->time() + 10; Lock lock(m_readyMutex); while (!m_readyCondVar->wait()) { if (ARCH->time() > timeout) { throw std::runtime_error("event queue is not ready within 5 sec"); } } } // // EventQueue::Timer // EventQueue::Timer::Timer(EventQueueTimer* timer, double timeout, double initialTime, void* target, bool oneShot) : m_timer(timer), m_timeout(timeout), m_target(target), m_oneShot(oneShot), m_time(initialTime) { assert(m_timeout > 0.0); } EventQueue::Timer::~Timer() { // do nothing } void EventQueue::Timer::reset() { m_time = m_timeout; } EventQueue::Timer& EventQueue::Timer::operator-=(double dt) { m_time -= dt; return *this; } EventQueue::Timer::operator double() const { return m_time; } bool EventQueue::Timer::isOneShot() const { return m_oneShot; } EventQueueTimer* EventQueue::Timer::getTimer() const { return m_timer; } void* EventQueue::Timer::getTarget() const { return m_target; } void EventQueue::Timer::fillEvent(TimerEvent& event) const { event.m_timer = m_timer; event.m_count = 0; if (m_time <= 0.0) { event.m_count = static_cast((m_timeout - m_time) / m_timeout); } } bool EventQueue::Timer::operator<(const Timer& t) const { return m_time < t.m_time; } synergy-1.8.8-stable/src/lib/base/EventQueue.h000066400000000000000000000134741305627404700212270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "mt/CondVar.h" #include "arch/IArchMultithread.h" #include "base/IEventQueue.h" #include "base/Event.h" #include "base/PriorityQueue.h" #include "base/Stopwatch.h" #include "common/stdmap.h" #include "common/stdset.h" #include class Mutex; //! Event queue /*! An event queue that implements the platform independent parts and delegates the platform dependent parts to a subclass. */ class EventQueue : public IEventQueue { public: EventQueue(); virtual ~EventQueue(); // IEventQueue overrides virtual void loop(); virtual void adoptBuffer(IEventQueueBuffer*); virtual bool getEvent(Event& event, double timeout = -1.0); virtual bool dispatchEvent(const Event& event); virtual void addEvent(const Event& event); virtual EventQueueTimer* newTimer(double duration, void* target); virtual EventQueueTimer* newOneShotTimer(double duration, void* target); virtual void deleteTimer(EventQueueTimer*); virtual void adoptHandler(Event::Type type, void* target, IEventJob* handler); virtual void removeHandler(Event::Type type, void* target); virtual void removeHandlers(void* target); virtual Event::Type registerTypeOnce(Event::Type& type, const char* name); virtual bool isEmpty() const; virtual IEventJob* getHandler(Event::Type type, void* target) const; virtual const char* getTypeName(Event::Type type); virtual Event::Type getRegisteredType(const String& name) const; void* getSystemTarget(); virtual void waitForReady() const; private: UInt32 saveEvent(const Event& event); Event removeEvent(UInt32 eventID); bool hasTimerExpired(Event& event); double getNextTimerTimeout() const; void addEventToBuffer(const Event& event); private: class Timer { public: Timer(EventQueueTimer*, double timeout, double initialTime, void* target, bool oneShot); ~Timer(); void reset(); Timer& operator-=(double); operator double() const; bool isOneShot() const; EventQueueTimer* getTimer() const; void* getTarget() const; void fillEvent(TimerEvent&) const; bool operator<(const Timer&) const; private: EventQueueTimer* m_timer; double m_timeout; void* m_target; bool m_oneShot; double m_time; }; typedef std::set Timers; typedef PriorityQueue TimerQueue; typedef std::map EventTable; typedef std::vector EventIDList; typedef std::map TypeMap; typedef std::map NameMap; typedef std::map TypeHandlerTable; typedef std::map HandlerTable; int m_systemTarget; ArchMutex m_mutex; // registered events Event::Type m_nextType; TypeMap m_typeMap; NameMap m_nameMap; // buffer of events IEventQueueBuffer* m_buffer; // saved events EventTable m_events; EventIDList m_oldEventIDs; // timers Stopwatch m_time; Timers m_timers; TimerQueue m_timerQueue; TimerEvent m_timerEvent; // event handlers HandlerTable m_handlers; public: // // Event type providers. // ClientEvents& forClient(); IStreamEvents& forIStream(); IpcClientEvents& forIpcClient(); IpcClientProxyEvents& forIpcClientProxy(); IpcServerEvents& forIpcServer(); IpcServerProxyEvents& forIpcServerProxy(); IDataSocketEvents& forIDataSocket(); IListenSocketEvents& forIListenSocket(); ISocketEvents& forISocket(); OSXScreenEvents& forOSXScreen(); ClientListenerEvents& forClientListener(); ClientProxyEvents& forClientProxy(); ClientProxyUnknownEvents& forClientProxyUnknown(); ServerEvents& forServer(); ServerAppEvents& forServerApp(); IKeyStateEvents& forIKeyState(); IPrimaryScreenEvents& forIPrimaryScreen(); IScreenEvents& forIScreen(); ClipboardEvents& forClipboard(); FileEvents& forFile(); private: ClientEvents* m_typesForClient; IStreamEvents* m_typesForIStream; IpcClientEvents* m_typesForIpcClient; IpcClientProxyEvents* m_typesForIpcClientProxy; IpcServerEvents* m_typesForIpcServer; IpcServerProxyEvents* m_typesForIpcServerProxy; IDataSocketEvents* m_typesForIDataSocket; IListenSocketEvents* m_typesForIListenSocket; ISocketEvents* m_typesForISocket; OSXScreenEvents* m_typesForOSXScreen; ClientListenerEvents* m_typesForClientListener; ClientProxyEvents* m_typesForClientProxy; ClientProxyUnknownEvents* m_typesForClientProxyUnknown; ServerEvents* m_typesForServer; ServerAppEvents* m_typesForServerApp; IKeyStateEvents* m_typesForIKeyState; IPrimaryScreenEvents* m_typesForIPrimaryScreen; IScreenEvents* m_typesForIScreen; ClipboardEvents* m_typesForClipboard; FileEvents* m_typesForFile; Mutex* m_readyMutex; CondVar* m_readyCondVar; std::queue m_pending; }; #define EVENT_TYPE_ACCESSOR(type_) \ type_##Events& \ EventQueue::for##type_() { \ if (m_typesFor##type_ == NULL) { \ m_typesFor##type_ = new type_##Events(); \ m_typesFor##type_->setEvents(dynamic_cast(this)); \ } \ return *m_typesFor##type_; \ } synergy-1.8.8-stable/src/lib/base/EventTypes.cpp000066400000000000000000000076461305627404700216060ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "base/EventTypes.h" #include "base/IEventQueue.h" #include #include EventTypes::EventTypes() : m_events(NULL) { } IEventQueue* EventTypes::getEvents() const { assert(m_events != NULL); return m_events; } void EventTypes::setEvents(IEventQueue* events) { m_events = events; } // // Client // REGISTER_EVENT(Client, connected) REGISTER_EVENT(Client, connectionFailed) REGISTER_EVENT(Client, disconnected) // // IStream // REGISTER_EVENT(IStream, inputReady) REGISTER_EVENT(IStream, outputFlushed) REGISTER_EVENT(IStream, outputError) REGISTER_EVENT(IStream, inputShutdown) REGISTER_EVENT(IStream, outputShutdown) // // IpcClient // REGISTER_EVENT(IpcClient, connected) REGISTER_EVENT(IpcClient, messageReceived) // // IpcClientProxy // REGISTER_EVENT(IpcClientProxy, messageReceived) REGISTER_EVENT(IpcClientProxy, disconnected) // // IpcServerProxy // REGISTER_EVENT(IpcServerProxy, messageReceived) // // IDataSocket // REGISTER_EVENT(IDataSocket, connected) REGISTER_EVENT(IDataSocket, secureConnected) REGISTER_EVENT(IDataSocket, connectionFailed) // // IListenSocket // REGISTER_EVENT(IListenSocket, connecting) // // ISocket // REGISTER_EVENT(ISocket, disconnected) REGISTER_EVENT(ISocket, stopRetry) // // OSXScreen // REGISTER_EVENT(OSXScreen, confirmSleep) // // ClientListener // REGISTER_EVENT(ClientListener, accepted) REGISTER_EVENT(ClientListener, connected) // // ClientProxy // REGISTER_EVENT(ClientProxy, ready) REGISTER_EVENT(ClientProxy, disconnected) // // ClientProxyUnknown // REGISTER_EVENT(ClientProxyUnknown, success) REGISTER_EVENT(ClientProxyUnknown, failure) // // Server // REGISTER_EVENT(Server, error) REGISTER_EVENT(Server, connected) REGISTER_EVENT(Server, disconnected) REGISTER_EVENT(Server, switchToScreen) REGISTER_EVENT(Server, switchInDirection) REGISTER_EVENT(Server, keyboardBroadcast) REGISTER_EVENT(Server, lockCursorToScreen) REGISTER_EVENT(Server, screenSwitched) // // ServerApp // REGISTER_EVENT(ServerApp, reloadConfig) REGISTER_EVENT(ServerApp, forceReconnect) REGISTER_EVENT(ServerApp, resetServer) // // IKeyState // REGISTER_EVENT(IKeyState, keyDown) REGISTER_EVENT(IKeyState, keyUp) REGISTER_EVENT(IKeyState, keyRepeat) // // IPrimaryScreen // REGISTER_EVENT(IPrimaryScreen, buttonDown) REGISTER_EVENT(IPrimaryScreen, buttonUp) REGISTER_EVENT(IPrimaryScreen, motionOnPrimary) REGISTER_EVENT(IPrimaryScreen, motionOnSecondary) REGISTER_EVENT(IPrimaryScreen, wheel) REGISTER_EVENT(IPrimaryScreen, screensaverActivated) REGISTER_EVENT(IPrimaryScreen, screensaverDeactivated) REGISTER_EVENT(IPrimaryScreen, hotKeyDown) REGISTER_EVENT(IPrimaryScreen, hotKeyUp) REGISTER_EVENT(IPrimaryScreen, fakeInputBegin) REGISTER_EVENT(IPrimaryScreen, fakeInputEnd) // // IScreen // REGISTER_EVENT(IScreen, error) REGISTER_EVENT(IScreen, shapeChanged) REGISTER_EVENT(IScreen, suspend) REGISTER_EVENT(IScreen, resume) // // IpcServer // REGISTER_EVENT(IpcServer, clientConnected) REGISTER_EVENT(IpcServer, messageReceived) // // Clipboard // REGISTER_EVENT(Clipboard, clipboardGrabbed) REGISTER_EVENT(Clipboard, clipboardChanged) REGISTER_EVENT(Clipboard, clipboardSending) // // File // REGISTER_EVENT(File, fileChunkSending) REGISTER_EVENT(File, fileRecieveCompleted) REGISTER_EVENT(File, keepAlive) synergy-1.8.8-stable/src/lib/base/EventTypes.h000066400000000000000000000421131305627404700212370ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/Event.h" class IEventQueue; class EventTypes { public: EventTypes(); void setEvents(IEventQueue* events); protected: IEventQueue* getEvents() const; private: IEventQueue* m_events; }; #define REGISTER_EVENT(type_, name_) \ Event::Type \ type_##Events::name_() \ { \ return getEvents()->registerTypeOnce(m_##name_, __FUNCTION__); \ } class ClientEvents : public EventTypes { public: ClientEvents() : m_connected(Event::kUnknown), m_connectionFailed(Event::kUnknown), m_disconnected(Event::kUnknown) { } //! @name accessors //@{ //! Get connected event type /*! Returns the connected event type. This is sent when the client has successfully connected to the server. */ Event::Type connected(); //! Get connection failed event type /*! Returns the connection failed event type. This is sent when the server fails for some reason. The event data is a FailInfo*. */ Event::Type connectionFailed(); //! Get disconnected event type /*! Returns the disconnected event type. This is sent when the client has disconnected from the server (and only after having successfully connected). */ Event::Type disconnected(); //@} private: Event::Type m_connected; Event::Type m_connectionFailed; Event::Type m_disconnected; }; class IStreamEvents : public EventTypes { public: IStreamEvents() : m_inputReady(Event::kUnknown), m_outputFlushed(Event::kUnknown), m_outputError(Event::kUnknown), m_inputShutdown(Event::kUnknown), m_outputShutdown(Event::kUnknown) { } //! @name accessors //@{ //! Get input ready event type /*! Returns the input ready event type. A stream sends this event when \c read() will return with data. */ Event::Type inputReady(); //! Get output flushed event type /*! Returns the output flushed event type. A stream sends this event when the output buffer has been flushed. If there have been no writes since the event was posted, calling \c shutdownOutput() or \c close() will not discard any data and \c flush() will return immediately. */ Event::Type outputFlushed(); //! Get output error event type /*! Returns the output error event type. A stream sends this event when a write has failed. */ Event::Type outputError(); //! Get input shutdown event type /*! Returns the input shutdown event type. This is sent when the input side of the stream has shutdown. When the input has shutdown, no more data will ever be available to read. */ Event::Type inputShutdown(); //! Get output shutdown event type /*! Returns the output shutdown event type. This is sent when the output side of the stream has shutdown. When the output has shutdown, no more data can ever be written to the stream. Any attempt to do so will generate a output error event. */ Event::Type outputShutdown(); //@} private: Event::Type m_inputReady; Event::Type m_outputFlushed; Event::Type m_outputError; Event::Type m_inputShutdown; Event::Type m_outputShutdown; }; class IpcClientEvents : public EventTypes { public: IpcClientEvents() : m_connected(Event::kUnknown), m_messageReceived(Event::kUnknown) { } //! @name accessors //@{ //! Raised when the socket is connected. Event::Type connected(); //! Raised when a message is received. Event::Type messageReceived(); //@} private: Event::Type m_connected; Event::Type m_messageReceived; }; class IpcClientProxyEvents : public EventTypes { public: IpcClientProxyEvents() : m_messageReceived(Event::kUnknown), m_disconnected(Event::kUnknown) { } //! @name accessors //@{ //! Raised when the server receives a message from a client. Event::Type messageReceived(); //! Raised when the client disconnects from the server. Event::Type disconnected(); //@} private: Event::Type m_messageReceived; Event::Type m_disconnected; }; class IpcServerEvents : public EventTypes { public: IpcServerEvents() : m_clientConnected(Event::kUnknown), m_messageReceived(Event::kUnknown) { } //! @name accessors //@{ //! Raised when we have created the client proxy. Event::Type clientConnected(); //! Raised when a message is received through a client proxy. Event::Type messageReceived(); //@} private: Event::Type m_clientConnected; Event::Type m_messageReceived; }; class IpcServerProxyEvents : public EventTypes { public: IpcServerProxyEvents() : m_messageReceived(Event::kUnknown) { } //! @name accessors //@{ //! Raised when the client receives a message from the server. Event::Type messageReceived(); //@} private: Event::Type m_messageReceived; }; class IDataSocketEvents : public EventTypes { public: IDataSocketEvents() : m_connected(Event::kUnknown), m_secureConnected(Event::kUnknown), m_connectionFailed(Event::kUnknown) { } //! @name accessors //@{ //! Get connected event type /*! Returns the socket connected event type. A socket sends this event when a remote connection has been established. */ Event::Type connected(); //! Get secure connected event type /*! Returns the secure socket connected event type. A secure socket sends this event when a remote connection has been established. */ Event::Type secureConnected(); //! Get connection failed event type /*! Returns the socket connection failed event type. A socket sends this event when an attempt to connect to a remote port has failed. The data is a pointer to a ConnectionFailedInfo. */ Event::Type connectionFailed(); //@} private: Event::Type m_connected; Event::Type m_secureConnected; Event::Type m_connectionFailed; }; class IListenSocketEvents : public EventTypes { public: IListenSocketEvents() : m_connecting(Event::kUnknown) { } //! @name accessors //@{ //! Get connecting event type /*! Returns the socket connecting event type. A socket sends this event when a remote connection is waiting to be accepted. */ Event::Type connecting(); //@} private: Event::Type m_connecting; }; class ISocketEvents : public EventTypes { public: ISocketEvents() : m_disconnected(Event::kUnknown), m_stopRetry(Event::kUnknown) { } //! @name accessors //@{ //! Get disconnected event type /*! Returns the socket disconnected event type. A socket sends this event when the remote side of the socket has disconnected or shutdown both input and output. */ Event::Type disconnected(); //! Get stop retry event type /*! Returns the stop retry event type. This is sent when the client doesn't want to reconnect after it disconnects from the server. */ Event::Type stopRetry(); //@} private: Event::Type m_disconnected; Event::Type m_stopRetry; }; class OSXScreenEvents : public EventTypes { public: OSXScreenEvents() : m_confirmSleep(Event::kUnknown) { } //! @name accessors //@{ Event::Type confirmSleep(); //@} private: Event::Type m_confirmSleep; }; class ClientListenerEvents : public EventTypes { public: ClientListenerEvents() : m_accepted(Event::kUnknown), m_connected(Event::kUnknown) { } //! @name accessors //@{ //! Get accepted event type /*! Returns the accepted event type. This is sent whenever a server accepts a client. */ Event::Type accepted(); //! Get connected event type /*! Returns the connected event type. This is sent whenever a a client connects. */ Event::Type connected(); //@} private: Event::Type m_accepted; Event::Type m_connected; }; class ClientProxyEvents : public EventTypes { public: ClientProxyEvents() : m_ready(Event::kUnknown), m_disconnected(Event::kUnknown) { } //! @name accessors //@{ //! Get ready event type /*! Returns the ready event type. This is sent when the client has completed the initial handshake. Until it is sent, the client is not fully connected. */ Event::Type ready(); //! Get disconnect event type /*! Returns the disconnect event type. This is sent when the client disconnects or is disconnected. The target is getEventTarget(). */ Event::Type disconnected(); //@} private: Event::Type m_ready; Event::Type m_disconnected; }; class ClientProxyUnknownEvents : public EventTypes { public: ClientProxyUnknownEvents() : m_success(Event::kUnknown), m_failure(Event::kUnknown) { } //! @name accessors //@{ //! Get success event type /*! Returns the success event type. This is sent when the client has correctly responded to the hello message. The target is this. */ Event::Type success(); //! Get failure event type /*! Returns the failure event type. This is sent when a client fails to correctly respond to the hello message. The target is this. */ Event::Type failure(); //@} private: Event::Type m_success; Event::Type m_failure; }; class ServerEvents : public EventTypes { public: ServerEvents() : m_error(Event::kUnknown), m_connected(Event::kUnknown), m_disconnected(Event::kUnknown), m_switchToScreen(Event::kUnknown), m_switchInDirection(Event::kUnknown), m_keyboardBroadcast(Event::kUnknown), m_lockCursorToScreen(Event::kUnknown), m_screenSwitched(Event::kUnknown) { } //! @name accessors //@{ //! Get error event type /*! Returns the error event type. This is sent when the server fails for some reason. */ Event::Type error(); //! Get connected event type /*! Returns the connected event type. This is sent when a client screen has connected. The event data is a \c ScreenConnectedInfo* that indicates the connected screen. */ Event::Type connected(); //! Get disconnected event type /*! Returns the disconnected event type. This is sent when all the clients have disconnected. */ Event::Type disconnected(); //! Get switch to screen event type /*! Returns the switch to screen event type. The server responds to this by switching screens. The event data is a \c SwitchToScreenInfo* that indicates the target screen. */ Event::Type switchToScreen(); //! Get switch in direction event type /*! Returns the switch in direction event type. The server responds to this by switching screens. The event data is a \c SwitchInDirectionInfo* that indicates the target direction. */ Event::Type switchInDirection(); //! Get keyboard broadcast event type /*! Returns the keyboard broadcast event type. The server responds to this by turning on keyboard broadcasting or turning it off. The event data is a \c KeyboardBroadcastInfo*. */ Event::Type keyboardBroadcast(); //! Get lock cursor event type /*! Returns the lock cursor event type. The server responds to this by locking the cursor to the active screen or unlocking it. The event data is a \c LockCursorToScreenInfo*. */ Event::Type lockCursorToScreen(); //! Get screen switched event type /*! Returns the screen switched event type. This is raised when the screen has been switched to a client. */ Event::Type screenSwitched(); //@} private: Event::Type m_error; Event::Type m_connected; Event::Type m_disconnected; Event::Type m_switchToScreen; Event::Type m_switchInDirection; Event::Type m_keyboardBroadcast; Event::Type m_lockCursorToScreen; Event::Type m_screenSwitched; }; class ServerAppEvents : public EventTypes { public: ServerAppEvents() : m_reloadConfig(Event::kUnknown), m_forceReconnect(Event::kUnknown), m_resetServer(Event::kUnknown) { } //! @name accessors //@{ Event::Type reloadConfig(); Event::Type forceReconnect(); Event::Type resetServer(); //@} private: Event::Type m_reloadConfig; Event::Type m_forceReconnect; Event::Type m_resetServer; }; class IKeyStateEvents : public EventTypes { public: IKeyStateEvents() : m_keyDown(Event::kUnknown), m_keyUp(Event::kUnknown), m_keyRepeat(Event::kUnknown) { } //! @name accessors //@{ //! Get key down event type. Event data is KeyInfo*, count == 1. Event::Type keyDown(); //! Get key up event type. Event data is KeyInfo*, count == 1. Event::Type keyUp(); //! Get key repeat event type. Event data is KeyInfo*. Event::Type keyRepeat(); //@} private: Event::Type m_keyDown; Event::Type m_keyUp; Event::Type m_keyRepeat; }; class IPrimaryScreenEvents : public EventTypes { public: IPrimaryScreenEvents() : m_buttonDown(Event::kUnknown), m_buttonUp(Event::kUnknown), m_motionOnPrimary(Event::kUnknown), m_motionOnSecondary(Event::kUnknown), m_wheel(Event::kUnknown), m_screensaverActivated(Event::kUnknown), m_screensaverDeactivated(Event::kUnknown), m_hotKeyDown(Event::kUnknown), m_hotKeyUp(Event::kUnknown), m_fakeInputBegin(Event::kUnknown), m_fakeInputEnd(Event::kUnknown) { } //! @name accessors //@{ //! button down event type. Event data is ButtonInfo*. Event::Type buttonDown(); //! button up event type. Event data is ButtonInfo*. Event::Type buttonUp(); //! mouse motion on the primary screen event type /*! Event data is MotionInfo* and the values are an absolute position. */ Event::Type motionOnPrimary(); //! mouse motion on a secondary screen event type /*! Event data is MotionInfo* and the values are motion deltas not absolute coordinates. */ Event::Type motionOnSecondary(); //! mouse wheel event type. Event data is WheelInfo*. Event::Type wheel(); //! screensaver activated event type Event::Type screensaverActivated(); //! screensaver deactivated event type Event::Type screensaverDeactivated(); //! hot key down event type. Event data is HotKeyInfo*. Event::Type hotKeyDown(); //! hot key up event type. Event data is HotKeyInfo*. Event::Type hotKeyUp(); //! start of fake input event type Event::Type fakeInputBegin(); //! end of fake input event type Event::Type fakeInputEnd(); //@} private: Event::Type m_buttonDown; Event::Type m_buttonUp; Event::Type m_motionOnPrimary; Event::Type m_motionOnSecondary; Event::Type m_wheel; Event::Type m_screensaverActivated; Event::Type m_screensaverDeactivated; Event::Type m_hotKeyDown; Event::Type m_hotKeyUp; Event::Type m_fakeInputBegin; Event::Type m_fakeInputEnd; }; class IScreenEvents : public EventTypes { public: IScreenEvents() : m_error(Event::kUnknown), m_shapeChanged(Event::kUnknown), m_suspend(Event::kUnknown), m_resume(Event::kUnknown) { } //! @name accessors //@{ //! Get error event type /*! Returns the error event type. This is sent whenever the screen has failed for some reason (e.g. the X Windows server died). */ Event::Type error(); //! Get shape changed event type /*! Returns the shape changed event type. This is sent whenever the screen's shape changes. */ Event::Type shapeChanged(); //! Get suspend event type /*! Returns the suspend event type. This is sent whenever the system goes to sleep or a user session is deactivated (fast user switching). */ Event::Type suspend(); //! Get resume event type /*! Returns the resume event type. This is sent whenever the system wakes up or a user session is activated (fast user switching). */ Event::Type resume(); //@} private: Event::Type m_error; Event::Type m_shapeChanged; Event::Type m_suspend; Event::Type m_resume; }; class ClipboardEvents : public EventTypes { public: ClipboardEvents() : m_clipboardGrabbed(Event::kUnknown), m_clipboardChanged(Event::kUnknown), m_clipboardSending(Event::kUnknown) { } //! @name accessors //@{ //! Get clipboard grabbed event type /*! Returns the clipboard grabbed event type. This is sent whenever the clipboard is grabbed by some other application so we don't own it anymore. The data is a pointer to a ClipboardInfo. */ Event::Type clipboardGrabbed(); //! Get clipboard changed event type /*! Returns the clipboard changed event type. This is sent whenever the contents of the clipboard has changed. The data is a pointer to a IScreen::ClipboardInfo. */ Event::Type clipboardChanged(); //! Clipboard sending event type /*! Returns the clipboard sending event type. This is used to send clipboard chunks. */ Event::Type clipboardSending(); //@} private: Event::Type m_clipboardGrabbed; Event::Type m_clipboardChanged; Event::Type m_clipboardSending; }; class FileEvents : public EventTypes { public: FileEvents() : m_fileChunkSending(Event::kUnknown), m_fileRecieveCompleted(Event::kUnknown), m_keepAlive(Event::kUnknown) { } //! @name accessors //@{ //! Sending a file chunk Event::Type fileChunkSending(); //! Completed receiving a file Event::Type fileRecieveCompleted(); //! Send a keep alive Event::Type keepAlive(); //@} private: Event::Type m_fileChunkSending; Event::Type m_fileRecieveCompleted; Event::Type m_keepAlive; }; synergy-1.8.8-stable/src/lib/base/FunctionEventJob.cpp000066400000000000000000000021011305627404700226770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "base/FunctionEventJob.h" // // FunctionEventJob // FunctionEventJob::FunctionEventJob( void (*func)(const Event&, void*), void* arg) : m_func(func), m_arg(arg) { // do nothing } FunctionEventJob::~FunctionEventJob() { // do nothing } void FunctionEventJob::run(const Event& event) { if (m_func != NULL) { m_func(event, m_arg); } } synergy-1.8.8-stable/src/lib/base/FunctionEventJob.h000066400000000000000000000022311305627404700223500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/IEventJob.h" //! Use a function as an event job /*! An event job class that invokes a function. */ class FunctionEventJob : public IEventJob { public: //! run() invokes \c func(arg) FunctionEventJob(void (*func)(const Event&, void*), void* arg = NULL); virtual ~FunctionEventJob(); // IEventJob overrides virtual void run(const Event&); private: void (*m_func)(const Event&, void*); void* m_arg; }; synergy-1.8.8-stable/src/lib/base/FunctionJob.cpp000066400000000000000000000017621305627404700217110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "base/FunctionJob.h" // // FunctionJob // FunctionJob::FunctionJob(void (*func)(void*), void* arg) : m_func(func), m_arg(arg) { // do nothing } FunctionJob::~FunctionJob() { // do nothing } void FunctionJob::run() { if (m_func != NULL) { m_func(m_arg); } } synergy-1.8.8-stable/src/lib/base/FunctionJob.h000066400000000000000000000021051305627404700213460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/IJob.h" //! Use a function as a job /*! A job class that invokes a function. */ class FunctionJob : public IJob { public: //! run() invokes \c func(arg) FunctionJob(void (*func)(void*), void* arg = NULL); virtual ~FunctionJob(); // IJob overrides virtual void run(); private: void (*m_func)(void*); void* m_arg; }; synergy-1.8.8-stable/src/lib/base/IEventJob.h000066400000000000000000000017371305627404700207650ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" class Event; //! Event handler interface /*! An event job is an interface for executing a event handler. */ class IEventJob : public IInterface { public: //! Run the job virtual void run(const Event&) = 0; }; synergy-1.8.8-stable/src/lib/base/IEventQueue.h000066400000000000000000000174041305627404700213350ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "base/Event.h" #include "base/String.h" class IEventJob; class IEventQueueBuffer; // Opaque type for timer info. This is defined by subclasses of // IEventQueueBuffer. class EventQueueTimer; // Event type registration classes. class ClientEvents; class IStreamEvents; class IpcClientEvents; class IpcClientProxyEvents; class IpcServerEvents; class IpcServerProxyEvents; class IDataSocketEvents; class IListenSocketEvents; class ISocketEvents; class OSXScreenEvents; class ClientListenerEvents; class ClientProxyEvents; class ClientProxyUnknownEvents; class ServerEvents; class ServerAppEvents; class IKeyStateEvents; class IPrimaryScreenEvents; class IScreenEvents; class ClipboardEvents; class FileEvents; //! Event queue interface /*! An event queue provides a queue of Events. Clients can block waiting on any event becoming available at the head of the queue and can place new events at the end of the queue. Clients can also add and remove timers which generate events periodically. */ class IEventQueue : public IInterface { public: class TimerEvent { public: EventQueueTimer* m_timer; //!< The timer UInt32 m_count; //!< Number of repeats }; //! @name manipulators //@{ //! Loop the event queue until quit /*! Dequeues and dispatches events until the kQuit event is found. */ virtual void loop() = 0; //! Set the buffer /*! Replace the current event queue buffer. Any queued events are discarded. The queue takes ownership of the buffer. */ virtual void adoptBuffer(IEventQueueBuffer*) = 0; //! Remove event from queue /*! Returns the next event on the queue into \p event. If no event is available then blocks for up to \p timeout seconds, or forever if \p timeout is negative. Returns true iff an event was available. */ virtual bool getEvent(Event& event, double timeout = -1.0) = 0; //! Dispatch an event /*! Looks up the dispatcher for the event's target and invokes it. Returns true iff a dispatcher exists for the target. */ virtual bool dispatchEvent(const Event& event) = 0; //! Add event to queue /*! Adds \p event to the end of the queue. */ virtual void addEvent(const Event& event) = 0; //! Create a recurring timer /*! Creates and returns a timer. An event is returned after \p duration seconds and the timer is reset to countdown again. When a timer event is returned the data points to a \c TimerEvent. The client must pass the returned timer to \c deleteTimer() (whether or not the timer has expired) to release the timer. The returned timer event uses the given \p target. If \p target is NULL it uses the returned timer as the target. Events for a single timer don't accumulate in the queue, even if the client reading events can't keep up. Instead, the \c m_count member of the \c TimerEvent indicates how many events for the timer would have been put on the queue since the last event for the timer was removed (or since the timer was added). */ virtual EventQueueTimer* newTimer(double duration, void* target) = 0; //! Create a one-shot timer /*! Creates and returns a one-shot timer. An event is returned when the timer expires and the timer is removed from further handling. When a timer event is returned the data points to a \c TimerEvent. The c_count member of the \c TimerEvent is always 1. The client must pass the returned timer to \c deleteTimer() (whether or not the timer has expired) to release the timer. The returned timer event uses the given \p target. If \p target is NULL it uses the returned timer as the target. */ virtual EventQueueTimer* newOneShotTimer(double duration, void* target) = 0; //! Destroy a timer /*! Destroys a previously created timer. The timer is removed from the queue and will not generate event, even if the timer has expired. */ virtual void deleteTimer(EventQueueTimer*) = 0; //! Register an event handler for an event type /*! Registers an event handler for \p type and \p target. The \p handler is adopted. Any existing handler for the type,target pair is deleted. \c dispatchEvent() will invoke \p handler for any event for \p target of type \p type. If no such handler exists it will use the handler for \p target and type \p kUnknown if it exists. */ virtual void adoptHandler(Event::Type type, void* target, IEventJob* handler) = 0; //! Unregister an event handler for an event type /*! Unregisters an event handler for the \p type, \p target pair and deletes it. */ virtual void removeHandler(Event::Type type, void* target) = 0; //! Unregister all event handlers for an event target /*! Unregisters all event handlers for the \p target and deletes them. */ virtual void removeHandlers(void* target) = 0; //! Creates a new event type /*! If \p type contains \c kUnknown then it is set to a unique event type id otherwise it is left alone. The final value of \p type is returned. */ virtual Event::Type registerTypeOnce(Event::Type& type, const char* name) = 0; //! Wait for event queue to become ready /*! Blocks on the current thread until the event queue is ready for events to be added. */ virtual void waitForReady() const = 0; //@} //! @name accessors //@{ //! Test if queue is empty /*! Returns true iff the queue has no events in it, including timer events. */ virtual bool isEmpty() const = 0; //! Get an event handler /*! Finds and returns the event handler for the \p type, \p target pair if it exists, otherwise it returns NULL. */ virtual IEventJob* getHandler(Event::Type type, void* target) const = 0; //! Get name for event /*! Returns the name for the event \p type. This is primarily for debugging. */ virtual const char* getTypeName(Event::Type type) = 0; //! Get an event type by name /*! Returns the registered type for an event for a given name. */ virtual Event::Type getRegisteredType(const String& name) const = 0; //! Get the system event type target /*! Returns the target to use for dispatching \c Event::kSystem events. */ virtual void* getSystemTarget() = 0; //@} // // Event type providers. // virtual ClientEvents& forClient() = 0; virtual IStreamEvents& forIStream() = 0; virtual IpcClientEvents& forIpcClient() = 0; virtual IpcClientProxyEvents& forIpcClientProxy() = 0; virtual IpcServerEvents& forIpcServer() = 0; virtual IpcServerProxyEvents& forIpcServerProxy() = 0; virtual IDataSocketEvents& forIDataSocket() = 0; virtual IListenSocketEvents& forIListenSocket() = 0; virtual ISocketEvents& forISocket() = 0; virtual OSXScreenEvents& forOSXScreen() = 0; virtual ClientListenerEvents& forClientListener() = 0; virtual ClientProxyEvents& forClientProxy() = 0; virtual ClientProxyUnknownEvents& forClientProxyUnknown() = 0; virtual ServerEvents& forServer() = 0; virtual ServerAppEvents& forServerApp() = 0; virtual IKeyStateEvents& forIKeyState() = 0; virtual IPrimaryScreenEvents& forIPrimaryScreen() = 0; virtual IScreenEvents& forIScreen() = 0; virtual ClipboardEvents& forClipboard() = 0; virtual FileEvents& forFile() = 0; }; synergy-1.8.8-stable/src/lib/base/IEventQueueBuffer.h000066400000000000000000000054561305627404700224730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "common/basic_types.h" class Event; class EventQueueTimer; //! Event queue buffer interface /*! An event queue buffer provides a queue of events for an IEventQueue. */ class IEventQueueBuffer : public IInterface { public: enum Type { kNone, //!< No event is available kSystem, //!< Event is a system event kUser //!< Event is a user event }; //! @name manipulators //@{ //! Initialize /*! Useful for platform-specific initialisation from a specific thread. */ virtual void init() = 0; //! Block waiting for an event /*! Wait for an event in the event queue buffer for up to \p timeout seconds. */ virtual void waitForEvent(double timeout) = 0; //! Get the next event /*! Get the next event from the buffer. Return kNone if no event is available. If a system event is next, return kSystem and fill in event. The event data in a system event can point to a static buffer (because Event::deleteData() will not attempt to delete data in a kSystem event). Otherwise, return kUser and fill in \p dataID with the value passed to \c addEvent(). */ virtual Type getEvent(Event& event, UInt32& dataID) = 0; //! Post an event /*! Add the given event to the end of the queue buffer. This is a user event and \c getEvent() must be able to identify it as such and return \p dataID. This method must cause \c waitForEvent() to return at some future time if it's blocked waiting on an event. */ virtual bool addEvent(UInt32 dataID) = 0; //@} //! @name accessors //@{ //! Check if event queue buffer is empty /*! Return true iff the event queue buffer is empty. */ virtual bool isEmpty() const = 0; //! Create a timer object /*! Create and return a timer object. The object is opaque and is used only by the buffer but it must be a valid object (i.e. not NULL). */ virtual EventQueueTimer* newTimer(double duration, bool oneShot) const = 0; //! Destroy a timer object /*! Destroy a timer object previously returned by \c newTimer(). */ virtual void deleteTimer(EventQueueTimer*) const = 0; //@} }; synergy-1.8.8-stable/src/lib/base/IJob.h000066400000000000000000000016551305627404700177620ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" //! Job interface /*! A job is an interface for executing some function. */ class IJob : public IInterface { public: //! Run the job virtual void run() = 0; }; synergy-1.8.8-stable/src/lib/base/ILogOutputter.h000066400000000000000000000041271305627404700217220ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/Log.h" #include "base/ELevel.h" #include "common/IInterface.h" //! Outputter interface /*! Type of outputter interface. The logger performs all output through outputters. ILogOutputter overrides must not call any log functions directly or indirectly. */ class ILogOutputter : public IInterface { public: //! @name manipulators //@{ //! Open the outputter /*! Opens the outputter for writing. Calling this method on an already open outputter must have no effect. */ virtual void open(const char* title) = 0; //! Close the outputter /*! Close the outputter. Calling this method on an already closed outputter must have no effect. */ virtual void close() = 0; //! Show the outputter /*! Causes the output to become visible. This generally only makes sense for a logger in a graphical user interface. Other implementations will do nothing. Iff \p showIfEmpty is \c false then the implementation may optionally only show the log if it's not empty. */ virtual void show(bool showIfEmpty) = 0; //! Write a message with level /*! Writes \c message, which has the given \c level, to a log. If this method returns true then Log will stop passing the message to all outputters in the outputter chain, otherwise it continues. Most implementations should return true. */ virtual bool write(ELevel level, const char* message) = 0; //@} }; synergy-1.8.8-stable/src/lib/base/Log.cpp000066400000000000000000000150721305627404700202110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/Arch.h" #include "arch/XArch.h" #include "base/Log.h" #include "base/String.h" #include "base/log_outputters.h" #include "common/Version.h" #include #include #include #include // names of priorities static const char* g_priority[] = { "FATAL", "ERROR", "WARNING", "NOTE", "INFO", "DEBUG", "DEBUG1", "DEBUG2", "DEBUG3", "DEBUG4", "DEBUG5" }; // number of priorities static const int g_numPriority = (int)(sizeof(g_priority) / sizeof(g_priority[0])); // the default priority #ifndef NDEBUG static const int g_defaultMaxPriority = kDEBUG; #else static const int g_defaultMaxPriority = kINFO; #endif // // Log // Log* Log::s_log = NULL; Log::Log() { assert(s_log == NULL); // create mutex for multithread safe operation m_mutex = ARCH->newMutex(); // other initalization m_maxPriority = g_defaultMaxPriority; m_maxNewlineLength = 0; insert(new ConsoleLogOutputter); s_log = this; } Log::Log(Log* src) { s_log = src; } Log::~Log() { // clean up for (OutputterList::iterator index = m_outputters.begin(); index != m_outputters.end(); ++index) { delete *index; } for (OutputterList::iterator index = m_alwaysOutputters.begin(); index != m_alwaysOutputters.end(); ++index) { delete *index; } ARCH->closeMutex(m_mutex); } Log* Log::getInstance() { assert(s_log != NULL); return s_log; } const char* Log::getFilterName() const { return getFilterName(getFilter()); } const char* Log::getFilterName(int level) const { if (level < 0) { return "Message"; } return g_priority[level]; } void Log::print(const char* file, int line, const char* fmt, ...) { // check if fmt begins with a priority argument ELevel priority = kINFO; if ((strlen(fmt) > 2) && (fmt[0] == '%' && fmt[1] == 'z')) { // 060 in octal is 0 (48 in decimal), so subtracting this converts ascii // number it a true number. we could use atoi instead, but this is how // it was done originally. priority = (ELevel)(fmt[2] - '\060'); // move the pointer on past the debug priority char fmt += 3; } // done if below priority threshold if (priority > getFilter()) { return; } // compute prefix padding length char stack[1024]; // compute suffix padding length int sPad = m_maxNewlineLength; // print to buffer, leaving space for a newline at the end and prefix // at the beginning. char* buffer = stack; int len = (int)(sizeof(stack) / sizeof(stack[0])); while (true) { // try printing into the buffer va_list args; va_start(args, fmt); int n = ARCH->vsnprintf(buffer, len - sPad, fmt, args); va_end(args); // if the buffer wasn't big enough then make it bigger and try again if (n < 0 || n > (int)len) { if (buffer != stack) { delete[] buffer; } len *= 2; buffer = new char[len]; } // if the buffer was big enough then continue else { break; } } // print the prefix to the buffer. leave space for priority label. // do not prefix time and file for kPRINT (CLOG_PRINT) if (priority != kPRINT) { struct tm *tm; char timestamp[50]; time_t t; time(&t); tm = localtime(&t); sprintf(timestamp, "%04i-%02i-%02iT%02i:%02i:%02i", tm->tm_year + 1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); // square brackets, spaces, comma and null terminator take about 10 int size = 10; size += strlen(timestamp); size += strlen(g_priority[priority]); size += strlen(buffer); #ifndef NDEBUG size += strlen(file); // assume there is no file contains over 100k lines of code size += 6; #endif char* message = new char[size]; #ifndef NDEBUG sprintf(message, "[%s] %s: %s\n\t%s,%d", timestamp, g_priority[priority], buffer, file, line); #else sprintf(message, "[%s] %s: %s", timestamp, g_priority[priority], buffer); #endif output(priority, message); delete[] message; } else { output(priority, buffer); } // clean up if (buffer != stack) { delete[] buffer; } } void Log::insert(ILogOutputter* outputter, bool alwaysAtHead) { assert(outputter != NULL); ArchMutexLock lock(m_mutex); if (alwaysAtHead) { m_alwaysOutputters.push_front(outputter); } else { m_outputters.push_front(outputter); } outputter->open(kAppVersion); // Issue 41 // don't show log unless user requests it, as some users find this // feature irritating (i.e. when they lose network connectivity). // in windows the log window can be displayed by selecting "show log" // from the synergy system tray icon. // if this causes problems for other architectures, then a different // work around should be attempted. //outputter->show(false); } void Log::remove(ILogOutputter* outputter) { ArchMutexLock lock(m_mutex); m_outputters.remove(outputter); m_alwaysOutputters.remove(outputter); } void Log::pop_front(bool alwaysAtHead) { ArchMutexLock lock(m_mutex); OutputterList* list = alwaysAtHead ? &m_alwaysOutputters : &m_outputters; if (!list->empty()) { delete list->front(); list->pop_front(); } } bool Log::setFilter(const char* maxPriority) { if (maxPriority != NULL) { for (int i = 0; i < g_numPriority; ++i) { if (strcmp(maxPriority, g_priority[i]) == 0) { setFilter(i); return true; } } return false; } return true; } void Log::setFilter(int maxPriority) { ArchMutexLock lock(m_mutex); m_maxPriority = maxPriority; } int Log::getFilter() const { ArchMutexLock lock(m_mutex); return m_maxPriority; } void Log::output(ELevel priority, char* msg) { assert(priority >= -1 && priority < g_numPriority); assert(msg != NULL); if (!msg) return; ArchMutexLock lock(m_mutex); OutputterList::const_iterator i; for (i = m_alwaysOutputters.begin(); i != m_alwaysOutputters.end(); ++i) { // write to outputter (*i)->write(priority, msg); } for (i = m_outputters.begin(); i != m_outputters.end(); ++i) { // write to outputter and break out of loop if it returns false if (!(*i)->write(priority, msg)) { break; } } } synergy-1.8.8-stable/src/lib/base/Log.h000066400000000000000000000157321305627404700176610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchMultithread.h" #include "arch/Arch.h" #include "common/common.h" #include "common/stdlist.h" #include #define CLOG (Log::getInstance()) #define BYE "\nTry `%s --help' for more information." class ILogOutputter; class Thread; //! Logging facility /*! The logging class; all console output should go through this class. It supports multithread safe operation, several message priority levels, filtering by priority, and output redirection. The macros LOG() and LOGC() provide convenient access. */ class Log { public: Log(); Log(Log* src); ~Log(); //! @name manipulators //@{ //! Add an outputter to the head of the list /*! Inserts an outputter to the head of the outputter list. When the logger writes a message, it goes to the outputter at the head of the outputter list. If that outputter's \c write() method returns true then it also goes to the next outputter, as so on until an outputter returns false or there are no more outputters. Outputters still in the outputter list when the log is destroyed will be deleted. If \c alwaysAtHead is true then the outputter is always called before all outputters with \c alwaysAtHead false and the return value of the outputter is ignored. By default, the logger has one outputter installed which writes to the console. */ void insert(ILogOutputter* adopted, bool alwaysAtHead = false); //! Remove an outputter from the list /*! Removes the first occurrence of the given outputter from the outputter list. It does nothing if the outputter is not in the list. The outputter is not deleted. */ void remove(ILogOutputter* orphaned); //! Remove the outputter from the head of the list /*! Removes and deletes the outputter at the head of the outputter list. This does nothing if the outputter list is empty. Only removes outputters that were inserted with the matching \c alwaysAtHead. */ void pop_front(bool alwaysAtHead = false); //! Set the minimum priority filter. /*! Set the filter. Messages below this priority are discarded. The default priority is 4 (INFO) (unless built without NDEBUG in which case it's 5 (DEBUG)). setFilter(const char*) returns true if the priority \c name was recognized; if \c name is NULL then it simply returns true. */ bool setFilter(const char* name); //! Set the minimum priority filter (by ordinal). void setFilter(int); //@} //! @name accessors //@{ //! Print a log message /*! Print a log message using the printf-like \c format and arguments preceded by the filename and line number. If \c file is NULL then neither the file nor the line are printed. */ void print(const char* file, int line, const char* format, ...); //! Get the minimum priority level. int getFilter() const; //! Get the filter name of the current filter level. const char* getFilterName() const; //! Get the filter name of a specified filter level. const char* getFilterName(int level) const; //! Get the singleton instance of the log static Log* getInstance(); //! Get the console filter level (messages above this are not sent to console). int getConsoleMaxLevel() const { return kDEBUG2; } //@} private: void output(ELevel priority, char* msg); private: typedef std::list OutputterList; static Log* s_log; ArchMutex m_mutex; OutputterList m_outputters; OutputterList m_alwaysOutputters; int m_maxNewlineLength; int m_maxPriority; }; /*! \def LOG(arg) Write to the log. Because macros cannot accept variable arguments, this should be invoked like so: \code LOG((CLOG_XXX "%d and %d are %s", x, y, x == y ? "equal" : "not equal")); \endcode In particular, notice the double open and close parentheses. Also note that there is no comma after the \c CLOG_XXX. The \c XXX should be replaced by one of enumerants in \c Log::ELevel without the leading \c k. For example, \c CLOG_INFO. The special \c CLOG_PRINT level will not be filtered and is never prefixed by the filename and line number. If \c NOLOGGING is defined during the build then this macro expands to nothing. If \c NDEBUG is defined during the build then it expands to a call to Log::print. Otherwise it expands to a call to Log::printt, which includes the filename and line number. */ /*! \def LOGC(expr, arg) Write to the log if and only if expr is true. Because macros cannot accept variable arguments, this should be invoked like so: \code LOGC(x == y, (CLOG_XXX "%d and %d are equal", x, y)); \endcode In particular, notice the parentheses around everything after the boolean expression. Also note that there is no comma after the \c CLOG_XXX. The \c XXX should be replaced by one of enumerants in \c Log::ELevel without the leading \c k. For example, \c CLOG_INFO. The special \c CLOG_PRINT level will not be filtered and is never prefixed by the filename and line number. If \c NOLOGGING is defined during the build then this macro expands to nothing. If \c NDEBUG is not defined during the build then it expands to a call to Log::print that prints the filename and line number, otherwise it expands to a call that doesn't. */ #if defined(NOLOGGING) #define LOG(_a1) #define LOGC(_a1, _a2) #define CLOG_TRACE #elif defined(NDEBUG) #define LOG(_a1) CLOG->print _a1 #define LOGC(_a1, _a2) if (_a1) CLOG->print _a2 #define CLOG_TRACE NULL, 0, #else #define LOG(_a1) CLOG->print _a1 #define LOGC(_a1, _a2) if (_a1) CLOG->print _a2 #define CLOG_TRACE __FILE__, __LINE__, #endif // the CLOG_* defines are line and file plus %z and an octal number (060=0, // 071=9), but the limitation is that once we run out of numbers at either // end, then we resort to using non-numerical chars. this still works (since // to deduce the number we subtract octal \060, so '/' is -1, and ':' is 10 #define CLOG_PRINT CLOG_TRACE "%z\057" // char is '/' #define CLOG_CRIT CLOG_TRACE "%z\060" // char is '0' #define CLOG_ERR CLOG_TRACE "%z\061" #define CLOG_WARN CLOG_TRACE "%z\062" #define CLOG_NOTE CLOG_TRACE "%z\063" #define CLOG_INFO CLOG_TRACE "%z\064" #define CLOG_DEBUG CLOG_TRACE "%z\065" #define CLOG_DEBUG1 CLOG_TRACE "%z\066" #define CLOG_DEBUG2 CLOG_TRACE "%z\067" #define CLOG_DEBUG3 CLOG_TRACE "%z\070" #define CLOG_DEBUG4 CLOG_TRACE "%z\071" // char is '9' #define CLOG_DEBUG5 CLOG_TRACE "%z\072" // char is ':' synergy-1.8.8-stable/src/lib/base/PriorityQueue.h000066400000000000000000000055761305627404700217730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/stdvector.h" #include #include //! A priority queue with an iterator /*! This priority queue is the same as a standard priority queue except: it sorts by std::greater, it has a forward iterator through the elements (which can appear in any order), and its contents can be swapped. */ template , #if defined(_MSC_VER) class Compare = std::greater > #else class Compare = std::greater > #endif class PriorityQueue { public: typedef typename Container::value_type value_type; typedef typename Container::size_type size_type; typedef typename Container::iterator iterator; typedef typename Container::const_iterator const_iterator; typedef Container container_type; PriorityQueue() { } PriorityQueue(Container& swappedIn) { swap(swappedIn); } ~PriorityQueue() { } //! @name manipulators //@{ //! Add element void push(const value_type& v) { c.push_back(v); std::push_heap(c.begin(), c.end(), comp); } //! Remove head element void pop() { std::pop_heap(c.begin(), c.end(), comp); c.pop_back(); } //! Erase element void erase(iterator i) { c.erase(i); std::make_heap(c.begin(), c.end(), comp); } //! Get start iterator iterator begin() { return c.begin(); } //! Get end iterator iterator end() { return c.end(); } //! Swap contents with another priority queue void swap(PriorityQueue& q) { c.swap(q.c); } //! Swap contents with another container void swap(Container& c2) { c.swap(c2); std::make_heap(c.begin(), c.end(), comp); } //@} //! @name accessors //@{ //! Returns true if there are no elements bool empty() const { return c.empty(); } //! Returns the number of elements size_type size() const { return c.size(); } //! Returns the head element const value_type& top() const { return c.front(); } //! Get start iterator const_iterator begin() const { return c.begin(); } //! Get end iterator const_iterator end() const { return c.end(); } //@} private: Container c; Compare comp; }; synergy-1.8.8-stable/src/lib/base/SimpleEventQueueBuffer.cpp000066400000000000000000000043451305627404700240630ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "base/SimpleEventQueueBuffer.h" #include "base/Stopwatch.h" #include "arch/Arch.h" // // SimpleEventQueueBuffer // SimpleEventQueueBuffer::SimpleEventQueueBuffer() { m_queueMutex = ARCH->newMutex(); m_queueReadyCond = ARCH->newCondVar(); m_queueReady = false; } SimpleEventQueueBuffer::~SimpleEventQueueBuffer() { ARCH->closeCondVar(m_queueReadyCond); ARCH->closeMutex(m_queueMutex); } void SimpleEventQueueBuffer::waitForEvent(double timeout) { ArchMutexLock lock(m_queueMutex); Stopwatch timer(true); while (!m_queueReady) { double timeLeft = timeout; if (timeLeft >= 0.0) { timeLeft -= timer.getTime(); if (timeLeft < 0.0) { return; } } ARCH->waitCondVar(m_queueReadyCond, m_queueMutex, timeLeft); } } IEventQueueBuffer::Type SimpleEventQueueBuffer::getEvent(Event&, UInt32& dataID) { ArchMutexLock lock(m_queueMutex); if (!m_queueReady) { return kNone; } dataID = m_queue.back(); m_queue.pop_back(); m_queueReady = !m_queue.empty(); return kUser; } bool SimpleEventQueueBuffer::addEvent(UInt32 dataID) { ArchMutexLock lock(m_queueMutex); m_queue.push_front(dataID); if (!m_queueReady) { m_queueReady = true; ARCH->broadcastCondVar(m_queueReadyCond); } return true; } bool SimpleEventQueueBuffer::isEmpty() const { ArchMutexLock lock(m_queueMutex); return !m_queueReady; } EventQueueTimer* SimpleEventQueueBuffer::newTimer(double, bool) const { return new EventQueueTimer; } void SimpleEventQueueBuffer::deleteTimer(EventQueueTimer* timer) const { delete timer; } synergy-1.8.8-stable/src/lib/base/SimpleEventQueueBuffer.h000066400000000000000000000032221305627404700235210ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/IEventQueueBuffer.h" #include "arch/IArchMultithread.h" #include "common/stddeque.h" //! In-memory event queue buffer /*! An event queue buffer provides a queue of events for an IEventQueue. */ class SimpleEventQueueBuffer : public IEventQueueBuffer { public: SimpleEventQueueBuffer(); ~SimpleEventQueueBuffer(); // IEventQueueBuffer overrides void init() { } virtual void waitForEvent(double timeout); virtual Type getEvent(Event& event, UInt32& dataID); virtual bool addEvent(UInt32 dataID); virtual bool isEmpty() const; virtual EventQueueTimer* newTimer(double duration, bool oneShot) const; virtual void deleteTimer(EventQueueTimer*) const; private: typedef std::deque EventDeque; ArchMutex m_queueMutex; ArchCond m_queueReadyCond; bool m_queueReady; EventDeque m_queue; }; class EventQueueTimer { public: EventQueueTimer() { } virtual ~EventQueueTimer() { } }; synergy-1.8.8-stable/src/lib/base/Stopwatch.cpp000066400000000000000000000040671305627404700214460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "base/Stopwatch.h" #include "arch/Arch.h" // // Stopwatch // Stopwatch::Stopwatch(bool triggered) : m_mark(0.0), m_triggered(triggered), m_stopped(triggered) { if (!triggered) { m_mark = ARCH->time(); } } Stopwatch::~Stopwatch() { // do nothing } double Stopwatch::reset() { if (m_stopped) { const double dt = m_mark; m_mark = 0.0; return dt; } else { const double t = ARCH->time(); const double dt = t - m_mark; m_mark = t; return dt; } } void Stopwatch::stop() { if (m_stopped) { return; } // save the elapsed time m_mark = ARCH->time() - m_mark; m_stopped = true; } void Stopwatch::start() { m_triggered = false; if (!m_stopped) { return; } // set the mark such that it reports the time elapsed at stop() m_mark = ARCH->time() - m_mark; m_stopped = false; } void Stopwatch::setTrigger() { stop(); m_triggered = true; } double Stopwatch::getTime() { if (m_triggered) { const double dt = m_mark; start(); return dt; } else if (m_stopped) { return m_mark; } else { return ARCH->time() - m_mark; } } Stopwatch::operator double() { return getTime(); } bool Stopwatch::isStopped() const { return m_stopped; } double Stopwatch::getTime() const { if (m_stopped) { return m_mark; } else { return ARCH->time() - m_mark; } } Stopwatch::operator double() const { return getTime(); } synergy-1.8.8-stable/src/lib/base/Stopwatch.h000066400000000000000000000053571305627404700211160ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" //! A timer class /*! This class measures time intervals. All time interval measurement should use this class. */ class Stopwatch { public: /*! The default constructor does an implicit reset() or setTrigger(). If triggered == false then the clock starts ticking. */ Stopwatch(bool triggered = false); ~Stopwatch(); //! @name manipulators //@{ //! Reset the timer to zero /*! Set the start time to the current time, returning the time since the last reset. This does not remove the trigger if it's set nor does it start a stopped clock. If the clock is stopped then subsequent reset()'s will return 0. */ double reset(); //! Stop the timer /*! Stop the stopwatch. The time interval while stopped is not counted by the stopwatch. stop() does not remove the trigger. Has no effect if already stopped. */ void stop(); //! Start the timer /*! Start the stopwatch. start() removes the trigger, even if the stopwatch was already started. */ void start(); //! Stop the timer and set the trigger /*! setTrigger() stops the clock like stop() except there's an implicit start() the next time (non-const) getTime() is called. This is useful when you want the clock to start the first time you check it. */ void setTrigger(); //! Get elapsed time /*! Returns the time since the last reset() (or calls reset() and returns zero if the trigger is set). */ double getTime(); //! Same as getTime() operator double(); //@} //! @name accessors //@{ //! Check if timer is stopped /*! Returns true if the stopwatch is stopped. */ bool isStopped() const; // return the time since the last reset(). //! Get elapsed time /*! Returns the time since the last reset(). This cannot trigger the stopwatch to start and will not clear the trigger. */ double getTime() const; //! Same as getTime() const operator double() const; //@} private: double getClock() const; private: double m_mark; bool m_triggered; bool m_stopped; }; synergy-1.8.8-stable/src/lib/base/String.cpp000066400000000000000000000135751305627404700207440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/Arch.h" #include "base/String.h" #include "common/common.h" #include "common/stdvector.h" #include #include #include #include #include #include #include #include #include #include namespace synergy { namespace string { String format(const char* fmt, ...) { va_list args; va_start(args, fmt); String result = vformat(fmt, args); va_end(args); return result; } String vformat(const char* fmt, va_list args) { // find highest indexed substitution and the locations of substitutions std::vector pos; std::vector width; std::vector index; int maxIndex = 0; for (const char* scan = fmt; *scan != '\0'; ++scan) { if (*scan == '%') { ++scan; if (*scan == '\0') { break; } else if (*scan == '%') { // literal index.push_back(0); pos.push_back(static_cast(scan - 1 - fmt)); width.push_back(2); } else if (*scan == '{') { // get argument index char* end; int i = static_cast(strtol(scan + 1, &end, 10)); if (*end != '}') { // invalid index -- ignore scan = end - 1; } else { index.push_back(i); pos.push_back(static_cast(scan - 1 - fmt)); width.push_back(static_cast(end - scan + 2)); if (i > maxIndex) { maxIndex = i; } scan = end; } } else { // improper escape -- ignore } } } // get args std::vector value; std::vector length; value.push_back("%"); length.push_back(1); for (int i = 0; i < maxIndex; ++i) { const char* arg = va_arg(args, const char*); size_t len = strlen(arg); value.push_back(arg); length.push_back(len); } // compute final length size_t resultLength = strlen(fmt); const int n = static_cast(pos.size()); for (int i = 0; i < n; ++i) { resultLength -= width[i]; resultLength += length[index[i]]; } // substitute String result; result.reserve(resultLength); size_t src = 0; for (int i = 0; i < n; ++i) { result.append(fmt + src, pos[i] - src); result.append(value[index[i]]); src = pos[i] + width[i]; } result.append(fmt + src); return result; } String sprintf(const char* fmt, ...) { char tmp[1024]; char* buffer = tmp; int len = (int)(sizeof(tmp) / sizeof(tmp[0])); String result; while (buffer != NULL) { // try printing into the buffer va_list args; va_start(args, fmt); int n = ARCH->vsnprintf(buffer, len, fmt, args); va_end(args); // if the buffer wasn't big enough then make it bigger and try again if (n < 0 || n > len) { if (buffer != tmp) { delete[] buffer; } len *= 2; buffer = new char[len]; } // if it was big enough then save the string and don't try again else { result = buffer; if (buffer != tmp) { delete[] buffer; } buffer = NULL; } } return result; } void findReplaceAll( String& subject, const String& find, const String& replace) { size_t pos = 0; while ((pos = subject.find(find, pos)) != String::npos) { subject.replace(pos, find.length(), replace); pos += replace.length(); } } String removeFileExt(String filename) { size_t dot = filename.find_last_of('.'); if (dot == String::npos) { return filename; } return filename.substr(0, dot); } void toHex(String& subject, int width, const char fill) { std::stringstream ss; ss << std::hex; for (unsigned int i = 0; i < subject.length(); i++) { ss << std::setw(width) << std::setfill(fill) << (int)(unsigned char)subject[i]; } subject = ss.str(); } void uppercase(String& subject) { std::transform(subject.begin(), subject.end(), subject.begin(), ::toupper); } void removeChar(String& subject, const char c) { subject.erase(std::remove(subject.begin(), subject.end(), c), subject.end()); } String sizeTypeToString(size_t n) { std::stringstream ss; ss << n; return ss.str(); } size_t stringToSizeType(String string) { std::istringstream iss(string); size_t value; iss >> value; return value; } std::vector splitString(String string, const char c) { std::vector results; size_t head = 0; size_t separator = string.find(c); while (separator != String::npos) { if (head!=separator) { results.push_back(string.substr(head, separator - head)); } head = separator + 1; separator = string.find(c, head); } if (head < string.size()) { results.push_back(string.substr(head, string.size() - head)); } return results; } // // CaselessCmp // bool CaselessCmp::cmpEqual( const String::value_type& a, const String::value_type& b) { // should use std::tolower but not in all versions of libstdc++ have it return tolower(a) == tolower(b); } bool CaselessCmp::cmpLess( const String::value_type& a, const String::value_type& b) { // should use std::tolower but not in all versions of libstdc++ have it return tolower(a) < tolower(b); } bool CaselessCmp::less(const String& a, const String& b) { return std::lexicographical_compare( a.begin(), a.end(), b.begin(), b.end(), &synergy::string::CaselessCmp::cmpLess); } bool CaselessCmp::equal(const String& a, const String& b) { return !(less(a, b) || less(b, a)); } bool CaselessCmp::operator()(const String& a, const String& b) const { return less(a, b); } } } synergy-1.8.8-stable/src/lib/base/String.h000066400000000000000000000070261305627404700204030ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" #include "common/stdstring.h" #include #include // use standard C++ string class for our string class typedef std::string String; namespace synergy { //! String utilities /*! Provides functions for string manipulation. */ namespace string { //! Format positional arguments /*! Format a string using positional arguments. fmt has literal characters and conversion specifications introduced by `\%': - \%\% -- literal `\%' - \%{n} -- positional element n, n a positive integer, {} are literal All arguments in the variable list are const char*. Positional elements are indexed from 1. */ String format(const char* fmt, ...); //! Format positional arguments /*! Same as format() except takes va_list. */ String vformat(const char* fmt, va_list); //! Print a string using sprintf-style formatting /*! Equivalent to sprintf() except the result is returned as a String. */ String sprintf(const char* fmt, ...); //! Find and replace all /*! Finds \c find inside \c subject and replaces it with \c replace */ void findReplaceAll(String& subject, const String& find, const String& replace); //! Remove file extension /*! Finds the last dot and remove all characters from the dot to the end */ String removeFileExt(String filename); //! Convert into hexdecimal /*! Convert each character in \c subject into hexdecimal form with \c width */ void toHex(String& subject, int width, const char fill = '0'); //! Convert to all uppercase /*! Convert each character in \c subject to uppercase */ void uppercase(String& subject); //! Remove all specific char in suject /*! Remove all specific \c c in \c suject */ void removeChar(String& subject, const char c); //! Convert a size type to a string /*! Convert an size type to a string */ String sizeTypeToString(size_t n); //! Convert a string to a size type /*! Convert an a \c string to an size type */ size_t stringToSizeType(String string); //! Split a string into substrings /*! Split a \c string that separated by a \c c into substrings */ std::vector splitString(String string, const char c); //! Case-insensitive comparisons /*! This class provides case-insensitve comparison functions. */ class CaselessCmp { public: //! Same as less() bool operator()(const String& a, const String& b) const; //! Returns true iff \c a is lexicographically less than \c b static bool less(const String& a, const String& b); //! Returns true iff \c a is lexicographically equal to \c b static bool equal(const String& a, const String& b); //! Returns true iff \c a is lexicographically less than \c b static bool cmpLess(const String::value_type& a, const String::value_type& b); //! Returns true iff \c a is lexicographically equal to \c b static bool cmpEqual(const String::value_type& a, const String::value_type& b); }; } } synergy-1.8.8-stable/src/lib/base/TMethodEventJob.h000066400000000000000000000032501305627404700221310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "IEventJob.h" //! Use a member function as an event job /*! An event job class that invokes a member function. */ template class TMethodEventJob : public IEventJob { public: //! run(event) invokes \c object->method(event, arg) TMethodEventJob(T* object, void (T::*method)(const Event&, void*), void* arg = NULL); virtual ~TMethodEventJob(); // IJob overrides virtual void run(const Event&); private: T* m_object; void (T::*m_method)(const Event&, void*); void* m_arg; }; template inline TMethodEventJob::TMethodEventJob(T* object, void (T::*method)(const Event&, void*), void* arg) : m_object(object), m_method(method), m_arg(arg) { // do nothing } template inline TMethodEventJob::~TMethodEventJob() { // do nothing } template inline void TMethodEventJob::run(const Event& event) { if (m_object != NULL) { (m_object->*m_method)(event, m_arg); } } synergy-1.8.8-stable/src/lib/base/TMethodJob.h000066400000000000000000000027641305627404700211400ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "IJob.h" //! Use a function as a job /*! A job class that invokes a member function. */ template class TMethodJob : public IJob { public: //! run() invokes \c object->method(arg) TMethodJob(T* object, void (T::*method)(void*), void* arg = NULL); virtual ~TMethodJob(); // IJob overrides virtual void run(); private: T* m_object; void (T::*m_method)(void*); void* m_arg; }; template inline TMethodJob::TMethodJob(T* object, void (T::*method)(void*), void* arg) : m_object(object), m_method(method), m_arg(arg) { // do nothing } template inline TMethodJob::~TMethodJob() { // do nothing } template inline void TMethodJob::run() { if (m_object != NULL) { (m_object->*m_method)(m_arg); } } synergy-1.8.8-stable/src/lib/base/Unicode.cpp000066400000000000000000000403361305627404700210570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/Arch.h" #include "base/Unicode.h" #include // // local utility functions // inline static UInt16 decode16(const UInt8* n, bool byteSwapped) { union x16 { UInt8 n8[2]; UInt16 n16; } c; if (byteSwapped) { c.n8[0] = n[1]; c.n8[1] = n[0]; } else { c.n8[0] = n[0]; c.n8[1] = n[1]; } return c.n16; } inline static UInt32 decode32(const UInt8* n, bool byteSwapped) { union x32 { UInt8 n8[4]; UInt32 n32; } c; if (byteSwapped) { c.n8[0] = n[3]; c.n8[1] = n[2]; c.n8[2] = n[1]; c.n8[3] = n[0]; } else { c.n8[0] = n[0]; c.n8[1] = n[1]; c.n8[2] = n[2]; c.n8[3] = n[3]; } return c.n32; } inline static void resetError(bool* errors) { if (errors != NULL) { *errors = false; } } inline static void setError(bool* errors) { if (errors != NULL) { *errors = true; } } // // Unicode // UInt32 Unicode::s_invalid = 0x0000ffff; UInt32 Unicode::s_replacement = 0x0000fffd; bool Unicode::isUTF8(const String& src) { // convert and test each character const UInt8* data = reinterpret_cast(src.c_str()); for (UInt32 n = (UInt32)src.size(); n > 0; ) { if (fromUTF8(data, n) == s_invalid) { return false; } } return true; } String Unicode::UTF8ToUCS2(const String& src, bool* errors) { // default to success resetError(errors); // get size of input string and reserve some space in output UInt32 n = (UInt32)src.size(); String dst; dst.reserve(2 * n); // convert each character const UInt8* data = reinterpret_cast(src.c_str()); while (n > 0) { UInt32 c = fromUTF8(data, n); if (c == s_invalid) { c = s_replacement; } else if (c >= 0x00010000) { setError(errors); c = s_replacement; } UInt16 ucs2 = static_cast(c); dst.append(reinterpret_cast(&ucs2), 2); } return dst; } String Unicode::UTF8ToUCS4(const String& src, bool* errors) { // default to success resetError(errors); // get size of input string and reserve some space in output UInt32 n = (UInt32)src.size(); String dst; dst.reserve(4 * n); // convert each character const UInt8* data = reinterpret_cast(src.c_str()); while (n > 0) { UInt32 c = fromUTF8(data, n); if (c == s_invalid) { c = s_replacement; } dst.append(reinterpret_cast(&c), 4); } return dst; } String Unicode::UTF8ToUTF16(const String& src, bool* errors) { // default to success resetError(errors); // get size of input string and reserve some space in output UInt32 n = (UInt32)src.size(); String dst; dst.reserve(2 * n); // convert each character const UInt8* data = reinterpret_cast(src.c_str()); while (n > 0) { UInt32 c = fromUTF8(data, n); if (c == s_invalid) { c = s_replacement; } else if (c >= 0x00110000) { setError(errors); c = s_replacement; } if (c < 0x00010000) { UInt16 ucs2 = static_cast(c); dst.append(reinterpret_cast(&ucs2), 2); } else { c -= 0x00010000; UInt16 utf16h = static_cast((c >> 10) + 0xd800); UInt16 utf16l = static_cast((c & 0x03ff) + 0xdc00); dst.append(reinterpret_cast(&utf16h), 2); dst.append(reinterpret_cast(&utf16l), 2); } } return dst; } String Unicode::UTF8ToUTF32(const String& src, bool* errors) { // default to success resetError(errors); // get size of input string and reserve some space in output UInt32 n = (UInt32)src.size(); String dst; dst.reserve(4 * n); // convert each character const UInt8* data = reinterpret_cast(src.c_str()); while (n > 0) { UInt32 c = fromUTF8(data, n); if (c == s_invalid) { c = s_replacement; } else if (c >= 0x00110000) { setError(errors); c = s_replacement; } dst.append(reinterpret_cast(&c), 4); } return dst; } String Unicode::UTF8ToText(const String& src, bool* errors) { // default to success resetError(errors); // convert to wide char UInt32 size; wchar_t* tmp = UTF8ToWideChar(src, size, errors); // convert string to multibyte int len = ARCH->convStringWCToMB(NULL, tmp, size, errors); char* mbs = new char[len + 1]; ARCH->convStringWCToMB(mbs, tmp, size, errors); String text(mbs, len); // clean up delete[] mbs; delete[] tmp; return text; } String Unicode::UCS2ToUTF8(const String& src, bool* errors) { // default to success resetError(errors); // convert UInt32 n = (UInt32)src.size() >> 1; return doUCS2ToUTF8(reinterpret_cast(src.data()), n, errors); } String Unicode::UCS4ToUTF8(const String& src, bool* errors) { // default to success resetError(errors); // convert UInt32 n = (UInt32)src.size() >> 2; return doUCS4ToUTF8(reinterpret_cast(src.data()), n, errors); } String Unicode::UTF16ToUTF8(const String& src, bool* errors) { // default to success resetError(errors); // convert UInt32 n = (UInt32)src.size() >> 1; return doUTF16ToUTF8(reinterpret_cast(src.data()), n, errors); } String Unicode::UTF32ToUTF8(const String& src, bool* errors) { // default to success resetError(errors); // convert UInt32 n = (UInt32)src.size() >> 2; return doUTF32ToUTF8(reinterpret_cast(src.data()), n, errors); } String Unicode::textToUTF8(const String& src, bool* errors) { // default to success resetError(errors); // convert string to wide characters UInt32 n = (UInt32)src.size(); int len = ARCH->convStringMBToWC(NULL, src.c_str(), n, errors); wchar_t* wcs = new wchar_t[len + 1]; ARCH->convStringMBToWC(wcs, src.c_str(), n, errors); // convert to UTF8 String utf8 = wideCharToUTF8(wcs, len, errors); // clean up delete[] wcs; return utf8; } wchar_t* Unicode::UTF8ToWideChar(const String& src, UInt32& size, bool* errors) { // convert to platform's wide character encoding String tmp; switch (ARCH->getWideCharEncoding()) { case IArchString::kUCS2: tmp = UTF8ToUCS2(src, errors); size = (UInt32)tmp.size() >> 1; break; case IArchString::kUCS4: tmp = UTF8ToUCS4(src, errors); size = (UInt32)tmp.size() >> 2; break; case IArchString::kUTF16: tmp = UTF8ToUTF16(src, errors); size = (UInt32)tmp.size() >> 1; break; case IArchString::kUTF32: tmp = UTF8ToUTF32(src, errors); size = (UInt32)tmp.size() >> 2; break; default: assert(0 && "unknown wide character encoding"); } // copy to a wchar_t array wchar_t* dst = new wchar_t[size]; ::memcpy(dst, tmp.data(), sizeof(wchar_t) * size); return dst; } String Unicode::wideCharToUTF8(const wchar_t* src, UInt32 size, bool* errors) { // convert from platform's wide character encoding. // note -- this must include a wide nul character (independent of // the String's nul character). switch (ARCH->getWideCharEncoding()) { case IArchString::kUCS2: return doUCS2ToUTF8(reinterpret_cast(src), size, errors); case IArchString::kUCS4: return doUCS4ToUTF8(reinterpret_cast(src), size, errors); case IArchString::kUTF16: return doUTF16ToUTF8(reinterpret_cast(src), size, errors); case IArchString::kUTF32: return doUTF32ToUTF8(reinterpret_cast(src), size, errors); default: assert(0 && "unknown wide character encoding"); return String(); } } String Unicode::doUCS2ToUTF8(const UInt8* data, UInt32 n, bool* errors) { // make some space String dst; dst.reserve(n); // check if first character is 0xfffe or 0xfeff bool byteSwapped = false; if (n >= 1) { switch (decode16(data, false)) { case 0x0000feff: data += 2; --n; break; case 0x0000fffe: byteSwapped = true; data += 2; --n; break; default: break; } } // convert each character for (; n > 0; data += 2, --n) { UInt32 c = decode16(data, byteSwapped); toUTF8(dst, c, errors); } return dst; } String Unicode::doUCS4ToUTF8(const UInt8* data, UInt32 n, bool* errors) { // make some space String dst; dst.reserve(n); // check if first character is 0xfffe or 0xfeff bool byteSwapped = false; if (n >= 1) { switch (decode32(data, false)) { case 0x0000feff: data += 4; --n; break; case 0x0000fffe: byteSwapped = true; data += 4; --n; break; default: break; } } // convert each character for (; n > 0; data += 4, --n) { UInt32 c = decode32(data, byteSwapped); toUTF8(dst, c, errors); } return dst; } String Unicode::doUTF16ToUTF8(const UInt8* data, UInt32 n, bool* errors) { // make some space String dst; dst.reserve(n); // check if first character is 0xfffe or 0xfeff bool byteSwapped = false; if (n >= 1) { switch (decode16(data, false)) { case 0x0000feff: data += 2; --n; break; case 0x0000fffe: byteSwapped = true; data += 2; --n; break; default: break; } } // convert each character for (; n > 0; data += 2, --n) { UInt32 c = decode16(data, byteSwapped); if (c < 0x0000d800 || c > 0x0000dfff) { toUTF8(dst, c, errors); } else if (n == 1) { // error -- missing second word setError(errors); toUTF8(dst, s_replacement, NULL); } else if (c >= 0x0000d800 && c <= 0x0000dbff) { UInt32 c2 = decode16(data, byteSwapped); data += 2; --n; if (c2 < 0x0000dc00 || c2 > 0x0000dfff) { // error -- [d800,dbff] not followed by [dc00,dfff] setError(errors); toUTF8(dst, s_replacement, NULL); } else { c = (((c - 0x0000d800) << 10) | (c2 - 0x0000dc00)) + 0x00010000; toUTF8(dst, c, errors); } } else { // error -- [dc00,dfff] without leading [d800,dbff] setError(errors); toUTF8(dst, s_replacement, NULL); } } return dst; } String Unicode::doUTF32ToUTF8(const UInt8* data, UInt32 n, bool* errors) { // make some space String dst; dst.reserve(n); // check if first character is 0xfffe or 0xfeff bool byteSwapped = false; if (n >= 1) { switch (decode32(data, false)) { case 0x0000feff: data += 4; --n; break; case 0x0000fffe: byteSwapped = true; data += 4; --n; break; default: break; } } // convert each character for (; n > 0; data += 4, --n) { UInt32 c = decode32(data, byteSwapped); if (c >= 0x00110000) { setError(errors); c = s_replacement; } toUTF8(dst, c, errors); } return dst; } UInt32 Unicode::fromUTF8(const UInt8*& data, UInt32& n) { assert(data != NULL); assert(n != 0); // compute character encoding length, checking for overlong // sequences (i.e. characters that don't use the shortest // possible encoding). UInt32 size; if (data[0] < 0x80) { // 0xxxxxxx size = 1; } else if (data[0] < 0xc0) { // 10xxxxxx -- in the middle of a multibyte character. counts // as one invalid character. --n; ++data; return s_invalid; } else if (data[0] < 0xe0) { // 110xxxxx size = 2; } else if (data[0] < 0xf0) { // 1110xxxx size = 3; } else if (data[0] < 0xf8) { // 11110xxx size = 4; } else if (data[0] < 0xfc) { // 111110xx size = 5; } else if (data[0] < 0xfe) { // 1111110x size = 6; } else { // invalid sequence. dunno how many bytes to skip so skip one. --n; ++data; return s_invalid; } // make sure we have enough data if (size > n) { data += n; n = 0; return s_invalid; } // extract character UInt32 c; switch (size) { case 1: c = static_cast(data[0]); break; case 2: c = ((static_cast(data[0]) & 0x1f) << 6) | ((static_cast(data[1]) & 0x3f) ); break; case 3: c = ((static_cast(data[0]) & 0x0f) << 12) | ((static_cast(data[1]) & 0x3f) << 6) | ((static_cast(data[2]) & 0x3f) ); break; case 4: c = ((static_cast(data[0]) & 0x07) << 18) | ((static_cast(data[1]) & 0x3f) << 12) | ((static_cast(data[1]) & 0x3f) << 6) | ((static_cast(data[1]) & 0x3f) ); break; case 5: c = ((static_cast(data[0]) & 0x03) << 24) | ((static_cast(data[1]) & 0x3f) << 18) | ((static_cast(data[1]) & 0x3f) << 12) | ((static_cast(data[1]) & 0x3f) << 6) | ((static_cast(data[1]) & 0x3f) ); break; case 6: c = ((static_cast(data[0]) & 0x01) << 30) | ((static_cast(data[1]) & 0x3f) << 24) | ((static_cast(data[1]) & 0x3f) << 18) | ((static_cast(data[1]) & 0x3f) << 12) | ((static_cast(data[1]) & 0x3f) << 6) | ((static_cast(data[1]) & 0x3f) ); break; default: assert(0 && "invalid size"); return s_invalid; } // check that all bytes after the first have the pattern 10xxxxxx. // truncated sequences are treated as a single malformed character. bool truncated = false; switch (size) { case 6: if ((data[5] & 0xc0) != 0x80) { truncated = true; size = 5; } // fall through case 5: if ((data[4] & 0xc0) != 0x80) { truncated = true; size = 4; } // fall through case 4: if ((data[3] & 0xc0) != 0x80) { truncated = true; size = 3; } // fall through case 3: if ((data[2] & 0xc0) != 0x80) { truncated = true; size = 2; } // fall through case 2: if ((data[1] & 0xc0) != 0x80) { truncated = true; size = 1; } } // update parameters data += size; n -= size; // invalid if sequence was truncated if (truncated) { return s_invalid; } // check for characters that didn't use the smallest possible encoding static UInt32 s_minChar[] = { 0, 0x00000000, 0x00000080, 0x00000800, 0x00010000, 0x00200000, 0x04000000 }; if (c < s_minChar[size]) { return s_invalid; } // check for characters not in ISO-10646 if (c >= 0x0000d800 && c <= 0x0000dfff) { return s_invalid; } if (c >= 0x0000fffe && c <= 0x0000ffff) { return s_invalid; } return c; } void Unicode::toUTF8(String& dst, UInt32 c, bool* errors) { UInt8 data[6]; // handle characters outside the valid range if ((c >= 0x0000d800 && c <= 0x0000dfff) || c >= 0x80000000) { setError(errors); c = s_replacement; } // convert to UTF-8 if (c < 0x00000080) { data[0] = static_cast(c); dst.append(reinterpret_cast(data), 1); } else if (c < 0x00000800) { data[0] = static_cast(((c >> 6) & 0x0000001f) + 0xc0); data[1] = static_cast((c & 0x0000003f) + 0x80); dst.append(reinterpret_cast(data), 2); } else if (c < 0x00010000) { data[0] = static_cast(((c >> 12) & 0x0000000f) + 0xe0); data[1] = static_cast(((c >> 6) & 0x0000003f) + 0x80); data[2] = static_cast((c & 0x0000003f) + 0x80); dst.append(reinterpret_cast(data), 3); } else if (c < 0x00200000) { data[0] = static_cast(((c >> 18) & 0x00000007) + 0xf0); data[1] = static_cast(((c >> 12) & 0x0000003f) + 0x80); data[2] = static_cast(((c >> 6) & 0x0000003f) + 0x80); data[3] = static_cast((c & 0x0000003f) + 0x80); dst.append(reinterpret_cast(data), 4); } else if (c < 0x04000000) { data[0] = static_cast(((c >> 24) & 0x00000003) + 0xf8); data[1] = static_cast(((c >> 18) & 0x0000003f) + 0x80); data[2] = static_cast(((c >> 12) & 0x0000003f) + 0x80); data[3] = static_cast(((c >> 6) & 0x0000003f) + 0x80); data[4] = static_cast((c & 0x0000003f) + 0x80); dst.append(reinterpret_cast(data), 5); } else if (c < 0x80000000) { data[0] = static_cast(((c >> 30) & 0x00000001) + 0xfc); data[1] = static_cast(((c >> 24) & 0x0000003f) + 0x80); data[2] = static_cast(((c >> 18) & 0x0000003f) + 0x80); data[3] = static_cast(((c >> 12) & 0x0000003f) + 0x80); data[4] = static_cast(((c >> 6) & 0x0000003f) + 0x80); data[5] = static_cast((c & 0x0000003f) + 0x80); dst.append(reinterpret_cast(data), 6); } else { assert(0 && "character out of range"); } } synergy-1.8.8-stable/src/lib/base/Unicode.h000066400000000000000000000114101305627404700205130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" #include "common/basic_types.h" //! Unicode utility functions /*! This class provides functions for converting between various Unicode encodings and the current locale encoding. */ class Unicode { public: //! @name accessors //@{ //! Test UTF-8 string for validity /*! Returns true iff the string contains a valid sequence of UTF-8 encoded characters. */ static bool isUTF8(const String&); //! Convert from UTF-8 to UCS-2 encoding /*! Convert from UTF-8 to UCS-2. If errors is not NULL then *errors is set to true iff any character could not be encoded in UCS-2. Decoding errors do not set *errors. */ static String UTF8ToUCS2(const String&, bool* errors = NULL); //! Convert from UTF-8 to UCS-4 encoding /*! Convert from UTF-8 to UCS-4. If errors is not NULL then *errors is set to true iff any character could not be encoded in UCS-4. Decoding errors do not set *errors. */ static String UTF8ToUCS4(const String&, bool* errors = NULL); //! Convert from UTF-8 to UTF-16 encoding /*! Convert from UTF-8 to UTF-16. If errors is not NULL then *errors is set to true iff any character could not be encoded in UTF-16. Decoding errors do not set *errors. */ static String UTF8ToUTF16(const String&, bool* errors = NULL); //! Convert from UTF-8 to UTF-32 encoding /*! Convert from UTF-8 to UTF-32. If errors is not NULL then *errors is set to true iff any character could not be encoded in UTF-32. Decoding errors do not set *errors. */ static String UTF8ToUTF32(const String&, bool* errors = NULL); //! Convert from UTF-8 to the current locale encoding /*! Convert from UTF-8 to the current locale encoding. If errors is not NULL then *errors is set to true iff any character could not be encoded. Decoding errors do not set *errors. */ static String UTF8ToText(const String&, bool* errors = NULL); //! Convert from UCS-2 to UTF-8 /*! Convert from UCS-2 to UTF-8. If errors is not NULL then *errors is set to true iff any character could not be decoded. */ static String UCS2ToUTF8(const String&, bool* errors = NULL); //! Convert from UCS-4 to UTF-8 /*! Convert from UCS-4 to UTF-8. If errors is not NULL then *errors is set to true iff any character could not be decoded. */ static String UCS4ToUTF8(const String&, bool* errors = NULL); //! Convert from UTF-16 to UTF-8 /*! Convert from UTF-16 to UTF-8. If errors is not NULL then *errors is set to true iff any character could not be decoded. */ static String UTF16ToUTF8(const String&, bool* errors = NULL); //! Convert from UTF-32 to UTF-8 /*! Convert from UTF-32 to UTF-8. If errors is not NULL then *errors is set to true iff any character could not be decoded. */ static String UTF32ToUTF8(const String&, bool* errors = NULL); //! Convert from the current locale encoding to UTF-8 /*! Convert from the current locale encoding to UTF-8. If errors is not NULL then *errors is set to true iff any character could not be decoded. */ static String textToUTF8(const String&, bool* errors = NULL); //@} private: // convert UTF8 to wchar_t string (using whatever encoding is native // to the platform). caller must delete[] the returned string. the // string is *not* nul terminated; the length (in characters) is // returned in size. static wchar_t* UTF8ToWideChar(const String&, UInt32& size, bool* errors); // convert nul terminated wchar_t string (in platform's native // encoding) to UTF8. static String wideCharToUTF8(const wchar_t*, UInt32 size, bool* errors); // internal conversion to UTF8 static String doUCS2ToUTF8(const UInt8* src, UInt32 n, bool* errors); static String doUCS4ToUTF8(const UInt8* src, UInt32 n, bool* errors); static String doUTF16ToUTF8(const UInt8* src, UInt32 n, bool* errors); static String doUTF32ToUTF8(const UInt8* src, UInt32 n, bool* errors); // convert characters to/from UTF8 static UInt32 fromUTF8(const UInt8*& src, UInt32& size); static void toUTF8(String& dst, UInt32 c, bool* errors); private: static UInt32 s_invalid; static UInt32 s_replacement; }; synergy-1.8.8-stable/src/lib/base/XBase.cpp000066400000000000000000000030441305627404700204660ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "base/XBase.h" #include "base/String.h" #include #include // // XBase // XBase::XBase() : std::runtime_error("") { // do nothing } XBase::XBase(const String& msg) : std::runtime_error(msg) { // do nothing } XBase::~XBase() _NOEXCEPT { // do nothing } const char* XBase::what() const _NOEXCEPT { const char* what = std::runtime_error::what(); if (strlen(what) == 0) { m_what = getWhat(); return m_what.c_str(); } return what; } String XBase::format(const char* /*id*/, const char* fmt, ...) const throw() { // FIXME -- lookup message string using id as an index. set // fmt to that string if it exists. // format String result; va_list args; va_start(args, fmt); try { result = synergy::string::vformat(fmt, args); } catch (...) { // ignore } va_end(args); return result; } synergy-1.8.8-stable/src/lib/base/XBase.h000066400000000000000000000075041305627404700201400ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" #include "common/stdexcept.h" //! Exception base class /*! This is the base class of most exception types. */ class XBase : public std::runtime_error { public: //! Use getWhat() as the result of what() XBase(); //! Use \c msg as the result of what() XBase(const String& msg); virtual ~XBase() _NOEXCEPT; //! Reason for exception virtual const char* what() const _NOEXCEPT; protected: //! Get a human readable string describing the exception virtual String getWhat() const throw() { return ""; } //! Format a string /*! Looks up a message format using \c id, using \c defaultFormat if no format can be found, then replaces positional parameters in the format string and returns the result. */ virtual String format(const char* id, const char* defaultFormat, ...) const throw(); private: mutable String m_what; }; /*! \def XBASE_SUBCLASS Convenience macro to subclass from XBase (or a subclass of it), providing the c'tor taking a const String&. getWhat() is not declared. */ #define XBASE_SUBCLASS(name_, super_) \ class name_ : public super_ { \ public: \ name_() : super_() { } \ name_(const String& msg) : super_(msg) { } \ virtual ~name_() _NOEXCEPT { } \ } /*! \def XBASE_SUBCLASS Convenience macro to subclass from XBase (or a subclass of it), providing the c'tor taking a const String&. getWhat() must be implemented. */ #define XBASE_SUBCLASS_WHAT(name_, super_) \ class name_ : public super_ { \ public: \ name_() : super_() { } \ name_(const String& msg) : super_(msg) { } \ virtual ~name_() _NOEXCEPT { } \ \ protected: \ virtual String getWhat() const throw(); \ } /*! \def XBASE_SUBCLASS_FORMAT Convenience macro to subclass from XBase (or a subclass of it), providing the c'tor taking a const String&. what() is overridden to call getWhat() when first called; getWhat() can format the error message and can call what() to get the message passed to the c'tor. */ #define XBASE_SUBCLASS_FORMAT(name_, super_) \ class name_ : public super_ { \ private: \ enum EState { kFirst, kFormat, kDone }; \ \ public: \ name_() : super_(), m_state(kDone) { } \ name_(const String& msg) : super_(msg), m_state(kFirst) { } \ virtual ~name_() _NOEXCEPT { } \ \ virtual const char* what() const _NOEXCEPT \ { \ if (m_state == kFirst) { \ m_state = kFormat; \ m_formatted = getWhat(); \ m_state = kDone; \ } \ if (m_state == kDone) { \ return m_formatted.c_str(); \ } \ else { \ return super_::what(); \ } \ } \ \ protected: \ virtual String getWhat() const throw(); \ \ private: \ mutable EState m_state; \ mutable std::string m_formatted; \ } synergy-1.8.8-stable/src/lib/base/log_outputters.cpp000066400000000000000000000121571305627404700225700ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "base/log_outputters.h" #include "base/TMethodJob.h" #include "arch/Arch.h" #include enum EFileLogOutputter { kFileSizeLimit = 1024 // kb }; // // StopLogOutputter // StopLogOutputter::StopLogOutputter() { // do nothing } StopLogOutputter::~StopLogOutputter() { // do nothing } void StopLogOutputter::open(const char*) { // do nothing } void StopLogOutputter::close() { // do nothing } void StopLogOutputter::show(bool) { // do nothing } bool StopLogOutputter::write(ELevel, const char*) { return false; } // // ConsoleLogOutputter // ConsoleLogOutputter::ConsoleLogOutputter() { } ConsoleLogOutputter::~ConsoleLogOutputter() { } void ConsoleLogOutputter::open(const char* title) { ARCH->openConsole(title); } void ConsoleLogOutputter::close() { ARCH->closeConsole(); } void ConsoleLogOutputter::show(bool showIfEmpty) { ARCH->showConsole(showIfEmpty); } bool ConsoleLogOutputter::write(ELevel level, const char* msg) { ARCH->writeConsole(level, msg); return true; } void ConsoleLogOutputter::flush() { } // // SystemLogOutputter // SystemLogOutputter::SystemLogOutputter() { // do nothing } SystemLogOutputter::~SystemLogOutputter() { // do nothing } void SystemLogOutputter::open(const char* title) { ARCH->openLog(title); } void SystemLogOutputter::close() { ARCH->closeLog(); } void SystemLogOutputter::show(bool showIfEmpty) { ARCH->showLog(showIfEmpty); } bool SystemLogOutputter::write(ELevel level, const char* msg) { ARCH->writeLog(level, msg); return true; } // // SystemLogger // SystemLogger::SystemLogger(const char* title, bool blockConsole) : m_stop(NULL) { // redirect log messages if (blockConsole) { m_stop = new StopLogOutputter; CLOG->insert(m_stop); } m_syslog = new SystemLogOutputter; m_syslog->open(title); CLOG->insert(m_syslog); } SystemLogger::~SystemLogger() { CLOG->remove(m_syslog); delete m_syslog; if (m_stop != NULL) { CLOG->remove(m_stop); delete m_stop; } } // // BufferedLogOutputter // BufferedLogOutputter::BufferedLogOutputter(UInt32 maxBufferSize) : m_maxBufferSize(maxBufferSize) { // do nothing } BufferedLogOutputter::~BufferedLogOutputter() { // do nothing } BufferedLogOutputter::const_iterator BufferedLogOutputter::begin() const { return m_buffer.begin(); } BufferedLogOutputter::const_iterator BufferedLogOutputter::end() const { return m_buffer.end(); } void BufferedLogOutputter::open(const char*) { // do nothing } void BufferedLogOutputter::close() { // remove all elements from the buffer m_buffer.clear(); } void BufferedLogOutputter::show(bool) { // do nothing } bool BufferedLogOutputter::write(ELevel, const char* message) { while (m_buffer.size() >= m_maxBufferSize) { m_buffer.pop_front(); } m_buffer.push_back(String(message)); return true; } // // FileLogOutputter // FileLogOutputter::FileLogOutputter(const char* logFile) { setLogFilename(logFile); } FileLogOutputter::~FileLogOutputter() { } void FileLogOutputter::setLogFilename(const char* logFile) { assert(logFile != NULL); m_fileName = logFile; } bool FileLogOutputter::write(ELevel level, const char *message) { bool moveFile = false; std::ofstream m_handle; m_handle.open(m_fileName.c_str(), std::fstream::app); if (m_handle.is_open() && m_handle.fail() != true) { m_handle << message << std::endl; // when file size exceeds limits, move to 'old log' filename. size_t p = m_handle.tellp(); if (p > (kFileSizeLimit * 1024)) { moveFile = true; } } m_handle.close(); if (moveFile) { String oldLogFilename = synergy::string::sprintf("%s.1", m_fileName.c_str()); remove(oldLogFilename.c_str()); rename(m_fileName.c_str(), oldLogFilename.c_str()); } return true; } void FileLogOutputter::open(const char *title) {} void FileLogOutputter::close() {} void FileLogOutputter::show(bool showIfEmpty) {} // // MesssageBoxLogOutputter // MesssageBoxLogOutputter::MesssageBoxLogOutputter() { // do nothing } MesssageBoxLogOutputter::~MesssageBoxLogOutputter() { // do nothing } void MesssageBoxLogOutputter::open(const char* title) { // do nothing } void MesssageBoxLogOutputter::close() { // do nothing } void MesssageBoxLogOutputter::show(bool showIfEmpty) { // do nothing } bool MesssageBoxLogOutputter::write(ELevel level, const char* msg) { // don't spam user with messages. if (level > kERROR) { return true; } #if SYSAPI_WIN32 MessageBox(NULL, msg, CLOG->getFilterName(level), MB_OK); #endif return true; } synergy-1.8.8-stable/src/lib/base/log_outputters.h000066400000000000000000000104611305627404700222310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "mt/Thread.h" #include "base/ILogOutputter.h" #include "base/String.h" #include "common/basic_types.h" #include "common/stddeque.h" #include #include //! Stop traversing log chain outputter /*! This outputter performs no output and returns false from \c write(), causing the logger to stop traversing the outputter chain. Insert this to prevent already inserted outputters from writing. */ class StopLogOutputter : public ILogOutputter { public: StopLogOutputter(); virtual ~StopLogOutputter(); // ILogOutputter overrides virtual void open(const char* title); virtual void close(); virtual void show(bool showIfEmpty); virtual bool write(ELevel level, const char* message); }; //! Write log to console /*! This outputter writes output to the console. The level for each message is ignored. */ class ConsoleLogOutputter : public ILogOutputter { public: ConsoleLogOutputter(); virtual ~ConsoleLogOutputter(); // ILogOutputter overrides virtual void open(const char* title); virtual void close(); virtual void show(bool showIfEmpty); virtual bool write(ELevel level, const char* message); virtual void flush(); }; //! Write log to file /*! This outputter writes output to the file. The level for each message is ignored. */ class FileLogOutputter : public ILogOutputter { public: FileLogOutputter(const char* logFile); virtual ~FileLogOutputter(); // ILogOutputter overrides virtual void open(const char* title); virtual void close(); virtual void show(bool showIfEmpty); virtual bool write(ELevel level, const char* message); void setLogFilename(const char* title); private: std::string m_fileName; }; //! Write log to system log /*! This outputter writes output to the system log. */ class SystemLogOutputter : public ILogOutputter { public: SystemLogOutputter(); virtual ~SystemLogOutputter(); // ILogOutputter overrides virtual void open(const char* title); virtual void close(); virtual void show(bool showIfEmpty); virtual bool write(ELevel level, const char* message); }; //! Write log to system log only /*! Creating an object of this type inserts a StopLogOutputter followed by a SystemLogOutputter into Log. The destructor removes those outputters. Add one of these to any scope that needs to write to the system log (only) and restore the old outputters when exiting the scope. */ class SystemLogger { public: SystemLogger(const char* title, bool blockConsole); ~SystemLogger(); private: ILogOutputter* m_syslog; ILogOutputter* m_stop; }; //! Save log history /*! This outputter records the last N log messages. */ class BufferedLogOutputter : public ILogOutputter { private: typedef std::deque Buffer; public: typedef Buffer::const_iterator const_iterator; BufferedLogOutputter(UInt32 maxBufferSize); virtual ~BufferedLogOutputter(); //! @name accessors //@{ //! Get start of buffer const_iterator begin() const; //! Get end of buffer const_iterator end() const; //@} // ILogOutputter overrides virtual void open(const char* title); virtual void close(); virtual void show(bool showIfEmpty); virtual bool write(ELevel level, const char* message); private: UInt32 m_maxBufferSize; Buffer m_buffer; }; //! Write log to message box /*! The level for each message is ignored. */ class MesssageBoxLogOutputter : public ILogOutputter { public: MesssageBoxLogOutputter(); virtual ~MesssageBoxLogOutputter(); // ILogOutputter overrides virtual void open(const char* title); virtual void close(); virtual void show(bool showIfEmpty); virtual bool write(ELevel level, const char* message); }; synergy-1.8.8-stable/src/lib/client/000077500000000000000000000000001305627404700173235ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/client/CMakeLists.txt000066400000000000000000000017771305627404700220770ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ../../../ext ) if (UNIX) include_directories( ../../.. ) endif() add_library(client STATIC ${sources}) if (UNIX) target_link_libraries(client synergy io) endif() synergy-1.8.8-stable/src/lib/client/Client.cpp000066400000000000000000000452361305627404700212570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "client/Client.h" #include "client/ServerProxy.h" #include "synergy/Screen.h" #include "synergy/FileChunk.h" #include "synergy/DropHelper.h" #include "synergy/PacketStreamFilter.h" #include "synergy/ProtocolUtil.h" #include "synergy/protocol_types.h" #include "synergy/XSynergy.h" #include "synergy/StreamChunker.h" #include "synergy/IPlatformScreen.h" #include "mt/Thread.h" #include "net/TCPSocket.h" #include "net/IDataSocket.h" #include "net/ISocketFactory.h" #include "net/SecureSocket.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include "base/TMethodJob.h" #include "common/stdexcept.h" #include #include #include #include // // Client // Client::Client( IEventQueue* events, const String& name, const NetworkAddress& address, ISocketFactory* socketFactory, synergy::Screen* screen, ClientArgs const& args) : m_mock(false), m_name(name), m_serverAddress(address), m_socketFactory(socketFactory), m_screen(screen), m_stream(NULL), m_timer(NULL), m_server(NULL), m_ready(false), m_active(false), m_suspended(false), m_connectOnResume(false), m_events(events), m_sendFileThread(NULL), m_writeToDropDirThread(NULL), m_socket(NULL), m_useSecureNetwork(args.m_enableCrypto), m_args(args), m_enableClipboard(true) { assert(m_socketFactory != NULL); assert(m_screen != NULL); // register suspend/resume event handlers m_events->adoptHandler(m_events->forIScreen().suspend(), getEventTarget(), new TMethodEventJob(this, &Client::handleSuspend)); m_events->adoptHandler(m_events->forIScreen().resume(), getEventTarget(), new TMethodEventJob(this, &Client::handleResume)); if (m_args.m_enableDragDrop) { m_events->adoptHandler(m_events->forFile().fileChunkSending(), this, new TMethodEventJob(this, &Client::handleFileChunkSending)); m_events->adoptHandler(m_events->forFile().fileRecieveCompleted(), this, new TMethodEventJob(this, &Client::handleFileRecieveCompleted)); } } Client::~Client() { if (m_mock) { return; } m_events->removeHandler(m_events->forIScreen().suspend(), getEventTarget()); m_events->removeHandler(m_events->forIScreen().resume(), getEventTarget()); cleanupTimer(); cleanupScreen(); cleanupConnecting(); cleanupConnection(); delete m_socketFactory; } void Client::connect() { if (m_stream != NULL) { return; } if (m_suspended) { m_connectOnResume = true; return; } try { // resolve the server hostname. do this every time we connect // in case we couldn't resolve the address earlier or the address // has changed (which can happen frequently if this is a laptop // being shuttled between various networks). patch by Brent // Priddy. m_serverAddress.resolve(); // m_serverAddress will be null if the hostname address is not reolved if (m_serverAddress.getAddress() != NULL) { // to help users troubleshoot, show server host name (issue: 60) LOG((CLOG_NOTE "connecting to '%s': %s:%i", m_serverAddress.getHostname().c_str(), ARCH->addrToString(m_serverAddress.getAddress()).c_str(), m_serverAddress.getPort())); } // create the socket IDataSocket* socket = m_socketFactory->create(m_useSecureNetwork); m_socket = dynamic_cast(socket); // filter socket messages, including a packetizing filter m_stream = socket; m_stream = new PacketStreamFilter(m_events, m_stream, true); // connect LOG((CLOG_DEBUG1 "connecting to server")); setupConnecting(); setupTimer(); socket->connect(m_serverAddress); } catch (XBase& e) { cleanupTimer(); cleanupConnecting(); cleanupStream(); LOG((CLOG_DEBUG1 "connection failed")); sendConnectionFailedEvent(e.what()); return; } } void Client::disconnect(const char* msg) { m_connectOnResume = false; cleanupTimer(); cleanupScreen(); cleanupConnecting(); cleanupConnection(); if (msg != NULL) { sendConnectionFailedEvent(msg); } else { sendEvent(m_events->forClient().disconnected(), NULL); } } void Client::handshakeComplete() { m_ready = true; m_screen->enable(); sendEvent(m_events->forClient().connected(), NULL); } bool Client::isConnected() const { return (m_server != NULL); } bool Client::isConnecting() const { return (m_timer != NULL); } NetworkAddress Client::getServerAddress() const { return m_serverAddress; } void* Client::getEventTarget() const { return m_screen->getEventTarget(); } bool Client::getClipboard(ClipboardID id, IClipboard* clipboard) const { return m_screen->getClipboard(id, clipboard); } void Client::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { m_screen->getShape(x, y, w, h); } void Client::getCursorPos(SInt32& x, SInt32& y) const { m_screen->getCursorPos(x, y); } void Client::enter(SInt32 xAbs, SInt32 yAbs, UInt32, KeyModifierMask mask, bool) { m_active = true; m_screen->mouseMove(xAbs, yAbs); m_screen->enter(mask); if (m_sendFileThread != NULL) { StreamChunker::interruptFile(); m_sendFileThread = NULL; } } bool Client::leave() { m_active = false; m_screen->leave(); if (m_enableClipboard) { // send clipboards that we own and that have changed for (ClipboardID id = 0; id < kClipboardEnd; ++id) { if (m_ownClipboard[id]) { sendClipboard(id); } } } return true; } void Client::setClipboard(ClipboardID id, const IClipboard* clipboard) { m_screen->setClipboard(id, clipboard); m_ownClipboard[id] = false; m_sentClipboard[id] = false; } void Client::grabClipboard(ClipboardID id) { m_screen->grabClipboard(id); m_ownClipboard[id] = false; m_sentClipboard[id] = false; } void Client::setClipboardDirty(ClipboardID, bool) { assert(0 && "shouldn't be called"); } void Client::keyDown(KeyID id, KeyModifierMask mask, KeyButton button) { m_screen->keyDown(id, mask, button); } void Client::keyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) { m_screen->keyRepeat(id, mask, count, button); } void Client::keyUp(KeyID id, KeyModifierMask mask, KeyButton button) { m_screen->keyUp(id, mask, button); } void Client::mouseDown(ButtonID id) { m_screen->mouseDown(id); } void Client::mouseUp(ButtonID id) { m_screen->mouseUp(id); } void Client::mouseMove(SInt32 x, SInt32 y) { m_screen->mouseMove(x, y); } void Client::mouseRelativeMove(SInt32 dx, SInt32 dy) { m_screen->mouseRelativeMove(dx, dy); } void Client::mouseWheel(SInt32 xDelta, SInt32 yDelta) { m_screen->mouseWheel(xDelta, yDelta); } void Client::screensaver(bool activate) { m_screen->screensaver(activate); } void Client::resetOptions() { m_screen->resetOptions(); } void Client::setOptions(const OptionsList& options) { for (OptionsList::const_iterator index = options.begin(); index != options.end(); ++index) { const OptionID id = *index; if (id == kOptionClipboardSharing) { index++; if (*index == static_cast(false)) { LOG((CLOG_NOTE "clipboard sharing is disabled")); } m_enableClipboard = *index; break; } } m_screen->setOptions(options); } String Client::getName() const { return m_name; } void Client::sendClipboard(ClipboardID id) { // note -- m_mutex must be locked on entry assert(m_screen != NULL); assert(m_server != NULL); // get clipboard data. set the clipboard time to the last // clipboard time before getting the data from the screen // as the screen may detect an unchanged clipboard and // avoid copying the data. Clipboard clipboard; if (clipboard.open(m_timeClipboard[id])) { clipboard.close(); } m_screen->getClipboard(id, &clipboard); // check time if (m_timeClipboard[id] == 0 || clipboard.getTime() != m_timeClipboard[id]) { // save new time m_timeClipboard[id] = clipboard.getTime(); // marshall the data String data = clipboard.marshall(); // save and send data if different or not yet sent if (!m_sentClipboard[id] || data != m_dataClipboard[id]) { m_sentClipboard[id] = true; m_dataClipboard[id] = data; m_server->onClipboardChanged(id, &clipboard); } } } void Client::sendEvent(Event::Type type, void* data) { m_events->addEvent(Event(type, getEventTarget(), data)); } void Client::sendConnectionFailedEvent(const char* msg) { FailInfo* info = new FailInfo(msg); info->m_retry = true; Event event(m_events->forClient().connectionFailed(), getEventTarget(), info, Event::kDontFreeData); m_events->addEvent(event); } void Client::sendFileChunk(const void* data) { FileChunk* chunk = static_cast(const_cast(data)); LOG((CLOG_DEBUG1 "send file chunk")); assert(m_server != NULL); // relay m_server->fileChunkSending(chunk->m_chunk[0], &chunk->m_chunk[1], chunk->m_dataSize); } void Client::setupConnecting() { assert(m_stream != NULL); if (m_args.m_enableCrypto) { m_events->adoptHandler(m_events->forIDataSocket().secureConnected(), m_stream->getEventTarget(), new TMethodEventJob(this, &Client::handleConnected)); } else { m_events->adoptHandler(m_events->forIDataSocket().connected(), m_stream->getEventTarget(), new TMethodEventJob(this, &Client::handleConnected)); } m_events->adoptHandler(m_events->forIDataSocket().connectionFailed(), m_stream->getEventTarget(), new TMethodEventJob(this, &Client::handleConnectionFailed)); } void Client::setupConnection() { assert(m_stream != NULL); m_events->adoptHandler(m_events->forISocket().disconnected(), m_stream->getEventTarget(), new TMethodEventJob(this, &Client::handleDisconnected)); m_events->adoptHandler(m_events->forIStream().inputReady(), m_stream->getEventTarget(), new TMethodEventJob(this, &Client::handleHello)); m_events->adoptHandler(m_events->forIStream().outputError(), m_stream->getEventTarget(), new TMethodEventJob(this, &Client::handleOutputError)); m_events->adoptHandler(m_events->forIStream().inputShutdown(), m_stream->getEventTarget(), new TMethodEventJob(this, &Client::handleDisconnected)); m_events->adoptHandler(m_events->forIStream().outputShutdown(), m_stream->getEventTarget(), new TMethodEventJob(this, &Client::handleDisconnected)); m_events->adoptHandler(m_events->forISocket().stopRetry(), m_stream->getEventTarget(), new TMethodEventJob(this, &Client::handleStopRetry)); } void Client::setupScreen() { assert(m_server == NULL); m_ready = false; m_server = new ServerProxy(this, m_stream, m_events); m_events->adoptHandler(m_events->forIScreen().shapeChanged(), getEventTarget(), new TMethodEventJob(this, &Client::handleShapeChanged)); m_events->adoptHandler(m_events->forClipboard().clipboardGrabbed(), getEventTarget(), new TMethodEventJob(this, &Client::handleClipboardGrabbed)); } void Client::setupTimer() { assert(m_timer == NULL); m_timer = m_events->newOneShotTimer(15.0, NULL); m_events->adoptHandler(Event::kTimer, m_timer, new TMethodEventJob(this, &Client::handleConnectTimeout)); } void Client::cleanupConnecting() { if (m_stream != NULL) { m_events->removeHandler(m_events->forIDataSocket().connected(), m_stream->getEventTarget()); m_events->removeHandler(m_events->forIDataSocket().connectionFailed(), m_stream->getEventTarget()); } } void Client::cleanupConnection() { if (m_stream != NULL) { m_events->removeHandler(m_events->forIStream().inputReady(), m_stream->getEventTarget()); m_events->removeHandler(m_events->forIStream().outputError(), m_stream->getEventTarget()); m_events->removeHandler(m_events->forIStream().inputShutdown(), m_stream->getEventTarget()); m_events->removeHandler(m_events->forIStream().outputShutdown(), m_stream->getEventTarget()); m_events->removeHandler(m_events->forISocket().disconnected(), m_stream->getEventTarget()); m_events->removeHandler(m_events->forISocket().stopRetry(), m_stream->getEventTarget()); cleanupStream(); } } void Client::cleanupScreen() { if (m_server != NULL) { if (m_ready) { m_screen->disable(); m_ready = false; } m_events->removeHandler(m_events->forIScreen().shapeChanged(), getEventTarget()); m_events->removeHandler(m_events->forClipboard().clipboardGrabbed(), getEventTarget()); delete m_server; m_server = NULL; } } void Client::cleanupTimer() { if (m_timer != NULL) { m_events->removeHandler(Event::kTimer, m_timer); m_events->deleteTimer(m_timer); m_timer = NULL; } } void Client::cleanupStream() { delete m_stream; m_stream = NULL; } void Client::handleConnected(const Event&, void*) { LOG((CLOG_DEBUG1 "connected; wait for hello")); cleanupConnecting(); setupConnection(); // reset clipboard state for (ClipboardID id = 0; id < kClipboardEnd; ++id) { m_ownClipboard[id] = false; m_sentClipboard[id] = false; m_timeClipboard[id] = 0; } } void Client::handleConnectionFailed(const Event& event, void*) { IDataSocket::ConnectionFailedInfo* info = static_cast(event.getData()); cleanupTimer(); cleanupConnecting(); cleanupStream(); LOG((CLOG_DEBUG1 "connection failed")); sendConnectionFailedEvent(info->m_what.c_str()); delete info; } void Client::handleConnectTimeout(const Event&, void*) { cleanupTimer(); cleanupConnecting(); cleanupConnection(); cleanupStream(); LOG((CLOG_DEBUG1 "connection timed out")); sendConnectionFailedEvent("Timed out"); } void Client::handleOutputError(const Event&, void*) { cleanupTimer(); cleanupScreen(); cleanupConnection(); LOG((CLOG_WARN "error sending to server")); sendEvent(m_events->forClient().disconnected(), NULL); } void Client::handleDisconnected(const Event&, void*) { cleanupTimer(); cleanupScreen(); cleanupConnection(); LOG((CLOG_DEBUG1 "disconnected")); sendEvent(m_events->forClient().disconnected(), NULL); } void Client::handleShapeChanged(const Event&, void*) { LOG((CLOG_DEBUG "resolution changed")); m_server->onInfoChanged(); } void Client::handleClipboardGrabbed(const Event& event, void*) { if (!m_enableClipboard) { return; } const IScreen::ClipboardInfo* info = static_cast(event.getData()); // grab ownership m_server->onGrabClipboard(info->m_id); // we now own the clipboard and it has not been sent to the server m_ownClipboard[info->m_id] = true; m_sentClipboard[info->m_id] = false; m_timeClipboard[info->m_id] = 0; // if we're not the active screen then send the clipboard now, // otherwise we'll wait until we leave. if (!m_active) { sendClipboard(info->m_id); } } void Client::handleHello(const Event&, void*) { SInt16 major, minor; if (!ProtocolUtil::readf(m_stream, kMsgHello, &major, &minor)) { sendConnectionFailedEvent("Protocol error from server, check encryption settings"); cleanupTimer(); cleanupConnection(); return; } // check versions LOG((CLOG_DEBUG1 "got hello version %d.%d", major, minor)); if (major < kProtocolMajorVersion || (major == kProtocolMajorVersion && minor < kProtocolMinorVersion)) { sendConnectionFailedEvent(XIncompatibleClient(major, minor).what()); cleanupTimer(); cleanupConnection(); return; } // say hello back LOG((CLOG_DEBUG1 "say hello version %d.%d", kProtocolMajorVersion, kProtocolMinorVersion)); ProtocolUtil::writef(m_stream, kMsgHelloBack, kProtocolMajorVersion, kProtocolMinorVersion, &m_name); // now connected but waiting to complete handshake setupScreen(); cleanupTimer(); // make sure we process any remaining messages later. we won't // receive another event for already pending messages so we fake // one. if (m_stream->isReady()) { m_events->addEvent(Event(m_events->forIStream().inputReady(), m_stream->getEventTarget())); } } void Client::handleSuspend(const Event&, void*) { LOG((CLOG_INFO "suspend")); m_suspended = true; bool wasConnected = isConnected(); disconnect(NULL); m_connectOnResume = wasConnected; } void Client::handleResume(const Event&, void*) { LOG((CLOG_INFO "resume")); m_suspended = false; if (m_connectOnResume) { m_connectOnResume = false; connect(); } } void Client::handleFileChunkSending(const Event& event, void*) { sendFileChunk(event.getData()); } void Client::handleFileRecieveCompleted(const Event& event, void*) { onFileRecieveCompleted(); } void Client::onFileRecieveCompleted() { if (isReceivedFileSizeValid()) { m_writeToDropDirThread = new Thread( new TMethodJob( this, &Client::writeToDropDirThread)); } } void Client::handleStopRetry(const Event&, void*) { m_args.m_restartable = false; } void Client::writeToDropDirThread(void*) { LOG((CLOG_DEBUG "starting write to drop dir thread")); while (m_screen->isFakeDraggingStarted()) { ARCH->sleep(.1f); } DropHelper::writeToDir(m_screen->getDropTarget(), m_dragFileList, m_receivedFileData); } void Client::dragInfoReceived(UInt32 fileNum, String data) { // TODO: fix duplicate function from CServer if (!m_args.m_enableDragDrop) { LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info.")); return; } DragInformation::parseDragInfo(m_dragFileList, fileNum, data); m_screen->startDraggingFiles(m_dragFileList); } bool Client::isReceivedFileSizeValid() { return m_expectedFileSize == m_receivedFileData.size(); } void Client::sendFileToServer(const char* filename) { if (m_sendFileThread != NULL) { StreamChunker::interruptFile(); } m_sendFileThread = new Thread( new TMethodJob( this, &Client::sendFileThread, static_cast(const_cast(filename)))); } void Client::sendFileThread(void* filename) { try { char* name = static_cast(filename); StreamChunker::sendFile(name, m_events, this); } catch (std::runtime_error error) { LOG((CLOG_ERR "failed sending file chunks: %s", error.what())); } m_sendFileThread = NULL; } void Client::sendDragInfo(UInt32 fileCount, String& info, size_t size) { m_server->sendDragInfo(fileCount, info.c_str(), size); } synergy-1.8.8-stable/src/lib/client/Client.h000066400000000000000000000151371305627404700207210ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/IClient.h" #include "synergy/Clipboard.h" #include "synergy/DragInformation.h" #include "synergy/INode.h" #include "synergy/ClientArgs.h" #include "net/NetworkAddress.h" #include "base/EventTypes.h" #include "mt/CondVar.h" class EventQueueTimer; namespace synergy { class Screen; } class ServerProxy; class IDataSocket; class ISocketFactory; namespace synergy { class IStream; } class IEventQueue; class Thread; class TCPSocket; //! Synergy client /*! This class implements the top-level client algorithms for synergy. */ class Client : public IClient, public INode { public: class FailInfo { public: FailInfo(const char* what) : m_retry(false), m_what(what) { } bool m_retry; String m_what; }; public: /*! This client will attempt to connect to the server using \p name as its name and \p address as the server's address and \p factory to create the socket. \p screen is the local screen. */ Client(IEventQueue* events, const String& name, const NetworkAddress& address, ISocketFactory* socketFactory, synergy::Screen* screen, ClientArgs const& args); ~Client(); //! @name manipulators //@{ //! Connect to server /*! Starts an attempt to connect to the server. This is ignored if the client is trying to connect or is already connected. */ void connect(); //! Disconnect /*! Disconnects from the server with an optional error message. */ void disconnect(const char* msg); //! Notify of handshake complete /*! Notifies the client that the connection handshake has completed. */ virtual void handshakeComplete(); //! Received drag information void dragInfoReceived(UInt32 fileNum, String data); //! Create a new thread and use it to send file to Server void sendFileToServer(const char* filename); //! Send dragging file information back to server void sendDragInfo(UInt32 fileCount, String& info, size_t size); //@} //! @name accessors //@{ //! Test if connected /*! Returns true iff the client is successfully connected to the server. */ bool isConnected() const; //! Test if connecting /*! Returns true iff the client is currently attempting to connect to the server. */ bool isConnecting() const; //! Get address of server /*! Returns the address of the server the client is connected (or wants to connect) to. */ NetworkAddress getServerAddress() const; //! Return true if recieved file size is valid bool isReceivedFileSizeValid(); //! Return expected file size size_t& getExpectedFileSize() { return m_expectedFileSize; } //! Return received file data String& getReceivedFileData() { return m_receivedFileData; } //! Return drag file list DragFileList getDragFileList() { return m_dragFileList; } //@} // IScreen overrides virtual void* getEventTarget() const; virtual bool getClipboard(ClipboardID id, IClipboard*) const; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const; virtual void getCursorPos(SInt32& x, SInt32& y) const; // IClient overrides virtual void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, bool forScreensaver); virtual bool leave(); virtual void setClipboard(ClipboardID, const IClipboard*); virtual void grabClipboard(ClipboardID); virtual void setClipboardDirty(ClipboardID, bool); virtual void keyDown(KeyID, KeyModifierMask, KeyButton); virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton); virtual void keyUp(KeyID, KeyModifierMask, KeyButton); virtual void mouseDown(ButtonID); virtual void mouseUp(ButtonID); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta); virtual void screensaver(bool activate); virtual void resetOptions(); virtual void setOptions(const OptionsList& options); virtual String getName() const; private: void sendClipboard(ClipboardID); void sendEvent(Event::Type, void*); void sendConnectionFailedEvent(const char* msg); void sendFileChunk(const void* data); void sendFileThread(void*); void writeToDropDirThread(void*); void setupConnecting(); void setupConnection(); void setupScreen(); void setupTimer(); void cleanupConnecting(); void cleanupConnection(); void cleanupScreen(); void cleanupTimer(); void cleanupStream(); void handleConnected(const Event&, void*); void handleConnectionFailed(const Event&, void*); void handleConnectTimeout(const Event&, void*); void handleOutputError(const Event&, void*); void handleDisconnected(const Event&, void*); void handleShapeChanged(const Event&, void*); void handleClipboardGrabbed(const Event&, void*); void handleHello(const Event&, void*); void handleSuspend(const Event& event, void*); void handleResume(const Event& event, void*); void handleFileChunkSending(const Event&, void*); void handleFileRecieveCompleted(const Event&, void*); void handleStopRetry(const Event&, void*); void onFileRecieveCompleted(); void sendClipboardThread(void*); public: bool m_mock; private: String m_name; NetworkAddress m_serverAddress; ISocketFactory* m_socketFactory; synergy::Screen* m_screen; synergy::IStream* m_stream; EventQueueTimer* m_timer; ServerProxy* m_server; bool m_ready; bool m_active; bool m_suspended; bool m_connectOnResume; bool m_ownClipboard[kClipboardEnd]; bool m_sentClipboard[kClipboardEnd]; IClipboard::Time m_timeClipboard[kClipboardEnd]; String m_dataClipboard[kClipboardEnd]; IEventQueue* m_events; std::size_t m_expectedFileSize; String m_receivedFileData; DragFileList m_dragFileList; String m_dragFileExt; Thread* m_sendFileThread; Thread* m_writeToDropDirThread; TCPSocket* m_socket; bool m_useSecureNetwork; ClientArgs m_args; bool m_enableClipboard; }; synergy-1.8.8-stable/src/lib/client/ServerProxy.cpp000066400000000000000000000514321305627404700223440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "client/ServerProxy.h" #include "client/Client.h" #include "synergy/FileChunk.h" #include "synergy/ClipboardChunk.h" #include "synergy/StreamChunker.h" #include "synergy/Clipboard.h" #include "synergy/ProtocolUtil.h" #include "synergy/option_types.h" #include "synergy/protocol_types.h" #include "io/IStream.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include "base/XBase.h" #include // // ServerProxy // ServerProxy::ServerProxy(Client* client, synergy::IStream* stream, IEventQueue* events) : m_client(client), m_stream(stream), m_seqNum(0), m_compressMouse(false), m_compressMouseRelative(false), m_xMouse(0), m_yMouse(0), m_dxMouse(0), m_dyMouse(0), m_ignoreMouse(false), m_keepAliveAlarm(0.0), m_keepAliveAlarmTimer(NULL), m_parser(&ServerProxy::parseHandshakeMessage), m_events(events) { assert(m_client != NULL); assert(m_stream != NULL); // initialize modifier translation table for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id) m_modifierTranslationTable[id] = id; // handle data on stream m_events->adoptHandler(m_events->forIStream().inputReady(), m_stream->getEventTarget(), new TMethodEventJob(this, &ServerProxy::handleData)); m_events->adoptHandler(m_events->forClipboard().clipboardSending(), this, new TMethodEventJob(this, &ServerProxy::handleClipboardSendingEvent)); // send heartbeat setKeepAliveRate(kKeepAliveRate); } ServerProxy::~ServerProxy() { setKeepAliveRate(-1.0); m_events->removeHandler(m_events->forIStream().inputReady(), m_stream->getEventTarget()); } void ServerProxy::resetKeepAliveAlarm() { if (m_keepAliveAlarmTimer != NULL) { m_events->removeHandler(Event::kTimer, m_keepAliveAlarmTimer); m_events->deleteTimer(m_keepAliveAlarmTimer); m_keepAliveAlarmTimer = NULL; } if (m_keepAliveAlarm > 0.0) { m_keepAliveAlarmTimer = m_events->newOneShotTimer(m_keepAliveAlarm, NULL); m_events->adoptHandler(Event::kTimer, m_keepAliveAlarmTimer, new TMethodEventJob(this, &ServerProxy::handleKeepAliveAlarm)); } } void ServerProxy::setKeepAliveRate(double rate) { m_keepAliveAlarm = rate * kKeepAlivesUntilDeath; resetKeepAliveAlarm(); } void ServerProxy::handleData(const Event&, void*) { // handle messages until there are no more. first read message code. UInt8 code[4]; UInt32 n = m_stream->read(code, 4); while (n != 0) { // verify we got an entire code if (n != 4) { LOG((CLOG_ERR "incomplete message from server: %d bytes", n)); m_client->disconnect("incomplete message from server"); return; } // parse message LOG((CLOG_DEBUG2 "msg from server: %c%c%c%c", code[0], code[1], code[2], code[3])); switch ((this->*m_parser)(code)) { case kOkay: break; case kUnknown: LOG((CLOG_ERR "invalid message from server: %c%c%c%c", code[0], code[1], code[2], code[3])); m_client->disconnect("invalid message from server"); return; case kDisconnect: return; } // next message n = m_stream->read(code, 4); } flushCompressedMouse(); } ServerProxy::EResult ServerProxy::parseHandshakeMessage(const UInt8* code) { if (memcmp(code, kMsgQInfo, 4) == 0) { queryInfo(); } else if (memcmp(code, kMsgCInfoAck, 4) == 0) { infoAcknowledgment(); } else if (memcmp(code, kMsgDSetOptions, 4) == 0) { setOptions(); // handshake is complete m_parser = &ServerProxy::parseMessage; m_client->handshakeComplete(); } else if (memcmp(code, kMsgCResetOptions, 4) == 0) { resetOptions(); } else if (memcmp(code, kMsgCKeepAlive, 4) == 0) { // echo keep alives and reset alarm ProtocolUtil::writef(m_stream, kMsgCKeepAlive); resetKeepAliveAlarm(); } else if (memcmp(code, kMsgCNoop, 4) == 0) { // accept and discard no-op } else if (memcmp(code, kMsgCClose, 4) == 0) { // server wants us to hangup LOG((CLOG_DEBUG1 "recv close")); m_client->disconnect(NULL); return kDisconnect; } else if (memcmp(code, kMsgEIncompatible, 4) == 0) { SInt32 major, minor; ProtocolUtil::readf(m_stream, kMsgEIncompatible + 4, &major, &minor); LOG((CLOG_ERR "server has incompatible version %d.%d", major, minor)); m_client->disconnect("server has incompatible version"); return kDisconnect; } else if (memcmp(code, kMsgEBusy, 4) == 0) { LOG((CLOG_ERR "server already has a connected client with name \"%s\"", m_client->getName().c_str())); m_client->disconnect("server already has a connected client with our name"); return kDisconnect; } else if (memcmp(code, kMsgEUnknown, 4) == 0) { LOG((CLOG_ERR "server refused client with name \"%s\"", m_client->getName().c_str())); m_client->disconnect("server refused client with our name"); return kDisconnect; } else if (memcmp(code, kMsgEBad, 4) == 0) { LOG((CLOG_ERR "server disconnected due to a protocol error")); m_client->disconnect("server reported a protocol error"); return kDisconnect; } else { return kUnknown; } return kOkay; } ServerProxy::EResult ServerProxy::parseMessage(const UInt8* code) { if (memcmp(code, kMsgDMouseMove, 4) == 0) { mouseMove(); } else if (memcmp(code, kMsgDMouseRelMove, 4) == 0) { mouseRelativeMove(); } else if (memcmp(code, kMsgDMouseWheel, 4) == 0) { mouseWheel(); } else if (memcmp(code, kMsgDKeyDown, 4) == 0) { keyDown(); } else if (memcmp(code, kMsgDKeyUp, 4) == 0) { keyUp(); } else if (memcmp(code, kMsgDMouseDown, 4) == 0) { mouseDown(); } else if (memcmp(code, kMsgDMouseUp, 4) == 0) { mouseUp(); } else if (memcmp(code, kMsgDKeyRepeat, 4) == 0) { keyRepeat(); } else if (memcmp(code, kMsgCKeepAlive, 4) == 0) { // echo keep alives and reset alarm ProtocolUtil::writef(m_stream, kMsgCKeepAlive); resetKeepAliveAlarm(); } else if (memcmp(code, kMsgCNoop, 4) == 0) { // accept and discard no-op } else if (memcmp(code, kMsgCEnter, 4) == 0) { enter(); } else if (memcmp(code, kMsgCLeave, 4) == 0) { leave(); } else if (memcmp(code, kMsgCClipboard, 4) == 0) { grabClipboard(); } else if (memcmp(code, kMsgCScreenSaver, 4) == 0) { screensaver(); } else if (memcmp(code, kMsgQInfo, 4) == 0) { queryInfo(); } else if (memcmp(code, kMsgCInfoAck, 4) == 0) { infoAcknowledgment(); } else if (memcmp(code, kMsgDClipboard, 4) == 0) { setClipboard(); } else if (memcmp(code, kMsgCResetOptions, 4) == 0) { resetOptions(); } else if (memcmp(code, kMsgDSetOptions, 4) == 0) { setOptions(); } else if (memcmp(code, kMsgDFileTransfer, 4) == 0) { fileChunkReceived(); } else if (memcmp(code, kMsgDDragInfo, 4) == 0) { dragInfoReceived(); } else if (memcmp(code, kMsgCClose, 4) == 0) { // server wants us to hangup LOG((CLOG_DEBUG1 "recv close")); m_client->disconnect(NULL); return kDisconnect; } else if (memcmp(code, kMsgEBad, 4) == 0) { LOG((CLOG_ERR "server disconnected due to a protocol error")); m_client->disconnect("server reported a protocol error"); return kDisconnect; } else { return kUnknown; } // send a reply. this is intended to work around a delay when // running a linux server and an OS X (any BSD?) client. the // client waits to send an ACK (if the system control flag // net.inet.tcp.delayed_ack is 1) in hopes of piggybacking it // on a data packet. we provide that packet here. i don't // know why a delayed ACK should cause the server to wait since // TCP_NODELAY is enabled. ProtocolUtil::writef(m_stream, kMsgCNoop); return kOkay; } void ServerProxy::handleKeepAliveAlarm(const Event&, void*) { LOG((CLOG_NOTE "server is dead")); m_client->disconnect("server is not responding"); } void ServerProxy::onInfoChanged() { // ignore mouse motion until we receive acknowledgment of our info // change message. m_ignoreMouse = true; // send info update queryInfo(); } bool ServerProxy::onGrabClipboard(ClipboardID id) { LOG((CLOG_DEBUG1 "sending clipboard %d changed", id)); ProtocolUtil::writef(m_stream, kMsgCClipboard, id, m_seqNum); return true; } void ServerProxy::onClipboardChanged(ClipboardID id, const IClipboard* clipboard) { String data = IClipboard::marshall(clipboard); LOG((CLOG_DEBUG "sending clipboard %d seqnum=%d", id, m_seqNum)); StreamChunker::sendClipboard(data, data.size(), id, m_seqNum, m_events, this); } void ServerProxy::flushCompressedMouse() { if (m_compressMouse) { m_compressMouse = false; m_client->mouseMove(m_xMouse, m_yMouse); } if (m_compressMouseRelative) { m_compressMouseRelative = false; m_client->mouseRelativeMove(m_dxMouse, m_dyMouse); m_dxMouse = 0; m_dyMouse = 0; } } void ServerProxy::sendInfo(const ClientInfo& info) { LOG((CLOG_DEBUG1 "sending info shape=%d,%d %dx%d", info.m_x, info.m_y, info.m_w, info.m_h)); ProtocolUtil::writef(m_stream, kMsgDInfo, info.m_x, info.m_y, info.m_w, info.m_h, 0, info.m_mx, info.m_my); } KeyID ServerProxy::translateKey(KeyID id) const { static const KeyID s_translationTable[kKeyModifierIDLast][2] = { { kKeyNone, kKeyNone }, { kKeyShift_L, kKeyShift_R }, { kKeyControl_L, kKeyControl_R }, { kKeyAlt_L, kKeyAlt_R }, { kKeyMeta_L, kKeyMeta_R }, { kKeySuper_L, kKeySuper_R }, { kKeyAltGr, kKeyAltGr} }; KeyModifierID id2 = kKeyModifierIDNull; UInt32 side = 0; switch (id) { case kKeyShift_L: id2 = kKeyModifierIDShift; side = 0; break; case kKeyShift_R: id2 = kKeyModifierIDShift; side = 1; break; case kKeyControl_L: id2 = kKeyModifierIDControl; side = 0; break; case kKeyControl_R: id2 = kKeyModifierIDControl; side = 1; break; case kKeyAlt_L: id2 = kKeyModifierIDAlt; side = 0; break; case kKeyAlt_R: id2 = kKeyModifierIDAlt; side = 1; break; case kKeyAltGr: id2 = kKeyModifierIDAltGr; side = 1; // there is only one alt gr key on the right side break; case kKeyMeta_L: id2 = kKeyModifierIDMeta; side = 0; break; case kKeyMeta_R: id2 = kKeyModifierIDMeta; side = 1; break; case kKeySuper_L: id2 = kKeyModifierIDSuper; side = 0; break; case kKeySuper_R: id2 = kKeyModifierIDSuper; side = 1; break; } if (id2 != kKeyModifierIDNull) { return s_translationTable[m_modifierTranslationTable[id2]][side]; } else { return id; } } KeyModifierMask ServerProxy::translateModifierMask(KeyModifierMask mask) const { static const KeyModifierMask s_masks[kKeyModifierIDLast] = { 0x0000, KeyModifierShift, KeyModifierControl, KeyModifierAlt, KeyModifierMeta, KeyModifierSuper, KeyModifierAltGr }; KeyModifierMask newMask = mask & ~(KeyModifierShift | KeyModifierControl | KeyModifierAlt | KeyModifierMeta | KeyModifierSuper | KeyModifierAltGr ); if ((mask & KeyModifierShift) != 0) { newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDShift]]; } if ((mask & KeyModifierControl) != 0) { newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDControl]]; } if ((mask & KeyModifierAlt) != 0) { newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDAlt]]; } if ((mask & KeyModifierAltGr) != 0) { newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDAltGr]]; } if ((mask & KeyModifierMeta) != 0) { newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDMeta]]; } if ((mask & KeyModifierSuper) != 0) { newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDSuper]]; } return newMask; } void ServerProxy::enter() { // parse SInt16 x, y; UInt16 mask; UInt32 seqNum; ProtocolUtil::readf(m_stream, kMsgCEnter + 4, &x, &y, &seqNum, &mask); LOG((CLOG_DEBUG1 "recv enter, %d,%d %d %04x", x, y, seqNum, mask)); // discard old compressed mouse motion, if any m_compressMouse = false; m_compressMouseRelative = false; m_dxMouse = 0; m_dyMouse = 0; m_seqNum = seqNum; // forward m_client->enter(x, y, seqNum, static_cast(mask), false); } void ServerProxy::leave() { // parse LOG((CLOG_DEBUG1 "recv leave")); // send last mouse motion flushCompressedMouse(); // forward m_client->leave(); } void ServerProxy::setClipboard() { // parse static String dataCached; ClipboardID id; UInt32 seq; int r = ClipboardChunk::assemble(m_stream, dataCached, id, seq); if (r == kStart) { size_t size = ClipboardChunk::getExpectedSize(); LOG((CLOG_DEBUG "receiving clipboard %d size=%d", id, size)); } else if (r == kFinish) { LOG((CLOG_DEBUG "received clipboard %d size=%d", id, dataCached.size())); // forward Clipboard clipboard; clipboard.unmarshall(dataCached, 0); m_client->setClipboard(id, &clipboard); LOG((CLOG_INFO "clipboard was updated")); } } void ServerProxy::grabClipboard() { // parse ClipboardID id; UInt32 seqNum; ProtocolUtil::readf(m_stream, kMsgCClipboard + 4, &id, &seqNum); LOG((CLOG_DEBUG "recv grab clipboard %d", id)); // validate if (id >= kClipboardEnd) { return; } // forward m_client->grabClipboard(id); } void ServerProxy::keyDown() { // get mouse up to date flushCompressedMouse(); // parse UInt16 id, mask, button; ProtocolUtil::readf(m_stream, kMsgDKeyDown + 4, &id, &mask, &button); LOG((CLOG_DEBUG1 "recv key down id=0x%08x, mask=0x%04x, button=0x%04x", id, mask, button)); // translate KeyID id2 = translateKey(static_cast(id)); KeyModifierMask mask2 = translateModifierMask( static_cast(mask)); if (id2 != static_cast(id) || mask2 != static_cast(mask)) LOG((CLOG_DEBUG1 "key down translated to id=0x%08x, mask=0x%04x", id2, mask2)); // forward m_client->keyDown(id2, mask2, button); } void ServerProxy::keyRepeat() { // get mouse up to date flushCompressedMouse(); // parse UInt16 id, mask, count, button; ProtocolUtil::readf(m_stream, kMsgDKeyRepeat + 4, &id, &mask, &count, &button); LOG((CLOG_DEBUG1 "recv key repeat id=0x%08x, mask=0x%04x, count=%d, button=0x%04x", id, mask, count, button)); // translate KeyID id2 = translateKey(static_cast(id)); KeyModifierMask mask2 = translateModifierMask( static_cast(mask)); if (id2 != static_cast(id) || mask2 != static_cast(mask)) LOG((CLOG_DEBUG1 "key repeat translated to id=0x%08x, mask=0x%04x", id2, mask2)); // forward m_client->keyRepeat(id2, mask2, count, button); } void ServerProxy::keyUp() { // get mouse up to date flushCompressedMouse(); // parse UInt16 id, mask, button; ProtocolUtil::readf(m_stream, kMsgDKeyUp + 4, &id, &mask, &button); LOG((CLOG_DEBUG1 "recv key up id=0x%08x, mask=0x%04x, button=0x%04x", id, mask, button)); // translate KeyID id2 = translateKey(static_cast(id)); KeyModifierMask mask2 = translateModifierMask( static_cast(mask)); if (id2 != static_cast(id) || mask2 != static_cast(mask)) LOG((CLOG_DEBUG1 "key up translated to id=0x%08x, mask=0x%04x", id2, mask2)); // forward m_client->keyUp(id2, mask2, button); } void ServerProxy::mouseDown() { // get mouse up to date flushCompressedMouse(); // parse SInt8 id; ProtocolUtil::readf(m_stream, kMsgDMouseDown + 4, &id); LOG((CLOG_DEBUG1 "recv mouse down id=%d", id)); // forward m_client->mouseDown(static_cast(id)); } void ServerProxy::mouseUp() { // get mouse up to date flushCompressedMouse(); // parse SInt8 id; ProtocolUtil::readf(m_stream, kMsgDMouseUp + 4, &id); LOG((CLOG_DEBUG1 "recv mouse up id=%d", id)); // forward m_client->mouseUp(static_cast(id)); } void ServerProxy::mouseMove() { // parse bool ignore; SInt16 x, y; ProtocolUtil::readf(m_stream, kMsgDMouseMove + 4, &x, &y); // note if we should ignore the move ignore = m_ignoreMouse; // compress mouse motion events if more input follows if (!ignore && !m_compressMouse && m_stream->isReady()) { m_compressMouse = true; } // if compressing then ignore the motion but record it if (m_compressMouse) { m_compressMouseRelative = false; ignore = true; m_xMouse = x; m_yMouse = y; m_dxMouse = 0; m_dyMouse = 0; } LOG((CLOG_DEBUG2 "recv mouse move %d,%d", x, y)); // forward if (!ignore) { m_client->mouseMove(x, y); } } void ServerProxy::mouseRelativeMove() { // parse bool ignore; SInt16 dx, dy; ProtocolUtil::readf(m_stream, kMsgDMouseRelMove + 4, &dx, &dy); // note if we should ignore the move ignore = m_ignoreMouse; // compress mouse motion events if more input follows if (!ignore && !m_compressMouseRelative && m_stream->isReady()) { m_compressMouseRelative = true; } // if compressing then ignore the motion but record it if (m_compressMouseRelative) { ignore = true; m_dxMouse += dx; m_dyMouse += dy; } LOG((CLOG_DEBUG2 "recv mouse relative move %d,%d", dx, dy)); // forward if (!ignore) { m_client->mouseRelativeMove(dx, dy); } } void ServerProxy::mouseWheel() { // get mouse up to date flushCompressedMouse(); // parse SInt16 xDelta, yDelta; ProtocolUtil::readf(m_stream, kMsgDMouseWheel + 4, &xDelta, &yDelta); LOG((CLOG_DEBUG2 "recv mouse wheel %+d,%+d", xDelta, yDelta)); // forward m_client->mouseWheel(xDelta, yDelta); } void ServerProxy::screensaver() { // parse SInt8 on; ProtocolUtil::readf(m_stream, kMsgCScreenSaver + 4, &on); LOG((CLOG_DEBUG1 "recv screen saver on=%d", on)); // forward m_client->screensaver(on != 0); } void ServerProxy::resetOptions() { // parse LOG((CLOG_DEBUG1 "recv reset options")); // forward m_client->resetOptions(); // reset keep alive setKeepAliveRate(kKeepAliveRate); // reset modifier translation table for (KeyModifierID id = 0; id < kKeyModifierIDLast; ++id) { m_modifierTranslationTable[id] = id; } } void ServerProxy::setOptions() { // parse OptionsList options; ProtocolUtil::readf(m_stream, kMsgDSetOptions + 4, &options); LOG((CLOG_DEBUG1 "recv set options size=%d", options.size())); // forward m_client->setOptions(options); // update modifier table for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { KeyModifierID id = kKeyModifierIDNull; if (options[i] == kOptionModifierMapForShift) { id = kKeyModifierIDShift; } else if (options[i] == kOptionModifierMapForControl) { id = kKeyModifierIDControl; } else if (options[i] == kOptionModifierMapForAlt) { id = kKeyModifierIDAlt; } else if (options[i] == kOptionModifierMapForAltGr) { id = kKeyModifierIDAltGr; } else if (options[i] == kOptionModifierMapForMeta) { id = kKeyModifierIDMeta; } else if (options[i] == kOptionModifierMapForSuper) { id = kKeyModifierIDSuper; } else if (options[i] == kOptionHeartbeat) { // update keep alive setKeepAliveRate(1.0e-3 * static_cast(options[i + 1])); } if (id != kKeyModifierIDNull) { m_modifierTranslationTable[id] = static_cast(options[i + 1]); LOG((CLOG_DEBUG1 "modifier %d mapped to %d", id, m_modifierTranslationTable[id])); } } } void ServerProxy::queryInfo() { ClientInfo info; m_client->getShape(info.m_x, info.m_y, info.m_w, info.m_h); m_client->getCursorPos(info.m_mx, info.m_my); sendInfo(info); } void ServerProxy::infoAcknowledgment() { LOG((CLOG_DEBUG1 "recv info acknowledgment")); m_ignoreMouse = false; } void ServerProxy::fileChunkReceived() { int result = FileChunk::assemble( m_stream, m_client->getReceivedFileData(), m_client->getExpectedFileSize()); if (result == kFinish) { m_events->addEvent(Event(m_events->forFile().fileRecieveCompleted(), m_client)); } else if (result == kStart) { if (m_client->getDragFileList().size() > 0) { String filename = m_client->getDragFileList().at(0).getFilename(); LOG((CLOG_DEBUG "start receiving %s", filename.c_str())); } } } void ServerProxy::dragInfoReceived() { // parse UInt32 fileNum = 0; String content; ProtocolUtil::readf(m_stream, kMsgDDragInfo + 4, &fileNum, &content); m_client->dragInfoReceived(fileNum, content); } void ServerProxy::handleClipboardSendingEvent(const Event& event, void*) { ClipboardChunk::send(m_stream, event.getData()); } void ServerProxy::fileChunkSending(UInt8 mark, char* data, size_t dataSize) { FileChunk::send(m_stream, mark, data, dataSize); } void ServerProxy::sendDragInfo(UInt32 fileCount, const char* info, size_t size) { String data(info, size); ProtocolUtil::writef(m_stream, kMsgDDragInfo, fileCount, &data); } synergy-1.8.8-stable/src/lib/client/ServerProxy.h000066400000000000000000000066451305627404700220170ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/clipboard_types.h" #include "synergy/key_types.h" #include "base/Event.h" #include "base/Stopwatch.h" #include "base/String.h" class Client; class ClientInfo; class EventQueueTimer; class IClipboard; namespace synergy { class IStream; } class IEventQueue; //! Proxy for server /*! This class acts a proxy for the server, converting calls into messages to the server and messages from the server to calls on the client. */ class ServerProxy { public: /*! Process messages from the server on \p stream and forward to \p client. */ ServerProxy(Client* client, synergy::IStream* stream, IEventQueue* events); ~ServerProxy(); //! @name manipulators //@{ void onInfoChanged(); bool onGrabClipboard(ClipboardID); void onClipboardChanged(ClipboardID, const IClipboard*); //@} // sending file chunk to server void fileChunkSending(UInt8 mark, char* data, size_t dataSize); // sending dragging information to server void sendDragInfo(UInt32 fileCount, const char* info, size_t size); #ifdef TEST_ENV void handleDataForTest() { handleData(Event(), NULL); } #endif protected: enum EResult { kOkay, kUnknown, kDisconnect }; EResult parseHandshakeMessage(const UInt8* code); EResult parseMessage(const UInt8* code); private: // if compressing mouse motion then send the last motion now void flushCompressedMouse(); void sendInfo(const ClientInfo&); void resetKeepAliveAlarm(); void setKeepAliveRate(double); // modifier key translation KeyID translateKey(KeyID) const; KeyModifierMask translateModifierMask(KeyModifierMask) const; // event handlers void handleData(const Event&, void*); void handleKeepAliveAlarm(const Event&, void*); // message handlers void enter(); void leave(); void setClipboard(); void grabClipboard(); void keyDown(); void keyRepeat(); void keyUp(); void mouseDown(); void mouseUp(); void mouseMove(); void mouseRelativeMove(); void mouseWheel(); void screensaver(); void resetOptions(); void setOptions(); void queryInfo(); void infoAcknowledgment(); void fileChunkReceived(); void dragInfoReceived(); void handleClipboardSendingEvent(const Event&, void*); private: typedef EResult (ServerProxy::*MessageParser)(const UInt8*); Client* m_client; synergy::IStream* m_stream; UInt32 m_seqNum; bool m_compressMouse; bool m_compressMouseRelative; SInt32 m_xMouse, m_yMouse; SInt32 m_dxMouse, m_dyMouse; bool m_ignoreMouse; KeyModifierID m_modifierTranslationTable[kKeyModifierIDLast]; double m_keepAliveAlarm; EventQueueTimer* m_keepAliveAlarmTimer; MessageParser m_parser; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/common/000077500000000000000000000000001305627404700173355ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/common/CMakeLists.txt000066400000000000000000000016631305627404700221030ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ) if (UNIX) include_directories( ../../.. ) endif() add_library(common STATIC ${sources}) synergy-1.8.8-stable/src/lib/common/IInterface.h000066400000000000000000000017561305627404700215300ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" //! Base class of interfaces /*! This is the base class of all interface classes. An interface class has only pure virtual methods. */ class IInterface { public: //! Interface destructor does nothing virtual ~IInterface() { } }; synergy-1.8.8-stable/src/lib/common/MacOSXPrecomp.h000066400000000000000000000016261305627404700221330ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // // Prefix header for all source files of the 'deleteme' target in the 'deleteme' project. // #define MAC_OS_X_VERSION_MAX_ALLOWED MAC_OS_X_VERSION_10_2 #include synergy-1.8.8-stable/src/lib/common/Version.cpp000066400000000000000000000022501305627404700214650ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/Version.h" const char* kApplication = "Synergy"; const char* kCopyright = "Copyright (C) 2012-2016 Symless Ltd.\n" "Copyright (C) 2008-2014 Nick Bolton\n" "Copyright (C) 2002-2014 Chris Schoeneman"; const char* kContact = "Email: nick@symless.com"; const char* kWebsite = "http://symless.com/"; const char* kVersion = VERSION; const char* kAppVersion = "Synergy " VERSION; synergy-1.8.8-stable/src/lib/common/Version.h000066400000000000000000000023541305627404700211370ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" // set version macro if not set yet #if !defined(VERSION) #error Version was not set (should be passed to compiler). #endif // important strings extern const char* kApplication; extern const char* kCopyright; extern const char* kContact; extern const char* kWebsite; // build version. follows linux kernel style: an even minor number implies // a release version, odd implies development version. extern const char* kVersion; // application version extern const char* kAppVersion; synergy-1.8.8-stable/src/lib/common/basic_types.h000066400000000000000000000042441305627404700220170ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" // // pick types of particular sizes // #if !defined(TYPE_OF_SIZE_1) # if SIZEOF_CHAR == 1 # define TYPE_OF_SIZE_1 char # endif #endif #if !defined(TYPE_OF_SIZE_2) # if SIZEOF_INT == 2 # define TYPE_OF_SIZE_2 int # else # define TYPE_OF_SIZE_2 short # endif #endif #if !defined(TYPE_OF_SIZE_4) // Carbon defines SInt32 and UInt32 in terms of long # if SIZEOF_INT == 4 && !defined(__APPLE__) # define TYPE_OF_SIZE_4 int # else # define TYPE_OF_SIZE_4 long # endif #endif // // verify existence of required types // #if !defined(TYPE_OF_SIZE_1) # error No 1 byte integer type #endif #if !defined(TYPE_OF_SIZE_2) # error No 2 byte integer type #endif #if !defined(TYPE_OF_SIZE_4) # error No 4 byte integer type #endif // // make typedefs // // except for SInt8 and UInt8 these types are only guaranteed to be // at least as big as indicated (in bits). that is, they may be // larger than indicated. // // Added this because it doesn't compile on OS X 10.6 because they are already defined in Carbon #if !defined(__MACTYPES__) #if defined(__APPLE__) #include #else typedef signed TYPE_OF_SIZE_1 SInt8; typedef signed TYPE_OF_SIZE_2 SInt16; typedef signed TYPE_OF_SIZE_4 SInt32; typedef unsigned TYPE_OF_SIZE_1 UInt8; typedef unsigned TYPE_OF_SIZE_2 UInt16; typedef unsigned TYPE_OF_SIZE_4 UInt32; #endif #endif // // clean up // #undef TYPE_OF_SIZE_1 #undef TYPE_OF_SIZE_2 #undef TYPE_OF_SIZE_4 synergy-1.8.8-stable/src/lib/common/common.h000066400000000000000000000103501305627404700207750ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once // this file should be included, directly or indirectly by every other. #if HAVE_CONFIG_H # include "config.h" // don't use poll() on mac # if defined(__APPLE__) # undef HAVE_POLL # endif #else // we may not have run configure on win32 # if defined(_WIN32) # define SYSAPI_WIN32 1 # define WINAPI_MSWINDOWS 1 # endif // we may not have run configure on OS X # if defined(__APPLE__) # define SYSAPI_UNIX 1 # define WINAPI_CARBON 1 # define HAVE_CXX_BOOL 1 # define HAVE_CXX_CASTS 1 # define HAVE_CXX_EXCEPTIONS 1 # define HAVE_CXX_MUTABLE 1 # define HAVE_CXX_STDLIB 1 # define HAVE_GETPWUID_R 1 # define HAVE_GMTIME_R 1 # define HAVE_INET_ATON 1 # define HAVE_INTTYPES_H 1 # define HAVE_ISTREAM 1 # define HAVE_MEMORY_H 1 # define HAVE_NANOSLEEP 1 # define HAVE_OSTREAM 1 # define HAVE_POSIX_SIGWAIT 1 # define HAVE_PTHREAD 1 # define HAVE_PTHREAD_SIGNAL 1 # include # include # if defined(_SOCKLEN_T) # define HAVE_SOCKLEN_T 1 # endif # define HAVE_SSTREAM 1 # define HAVE_STDINT_H 1 # define HAVE_STDLIB_H 1 # define HAVE_STRINGS_H 1 # define HAVE_STRING_H 1 # define HAVE_SYS_SELECT_H 1 # define HAVE_SYS_SOCKET_H 1 # define HAVE_SYS_STAT_H 1 # define HAVE_SYS_TIME_H 1 # define HAVE_SYS_TYPES_H 1 # define HAVE_SYS_UTSNAME_H 1 # define HAVE_UNISTD_H 1 # define HAVE_VSNPRINTF 1 /* disable this so we can build with the 10.2.8 SDK */ /*# define HAVE_WCHAR_H 1*/ # define SELECT_TYPE_ARG1 int # define SELECT_TYPE_ARG234 (fd_set *) # define SELECT_TYPE_ARG5 (struct timeval *) # define SIZEOF_CHAR 1 # define SIZEOF_INT 4 # define SIZEOF_LONG 4 # define SIZEOF_SHORT 2 # define STDC_HEADERS 1 # define TIME_WITH_SYS_TIME 1 # define X_DISPLAY_MISSING 1 # endif #endif // VC++ specific #if (_MSC_VER >= 1200) // work around for statement scoping bug # define for if (false) { } else for // turn off bonehead warnings # pragma warning(disable: 4786) // identifier truncated in debug info # pragma warning(disable: 4514) // unreferenced inline function removed // this one's a little too aggressive # pragma warning(disable: 4127) // conditional expression is constant // Code Analysis # pragma warning(disable: 6011) // emitted incorrectly under release build in some circumstances # if defined(NDEBUG) # pragma warning(disable: 4702) // unreachable code # pragma warning(disable: 4701) // variable maybe used uninitialized # endif #endif // (_MSC_VER >= 1200) // VC++ has built-in sized types #if defined(_MSC_VER) # include # define TYPE_OF_SIZE_1 __int8 # define TYPE_OF_SIZE_2 __int16 # define TYPE_OF_SIZE_4 __int32 #else # define SIZE_OF_CHAR 1 # define SIZE_OF_SHORT 2 # define SIZE_OF_INT 4 # define SIZE_OF_LONG 4 #endif // FIXME -- including fp.h from Carbon.h causes a undefined symbol error // on my build system. the symbol is scalb. since we don't need any // math functions we define __FP__, the include guard macro for fp.h, to // prevent fp.h from being included. #if defined(__APPLE__) # define __FP__ #endif // define NULL #include // if not c++0x, future proof code by allowing use of nullptr #ifndef nullptr # define nullptr NULL #endif // make assert available since we use it a lot #include #include #include enum { kExitSuccess = 0, // successful completion kExitFailed = 1, // general failure kExitTerminated = 2, // killed by signal kExitArgs = 3, // bad arguments kExitConfig = 4, // cannot read configuration kExitSubscription = 5 // subscription error }; synergy-1.8.8-stable/src/lib/common/stdbitset.h000066400000000000000000000014451305627404700215170ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #include #include "common/stdpost.h" synergy-1.8.8-stable/src/lib/common/stddeque.h000066400000000000000000000014441305627404700213270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #include #include "common/stdpost.h" synergy-1.8.8-stable/src/lib/common/stdexcept.h000066400000000000000000000014331305627404700215120ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include // apple declares _NOEXCEPT #ifndef _NOEXCEPT # define _NOEXCEPT throw() #endif synergy-1.8.8-stable/src/lib/common/stdfstream.h000066400000000000000000000015051305627404700216630ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #include #include "common/stdpost.h" #include "common/stdistream.h" synergy-1.8.8-stable/src/lib/common/stdistream.h000066400000000000000000000027541305627404700216750ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #if HAVE_ISTREAM #include #else #include #endif #include "common/stdpost.h" #if defined(_MSC_VER) && _MSC_VER <= 1200 // VC++6 istream has no overloads for __int* types, .NET does inline std::istream& operator>>(std::istream& s, SInt8& i) { return s >> (signed char&)i; } inline std::istream& operator>>(std::istream& s, SInt16& i) { return s >> (short&)i; } inline std::istream& operator>>(std::istream& s, SInt32& i) { return s >> (int&)i; } inline std::istream& operator>>(std::istream& s, UInt8& i) { return s >> (unsigned char&)i; } inline std::istream& operator>>(std::istream& s, UInt16& i) { return s >> (unsigned short&)i; } inline std::istream& operator>>(std::istream& s, UInt32& i) { return s >> (unsigned int&)i; } #endif synergy-1.8.8-stable/src/lib/common/stdlist.h000066400000000000000000000014431305627404700211760ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #include #include "common/stdpost.h" synergy-1.8.8-stable/src/lib/common/stdmap.h000066400000000000000000000014421305627404700207770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #include #include "common/stdpost.h" synergy-1.8.8-stable/src/lib/common/stdostream.h000066400000000000000000000015301305627404700216720ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #if HAVE_OSTREAM #include #else #include #endif #include "common/stdpost.h" synergy-1.8.8-stable/src/lib/common/stdpost.h000066400000000000000000000014161305627404700212100ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if defined(_MSC_VER) #pragma warning(pop) #endif synergy-1.8.8-stable/src/lib/common/stdpre.h000066400000000000000000000025431305627404700210130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #if defined(_MSC_VER) #pragma warning(disable: 4786) // identifier truncated #pragma warning(disable: 4514) // unreferenced inline #pragma warning(disable: 4710) // not inlined #pragma warning(disable: 4663) // C++ change, template specialization #pragma warning(disable: 4503) // decorated name length too long #pragma warning(push, 3) #pragma warning(disable: 4018) // signed/unsigned mismatch #pragma warning(disable: 4284) #pragma warning(disable: 4146) // unary minus on unsigned value #pragma warning(disable: 4127) // conditional expression is constant #pragma warning(disable: 4701) // variable possibly used uninitialized #endif synergy-1.8.8-stable/src/lib/common/stdset.h000066400000000000000000000014421305627404700210150ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #include #include "common/stdpost.h" synergy-1.8.8-stable/src/lib/common/stdsstream.h000066400000000000000000000206421305627404700217030ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #if HAVE_SSTREAM || !defined(__GNUC__) || (__GNUC__ >= 3) #include #elif defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 95) // g++ 2.95 didn't ship with sstream. the following is a backport // by Magnus Fromreide of the sstream in g++ 3.0. /* This is part of libio/iostream, providing -*- C++ -*- input/output. Copyright (C) 2012-2016 Symless Ltd. Copyright (C) 2000 Free Software Foundation This file is part of the GNU IO Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This library 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. You should have received a copy of the GNU General Public License along with this library; see the file LICENSE. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. As a special exception, if you link this library with files compiled with a GNU compiler to produce an executable, this does not cause the resulting executable to be covered by the GNU General Public License. This exception does not however invalidate any other reasons why the executable file might be covered by the GNU General Public License. */ /* Written by Magnus Fromreide (magfr@lysator.liu.se). */ /* seekoff and ideas for overflow is largely borrowed from libstdc++-v3 */ #include #include #include namespace std { class stringbuf : public streambuf { public: typedef char char_type; typedef int int_type; typedef streampos pos_type; typedef streamoff off_type; explicit stringbuf(int which=ios::in|ios::out) : streambuf(), mode(static_cast(which)), stream(NULL), stream_len(0) { stringbuf_init(); } explicit stringbuf(const string &str, int which=ios::in|ios::out) : streambuf(), mode(static_cast(which)), stream(NULL), stream_len(0) { if (mode & (ios::in|ios::out)) { stream_len = str.size(); stream = new char_type[stream_len]; str.copy(stream, stream_len); } stringbuf_init(); } virtual ~stringbuf() { delete[] stream; } string str() const { if (pbase() != 0) return string(stream, pptr()-pbase()); else return string(); } void str(const string& str) { delete[] stream; stream_len = str.size(); stream = new char_type[stream_len]; str.copy(stream, stream_len); stringbuf_init(); } protected: // The buffer is already in gptr, so if it ends then it is out of data. virtual int underflow() { return EOF; } virtual int overflow(int c = EOF) { int res; if (mode & ios::out) { if (c != EOF) { streamsize old_stream_len = stream_len; stream_len += 1; char_type* new_stream = new char_type[stream_len]; memcpy(new_stream, stream, old_stream_len); delete[] stream; stream = new_stream; stringbuf_sync(gptr()-eback(), pptr()-pbase()); sputc(c); res = c; } else res = EOF; } else res = 0; return res; } virtual streambuf* setbuf(char_type* s, streamsize n) { if (n != 0) { delete[] stream; stream = new char_type[n]; memcpy(stream, s, n); stream_len = n; stringbuf_sync(0, 0); } return this; } virtual pos_type seekoff(off_type off, ios::seek_dir way, int which = ios::in | ios::out) { pos_type ret = pos_type(off_type(-1)); bool testin = which & ios::in && mode & ios::in; bool testout = which & ios::out && mode & ios::out; bool testboth = testin && testout && way != ios::cur; if (stream_len && ((testin != testout) || testboth)) { char_type* beg = stream; char_type* curi = NULL; char_type* curo = NULL; char_type* endi = NULL; char_type* endo = NULL; if (testin) { curi = gptr(); endi = egptr(); } if (testout) { curo = pptr(); endo = epptr(); } off_type newoffi = 0; off_type newoffo = 0; if (way == ios::beg) { newoffi = beg - curi; newoffo = beg - curo; } else if (way == ios::end) { newoffi = endi - curi; newoffo = endo - curo; } if (testin && newoffi + off + curi - beg >= 0 && endi - beg >= newoffi + off + curi - beg) { gbump(newoffi + off); ret = pos_type(newoffi + off + curi); } if (testout && newoffo + off + curo - beg >= 0 && endo - beg >= newoffo + off + curo - beg) { pbump(newoffo + off); ret = pos_type(newoffo + off + curo); } } return ret; } virtual pos_type seekpos(pos_type sp, int which = ios::in | ios::out) { pos_type ret = seekoff(sp, ios::beg, which); return ret; } private: void stringbuf_sync(streamsize i, streamsize o) { if (mode & ios::in) setg(stream, stream + i, stream + stream_len); if (mode & ios::out) { setp(stream, stream + stream_len); pbump(o); } } void stringbuf_init() { if (mode & ios::ate) stringbuf_sync(0, stream_len); else stringbuf_sync(0, 0); } private: ios::open_mode mode; char_type* stream; streamsize stream_len; }; class istringstream : public istream { public: typedef char char_type; typedef int int_type; typedef streampos pos_type; typedef streamoff off_type; explicit istringstream(int which=ios::in) : istream(&sb), sb(which | ios::in) { } explicit istringstream(const string& str, int which=ios::in) : istream(&sb), sb(str, which | ios::in) { } stringbuf* rdbuf() const { return const_cast(&sb); } string str() const { return rdbuf()->str(); } void str(const string& s) { rdbuf()->str(s); } private: stringbuf sb; }; class ostringstream : public ostream { public: typedef char char_type; typedef int int_type; typedef streampos pos_type; typedef streamoff off_type; explicit ostringstream(int which=ios::out) : ostream(&sb), sb(which | ios::out) { } explicit ostringstream(const string& str, int which=ios::out) : ostream(&sb), sb(str, which | ios::out) { } stringbuf* rdbuf() const { return const_cast(&sb); } string str() const { return rdbuf()->str(); } void str(const string& s) { rdbuf()->str(s); } private: stringbuf sb; }; class stringstream : public iostream { public: typedef char char_type; typedef int int_type; typedef streampos pos_type; typedef streamoff off_type; explicit stringstream(int which=ios::out|ios::in) : iostream(&sb), sb(which) { } explicit stringstream(const string& str, int which=ios::out|ios::in) : iostream(&sb), sb(str, which) { } stringbuf* rdbuf() const { return const_cast(&sb); } string str() const { return rdbuf()->str(); } void str(const string& s) { rdbuf()->str(s); } private: stringbuf sb; }; }; #else /* not g++ 2.95 and no */ #error "Standard C++ library is missing required sstream header." #endif /* not g++ 2.95 and no */ #include "common/stdpost.h" #include "common/stdistream.h" synergy-1.8.8-stable/src/lib/common/stdstring.h000066400000000000000000000014451305627404700215330ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #include #include "common/stdpost.h" synergy-1.8.8-stable/src/lib/common/stdvector.h000066400000000000000000000014451305627404700215270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "common/stdpre.h" #include #include "common/stdpost.h" synergy-1.8.8-stable/src/lib/io/000077500000000000000000000000001305627404700164545ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/io/CMakeLists.txt000066400000000000000000000016571305627404700212250ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ) if (UNIX) include_directories( ../../.. ) endif() add_library(io STATIC ${sources}) synergy-1.8.8-stable/src/lib/io/IStream.h000066400000000000000000000064021305627404700201730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "base/Event.h" #include "base/IEventQueue.h" #include "base/EventTypes.h" class IEventQueue; namespace synergy { //! Bidirectional stream interface /*! Defines the interface for all streams. */ class IStream : public IInterface { public: IStream() { } //! @name manipulators //@{ //! Close the stream /*! Closes the stream. Pending input data and buffered output data are discarded. Use \c flush() before \c close() to send buffered output data. Attempts to \c read() after a close return 0, attempts to \c write() generate output error events, and attempts to \c flush() return immediately. */ virtual void close() = 0; //! Read from stream /*! Read up to \p n bytes into \p buffer, returning the number read (zero if no data is available or input is shutdown). \p buffer may be NULL in which case the data is discarded. */ virtual UInt32 read(void* buffer, UInt32 n) = 0; //! Write to stream /*! Write \c n bytes from \c buffer to the stream. If this can't complete immediately it will block. Data may be buffered in order to return more quickly. A output error event is generated when writing fails. */ virtual void write(const void* buffer, UInt32 n) = 0; //! Flush the stream /*! Waits until all buffered data has been written to the stream. */ virtual void flush() = 0; //! Shutdown input /*! Shutdown the input side of the stream. Any pending input data is discarded and further reads immediately return 0. */ virtual void shutdownInput() = 0; //! Shutdown output /*! Shutdown the output side of the stream. Any buffered output data is discarded and further writes generate output error events. Use \c flush() before \c shutdownOutput() to send buffered output data. */ virtual void shutdownOutput() = 0; //@} //! @name accessors //@{ //! Get event target /*! Returns the event target for events generated by this stream. It should be the source stream in a chain of stream filters. */ virtual void* getEventTarget() const = 0; //! Test if \c read() will succeed /*! Returns true iff an immediate \c read() will return data. This may or may not be the same as \c getSize() > 0, depending on the stream type. */ virtual bool isReady() const = 0; //! Get bytes available to read /*! Returns a conservative estimate of the available bytes to read (i.e. a number not greater than the actual number of bytes). Some streams may not be able to determine this and will always return zero. */ virtual UInt32 getSize() const = 0; //@} }; } synergy-1.8.8-stable/src/lib/io/StreamBuffer.cpp000066400000000000000000000063061305627404700215520ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "io/StreamBuffer.h" // // StreamBuffer // const UInt32 StreamBuffer::kChunkSize = 4096; StreamBuffer::StreamBuffer() : m_size(0), m_headUsed(0) { // do nothing } StreamBuffer::~StreamBuffer() { // do nothing } const void* StreamBuffer::peek(UInt32 n) { assert(n <= m_size); // if requesting no data then return NULL so we don't try to access // an empty list. if (n == 0) { return NULL; } // reserve space in first chunk ChunkList::iterator head = m_chunks.begin(); head->reserve(n + m_headUsed); // consolidate chunks into the first chunk until it has n bytes ChunkList::iterator scan = head; ++scan; while (head->size() - m_headUsed < n && scan != m_chunks.end()) { head->insert(head->end(), scan->begin(), scan->end()); scan = m_chunks.erase(scan); } return static_cast(&(head->begin()[m_headUsed])); } void StreamBuffer::pop(UInt32 n) { // discard all chunks if n is greater than or equal to m_size if (n >= m_size) { m_size = 0; m_headUsed = 0; m_chunks.clear(); return; } // update size m_size -= n; // discard chunks until more than n bytes would've been discarded ChunkList::iterator scan = m_chunks.begin(); assert(scan != m_chunks.end()); while (scan->size() - m_headUsed <= n) { n -= (UInt32)scan->size() - m_headUsed; m_headUsed = 0; scan = m_chunks.erase(scan); assert(scan != m_chunks.end()); } // remove left over bytes from the head chunk if (n > 0) { m_headUsed += n; } } void StreamBuffer::write(const void* vdata, UInt32 n) { assert(vdata != NULL); // ignore if no data, otherwise update size if (n == 0) { return; } m_size += n; // cast data to bytes const UInt8* data = static_cast(vdata); // point to last chunk if it has space, otherwise append an empty chunk ChunkList::iterator scan = m_chunks.end(); if (scan != m_chunks.begin()) { --scan; if (scan->size() >= kChunkSize) { ++scan; } } if (scan == m_chunks.end()) { scan = m_chunks.insert(scan, Chunk()); } // append data in chunks while (n > 0) { // choose number of bytes for next chunk assert(scan->size() <= kChunkSize); UInt32 count = kChunkSize - (UInt32)scan->size(); if (count > n) count = n; // transfer data scan->insert(scan->end(), data, data + count); n -= count; data += count; // append another empty chunk if we're not done yet if (n > 0) { ++scan; scan = m_chunks.insert(scan, Chunk()); } } } UInt32 StreamBuffer::getSize() const { return m_size; } synergy-1.8.8-stable/src/lib/io/StreamBuffer.h000066400000000000000000000035051305627404700212150ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/EventTypes.h" #include "common/stdlist.h" #include "common/stdvector.h" //! FIFO of bytes /*! This class maintains a FIFO (first-in, last-out) buffer of bytes. */ class StreamBuffer { public: StreamBuffer(); ~StreamBuffer(); //! @name manipulators //@{ //! Read data without removing from buffer /*! Return a pointer to memory with the next \c n bytes in the buffer (which must be <= getSize()). The caller must not modify the returned memory nor delete it. */ const void* peek(UInt32 n); //! Discard data /*! Discards the next \c n bytes. If \c n >= getSize() then the buffer is cleared. */ void pop(UInt32 n); //! Write data to buffer /*! Appends \c n bytes from \c data to the buffer. */ void write(const void* data, UInt32 n); //@} //! @name accessors //@{ //! Get size of buffer /*! Returns the number of bytes in the buffer. */ UInt32 getSize() const; //@} private: static const UInt32 kChunkSize; typedef std::vector Chunk; typedef std::list ChunkList; ChunkList m_chunks; UInt32 m_size; UInt32 m_headUsed; }; synergy-1.8.8-stable/src/lib/io/StreamFilter.cpp000066400000000000000000000045521305627404700215670ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "io/StreamFilter.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" // // StreamFilter // StreamFilter::StreamFilter(IEventQueue* events, synergy::IStream* stream, bool adoptStream) : m_stream(stream), m_adopted(adoptStream), m_events(events) { // replace handlers for m_stream m_events->removeHandlers(m_stream->getEventTarget()); m_events->adoptHandler(Event::kUnknown, m_stream->getEventTarget(), new TMethodEventJob(this, &StreamFilter::handleUpstreamEvent)); } StreamFilter::~StreamFilter() { m_events->removeHandler(Event::kUnknown, m_stream->getEventTarget()); if (m_adopted) { delete m_stream; } } void StreamFilter::close() { getStream()->close(); } UInt32 StreamFilter::read(void* buffer, UInt32 n) { return getStream()->read(buffer, n); } void StreamFilter::write(const void* buffer, UInt32 n) { getStream()->write(buffer, n); } void StreamFilter::flush() { getStream()->flush(); } void StreamFilter::shutdownInput() { getStream()->shutdownInput(); } void StreamFilter::shutdownOutput() { getStream()->shutdownOutput(); } void* StreamFilter::getEventTarget() const { return const_cast(static_cast(this)); } bool StreamFilter::isReady() const { return getStream()->isReady(); } UInt32 StreamFilter::getSize() const { return getStream()->getSize(); } synergy::IStream* StreamFilter::getStream() const { return m_stream; } void StreamFilter::filterEvent(const Event& event) { m_events->dispatchEvent(Event(event.getType(), getEventTarget(), event.getData())); } void StreamFilter::handleUpstreamEvent(const Event& event, void*) { filterEvent(event); } synergy-1.8.8-stable/src/lib/io/StreamFilter.h000066400000000000000000000043021305627404700212250ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "io/IStream.h" #include "base/IEventQueue.h" //! A stream filter /*! This class wraps a stream. Subclasses provide indirect access to the wrapped stream, typically performing some filtering. */ class StreamFilter : public synergy::IStream { public: /*! Create a wrapper around \c stream. Iff \c adoptStream is true then this object takes ownership of the stream and will delete it in the d'tor. */ StreamFilter(IEventQueue* events, synergy::IStream* stream, bool adoptStream = true); virtual ~StreamFilter(); // IStream overrides // These all just forward to the underlying stream except getEventTarget. // Override as necessary. getEventTarget returns a pointer to this. virtual void close(); virtual UInt32 read(void* buffer, UInt32 n); virtual void write(const void* buffer, UInt32 n); virtual void flush(); virtual void shutdownInput(); virtual void shutdownOutput(); virtual void* getEventTarget() const; virtual bool isReady() const; virtual UInt32 getSize() const; //! Get the stream /*! Returns the stream passed to the c'tor. */ synergy::IStream* getStream() const; protected: //! Handle events from source stream /*! Does the event filtering. The default simply dispatches an event identical except using this object as the event target. */ virtual void filterEvent(const Event&); private: void handleUpstreamEvent(const Event&, void*); private: synergy::IStream* m_stream; bool m_adopted; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/io/XIO.cpp000066400000000000000000000021701305627404700176170ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "io/XIO.h" // // XIOClosed // String XIOClosed::getWhat() const throw() { return format("XIOClosed", "already closed"); } // // XIOEndOfStream // String XIOEndOfStream::getWhat() const throw() { return format("XIOEndOfStream", "reached end of stream"); } // // XIOWouldBlock // String XIOWouldBlock::getWhat() const throw() { return format("XIOWouldBlock", "stream operation would block"); } synergy-1.8.8-stable/src/lib/io/XIO.h000066400000000000000000000025061305627404700172670ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/XBase.h" //! Generic I/O exception XBASE_SUBCLASS(XIO, XBase); //! I/O closing exception /*! Thrown if a stream cannot be closed. */ XBASE_SUBCLASS(XIOClose, XIO); //! I/O already closed exception /*! Thrown when attempting to close or perform I/O on an already closed. stream. */ XBASE_SUBCLASS_WHAT(XIOClosed, XIO); //! I/O end of stream exception /*! Thrown when attempting to read beyond the end of a stream. */ XBASE_SUBCLASS_WHAT(XIOEndOfStream, XIO); //! I/O would block exception /*! Thrown if an operation on a stream would block. */ XBASE_SUBCLASS_WHAT(XIOWouldBlock, XIO); synergy-1.8.8-stable/src/lib/ipc/000077500000000000000000000000001305627404700166205ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/ipc/CMakeLists.txt000066400000000000000000000020021305627404700213520ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ) if (UNIX) include_directories( ../../.. ) endif() add_library(ipc STATIC ${sources}) if (UNIX) target_link_libraries(ipc arch base common mt io net synergy) endif() synergy-1.8.8-stable/src/lib/ipc/Ipc.cpp000066400000000000000000000016301305627404700200370ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ipc/Ipc.h" const char* kIpcMsgHello = "IHEL%1i"; const char* kIpcMsgLogLine = "ILOG%s"; const char* kIpcMsgCommand = "ICMD%s%1i"; const char* kIpcMsgShutdown = "ISDN"; synergy-1.8.8-stable/src/lib/ipc/Ipc.h000066400000000000000000000030421305627404700175030ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #define IPC_HOST "127.0.0.1" #define IPC_PORT 24801 enum EIpcMessage { kIpcHello, kIpcLogLine, kIpcCommand, kIpcShutdown, }; enum EIpcClientType { kIpcClientUnknown, kIpcClientGui, kIpcClientNode, }; // handshake: node/gui -> daemon // $1 = type, the client identifies it's self as gui or node (synergyc/s). extern const char* kIpcMsgHello; // log line: daemon -> gui // $1 = aggregate log lines collected from synergys/c or the daemon itself. extern const char* kIpcMsgLogLine; // command: gui -> daemon // $1 = command; the command for the daemon to launch, typically the full // path to synergys/c. $2 = true when process must be elevated on ms windows. extern const char* kIpcMsgCommand; // shutdown: daemon -> node // the daemon tells synergys/c to shut down gracefully. extern const char* kIpcMsgShutdown; synergy-1.8.8-stable/src/lib/ipc/IpcClient.cpp000066400000000000000000000052061305627404700212010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ipc/IpcClient.h" #include "ipc/Ipc.h" #include "ipc/IpcServerProxy.h" #include "ipc/IpcMessage.h" #include "base/TMethodEventJob.h" // // IpcClient // IpcClient::IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : m_serverAddress(NetworkAddress(IPC_HOST, IPC_PORT)), m_socket(events, socketMultiplexer), m_server(nullptr), m_events(events) { init(); } IpcClient::IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port) : m_serverAddress(NetworkAddress(IPC_HOST, port)), m_socket(events, socketMultiplexer), m_server(nullptr), m_events(events) { init(); } void IpcClient::init() { m_serverAddress.resolve(); } IpcClient::~IpcClient() { } void IpcClient::connect() { m_events->adoptHandler( m_events->forIDataSocket().connected(), m_socket.getEventTarget(), new TMethodEventJob( this, &IpcClient::handleConnected)); m_socket.connect(m_serverAddress); m_server = new IpcServerProxy(m_socket, m_events); m_events->adoptHandler( m_events->forIpcServerProxy().messageReceived(), m_server, new TMethodEventJob( this, &IpcClient::handleMessageReceived)); } void IpcClient::disconnect() { m_events->removeHandler(m_events->forIDataSocket().connected(), m_socket.getEventTarget()); m_events->removeHandler(m_events->forIpcServerProxy().messageReceived(), m_server); m_server->disconnect(); delete m_server; m_server = nullptr; } void IpcClient::send(const IpcMessage& message) { assert(m_server != nullptr); m_server->send(message); } void IpcClient::handleConnected(const Event&, void*) { m_events->addEvent(Event( m_events->forIpcClient().connected(), this, m_server, Event::kDontFreeData)); IpcHelloMessage message(kIpcClientNode); send(message); } void IpcClient::handleMessageReceived(const Event& e, void*) { Event event(m_events->forIpcClient().messageReceived(), this); event.setDataObject(e.getDataObject()); m_events->addEvent(event); } synergy-1.8.8-stable/src/lib/ipc/IpcClient.h000066400000000000000000000032601305627404700206440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "net/NetworkAddress.h" #include "net/TCPSocket.h" #include "base/EventTypes.h" class IpcServerProxy; class IpcMessage; class IEventQueue; class SocketMultiplexer; //! IPC client for communication between daemon and GUI. /*! * See \ref IpcServer description. */ class IpcClient { public: IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer); IpcClient(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port); virtual ~IpcClient(); //! @name manipulators //@{ //! Connects to the IPC server at localhost. void connect(); //! Disconnects from the IPC server. void disconnect(); //! Sends a message to the server. void send(const IpcMessage& message); //@} private: void init(); void handleConnected(const Event&, void*); void handleMessageReceived(const Event&, void*); private: NetworkAddress m_serverAddress; TCPSocket m_socket; IpcServerProxy* m_server; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/ipc/IpcClientProxy.cpp000066400000000000000000000122101305627404700222340ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ipc/IpcClientProxy.h" #include "ipc/Ipc.h" #include "ipc/IpcMessage.h" #include "synergy/ProtocolUtil.h" #include "io/IStream.h" #include "arch/Arch.h" #include "base/TMethodEventJob.h" #include "base/Log.h" // // IpcClientProxy // IpcClientProxy::IpcClientProxy(synergy::IStream& stream, IEventQueue* events) : m_stream(stream), m_clientType(kIpcClientUnknown), m_disconnecting(false), m_readMutex(ARCH->newMutex()), m_writeMutex(ARCH->newMutex()), m_events(events) { m_events->adoptHandler( m_events->forIStream().inputReady(), stream.getEventTarget(), new TMethodEventJob( this, &IpcClientProxy::handleData)); m_events->adoptHandler( m_events->forIStream().outputError(), stream.getEventTarget(), new TMethodEventJob( this, &IpcClientProxy::handleWriteError)); m_events->adoptHandler( m_events->forIStream().inputShutdown(), stream.getEventTarget(), new TMethodEventJob( this, &IpcClientProxy::handleDisconnect)); m_events->adoptHandler( m_events->forIStream().outputShutdown(), stream.getEventTarget(), new TMethodEventJob( this, &IpcClientProxy::handleWriteError)); } IpcClientProxy::~IpcClientProxy() { m_events->removeHandler( m_events->forIStream().inputReady(), m_stream.getEventTarget()); m_events->removeHandler( m_events->forIStream().outputError(), m_stream.getEventTarget()); m_events->removeHandler( m_events->forIStream().inputShutdown(), m_stream.getEventTarget()); m_events->removeHandler( m_events->forIStream().outputShutdown(), m_stream.getEventTarget()); // don't delete the stream while it's being used. ARCH->lockMutex(m_readMutex); ARCH->lockMutex(m_writeMutex); delete &m_stream; ARCH->unlockMutex(m_readMutex); ARCH->unlockMutex(m_writeMutex); ARCH->closeMutex(m_readMutex); ARCH->closeMutex(m_writeMutex); } void IpcClientProxy::handleDisconnect(const Event&, void*) { disconnect(); LOG((CLOG_DEBUG "ipc client disconnected")); } void IpcClientProxy::handleWriteError(const Event&, void*) { disconnect(); LOG((CLOG_DEBUG "ipc client write error")); } void IpcClientProxy::handleData(const Event&, void*) { // don't allow the dtor to destroy the stream while we're using it. ArchMutexLock lock(m_readMutex); LOG((CLOG_DEBUG "start ipc handle data")); UInt8 code[4]; UInt32 n = m_stream.read(code, 4); while (n != 0) { LOG((CLOG_DEBUG "ipc read: %c%c%c%c", code[0], code[1], code[2], code[3])); IpcMessage* m = nullptr; if (memcmp(code, kIpcMsgHello, 4) == 0) { m = parseHello(); } else if (memcmp(code, kIpcMsgCommand, 4) == 0) { m = parseCommand(); } else { LOG((CLOG_ERR "invalid ipc message")); disconnect(); } // don't delete with this event; the data is passed to a new event. Event e(m_events->forIpcClientProxy().messageReceived(), this, NULL, Event::kDontFreeData); e.setDataObject(m); m_events->addEvent(e); n = m_stream.read(code, 4); } LOG((CLOG_DEBUG "finished ipc handle data")); } void IpcClientProxy::send(const IpcMessage& message) { // don't allow other threads to write until we've finished the entire // message. stream write is locked, but only for that single write. // also, don't allow the dtor to destroy the stream while we're using it. ArchMutexLock lock(m_writeMutex); LOG((CLOG_DEBUG4 "ipc write: %d", message.type())); switch (message.type()) { case kIpcLogLine: { const IpcLogLineMessage& llm = static_cast(message); const String logLine = llm.logLine(); ProtocolUtil::writef(&m_stream, kIpcMsgLogLine, &logLine); break; } case kIpcShutdown: ProtocolUtil::writef(&m_stream, kIpcMsgShutdown); break; default: LOG((CLOG_ERR "ipc message not supported: %d", message.type())); break; } } IpcHelloMessage* IpcClientProxy::parseHello() { UInt8 type; ProtocolUtil::readf(&m_stream, kIpcMsgHello + 4, &type); m_clientType = static_cast(type); // must be deleted by event handler. return new IpcHelloMessage(m_clientType); } IpcCommandMessage* IpcClientProxy::parseCommand() { String command; UInt8 elevate; ProtocolUtil::readf(&m_stream, kIpcMsgCommand + 4, &command, &elevate); // must be deleted by event handler. return new IpcCommandMessage(command, elevate != 0); } void IpcClientProxy::disconnect() { LOG((CLOG_DEBUG "ipc disconnect, closing stream")); m_disconnecting = true; m_stream.close(); m_events->addEvent(Event(m_events->forIpcClientProxy().disconnected(), this)); } synergy-1.8.8-stable/src/lib/ipc/IpcClientProxy.h000066400000000000000000000030561305627404700217110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "ipc/Ipc.h" #include "arch/IArchMultithread.h" #include "base/EventTypes.h" #include "base/Event.h" namespace synergy { class IStream; } class IpcMessage; class IpcCommandMessage; class IpcHelloMessage; class IEventQueue; class IpcClientProxy { friend class IpcServer; public: IpcClientProxy(synergy::IStream& stream, IEventQueue* events); virtual ~IpcClientProxy(); private: void send(const IpcMessage& message); void handleData(const Event&, void*); void handleDisconnect(const Event&, void*); void handleWriteError(const Event&, void*); IpcHelloMessage* parseHello(); IpcCommandMessage* parseCommand(); void disconnect(); private: synergy::IStream& m_stream; EIpcClientType m_clientType; bool m_disconnecting; ArchMutex m_readMutex; ArchMutex m_writeMutex; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/ipc/IpcLogOutputter.cpp000066400000000000000000000114671305627404700224460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ipc/IpcLogOutputter.h" #include "ipc/IpcServer.h" #include "ipc/IpcMessage.h" #include "ipc/Ipc.h" #include "ipc/IpcClientProxy.h" #include "mt/Thread.h" #include "arch/Arch.h" #include "arch/XArch.h" #include "base/Event.h" #include "base/EventQueue.h" #include "base/TMethodEventJob.h" #include "base/TMethodJob.h" enum EIpcLogOutputter { kBufferMaxSize = 1000, kMaxSendLines = 100, kBufferRateWriteLimit = 1000, // writes per kBufferRateTime kBufferRateTimeLimit = 1 // seconds }; IpcLogOutputter::IpcLogOutputter(IpcServer& ipcServer, EIpcClientType clientType, bool useThread) : m_ipcServer(ipcServer), m_bufferMutex(ARCH->newMutex()), m_sending(false), m_bufferThread(nullptr), m_running(false), m_notifyCond(ARCH->newCondVar()), m_notifyMutex(ARCH->newMutex()), m_bufferWaiting(false), m_bufferMaxSize(kBufferMaxSize), m_bufferRateWriteLimit(kBufferRateWriteLimit), m_bufferRateTimeLimit(kBufferRateTimeLimit), m_bufferWriteCount(0), m_bufferRateStart(ARCH->time()), m_clientType(clientType), m_runningMutex(ARCH->newMutex()) { if (useThread) { m_bufferThread = new Thread(new TMethodJob( this, &IpcLogOutputter::bufferThread)); } } IpcLogOutputter::~IpcLogOutputter() { close(); ARCH->closeMutex(m_bufferMutex); if (m_bufferThread != nullptr) { m_bufferThread->cancel(); m_bufferThread->wait(); delete m_bufferThread; } ARCH->closeCondVar(m_notifyCond); ARCH->closeMutex(m_notifyMutex); } void IpcLogOutputter::open(const char* title) { } void IpcLogOutputter::close() { if (m_bufferThread != nullptr) { ArchMutexLock lock(m_runningMutex); m_running = false; notifyBuffer(); m_bufferThread->wait(5); } } void IpcLogOutputter::show(bool showIfEmpty) { } bool IpcLogOutputter::write(ELevel, const char* text) { // ignore events from the buffer thread (would cause recursion). if (m_bufferThread != nullptr && Thread::getCurrentThread().getID() == m_bufferThreadId) { return true; } appendBuffer(text); notifyBuffer(); return true; } void IpcLogOutputter::appendBuffer(const String& text) { ArchMutexLock lock(m_bufferMutex); double elapsed = ARCH->time() - m_bufferRateStart; if (elapsed < m_bufferRateTimeLimit) { if (m_bufferWriteCount >= m_bufferRateWriteLimit) { // discard the log line if we've logged too much. return; } } else { m_bufferWriteCount = 0; m_bufferRateStart = ARCH->time(); } if (m_buffer.size() >= m_bufferMaxSize) { // if the queue is exceeds size limit, // throw away the oldest item m_buffer.pop_front(); } m_buffer.push_back(text); m_bufferWriteCount++; } bool IpcLogOutputter::isRunning() { ArchMutexLock lock(m_runningMutex); return m_running; } void IpcLogOutputter::bufferThread(void*) { m_bufferThreadId = m_bufferThread->getID(); m_running = true; try { while (isRunning()) { if (m_buffer.empty() || !m_ipcServer.hasClients(m_clientType)) { ArchMutexLock lock(m_notifyMutex); ARCH->waitCondVar(m_notifyCond, m_notifyMutex, -1); } sendBuffer(); } } catch (XArch& e) { LOG((CLOG_ERR "ipc log buffer thread error, %s", e.what())); } LOG((CLOG_DEBUG "ipc log buffer thread finished")); } void IpcLogOutputter::notifyBuffer() { ArchMutexLock lock(m_notifyMutex); ARCH->broadcastCondVar(m_notifyCond); } String IpcLogOutputter::getChunk(size_t count) { ArchMutexLock lock(m_bufferMutex); if (m_buffer.size() < count) { count = m_buffer.size(); } String chunk; for (size_t i = 0; i < count; i++) { chunk.append(m_buffer.front()); chunk.append("\n"); m_buffer.pop_front(); } return chunk; } void IpcLogOutputter::sendBuffer() { if (m_buffer.empty() || !m_ipcServer.hasClients(m_clientType)) { return; } IpcLogLineMessage message(getChunk(kMaxSendLines)); m_sending = true; m_ipcServer.send(message, kIpcClientGui); m_sending = false; } void IpcLogOutputter::bufferMaxSize(UInt16 bufferMaxSize) { m_bufferMaxSize = bufferMaxSize; } UInt16 IpcLogOutputter::bufferMaxSize() const { return m_bufferMaxSize; } void IpcLogOutputter::bufferRateLimit(UInt16 writeLimit, double timeLimit) { m_bufferRateWriteLimit = writeLimit; m_bufferRateTimeLimit = timeLimit; } synergy-1.8.8-stable/src/lib/ipc/IpcLogOutputter.h000066400000000000000000000057001305627404700221040ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/Arch.h" #include "arch/IArchMultithread.h" #include "base/ILogOutputter.h" #include "ipc/Ipc.h" #include class IpcServer; class Event; class IpcClientProxy; //! Write log to GUI over IPC /*! This outputter writes output to the GUI via IPC. */ class IpcLogOutputter : public ILogOutputter { public: /*! If \p useThread is \c true, the buffer will be sent using a thread. If \p useThread is \c false, then the buffer needs to be sent manually using the \c sendBuffer() function. */ IpcLogOutputter(IpcServer& ipcServer, EIpcClientType clientType, bool useThread); virtual ~IpcLogOutputter(); // ILogOutputter overrides virtual void open(const char* title); virtual void close(); virtual void show(bool showIfEmpty); virtual bool write(ELevel level, const char* message); //! @name manipulators //@{ //! Notify that the buffer should be sent. void notifyBuffer(); //! Set the buffer size /*! Set the maximum size of the buffer to protect memory from runaway logging. */ void bufferMaxSize(UInt16 bufferMaxSize); //! Set the rate limit /*! Set the maximum number of \p writeRate for every \p timeRate in seconds. */ void bufferRateLimit(UInt16 writeLimit, double timeLimit); //! Send the buffer /*! Sends a chunk of the buffer to the IPC server, normally called when threaded mode is on. */ void sendBuffer(); //@} //! @name accessors //@{ //! Get the buffer size /*! Returns the maximum size of the buffer. */ UInt16 bufferMaxSize() const; //@} private: void init(); void bufferThread(void*); String getChunk(size_t count); void appendBuffer(const String& text); bool isRunning(); private: typedef std::deque Buffer; IpcServer& m_ipcServer; Buffer m_buffer; ArchMutex m_bufferMutex; bool m_sending; Thread* m_bufferThread; bool m_running; ArchCond m_notifyCond; ArchMutex m_notifyMutex; bool m_bufferWaiting; IArchMultithread::ThreadID m_bufferThreadId; UInt16 m_bufferMaxSize; UInt16 m_bufferRateWriteLimit; double m_bufferRateTimeLimit; UInt16 m_bufferWriteCount; double m_bufferRateStart; bool m_useThread; EIpcClientType m_clientType; ArchMutex m_runningMutex; }; synergy-1.8.8-stable/src/lib/ipc/IpcMessage.cpp000066400000000000000000000027171305627404700213530ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ipc/IpcMessage.h" #include "ipc/Ipc.h" IpcMessage::IpcMessage(UInt8 type) : m_type(type) { } IpcMessage::~IpcMessage() { } IpcHelloMessage::IpcHelloMessage(EIpcClientType clientType) : IpcMessage(kIpcHello), m_clientType(clientType) { } IpcHelloMessage::~IpcHelloMessage() { } IpcShutdownMessage::IpcShutdownMessage() : IpcMessage(kIpcShutdown) { } IpcShutdownMessage::~IpcShutdownMessage() { } IpcLogLineMessage::IpcLogLineMessage(const String& logLine) : IpcMessage(kIpcLogLine), m_logLine(logLine) { } IpcLogLineMessage::~IpcLogLineMessage() { } IpcCommandMessage::IpcCommandMessage(const String& command, bool elevate) : IpcMessage(kIpcCommand), m_command(command), m_elevate(elevate) { } IpcCommandMessage::~IpcCommandMessage() { } synergy-1.8.8-stable/src/lib/ipc/IpcMessage.h000066400000000000000000000040161305627404700210120ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "ipc/Ipc.h" #include "base/EventTypes.h" #include "base/String.h" #include "base/Event.h" class IpcMessage : public EventData { public: virtual ~IpcMessage(); //! Gets the message type ID. UInt8 type() const { return m_type; } protected: IpcMessage(UInt8 type); private: UInt8 m_type; }; class IpcHelloMessage : public IpcMessage { public: IpcHelloMessage(EIpcClientType clientType); virtual ~IpcHelloMessage(); //! Gets the message type ID. EIpcClientType clientType() const { return m_clientType; } private: EIpcClientType m_clientType; }; class IpcShutdownMessage : public IpcMessage { public: IpcShutdownMessage(); virtual ~IpcShutdownMessage(); }; class IpcLogLineMessage : public IpcMessage { public: IpcLogLineMessage(const String& logLine); virtual ~IpcLogLineMessage(); //! Gets the log line. String logLine() const { return m_logLine; } private: String m_logLine; }; class IpcCommandMessage : public IpcMessage { public: IpcCommandMessage(const String& command, bool elevate); virtual ~IpcCommandMessage(); //! Gets the command. String command() const { return m_command; } //! Gets whether or not the process should be elevated on MS Windows. bool elevate() const { return m_elevate; } private: String m_command; bool m_elevate; }; synergy-1.8.8-stable/src/lib/ipc/IpcServer.cpp000066400000000000000000000110261305627404700212260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ipc/IpcServer.h" #include "ipc/Ipc.h" #include "ipc/IpcClientProxy.h" #include "ipc/IpcMessage.h" #include "net/IDataSocket.h" #include "io/IStream.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include "base/Event.h" #include "base/Log.h" // // IpcServer // IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : m_mock(false), m_events(events), m_socketMultiplexer(socketMultiplexer), m_socket(nullptr), m_address(NetworkAddress(IPC_HOST, IPC_PORT)) { init(); } IpcServer::IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port) : m_mock(false), m_events(events), m_socketMultiplexer(socketMultiplexer), m_address(NetworkAddress(IPC_HOST, port)) { init(); } void IpcServer::init() { m_socket = new TCPListenSocket(m_events, m_socketMultiplexer); m_clientsMutex = ARCH->newMutex(); m_address.resolve(); m_events->adoptHandler( m_events->forIListenSocket().connecting(), m_socket, new TMethodEventJob( this, &IpcServer::handleClientConnecting)); } IpcServer::~IpcServer() { if (m_mock) { return; } if (m_socket != nullptr) { delete m_socket; } ARCH->lockMutex(m_clientsMutex); ClientList::iterator it; for (it = m_clients.begin(); it != m_clients.end(); it++) { deleteClient(*it); } m_clients.empty(); ARCH->unlockMutex(m_clientsMutex); ARCH->closeMutex(m_clientsMutex); m_events->removeHandler(m_events->forIListenSocket().connecting(), m_socket); } void IpcServer::listen() { m_socket->bind(m_address); } void IpcServer::handleClientConnecting(const Event&, void*) { synergy::IStream* stream = m_socket->accept(); if (stream == NULL) { return; } LOG((CLOG_DEBUG "accepted ipc client connection")); ARCH->lockMutex(m_clientsMutex); IpcClientProxy* proxy = new IpcClientProxy(*stream, m_events); m_clients.push_back(proxy); ARCH->unlockMutex(m_clientsMutex); m_events->adoptHandler( m_events->forIpcClientProxy().disconnected(), proxy, new TMethodEventJob( this, &IpcServer::handleClientDisconnected)); m_events->adoptHandler( m_events->forIpcClientProxy().messageReceived(), proxy, new TMethodEventJob( this, &IpcServer::handleMessageReceived)); m_events->addEvent(Event( m_events->forIpcServer().clientConnected(), this, proxy, Event::kDontFreeData)); } void IpcServer::handleClientDisconnected(const Event& e, void*) { IpcClientProxy* proxy = static_cast(e.getTarget()); ArchMutexLock lock(m_clientsMutex); m_clients.remove(proxy); deleteClient(proxy); LOG((CLOG_DEBUG "ipc client proxy removed, connected=%d", m_clients.size())); } void IpcServer::handleMessageReceived(const Event& e, void*) { Event event(m_events->forIpcServer().messageReceived(), this); event.setDataObject(e.getDataObject()); m_events->addEvent(event); } void IpcServer::deleteClient(IpcClientProxy* proxy) { m_events->removeHandler(m_events->forIpcClientProxy().messageReceived(), proxy); m_events->removeHandler(m_events->forIpcClientProxy().disconnected(), proxy); delete proxy; } bool IpcServer::hasClients(EIpcClientType clientType) const { ArchMutexLock lock(m_clientsMutex); if (m_clients.empty()) { return false; } ClientList::const_iterator it; for (it = m_clients.begin(); it != m_clients.end(); it++) { // at least one client is alive and type matches, there are clients. IpcClientProxy* p = *it; if (!p->m_disconnecting && p->m_clientType == clientType) { return true; } } // all clients must be disconnecting, no active clients. return false; } void IpcServer::send(const IpcMessage& message, EIpcClientType filterType) { ArchMutexLock lock(m_clientsMutex); ClientList::iterator it; for (it = m_clients.begin(); it != m_clients.end(); it++) { IpcClientProxy* proxy = *it; if (proxy->m_clientType == filterType) { proxy->send(message); } } } synergy-1.8.8-stable/src/lib/ipc/IpcServer.h000066400000000000000000000050621305627404700206760ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "ipc/Ipc.h" #include "net/TCPListenSocket.h" #include "net/NetworkAddress.h" #include "arch/Arch.h" #include "base/EventTypes.h" #include class Event; class IpcClientProxy; class IpcMessage; class IEventQueue; class SocketMultiplexer; //! IPC server for communication between daemon and GUI. /*! The IPC server listens on localhost. The IPC client runs on both the client/server process or the GUI. The IPC server runs on the daemon process. This allows the GUI to send config changes to the daemon and client/server, and allows the daemon and client/server to send log data to the GUI. */ class IpcServer { public: IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer); IpcServer(IEventQueue* events, SocketMultiplexer* socketMultiplexer, int port); virtual ~IpcServer(); //! @name manipulators //@{ //! Opens a TCP socket only allowing local connections. virtual void listen(); //! Send a message to all clients matching the filter type. virtual void send(const IpcMessage& message, EIpcClientType filterType); //@} //! @name accessors //@{ //! Returns true when there are clients of the specified type connected. virtual bool hasClients(EIpcClientType clientType) const; //@} private: void init(); void handleClientConnecting(const Event&, void*); void handleClientDisconnected(const Event&, void*); void handleMessageReceived(const Event&, void*); void deleteClient(IpcClientProxy* proxy); private: typedef std::list ClientList; bool m_mock; IEventQueue* m_events; SocketMultiplexer* m_socketMultiplexer; TCPListenSocket* m_socket; NetworkAddress m_address; ClientList m_clients; ArchMutex m_clientsMutex; #ifdef TEST_ENV public: IpcServer() : m_mock(true), m_events(nullptr), m_socketMultiplexer(nullptr), m_socket(nullptr) { } #endif }; synergy-1.8.8-stable/src/lib/ipc/IpcServerProxy.cpp000066400000000000000000000060651305627404700222770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ipc/IpcServerProxy.h" #include "ipc/IpcMessage.h" #include "ipc/Ipc.h" #include "synergy/ProtocolUtil.h" #include "io/IStream.h" #include "base/TMethodEventJob.h" #include "base/Log.h" // // IpcServerProxy // IpcServerProxy::IpcServerProxy(synergy::IStream& stream, IEventQueue* events) : m_stream(stream), m_events(events) { m_events->adoptHandler(m_events->forIStream().inputReady(), stream.getEventTarget(), new TMethodEventJob( this, &IpcServerProxy::handleData)); } IpcServerProxy::~IpcServerProxy() { m_events->removeHandler(m_events->forIStream().inputReady(), m_stream.getEventTarget()); } void IpcServerProxy::handleData(const Event&, void*) { LOG((CLOG_DEBUG "start ipc handle data")); UInt8 code[4]; UInt32 n = m_stream.read(code, 4); while (n != 0) { LOG((CLOG_DEBUG "ipc read: %c%c%c%c", code[0], code[1], code[2], code[3])); IpcMessage* m = nullptr; if (memcmp(code, kIpcMsgLogLine, 4) == 0) { m = parseLogLine(); } else if (memcmp(code, kIpcMsgShutdown, 4) == 0) { m = new IpcShutdownMessage(); } else { LOG((CLOG_ERR "invalid ipc message")); disconnect(); } // don't delete with this event; the data is passed to a new event. Event e(m_events->forIpcServerProxy().messageReceived(), this, NULL, Event::kDontFreeData); e.setDataObject(m); m_events->addEvent(e); n = m_stream.read(code, 4); } LOG((CLOG_DEBUG "finished ipc handle data")); } void IpcServerProxy::send(const IpcMessage& message) { LOG((CLOG_DEBUG4 "ipc write: %d", message.type())); switch (message.type()) { case kIpcHello: { const IpcHelloMessage& hm = static_cast(message); ProtocolUtil::writef(&m_stream, kIpcMsgHello, hm.clientType()); break; } case kIpcCommand: { const IpcCommandMessage& cm = static_cast(message); const String command = cm.command(); ProtocolUtil::writef(&m_stream, kIpcMsgCommand, &command); break; } default: LOG((CLOG_ERR "ipc message not supported: %d", message.type())); break; } } IpcLogLineMessage* IpcServerProxy::parseLogLine() { String logLine; ProtocolUtil::readf(&m_stream, kIpcMsgLogLine + 4, &logLine); // must be deleted by event handler. return new IpcLogLineMessage(logLine); } void IpcServerProxy::disconnect() { LOG((CLOG_DEBUG "ipc disconnect, closing stream")); m_stream.close(); } synergy-1.8.8-stable/src/lib/ipc/IpcServerProxy.h000066400000000000000000000023611305627404700217370ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/Event.h" #include "base/EventTypes.h" namespace synergy { class IStream; } class IpcMessage; class IpcLogLineMessage; class IEventQueue; class IpcServerProxy { friend class IpcClient; public: IpcServerProxy(synergy::IStream& stream, IEventQueue* events); virtual ~IpcServerProxy(); private: void send(const IpcMessage& message); void handleData(const Event&, void*); IpcLogLineMessage* parseLogLine(); void disconnect(); private: synergy::IStream& m_stream; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/mt/000077500000000000000000000000001305627404700164655ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/mt/CMakeLists.txt000066400000000000000000000016571305627404700212360ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ) if (UNIX) include_directories( ../../.. ) endif() add_library(mt STATIC ${sources}) synergy-1.8.8-stable/src/lib/mt/CondVar.cpp000066400000000000000000000037041305627404700205310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mt/CondVar.h" #include "arch/Arch.h" #include "base/Stopwatch.h" // // CondVarBase // CondVarBase::CondVarBase(Mutex* mutex) : m_mutex(mutex) { assert(m_mutex != NULL); m_cond = ARCH->newCondVar(); } CondVarBase::~CondVarBase() { ARCH->closeCondVar(m_cond); } void CondVarBase::lock() const { m_mutex->lock(); } void CondVarBase::unlock() const { m_mutex->unlock(); } void CondVarBase::signal() { ARCH->signalCondVar(m_cond); } void CondVarBase::broadcast() { ARCH->broadcastCondVar(m_cond); } bool CondVarBase::wait(Stopwatch& timer, double timeout) const { double remain = timeout-timer.getTime(); // Some ARCH wait()s return prematurely, retry until really timed out // In particular, ArchMultithreadPosix::waitCondVar() returns every 100ms do { // Always call wait at least once, even if remain is 0, to give // other thread a chance to grab the mutex to avoid deadlocks on // busy waiting. if (remain<0.0) remain=0.0; if (wait(remain)) return true; remain = timeout - timer.getTime(); } while (remain >= 0.0); return false; } bool CondVarBase::wait(double timeout) const { return ARCH->waitCondVar(m_cond, m_mutex->m_mutex, timeout); } Mutex* CondVarBase::getMutex() const { return m_mutex; } synergy-1.8.8-stable/src/lib/mt/CondVar.h000066400000000000000000000114551305627404700202000ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "mt/Mutex.h" #include "common/basic_types.h" class Stopwatch; //! Generic condition variable /*! This class provides functionality common to all condition variables but doesn't provide the actual variable storage. A condition variable is a multiprocessing primitive that can be waited on. Every condition variable has an associated mutex. */ class CondVarBase { public: /*! \c mutex must not be NULL. All condition variables have an associated mutex. The mutex needn't be unique to one condition variable. */ CondVarBase(Mutex* mutex); ~CondVarBase(); //! @name manipulators //@{ //! Lock the condition variable's mutex /*! Lock the condition variable's mutex. The condition variable should be locked before reading or writing it. It must be locked for a call to wait(). Locks are not recursive; locking a locked mutex will deadlock the thread. */ void lock() const; //! Unlock the condition variable's mutex void unlock() const; //! Signal the condition variable /*! Wake up one waiting thread, if there are any. Which thread gets woken is undefined. */ void signal(); //! Signal the condition variable /*! Wake up all waiting threads, if any. */ void broadcast(); //@} //! @name accessors //@{ //! Wait on the condition variable /*! Wait on the condition variable. If \c timeout < 0 then wait until signalled, otherwise up to \c timeout seconds or until signalled, whichever comes first. Returns true if the object was signalled during the wait, false otherwise. The proper way to wait for a condition is: \code cv.lock(); while (cv-expr) { cv.wait(); } cv.unlock(); \endcode where \c cv-expr involves the value of \c cv and is false when the condition is satisfied. (cancellation point) */ bool wait(double timeout = -1.0) const; //! Wait on the condition variable /*! Same as \c wait(double) but use \c timer to compare against \c timeout. Since clients normally wait on condition variables in a loop, clients can use this to avoid recalculating \c timeout on each iteration. Passing a stopwatch with a negative \c timeout is pointless (it will never time out) but permitted. (cancellation point) */ bool wait(Stopwatch& timer, double timeout) const; //! Get the mutex /*! Get the mutex passed to the c'tor. */ Mutex* getMutex() const; //@} private: // not implemented CondVarBase(const CondVarBase&); CondVarBase& operator=(const CondVarBase&); private: Mutex* m_mutex; ArchCond m_cond; }; //! Condition variable /*! A condition variable with storage for type \c T. */ template class CondVar : public CondVarBase { public: //! Initialize using \c value CondVar(Mutex* mutex, const T& value); //! Initialize using another condition variable's value CondVar(const CondVar&); ~CondVar(); //! @name manipulators //@{ //! Assigns the value of \c cv to this /*! Set the variable's value. The condition variable should be locked before calling this method. */ CondVar& operator=(const CondVar& cv); //! Assigns \c value to this /*! Set the variable's value. The condition variable should be locked before calling this method. */ CondVar& operator=(const T& v); //@} //! @name accessors //@{ //! Get the variable's value /*! Get the variable's value. The condition variable should be locked before calling this method. */ operator const volatile T&() const; //@} private: volatile T m_data; }; template inline CondVar::CondVar( Mutex* mutex, const T& data) : CondVarBase(mutex), m_data(data) { // do nothing } template inline CondVar::CondVar( const CondVar& cv) : CondVarBase(cv.getMutex()), m_data(cv.m_data) { // do nothing } template inline CondVar::~CondVar() { // do nothing } template inline CondVar& CondVar::operator=(const CondVar& cv) { m_data = cv.m_data; return *this; } template inline CondVar& CondVar::operator=(const T& data) { m_data = data; return *this; } template inline CondVar::operator const volatile T&() const { return m_data; } synergy-1.8.8-stable/src/lib/mt/Lock.cpp000066400000000000000000000017611305627404700200660ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mt/Lock.h" #include "mt/CondVar.h" #include "mt/Mutex.h" // // Lock // Lock::Lock(const Mutex* mutex) : m_mutex(mutex) { m_mutex->lock(); } Lock::Lock(const CondVarBase* cv) : m_mutex(cv->getMutex()) { m_mutex->lock(); } Lock::~Lock() { m_mutex->unlock(); } synergy-1.8.8-stable/src/lib/mt/Lock.h000066400000000000000000000026241305627404700175320ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" class Mutex; class CondVarBase; //! Mutual exclusion lock utility /*! This class locks a mutex or condition variable in the c'tor and unlocks it in the d'tor. It's easier and safer than manually locking and unlocking since unlocking must usually be done no matter how a function exits (including by unwinding due to an exception). */ class Lock { public: //! Lock the mutex \c mutex Lock(const Mutex* mutex); //! Lock the condition variable \c cv Lock(const CondVarBase* cv); //! Unlock the mutex or condition variable ~Lock(); private: // not implemented Lock(const Lock&); Lock& operator=(const Lock&); private: const Mutex* m_mutex; }; synergy-1.8.8-stable/src/lib/mt/Mutex.cpp000066400000000000000000000021511305627404700202720ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mt/Mutex.h" #include "arch/Arch.h" // // Mutex // Mutex::Mutex() { m_mutex = ARCH->newMutex(); } Mutex::Mutex(const Mutex&) { m_mutex = ARCH->newMutex(); } Mutex::~Mutex() { ARCH->closeMutex(m_mutex); } Mutex& Mutex::operator=(const Mutex&) { return *this; } void Mutex::lock() const { ARCH->lockMutex(m_mutex); } void Mutex::unlock() const { ARCH->unlockMutex(m_mutex); } synergy-1.8.8-stable/src/lib/mt/Mutex.h000066400000000000000000000040221305627404700177360ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchMultithread.h" //! Mutual exclusion /*! A non-recursive mutual exclusion object. Only one thread at a time can hold a lock on a mutex. Any thread that attempts to lock a locked mutex will block until the mutex is unlocked. At that time, if any threads are blocked, exactly one waiting thread will acquire the lock and continue running. A thread may not lock a mutex it already owns the lock on; if it tries it will deadlock itself. */ class Mutex { public: Mutex(); //! Equivalent to default c'tor /*! Copy c'tor doesn't copy anything. It just makes it possible to copy objects that contain a mutex. */ Mutex(const Mutex&); ~Mutex(); //! @name manipulators //@{ //! Does nothing /*! This does nothing. It just makes it possible to assign objects that contain a mutex. */ Mutex& operator=(const Mutex&); //@} //! @name accessors //@{ //! Lock the mutex /*! Locks the mutex, which must not have been previously locked by the calling thread. This blocks if the mutex is already locked by another thread. (cancellation point) */ void lock() const; //! Unlock the mutex /*! Unlocks the mutex, which must have been previously locked by the calling thread. */ void unlock() const; //@} private: friend class CondVarBase; ArchMutex m_mutex; }; synergy-1.8.8-stable/src/lib/mt/Thread.cpp000066400000000000000000000066141305627404700204070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "mt/Thread.h" #include "mt/XMT.h" #include "mt/XThread.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/IJob.h" // // Thread // Thread::Thread(IJob* job) { m_thread = ARCH->newThread(&Thread::threadFunc, job); if (m_thread == NULL) { // couldn't create thread delete job; throw XMTThreadUnavailable(); } } Thread::Thread(const Thread& thread) { m_thread = ARCH->copyThread(thread.m_thread); } Thread::Thread(ArchThread adoptedThread) { m_thread = adoptedThread; } Thread::~Thread() { ARCH->closeThread(m_thread); } Thread& Thread::operator=(const Thread& thread) { // copy given thread and release ours ArchThread copy = ARCH->copyThread(thread.m_thread); ARCH->closeThread(m_thread); // cut over m_thread = copy; return *this; } void Thread::exit(void* result) { throw XThreadExit(result); } void Thread::cancel() { ARCH->cancelThread(m_thread); } void Thread::setPriority(int n) { ARCH->setPriorityOfThread(m_thread, n); } void Thread::unblockPollSocket() { ARCH->unblockPollSocket(m_thread); } Thread Thread::getCurrentThread() { return Thread(ARCH->newCurrentThread()); } void Thread::testCancel() { ARCH->testCancelThread(); } bool Thread::wait(double timeout) const { return ARCH->wait(m_thread, timeout); } void* Thread::getResult() const { if (wait()) return ARCH->getResultOfThread(m_thread); else return NULL; } IArchMultithread::ThreadID Thread::getID() const { return ARCH->getIDOfThread(m_thread); } bool Thread::operator==(const Thread& thread) const { return ARCH->isSameThread(m_thread, thread.m_thread); } bool Thread::operator!=(const Thread& thread) const { return !ARCH->isSameThread(m_thread, thread.m_thread); } void* Thread::threadFunc(void* vjob) { // get this thread's id for logging IArchMultithread::ThreadID id; { ArchThread thread = ARCH->newCurrentThread(); id = ARCH->getIDOfThread(thread); ARCH->closeThread(thread); } // get job IJob* job = static_cast(vjob); // run job void* result = NULL; try { // go LOG((CLOG_DEBUG1 "thread 0x%08x entry", id)); job->run(); LOG((CLOG_DEBUG1 "thread 0x%08x exit", id)); } catch (XThreadCancel&) { // client called cancel() LOG((CLOG_DEBUG1 "caught cancel on thread 0x%08x", id)); delete job; throw; } catch (XThreadExit& e) { // client called exit() result = e.m_result; LOG((CLOG_DEBUG1 "caught exit on thread 0x%08x, result %p", id, result)); } catch (XBase& e) { LOG((CLOG_ERR "exception on thread 0x%08x: %s", id, e.what())); delete job; throw; } catch (...) { LOG((CLOG_ERR "exception on thread 0x%08x: ", id)); delete job; throw; } // done with job delete job; // return exit result return result; } synergy-1.8.8-stable/src/lib/mt/Thread.h000066400000000000000000000150231305627404700200460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchMultithread.h" class IJob; //! Thread handle /*! Creating a Thread creates a new context of execution (i.e. thread) that runs simulatenously with the calling thread. A Thread is only a handle to a thread; deleting a Thread does not cancel or destroy the thread it refers to and multiple Thread objects can refer to the same thread. Threads can terminate themselves but cannot be forced to terminate by other threads. However, other threads can signal a thread to terminate itself by cancelling it. And a thread can wait (block) on another thread to terminate. Most functions that can block for an arbitrary time are cancellation points. A cancellation point is a function that can be interrupted by a request to cancel the thread. Cancellation points are noted in the documentation. */ // note -- do not derive from this class class Thread { public: //! Run \c adoptedJob in a new thread /*! Create and start a new thread executing the \c adoptedJob. The new thread takes ownership of \c adoptedJob and will delete it. */ Thread(IJob* adoptedJob); //! Duplicate a thread handle /*! Make a new thread object that refers to an existing thread. This does \b not start a new thread. */ Thread(const Thread&); //! Release a thread handle /*! Release a thread handle. This does not terminate the thread. A thread will keep running until the job completes or calls exit() or allows itself to be cancelled. */ ~Thread(); //! @name manipulators //@{ //! Assign thread handle /*! Assign a thread handle. This has no effect on the threads, it simply makes this thread object refer to another thread. It does \b not start a new thread. */ Thread& operator=(const Thread&); //! Terminate the calling thread /*! Terminate the calling thread. This function does not return but the stack is unwound and automatic objects are destroyed, as if exit() threw an exception (which is, in fact, what it does). The argument is saved as the result returned by getResult(). If you have \c catch(...) blocks then you should add the following before each to avoid catching the exit: \code catch(ThreadExit&) { throw; } \endcode or add the \c RETHROW_XTHREAD macro to the \c catch(...) block. */ static void exit(void*); //! Cancel thread /*! Cancel the thread. cancel() never waits for the thread to terminate; it just posts the cancel and returns. A thread will terminate when it enters a cancellation point with cancellation enabled. If cancellation is disabled then the cancel is remembered but not acted on until the first call to a cancellation point after cancellation is enabled. A cancellation point is a function that can act on cancellation. A cancellation point does not return if there's a cancel pending. Instead, it unwinds the stack and destroys automatic objects, as if cancel() threw an exception (which is, in fact, what it does). Threads must take care to unlock and clean up any resources they may have, especially mutexes. They can \c catch(XThreadCancel) to do that then rethrow the exception or they can let it happen automatically by doing clean up in the d'tors of automatic objects (like Lock). Clients are strongly encouraged to do the latter. During cancellation, further cancel() calls are ignored (i.e. a thread cannot be interrupted by a cancel during cancellation). Clients that \c catch(XThreadCancel) must always rethrow the exception. Clients that \c catch(...) must either rethrow the exception or include a \c catch(XThreadCancel) handler that rethrows. The \c RETHROW_XTHREAD macro may be useful for that. */ void cancel(); //! Change thread priority /*! Change the priority of the thread. Normal priority is 0, 1 is the next lower, etc. -1 is the next higher, etc. but boosting the priority may not be permitted and will be silenty ignored. */ void setPriority(int n); //! Force pollSocket() to return /*! Forces a currently blocked pollSocket() in the thread to return immediately. */ void unblockPollSocket(); //@} //! @name accessors //@{ //! Get current thread's handle /*! Return a Thread object representing the calling thread. */ static Thread getCurrentThread(); //! Test for cancellation /*! testCancel() does nothing but is a cancellation point. Call this to make a function itself a cancellation point. If the thread was cancelled and cancellation is enabled this will cause the thread to unwind the stack and terminate. (cancellation point) */ static void testCancel(); //! Wait for thread to terminate /*! Waits for the thread to terminate (by exit() or cancel() or by returning from the thread job) for up to \c timeout seconds, returning true if the thread terminated and false otherwise. This returns immediately with false if called by a thread on itself and immediately with true if the thread has already terminated. This will wait forever if \c timeout < 0.0. (cancellation point) */ bool wait(double timeout = -1.0) const; //! Get the exit result /*! Returns the exit result. This does an implicit wait(). It returns NULL immediately if called by a thread on itself or on a thread that was cancelled. (cancellation point) */ void* getResult() const; //! Get the thread id /*! Returns an integer id for this thread. This id must not be used to check if two Thread objects refer to the same thread. Use operator==() for that. */ IArchMultithread::ThreadID getID() const; //! Compare thread handles /*! Returns true if two Thread objects refer to the same thread. */ bool operator==(const Thread&) const; //! Compare thread handles /*! Returns true if two Thread objects do not refer to the same thread. */ bool operator!=(const Thread&) const; //@} private: Thread(ArchThread); static void* threadFunc(void*); private: ArchThread m_thread; }; synergy-1.8.8-stable/src/lib/mt/XMT.cpp000066400000000000000000000016061305627404700176440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "XMT.h" // // XMTThreadUnavailable // String XMTThreadUnavailable::getWhat() const throw() { return format("XMTThreadUnavailable", "cannot create thread"); } synergy-1.8.8-stable/src/lib/mt/XMT.h000066400000000000000000000017021305627404700173060ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/XBase.h" //! Generic multithreading exception XBASE_SUBCLASS(XMT, XBase); //! Thread creation exception /*! Thrown when a thread cannot be created. */ XBASE_SUBCLASS_WHAT(XMTThreadUnavailable, XMT); synergy-1.8.8-stable/src/lib/mt/XThread.h000066400000000000000000000021751305627404700202020ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/XArch.h" //! Thread exception to exit /*! Thrown by Thread::exit() to exit a thread. Clients of Thread must not throw this type but must rethrow it if caught (by XThreadExit, XThread, or ...). */ class XThreadExit : public XThread { public: //! \c result is the result of the thread XThreadExit(void* result) : m_result(result) { } ~XThreadExit() { } public: void* m_result; }; synergy-1.8.8-stable/src/lib/net/000077500000000000000000000000001305627404700166335ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/net/CMakeLists.txt000066400000000000000000000026121305627404700213740ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ${OPENSSL_INCLUDE} ) if (UNIX) include_directories( ../../.. ) endif() add_library(net STATIC ${sources}) if (WIN32) add_custom_command( TARGET net POST_BUILD COMMAND xcopy /Y /Q ..\\..\\..\\..\\ext\\${OPENSSL_PLAT_DIR}\\out32dll\\libeay32.* ..\\..\\..\\..\\bin\\${CMAKE_CFG_INTDIR} ) add_custom_command( TARGET net POST_BUILD COMMAND xcopy /Y /Q ..\\..\\..\\..\\ext\\${OPENSSL_PLAT_DIR}\\out32dll\\ssleay32.* ..\\..\\..\\..\\bin\\${CMAKE_CFG_INTDIR} ) endif() if (UNIX) target_link_libraries(net mt io ${OPENSSL_LIBS}) endif() synergy-1.8.8-stable/src/lib/net/IDataSocket.cpp000066400000000000000000000021021305627404700214650ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "net/IDataSocket.h" #include "base/EventQueue.h" // // IDataSocket // void IDataSocket::close() { // this is here to work around a VC++6 bug. see the header file. assert(0 && "bad call"); } void* IDataSocket::getEventTarget() const { // this is here to work around a VC++6 bug. see the header file. assert(0 && "bad call"); return NULL; } synergy-1.8.8-stable/src/lib/net/IDataSocket.h000066400000000000000000000044261305627404700211450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "net/ISocket.h" #include "io/IStream.h" #include "base/String.h" #include "base/EventTypes.h" //! Data stream socket interface /*! This interface defines the methods common to all network sockets that represent a full-duplex data stream. */ class IDataSocket : public ISocket, public synergy::IStream { public: class ConnectionFailedInfo { public: ConnectionFailedInfo(const char* what) : m_what(what) { } String m_what; }; IDataSocket(IEventQueue* events) { } //! @name manipulators //@{ //! Connect socket /*! Attempt to connect to a remote endpoint. This returns immediately and sends a connected event when successful or a connection failed event when it fails. The stream acts as if shutdown for input and output until the stream connects. */ virtual void connect(const NetworkAddress&) = 0; //@} // ISocket overrides // close() and getEventTarget() aren't pure to work around a bug // in VC++6. it claims the methods are unused locals and warns // that it's removing them. it's presumably tickled by inheriting // methods with identical signatures from both superclasses. virtual void bind(const NetworkAddress&) = 0; virtual void close(); virtual void* getEventTarget() const; // IStream overrides virtual UInt32 read(void* buffer, UInt32 n) = 0; virtual void write(const void* buffer, UInt32 n) = 0; virtual void flush() = 0; virtual void shutdownInput() = 0; virtual void shutdownOutput() = 0; virtual bool isReady() const = 0; virtual bool isFatal() const = 0; virtual UInt32 getSize() const = 0; }; synergy-1.8.8-stable/src/lib/net/IListenSocket.h000066400000000000000000000026521305627404700215310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "net/ISocket.h" #include "base/EventTypes.h" class IDataSocket; //! Listen socket interface /*! This interface defines the methods common to all network sockets that listen for incoming connections. */ class IListenSocket : public ISocket { public: //! @name manipulators //@{ //! Accept connection /*! Accept a connection, returning a socket representing the full-duplex data stream. Returns NULL if no socket is waiting to be accepted. This is only valid after a call to \c bind(). */ virtual IDataSocket* accept() = 0; //@} // ISocket overrides virtual void bind(const NetworkAddress&) = 0; virtual void close() = 0; virtual void* getEventTarget() const = 0; }; synergy-1.8.8-stable/src/lib/net/ISocket.h000066400000000000000000000027341305627404700203530ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "base/Event.h" #include "base/EventTypes.h" class NetworkAddress; //! Generic socket interface /*! This interface defines the methods common to all network sockets. Generated events use \c this as the target. */ class ISocket : public IInterface { public: //! @name manipulators //@{ //! Bind socket to address /*! Binds the socket to a particular address. */ virtual void bind(const NetworkAddress&) = 0; //! Close socket /*! Closes the socket. This should flush the output stream. */ virtual void close() = 0; //@} //! @name accessors //@{ //! Get event target /*! Returns the event target for events generated by this socket. */ virtual void* getEventTarget() const = 0; //@} }; synergy-1.8.8-stable/src/lib/net/ISocketFactory.h000066400000000000000000000022361305627404700217000ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" class IDataSocket; class IListenSocket; //! Socket factory /*! This interface defines the methods common to all factories used to create sockets. */ class ISocketFactory : public IInterface { public: //! @name accessors //@{ //! Create data socket virtual IDataSocket* create(bool secure) const = 0; //! Create listen socket virtual IListenSocket* createListen(bool secure) const = 0; //@} }; synergy-1.8.8-stable/src/lib/net/ISocketMultiplexerJob.h000066400000000000000000000042651305627404700232420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchNetwork.h" #include "common/IInterface.h" //! Socket multiplexer job /*! A socket multiplexer job handles events on a socket. */ class ISocketMultiplexerJob : public IInterface { public: //! @name manipulators //@{ //! Handle socket event /*! Called by a socket multiplexer when the socket becomes readable, writable, or has an error. It should return itself if the same job can continue to service events, a new job if the socket must be serviced differently, or NULL if the socket should no longer be serviced. The socket is readable if \p readable is true, writable if \p writable is true, and in error if \p error is true. This call must not attempt to directly change the job for this socket by calling \c addSocket() or \c removeSocket() on the multiplexer. It must instead return the new job. It can, however, add or remove jobs for other sockets. */ virtual ISocketMultiplexerJob* run(bool readable, bool writable, bool error) = 0; //@} //! @name accessors //@{ //! Get the socket /*! Return the socket to multiplex */ virtual ArchSocket getSocket() const = 0; //! Check for interest in readability /*! Return true if the job is interested in being run if the socket becomes readable. */ virtual bool isReadable() const = 0; //! Check for interest in writability /*! Return true if the job is interested in being run if the socket becomes writable. */ virtual bool isWritable() const = 0; //@} }; synergy-1.8.8-stable/src/lib/net/NetworkAddress.cpp000066400000000000000000000116071305627404700223030ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "net/NetworkAddress.h" #include "net/XSocket.h" #include "arch/Arch.h" #include "arch/XArch.h" #include // // NetworkAddress // // name re-resolution adapted from a patch by Brent Priddy. NetworkAddress::NetworkAddress() : m_address(NULL), m_hostname(), m_port(0) { // note -- make no calls to Network socket interface here; // we're often called prior to Network::init(). } NetworkAddress::NetworkAddress(int port) : m_address(NULL), m_hostname(), m_port(port) { checkPort(); m_address = ARCH->newAnyAddr(IArchNetwork::kINET); ARCH->setAddrPort(m_address, m_port); } NetworkAddress::NetworkAddress(const NetworkAddress& addr) : m_address(addr.m_address != NULL ? ARCH->copyAddr(addr.m_address) : NULL), m_hostname(addr.m_hostname), m_port(addr.m_port) { // do nothing } NetworkAddress::NetworkAddress(const String& hostname, int port) : m_address(NULL), m_hostname(hostname), m_port(port) { // check for port suffix String::size_type i = m_hostname.rfind(':'); if (i != String::npos && i + 1 < m_hostname.size()) { // found a colon. see if it looks like an IPv6 address. bool colonNotation = false; bool dotNotation = false; bool doubleColon = false; for (String::size_type j = 0; j < i; ++j) { if (m_hostname[j] == ':') { colonNotation = true; dotNotation = false; if (m_hostname[j + 1] == ':') { doubleColon = true; } } else if (m_hostname[j] == '.' && colonNotation) { dotNotation = true; } } // port suffix is ambiguous with IPv6 notation if there's // a double colon and the end of the address is not in dot // notation. in that case we assume it's not a port suffix. // the user can replace the double colon with zeros to // disambiguate. if ((!doubleColon || dotNotation) || !colonNotation) { // parse port from hostname char* end; const char* chostname = m_hostname.c_str(); long suffixPort = strtol(chostname + i + 1, &end, 10); if (end == chostname + i + 1 || *end != '\0') { throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); } // trim port from hostname m_hostname.erase(i); // save port m_port = static_cast(suffixPort); } } // check port number checkPort(); } NetworkAddress::~NetworkAddress() { if (m_address != NULL) { ARCH->closeAddr(m_address); } } NetworkAddress& NetworkAddress::operator=(const NetworkAddress& addr) { ArchNetAddress newAddr = NULL; if (addr.m_address != NULL) { newAddr = ARCH->copyAddr(addr.m_address); } if (m_address != NULL) { ARCH->closeAddr(m_address); } m_address = newAddr; m_hostname = addr.m_hostname; m_port = addr.m_port; return *this; } void NetworkAddress::resolve() { // discard previous address if (m_address != NULL) { ARCH->closeAddr(m_address); m_address = NULL; } try { // if hostname is empty then use wildcard address otherwise look // up the name. if (m_hostname.empty()) { m_address = ARCH->newAnyAddr(IArchNetwork::kINET); } else { m_address = ARCH->nameToAddr(m_hostname); } } catch (XArchNetworkNameUnknown&) { throw XSocketAddress(XSocketAddress::kNotFound, m_hostname, m_port); } catch (XArchNetworkNameNoAddress&) { throw XSocketAddress(XSocketAddress::kNoAddress, m_hostname, m_port); } catch (XArchNetworkNameUnsupported&) { throw XSocketAddress(XSocketAddress::kUnsupported, m_hostname, m_port); } catch (XArchNetworkName&) { throw XSocketAddress(XSocketAddress::kUnknown, m_hostname, m_port); } // set port in address ARCH->setAddrPort(m_address, m_port); } bool NetworkAddress::operator==(const NetworkAddress& addr) const { return ARCH->isEqualAddr(m_address, addr.m_address); } bool NetworkAddress::operator!=(const NetworkAddress& addr) const { return !operator==(addr); } bool NetworkAddress::isValid() const { return (m_address != NULL); } const ArchNetAddress& NetworkAddress::getAddress() const { return m_address; } int NetworkAddress::getPort() const { return m_port; } String NetworkAddress::getHostname() const { return m_hostname; } void NetworkAddress::checkPort() { // check port number if (m_port <= 0 || m_port > 65535) { throw XSocketAddress(XSocketAddress::kBadPort, m_hostname, m_port); } } synergy-1.8.8-stable/src/lib/net/NetworkAddress.h000066400000000000000000000062021305627404700217430ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" #include "base/EventTypes.h" #include "arch/IArchNetwork.h" //! Network address type /*! This class represents a network address. */ class NetworkAddress { public: /*! Constructs the invalid address */ NetworkAddress(); /*! Construct the wildcard address with the given port. \c port must not be zero. */ NetworkAddress(int port); /*! Construct the network address for the given \c hostname and \c port. If \c hostname can be parsed as a numerical address then that's how it's used, otherwise it's used as a host name. If \c hostname ends in ":[0-9]+" then that suffix is extracted and used as the port, overridding the port parameter. The resulting port must be a valid port number (zero is not a valid port number) otherwise \c XSocketAddress is thrown with an error of \c XSocketAddress::kBadPort. The hostname is not resolved by the c'tor; use \c resolve to do that. */ NetworkAddress(const String& hostname, int port); NetworkAddress(const NetworkAddress&); ~NetworkAddress(); NetworkAddress& operator=(const NetworkAddress&); //! @name manipulators //@{ //! Resolve address /*! Resolves the hostname to an address. This can be done any number of times and is done automatically by the c'tor taking a hostname. Throws XSocketAddress if resolution is unsuccessful, after which \c isValid returns false until the next call to this method. */ void resolve(); //@} //! @name accessors //@{ //! Check address equality /*! Returns true if this address is equal to \p address. */ bool operator==(const NetworkAddress& address) const; //! Check address inequality /*! Returns true if this address is not equal to \p address. */ bool operator!=(const NetworkAddress& address) const; //! Check address validity /*! Returns true if this is not the invalid address. */ bool isValid() const; //! Get address /*! Returns the address in the platform's native network address structure. */ const ArchNetAddress& getAddress() const; //! Get port /*! Returns the port passed to the c'tor as a suffix to the hostname, if that existed, otherwise as passed directly to the c'tor. */ int getPort() const; //! Get hostname /*! Returns the hostname passed to the c'tor sans any port suffix. */ String getHostname() const; //@} private: void checkPort(); private: ArchNetAddress m_address; String m_hostname; int m_port; }; synergy-1.8.8-stable/src/lib/net/SecureListenSocket.cpp000066400000000000000000000043661305627404700231260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "SecureListenSocket.h" #include "SecureSocket.h" #include "net/NetworkAddress.h" #include "net/SocketMultiplexer.h" #include "net/TSocketMultiplexerMethodJob.h" #include "arch/XArch.h" static const char s_certificateDir[] = { "SSL" }; static const char s_certificateFilename[] = { "Synergy.pem" }; // // SecureListenSocket // SecureListenSocket::SecureListenSocket( IEventQueue* events, SocketMultiplexer* socketMultiplexer) : TCPListenSocket(events, socketMultiplexer) { } SecureListenSocket::~SecureListenSocket() { SecureSocketSet::iterator it; for (it = m_secureSocketSet.begin(); it != m_secureSocketSet.end(); it++) { delete *it; } m_secureSocketSet.clear(); } IDataSocket* SecureListenSocket::accept() { SecureSocket* socket = NULL; try { socket = new SecureSocket( m_events, m_socketMultiplexer, ARCH->acceptSocket(m_socket, NULL)); socket->initSsl(true); if (socket != NULL) { setListeningJob(); } String certificateFilename = synergy::string::sprintf("%s/%s/%s", ARCH->getProfileDirectory().c_str(), s_certificateDir, s_certificateFilename); bool loaded = socket->loadCertificates(certificateFilename); if (!loaded) { delete socket; return NULL; } socket->secureAccept(); m_secureSocketSet.insert(socket); return dynamic_cast(socket); } catch (XArchNetwork&) { if (socket != NULL) { delete socket; setListeningJob(); } return NULL; } catch (std::exception &ex) { if (socket != NULL) { delete socket; setListeningJob(); } throw ex; } } synergy-1.8.8-stable/src/lib/net/SecureListenSocket.h000066400000000000000000000022141305627404700225610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "net/TCPListenSocket.h" #include "common/stdset.h" class IEventQueue; class SocketMultiplexer; class IDataSocket; class SecureListenSocket : public TCPListenSocket{ public: SecureListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer); ~SecureListenSocket(); // IListenSocket overrides virtual IDataSocket* accept(); private: typedef std::set SecureSocketSet; SecureSocketSet m_secureSocketSet; }; synergy-1.8.8-stable/src/lib/net/SecureSocket.cpp000066400000000000000000000441011305627404700217360ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "SecureSocket.h" #include "net/TSocketMultiplexerMethodJob.h" #include "base/TMethodEventJob.h" #include "net/TCPSocket.h" #include "mt/Lock.h" #include "arch/XArch.h" #include "base/Log.h" #include #include #include #include #include #include // // SecureSocket // #define MAX_ERROR_SIZE 65535 static const float s_retryDelay = 0.01f; enum { kMsgSize = 128 }; static const char kFingerprintDirName[] = "SSL/Fingerprints"; //static const char kFingerprintLocalFilename[] = "Local.txt"; static const char kFingerprintTrustedServersFilename[] = "TrustedServers.txt"; //static const char kFingerprintTrustedClientsFilename[] = "TrustedClients.txt"; struct Ssl { SSL_CTX* m_context; SSL* m_ssl; }; SecureSocket::SecureSocket( IEventQueue* events, SocketMultiplexer* socketMultiplexer) : TCPSocket(events, socketMultiplexer), m_secureReady(false), m_fatal(false) { } SecureSocket::SecureSocket( IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket) : TCPSocket(events, socketMultiplexer, socket), m_secureReady(false), m_fatal(false) { } SecureSocket::~SecureSocket() { isFatal(true); if (m_ssl->m_ssl != NULL) { SSL_shutdown(m_ssl->m_ssl); SSL_free(m_ssl->m_ssl); m_ssl->m_ssl = NULL; } if (m_ssl->m_context != NULL) { SSL_CTX_free(m_ssl->m_context); m_ssl->m_context = NULL; } ARCH->sleep(1); delete m_ssl; } void SecureSocket::close() { isFatal(true); SSL_shutdown(m_ssl->m_ssl); TCPSocket::close(); } void SecureSocket::connect(const NetworkAddress& addr) { m_events->adoptHandler(m_events->forIDataSocket().connected(), getEventTarget(), new TMethodEventJob(this, &SecureSocket::handleTCPConnected)); TCPSocket::connect(addr); } ISocketMultiplexerJob* SecureSocket::newJob() { // after TCP connection is established, SecureSocket will pick up // connected event and do secureConnect if (m_connected && !m_secureReady) { return NULL; } return TCPSocket::newJob(); } void SecureSocket::secureConnect() { setJob(new TSocketMultiplexerMethodJob( this, &SecureSocket::serviceConnect, getSocket(), isReadable(), isWritable())); } void SecureSocket::secureAccept() { setJob(new TSocketMultiplexerMethodJob( this, &SecureSocket::serviceAccept, getSocket(), isReadable(), isWritable())); } TCPSocket::EJobResult SecureSocket::doRead() { static UInt8 buffer[4096]; memset(buffer, 0, sizeof(buffer)); int bytesRead = 0; int status = 0; if (isSecureReady()) { status = secureRead(buffer, sizeof(buffer), bytesRead); if (status < 0) { return kBreak; } else if (status == 0) { return kNew; } } else { return kRetry; } if (bytesRead > 0) { bool wasEmpty = (m_inputBuffer.getSize() == 0); // slurp up as much as possible do { m_inputBuffer.write(buffer, bytesRead); status = secureRead(buffer, sizeof(buffer), bytesRead); if (status < 0) { return kBreak; } } while (bytesRead > 0 || status > 0); // send input ready if input buffer was empty if (wasEmpty) { sendEvent(m_events->forIStream().inputReady()); } } else { // remote write end of stream hungup. our input side // has therefore shutdown but don't flush our buffer // since there's still data to be read. sendEvent(m_events->forIStream().inputShutdown()); if (!m_writable && m_inputBuffer.getSize() == 0) { sendEvent(m_events->forISocket().disconnected()); m_connected = false; } m_readable = false; return kNew; } return kRetry; } TCPSocket::EJobResult SecureSocket::doWrite() { static bool s_retry = false; static int s_retrySize = 0; static void* s_staticBuffer = NULL; // write data int bufferSize = 0; int bytesWrote = 0; int status = 0; if (s_retry) { bufferSize = s_retrySize; } else { bufferSize = m_outputBuffer.getSize(); s_staticBuffer = malloc(bufferSize); memcpy(s_staticBuffer, m_outputBuffer.peek(bufferSize), bufferSize); } if (bufferSize == 0) { return kRetry; } if (isSecureReady()) { status = secureWrite(s_staticBuffer, bufferSize, bytesWrote); if (status > 0) { s_retry = false; bufferSize = 0; free(s_staticBuffer); s_staticBuffer = NULL; } else if (status < 0) { return kBreak; } else if (status == 0) { s_retry = true; s_retrySize = bufferSize; return kNew; } } else { return kRetry; } if (bytesWrote > 0) { discardWrittenData(bytesWrote); return kNew; } return kRetry; } int SecureSocket::secureRead(void* buffer, int size, int& read) { if (m_ssl->m_ssl != NULL) { LOG((CLOG_DEBUG2 "reading secure socket")); read = SSL_read(m_ssl->m_ssl, buffer, size); static int retry; // Check result will cleanup the connection in the case of a fatal checkResult(read, retry); if (retry) { return 0; } if (isFatal()) { return -1; } } // According to SSL spec, the number of bytes read must not be negative and // not have an error code from SSL_get_error(). If this happens, it is // itself an error. Let the parent handle the case return read; } int SecureSocket::secureWrite(const void* buffer, int size, int& wrote) { if (m_ssl->m_ssl != NULL) { LOG((CLOG_DEBUG2 "writing secure socket:%p", this)); wrote = SSL_write(m_ssl->m_ssl, buffer, size); static int retry; // Check result will cleanup the connection in the case of a fatal checkResult(wrote, retry); if (retry) { return 0; } if (isFatal()) { return -1; } } // According to SSL spec, r must not be negative and not have an error code // from SSL_get_error(). If this happens, it is itself an error. Let the // parent handle the case return wrote; } bool SecureSocket::isSecureReady() { return m_secureReady; } void SecureSocket::initSsl(bool server) { m_ssl = new Ssl(); m_ssl->m_context = NULL; m_ssl->m_ssl = NULL; initContext(server); } bool SecureSocket::loadCertificates(String& filename) { if (filename.empty()) { showError("ssl certificate is not specified"); return false; } else { std::ifstream file(filename.c_str()); bool exist = file.good(); file.close(); if (!exist) { String errorMsg("ssl certificate doesn't exist: "); errorMsg.append(filename); showError(errorMsg.c_str()); return false; } } int r = 0; r = SSL_CTX_use_certificate_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM); if (r <= 0) { showError("could not use ssl certificate"); return false; } r = SSL_CTX_use_PrivateKey_file(m_ssl->m_context, filename.c_str(), SSL_FILETYPE_PEM); if (r <= 0) { showError("could not use ssl private key"); return false; } r = SSL_CTX_check_private_key(m_ssl->m_context); if (!r) { showError("could not verify ssl private key"); return false; } return true; } void SecureSocket::initContext(bool server) { SSL_library_init(); const SSL_METHOD* method; // load & register all cryptos, etc. OpenSSL_add_all_algorithms(); // load all error messages SSL_load_error_strings(); if (CLOG->getFilter() >= kINFO) { showSecureLibInfo(); } // SSLv23_method uses TLSv1, with the ability to fall back to SSLv3 if (server) { method = SSLv23_server_method(); } else { method = SSLv23_client_method(); } // create new context from method SSL_METHOD* m = const_cast(method); m_ssl->m_context = SSL_CTX_new(m); // drop SSLv3 support SSL_CTX_set_options(m_ssl->m_context, SSL_OP_NO_SSLv3); if (m_ssl->m_context == NULL) { showError(); } } void SecureSocket::createSSL() { // I assume just one instance is needed // get new SSL state with context if (m_ssl->m_ssl == NULL) { m_ssl->m_ssl = SSL_new(m_ssl->m_context); } } int SecureSocket::secureAccept(int socket) { createSSL(); // set connection socket to SSL state SSL_set_fd(m_ssl->m_ssl, socket); LOG((CLOG_DEBUG2 "accepting secure socket")); int r = SSL_accept(m_ssl->m_ssl); static int retry; checkResult(r, retry); if (isFatal()) { // tell user and sleep so the socket isn't hammered. LOG((CLOG_ERR "failed to accept secure socket")); LOG((CLOG_INFO "client connection may not be secure")); m_secureReady = false; ARCH->sleep(1); retry = 0; return -1; // Failed, error out } // If not fatal and no retry, state is good if (retry == 0) { m_secureReady = true; LOG((CLOG_INFO "accepted secure socket")); if (CLOG->getFilter() >= kDEBUG1) { showSecureCipherInfo(); } showSecureConnectInfo(); return 1; } // If not fatal and retry is set, not ready, and return retry if (retry > 0) { LOG((CLOG_DEBUG2 "retry accepting secure socket")); m_secureReady = false; ARCH->sleep(s_retryDelay); return 0; } // no good state exists here LOG((CLOG_ERR "unexpected state attempting to accept connection")); return -1; } int SecureSocket::secureConnect(int socket) { createSSL(); // attach the socket descriptor SSL_set_fd(m_ssl->m_ssl, socket); LOG((CLOG_DEBUG2 "connecting secure socket")); int r = SSL_connect(m_ssl->m_ssl); static int retry; checkResult(r, retry); if (isFatal()) { LOG((CLOG_ERR "failed to connect secure socket")); retry = 0; return -1; } // If we should retry, not ready and return 0 if (retry > 0) { LOG((CLOG_DEBUG2 "retry connect secure socket")); m_secureReady = false; ARCH->sleep(s_retryDelay); return 0; } retry = 0; // No error, set ready, process and return ok m_secureReady = true; if (verifyCertFingerprint()) { LOG((CLOG_INFO "connected to secure socket")); if (!showCertificate()) { disconnect(); return -1;// Cert fail, error } } else { LOG((CLOG_ERR "failed to verify server certificate fingerprint")); disconnect(); return -1; // Fingerprint failed, error } LOG((CLOG_DEBUG2 "connected secure socket")); if (CLOG->getFilter() >= kDEBUG1) { showSecureCipherInfo(); } showSecureConnectInfo(); return 1; } bool SecureSocket::showCertificate() { X509* cert; char* line; // get the server's certificate cert = SSL_get_peer_certificate(m_ssl->m_ssl); if (cert != NULL) { line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0); LOG((CLOG_INFO "server ssl certificate info: %s", line)); OPENSSL_free(line); X509_free(cert); } else { showError("server has no ssl certificate"); return false; } return true; } void SecureSocket::checkResult(int status, int& retry) { // ssl errors are a little quirky. the "want" errors are normal and // should result in a retry. int errorCode = SSL_get_error(m_ssl->m_ssl, status); switch (errorCode) { case SSL_ERROR_NONE: retry = 0; // operation completed break; case SSL_ERROR_ZERO_RETURN: // connection closed isFatal(true); LOG((CLOG_DEBUG "ssl connection closed")); break; case SSL_ERROR_WANT_READ: retry++; LOG((CLOG_DEBUG2 "want to read, error=%d, attempt=%d", errorCode, retry)); break; case SSL_ERROR_WANT_WRITE: // Need to make sure the socket is known to be writable so the impending // select action actually triggers on a write. This isn't necessary for // m_readable because the socket logic is always readable m_writable = true; retry++; LOG((CLOG_DEBUG2 "want to write, error=%d, attempt=%d", errorCode, retry)); break; case SSL_ERROR_WANT_CONNECT: retry++; LOG((CLOG_DEBUG2 "want to connect, error=%d, attempt=%d", errorCode, retry)); break; case SSL_ERROR_WANT_ACCEPT: retry++; LOG((CLOG_DEBUG2 "want to accept, error=%d, attempt=%d", errorCode, retry)); break; case SSL_ERROR_SYSCALL: LOG((CLOG_ERR "ssl error occurred (system call failure)")); if (ERR_peek_error() == 0) { if (status == 0) { LOG((CLOG_ERR "eof violates ssl protocol")); } else if (status == -1) { // underlying socket I/O reproted an error try { ARCH->throwErrorOnSocket(getSocket()); } catch (XArchNetwork& e) { LOG((CLOG_ERR "%s", e.what())); } } } isFatal(true); break; case SSL_ERROR_SSL: LOG((CLOG_ERR "ssl error occurred (generic failure)")); isFatal(true); break; default: LOG((CLOG_ERR "ssl error occurred (unknown failure)")); isFatal(true); break; } if (isFatal()) { retry = 0; showError(); disconnect(); } } void SecureSocket::showError(const char* reason) { if (reason != NULL) { LOG((CLOG_ERR "%s", reason)); } String error = getError(); if (!error.empty()) { LOG((CLOG_ERR "%s", error.c_str())); } } String SecureSocket::getError() { unsigned long e = ERR_get_error(); if (e != 0) { char error[MAX_ERROR_SIZE]; ERR_error_string_n(e, error, MAX_ERROR_SIZE); return error; } else { return ""; } } void SecureSocket::disconnect() { sendEvent(getEvents()->forISocket().stopRetry()); sendEvent(getEvents()->forISocket().disconnected()); sendEvent(getEvents()->forIStream().inputShutdown()); } void SecureSocket::formatFingerprint(String& fingerprint, bool hex, bool separator) { if (hex) { // to hexidecimal synergy::string::toHex(fingerprint, 2); } // all uppercase synergy::string::uppercase(fingerprint); if (separator) { // add colon to separate each 2 charactors size_t separators = fingerprint.size() / 2; for (size_t i = 1; i < separators; i++) { fingerprint.insert(i * 3 - 1, ":"); } } } bool SecureSocket::verifyCertFingerprint() { // calculate received certificate fingerprint X509 *cert = cert = SSL_get_peer_certificate(m_ssl->m_ssl); EVP_MD* tempDigest; unsigned char tempFingerprint[EVP_MAX_MD_SIZE]; unsigned int tempFingerprintLen; tempDigest = (EVP_MD*)EVP_sha1(); int digestResult = X509_digest(cert, tempDigest, tempFingerprint, &tempFingerprintLen); if (digestResult <= 0) { LOG((CLOG_ERR "failed to calculate fingerprint, digest result: %d", digestResult)); return false; } // format fingerprint into hexdecimal format with colon separator String fingerprint(reinterpret_cast(tempFingerprint), tempFingerprintLen); formatFingerprint(fingerprint); LOG((CLOG_NOTE "server fingerprint: %s", fingerprint.c_str())); String trustedServersFilename; trustedServersFilename = synergy::string::sprintf( "%s/%s/%s", ARCH->getProfileDirectory().c_str(), kFingerprintDirName, kFingerprintTrustedServersFilename); // check if this fingerprint exist String fileLine; std::ifstream file; file.open(trustedServersFilename.c_str()); bool isValid = false; while (!file.eof() && file.is_open()) { getline(file,fileLine); if (!fileLine.empty()) { if (fileLine.compare(fingerprint) == 0) { isValid = true; break; } } } file.close(); return isValid; } ISocketMultiplexerJob* SecureSocket::serviceConnect(ISocketMultiplexerJob* job, bool, bool write, bool error) { Lock lock(&getMutex()); int status = 0; #ifdef SYSAPI_WIN32 status = secureConnect(static_cast(getSocket()->m_socket)); #elif SYSAPI_UNIX status = secureConnect(getSocket()->m_fd); #endif // If status < 0, error happened if (status < 0) { return NULL; } // If status > 0, success if (status > 0) { sendEvent(m_events->forIDataSocket().secureConnected()); return newJob(); } // Retry case return new TSocketMultiplexerMethodJob( this, &SecureSocket::serviceConnect, getSocket(), isReadable(), isWritable()); } ISocketMultiplexerJob* SecureSocket::serviceAccept(ISocketMultiplexerJob* job, bool, bool write, bool error) { Lock lock(&getMutex()); int status = 0; #ifdef SYSAPI_WIN32 status = secureAccept(static_cast(getSocket()->m_socket)); #elif SYSAPI_UNIX status = secureAccept(getSocket()->m_fd); #endif // If status < 0, error happened if (status < 0) { return NULL; } // If status > 0, success if (status > 0) { sendEvent(m_events->forClientListener().accepted()); return newJob(); } // Retry case return new TSocketMultiplexerMethodJob( this, &SecureSocket::serviceAccept, getSocket(), isReadable(), isWritable()); } void showCipherStackDesc(STACK_OF(SSL_CIPHER) * stack) { char msg[kMsgSize]; int i = 0; for ( ; i < sk_SSL_CIPHER_num(stack) ; i++) { const SSL_CIPHER * cipher = sk_SSL_CIPHER_value(stack,i); SSL_CIPHER_description(cipher, msg, kMsgSize); // Why does SSL put a newline in the description? int pos = (int)strlen(msg) - 1; if (msg[pos] == '\n') { msg[pos] = '\0'; } LOG((CLOG_DEBUG1 "%s",msg)); } } void SecureSocket::showSecureCipherInfo() { STACK_OF(SSL_CIPHER) * sStack = SSL_get_ciphers(m_ssl->m_ssl); if (sStack == NULL) { LOG((CLOG_DEBUG1 "local cipher list not available")); } else { LOG((CLOG_DEBUG1 "available local ciphers:")); showCipherStackDesc(sStack); } // m_ssl->m_ssl->session->ciphers is not forward compatable, In future release // of OpenSSL, it's not visible, need to use SSL_get_client_ciphers() instead STACK_OF(SSL_CIPHER) * cStack = m_ssl->m_ssl->session->ciphers; if (cStack == NULL) { LOG((CLOG_DEBUG1 "remote cipher list not available")); } else { LOG((CLOG_DEBUG1 "available remote ciphers:")); showCipherStackDesc(cStack); } return; } void SecureSocket::showSecureLibInfo() { LOG((CLOG_INFO "%s",SSLeay_version(SSLEAY_VERSION))); LOG((CLOG_DEBUG1 "openSSL : %s",SSLeay_version(SSLEAY_CFLAGS))); LOG((CLOG_DEBUG1 "openSSL : %s",SSLeay_version(SSLEAY_BUILT_ON))); LOG((CLOG_DEBUG1 "openSSL : %s",SSLeay_version(SSLEAY_PLATFORM))); LOG((CLOG_DEBUG1 "%s",SSLeay_version(SSLEAY_DIR))); return; } void SecureSocket::showSecureConnectInfo() { const SSL_CIPHER* cipher = SSL_get_current_cipher(m_ssl->m_ssl); if (cipher != NULL) { char msg[kMsgSize]; SSL_CIPHER_description(cipher, msg, kMsgSize); LOG((CLOG_INFO "%s", msg)); } return; } void SecureSocket::handleTCPConnected(const Event& event, void*) { secureConnect(); } synergy-1.8.8-stable/src/lib/net/SecureSocket.h000066400000000000000000000050031305627404700214010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "net/TCPSocket.h" #include "net/XSocket.h" class IEventQueue; class SocketMultiplexer; class ISocketMultiplexerJob; struct Ssl; //! Secure socket /*! A secure socket using SSL. */ class SecureSocket : public TCPSocket { public: SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer); SecureSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket); ~SecureSocket(); // ISocket overrides void close(); // IDataSocket overrides virtual void connect(const NetworkAddress&); ISocketMultiplexerJob* newJob(); bool isFatal() const { return m_fatal; } void isFatal(bool b) { m_fatal = b; } bool isSecureReady(); void secureConnect(); void secureAccept(); int secureRead(void* buffer, int size, int& read); int secureWrite(const void* buffer, int size, int& wrote); EJobResult doRead(); EJobResult doWrite(); void initSsl(bool server); bool loadCertificates(String& CertFile); private: // SSL void initContext(bool server); void createSSL(); int secureAccept(int s); int secureConnect(int s); bool showCertificate(); void checkResult(int n, int& retry); void showError(const char* reason = NULL); String getError(); void disconnect(); void formatFingerprint(String& fingerprint, bool hex = true, bool separator = true); bool verifyCertFingerprint(); ISocketMultiplexerJob* serviceConnect(ISocketMultiplexerJob*, bool, bool, bool); ISocketMultiplexerJob* serviceAccept(ISocketMultiplexerJob*, bool, bool, bool); void showSecureConnectInfo(); void showSecureLibInfo(); void showSecureCipherInfo(); void handleTCPConnected(const Event& event, void*); private: Ssl* m_ssl; bool m_secureReady; bool m_fatal; }; synergy-1.8.8-stable/src/lib/net/SocketMultiplexer.cpp000066400000000000000000000201431305627404700230220ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "net/SocketMultiplexer.h" #include "net/ISocketMultiplexerJob.h" #include "mt/CondVar.h" #include "mt/Lock.h" #include "mt/Mutex.h" #include "mt/Thread.h" #include "arch/Arch.h" #include "arch/XArch.h" #include "base/Log.h" #include "base/TMethodJob.h" #include "common/stdvector.h" // // SocketMultiplexer // SocketMultiplexer::SocketMultiplexer() : m_mutex(new Mutex), m_thread(NULL), m_update(false), m_jobsReady(new CondVar(m_mutex, false)), m_jobListLock(new CondVar(m_mutex, false)), m_jobListLockLocked(new CondVar(m_mutex, false)), m_jobListLocker(NULL), m_jobListLockLocker(NULL) { // this pointer just has to be unique and not NULL. it will // never be dereferenced. it's used to identify cursor nodes // in the jobs list. // TODO: Remove this evilness m_cursorMark = reinterpret_cast(this); // start thread m_thread = new Thread(new TMethodJob( this, &SocketMultiplexer::serviceThread)); } SocketMultiplexer::~SocketMultiplexer() { m_thread->cancel(); m_thread->unblockPollSocket(); m_thread->wait(); delete m_thread; delete m_jobsReady; delete m_jobListLock; delete m_jobListLockLocked; delete m_jobListLocker; delete m_jobListLockLocker; delete m_mutex; // clean up jobs for (SocketJobMap::iterator i = m_socketJobMap.begin(); i != m_socketJobMap.end(); ++i) { delete *(i->second); } } void SocketMultiplexer::addSocket(ISocket* socket, ISocketMultiplexerJob* job) { assert(socket != NULL); assert(job != NULL); // prevent other threads from locking the job list lockJobListLock(); // break thread out of poll m_thread->unblockPollSocket(); // lock the job list lockJobList(); // insert/replace job SocketJobMap::iterator i = m_socketJobMap.find(socket); if (i == m_socketJobMap.end()) { // we *must* put the job at the end so the order of jobs in // the list continue to match the order of jobs in pfds in // serviceThread(). JobCursor j = m_socketJobs.insert(m_socketJobs.end(), job); m_update = true; m_socketJobMap.insert(std::make_pair(socket, j)); } else { JobCursor j = i->second; if (*j != job) { delete *j; *j = job; } m_update = true; } // unlock the job list unlockJobList(); } void SocketMultiplexer::removeSocket(ISocket* socket) { assert(socket != NULL); // prevent other threads from locking the job list lockJobListLock(); // break thread out of poll m_thread->unblockPollSocket(); // lock the job list lockJobList(); // remove job. rather than removing it from the map we put NULL // in the list instead so the order of jobs in the list continues // to match the order of jobs in pfds in serviceThread(). SocketJobMap::iterator i = m_socketJobMap.find(socket); if (i != m_socketJobMap.end()) { if (*(i->second) != NULL) { delete *(i->second); *(i->second) = NULL; m_update = true; } } // unlock the job list unlockJobList(); } void SocketMultiplexer::serviceThread(void*) { std::vector pfds; IArchNetwork::PollEntry pfd; // service the connections for (;;) { Thread::testCancel(); // wait until there are jobs to handle { Lock lock(m_mutex); while (!(bool)*m_jobsReady) { m_jobsReady->wait(); } } // lock the job list lockJobListLock(); lockJobList(); // collect poll entries if (m_update) { m_update = false; pfds.clear(); pfds.reserve(m_socketJobMap.size()); JobCursor cursor = newCursor(); JobCursor jobCursor = nextCursor(cursor); while (jobCursor != m_socketJobs.end()) { ISocketMultiplexerJob* job = *jobCursor; if (job != NULL) { pfd.m_socket = job->getSocket(); pfd.m_events = 0; if (job->isReadable()) { pfd.m_events |= IArchNetwork::kPOLLIN; } if (job->isWritable()) { pfd.m_events |= IArchNetwork::kPOLLOUT; } pfds.push_back(pfd); } jobCursor = nextCursor(cursor); } deleteCursor(cursor); } int status; try { // check for status if (!pfds.empty()) { status = ARCH->pollSocket(&pfds[0], (int)pfds.size(), -1); } else { status = 0; } } catch (XArchNetwork& e) { LOG((CLOG_WARN "error in socket multiplexer: %s", e.what())); status = 0; } if (status != 0) { // iterate over socket jobs, invoking each and saving the // new job. UInt32 i = 0; JobCursor cursor = newCursor(); JobCursor jobCursor = nextCursor(cursor); while (i < pfds.size() && jobCursor != m_socketJobs.end()) { if (*jobCursor != NULL) { // get poll state unsigned short revents = pfds[i].m_revents; bool read = ((revents & IArchNetwork::kPOLLIN) != 0); bool write = ((revents & IArchNetwork::kPOLLOUT) != 0); bool error = ((revents & (IArchNetwork::kPOLLERR | IArchNetwork::kPOLLNVAL)) != 0); // run job ISocketMultiplexerJob* job = *jobCursor; ISocketMultiplexerJob* newJob = job->run(read, write, error); // save job, if different if (newJob != job) { Lock lock(m_mutex); delete job; *jobCursor = newJob; m_update = true; } ++i; } // next job jobCursor = nextCursor(cursor); } deleteCursor(cursor); } // delete any removed socket jobs for (SocketJobMap::iterator i = m_socketJobMap.begin(); i != m_socketJobMap.end();) { if (*(i->second) == NULL) { m_socketJobs.erase(i->second); m_socketJobMap.erase(i++); m_update = true; } else { ++i; } } // unlock the job list unlockJobList(); } } SocketMultiplexer::JobCursor SocketMultiplexer::newCursor() { Lock lock(m_mutex); return m_socketJobs.insert(m_socketJobs.begin(), m_cursorMark); } SocketMultiplexer::JobCursor SocketMultiplexer::nextCursor(JobCursor cursor) { Lock lock(m_mutex); JobCursor j = m_socketJobs.end(); JobCursor i = cursor; while (++i != m_socketJobs.end()) { if (*i != m_cursorMark) { // found a real job (as opposed to a cursor) j = i; // move our cursor just past the job m_socketJobs.splice(++i, m_socketJobs, cursor); break; } } return j; } void SocketMultiplexer::deleteCursor(JobCursor cursor) { Lock lock(m_mutex); m_socketJobs.erase(cursor); } void SocketMultiplexer::lockJobListLock() { Lock lock(m_mutex); // wait for the lock on the lock while (*m_jobListLockLocked) { m_jobListLockLocked->wait(); } // take ownership of the lock on the lock *m_jobListLockLocked = true; m_jobListLockLocker = new Thread(Thread::getCurrentThread()); } void SocketMultiplexer::lockJobList() { Lock lock(m_mutex); // make sure we're the one that called lockJobListLock() assert(*m_jobListLockLocker == Thread::getCurrentThread()); // wait for the job list lock while (*m_jobListLock) { m_jobListLock->wait(); } // take ownership of the lock *m_jobListLock = true; m_jobListLocker = m_jobListLockLocker; m_jobListLockLocker = NULL; // release the lock on the lock *m_jobListLockLocked = false; m_jobListLockLocked->broadcast(); } void SocketMultiplexer::unlockJobList() { Lock lock(m_mutex); // make sure we're the one that called lockJobList() assert(*m_jobListLocker == Thread::getCurrentThread()); // release the lock delete m_jobListLocker; m_jobListLocker = NULL; *m_jobListLock = false; m_jobListLock->signal(); // set new jobs ready state bool isReady = !m_socketJobMap.empty(); if (*m_jobsReady != isReady) { *m_jobsReady = isReady; m_jobsReady->signal(); } } synergy-1.8.8-stable/src/lib/net/SocketMultiplexer.h000066400000000000000000000065351305627404700225000ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/IArchNetwork.h" #include "common/stdlist.h" #include "common/stdmap.h" template class CondVar; class Mutex; class Thread; class ISocket; class ISocketMultiplexerJob; //! Socket multiplexer /*! A socket multiplexer services multiple sockets simultaneously. */ class SocketMultiplexer { public: SocketMultiplexer(); ~SocketMultiplexer(); //! @name manipulators //@{ void addSocket(ISocket*, ISocketMultiplexerJob*); void removeSocket(ISocket*); //@} //! @name accessors //@{ // maybe belongs on ISocketMultiplexer static SocketMultiplexer* getInstance(); //@} private: // list of jobs. we use a list so we can safely iterate over it // while other threads modify it. typedef std::list SocketJobs; typedef SocketJobs::iterator JobCursor; typedef std::map SocketJobMap; // service sockets. the service thread will only access m_sockets // and m_update while m_pollable and m_polling are true. all other // threads must only modify these when m_pollable and m_polling are // false. only the service thread sets m_polling. void serviceThread(void*); // create, iterate, and destroy a cursor. a cursor is used to // safely iterate through the job list while other threads modify // the list. it works by inserting a dummy item in the list and // moving that item through the list. the dummy item will never // be removed by other edits so an iterator pointing at the item // remains valid until we remove the dummy item in deleteCursor(). // nextCursor() finds the next non-dummy item, moves our dummy // item just past it, and returns an iterator for the non-dummy // item. all cursor calls lock the mutex for their duration. JobCursor newCursor(); JobCursor nextCursor(JobCursor); void deleteCursor(JobCursor); // lock out locking the job list. this blocks if another thread // has already locked out locking. once it returns, only the // calling thread will be able to lock the job list after any // current lock is released. void lockJobListLock(); // lock the job list. this blocks if the job list is already // locked. the calling thread must have called requestJobLock. void lockJobList(); // unlock the job list and the lock out on locking. void unlockJobList(); private: Mutex* m_mutex; Thread* m_thread; bool m_update; CondVar* m_jobsReady; CondVar* m_jobListLock; CondVar* m_jobListLockLocked; Thread* m_jobListLocker; Thread* m_jobListLockLocker; SocketJobs m_socketJobs; SocketJobMap m_socketJobMap; ISocketMultiplexerJob* m_cursorMark; }; synergy-1.8.8-stable/src/lib/net/TCPListenSocket.cpp000066400000000000000000000070141305627404700223170ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "net/TCPListenSocket.h" #include "net/NetworkAddress.h" #include "net/SocketMultiplexer.h" #include "net/TCPSocket.h" #include "net/TSocketMultiplexerMethodJob.h" #include "net/XSocket.h" #include "io/XIO.h" #include "mt/Lock.h" #include "mt/Mutex.h" #include "arch/Arch.h" #include "arch/XArch.h" #include "base/IEventQueue.h" // // TCPListenSocket // TCPListenSocket::TCPListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : m_events(events), m_socketMultiplexer(socketMultiplexer) { m_mutex = new Mutex; try { m_socket = ARCH->newSocket(IArchNetwork::kINET, IArchNetwork::kSTREAM); } catch (XArchNetwork& e) { throw XSocketCreate(e.what()); } } TCPListenSocket::~TCPListenSocket() { try { if (m_socket != NULL) { m_socketMultiplexer->removeSocket(this); ARCH->closeSocket(m_socket); } } catch (...) { // ignore } delete m_mutex; } void TCPListenSocket::bind(const NetworkAddress& addr) { try { Lock lock(m_mutex); ARCH->setReuseAddrOnSocket(m_socket, true); ARCH->bindSocket(m_socket, addr.getAddress()); ARCH->listenOnSocket(m_socket); m_socketMultiplexer->addSocket(this, new TSocketMultiplexerMethodJob( this, &TCPListenSocket::serviceListening, m_socket, true, false)); } catch (XArchNetworkAddressInUse& e) { throw XSocketAddressInUse(e.what()); } catch (XArchNetwork& e) { throw XSocketBind(e.what()); } } void TCPListenSocket::close() { Lock lock(m_mutex); if (m_socket == NULL) { throw XIOClosed(); } try { m_socketMultiplexer->removeSocket(this); ARCH->closeSocket(m_socket); m_socket = NULL; } catch (XArchNetwork& e) { throw XSocketIOClose(e.what()); } } void* TCPListenSocket::getEventTarget() const { return const_cast(static_cast(this)); } IDataSocket* TCPListenSocket::accept() { IDataSocket* socket = NULL; try { socket = new TCPSocket(m_events, m_socketMultiplexer, ARCH->acceptSocket(m_socket, NULL)); if (socket != NULL) { setListeningJob(); } return socket; } catch (XArchNetwork&) { if (socket != NULL) { delete socket; setListeningJob(); } return NULL; } catch (std::exception &ex) { if (socket != NULL) { delete socket; setListeningJob(); } throw ex; } } void TCPListenSocket::setListeningJob() { m_socketMultiplexer->addSocket(this, new TSocketMultiplexerMethodJob( this, &TCPListenSocket::serviceListening, m_socket, true, false)); } ISocketMultiplexerJob* TCPListenSocket::serviceListening(ISocketMultiplexerJob* job, bool read, bool, bool error) { if (error) { close(); return NULL; } if (read) { m_events->addEvent(Event(m_events->forIListenSocket().connecting(), this, NULL)); // stop polling on this socket until the client accepts return NULL; } return job; } synergy-1.8.8-stable/src/lib/net/TCPListenSocket.h000066400000000000000000000030561305627404700217660ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "net/IListenSocket.h" #include "arch/IArchNetwork.h" class Mutex; class ISocketMultiplexerJob; class IEventQueue; class SocketMultiplexer; //! TCP listen socket /*! A listen socket using TCP. */ class TCPListenSocket : public IListenSocket { public: TCPListenSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer); virtual ~TCPListenSocket(); // ISocket overrides virtual void bind(const NetworkAddress&); virtual void close(); virtual void* getEventTarget() const; // IListenSocket overrides virtual IDataSocket* accept(); protected: void setListeningJob(); public: ISocketMultiplexerJob* serviceListening(ISocketMultiplexerJob*, bool, bool, bool); protected: ArchSocket m_socket; Mutex* m_mutex; IEventQueue* m_events; SocketMultiplexer* m_socketMultiplexer; }; synergy-1.8.8-stable/src/lib/net/TCPSocket.cpp000066400000000000000000000305421305627404700211420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "net/TCPSocket.h" #include "net/NetworkAddress.h" #include "net/SocketMultiplexer.h" #include "net/TSocketMultiplexerMethodJob.h" #include "net/XSocket.h" #include "mt/Lock.h" #include "arch/Arch.h" #include "arch/XArch.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "base/IEventJob.h" #include #include #include // // TCPSocket // TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : IDataSocket(events), m_events(events), m_mutex(), m_flushed(&m_mutex, true), m_socketMultiplexer(socketMultiplexer) { try { m_socket = ARCH->newSocket(IArchNetwork::kINET, IArchNetwork::kSTREAM); } catch (XArchNetwork& e) { throw XSocketCreate(e.what()); } init(); } TCPSocket::TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket) : IDataSocket(events), m_events(events), m_mutex(), m_socket(socket), m_flushed(&m_mutex, true), m_socketMultiplexer(socketMultiplexer) { assert(m_socket != NULL); // socket starts in connected state init(); onConnected(); setJob(newJob()); } TCPSocket::~TCPSocket() { try { close(); } catch (...) { // ignore } } void TCPSocket::bind(const NetworkAddress& addr) { try { ARCH->bindSocket(m_socket, addr.getAddress()); } catch (XArchNetworkAddressInUse& e) { throw XSocketAddressInUse(e.what()); } catch (XArchNetwork& e) { throw XSocketBind(e.what()); } } void TCPSocket::close() { // remove ourself from the multiplexer setJob(NULL); Lock lock(&m_mutex); // clear buffers and enter disconnected state if (m_connected) { sendEvent(m_events->forISocket().disconnected()); } onDisconnected(); // close the socket if (m_socket != NULL) { ArchSocket socket = m_socket; m_socket = NULL; try { ARCH->closeSocket(socket); } catch (XArchNetwork& e) { // ignore, there's not much we can do LOG((CLOG_WARN "error closing socket: %s", e.what())); } } } void* TCPSocket::getEventTarget() const { return const_cast(static_cast(this)); } UInt32 TCPSocket::read(void* buffer, UInt32 n) { // copy data directly from our input buffer Lock lock(&m_mutex); UInt32 size = m_inputBuffer.getSize(); if (n > size) { n = size; } if (buffer != NULL && n != 0) { memcpy(buffer, m_inputBuffer.peek(n), n); } m_inputBuffer.pop(n); // if no more data and we cannot read or write then send disconnected if (n > 0 && m_inputBuffer.getSize() == 0 && !m_readable && !m_writable) { sendEvent(m_events->forISocket().disconnected()); m_connected = false; } return n; } void TCPSocket::write(const void* buffer, UInt32 n) { bool wasEmpty; { Lock lock(&m_mutex); // must not have shutdown output if (!m_writable) { sendEvent(m_events->forIStream().outputError()); return; } // ignore empty writes if (n == 0) { return; } // copy data to the output buffer wasEmpty = (m_outputBuffer.getSize() == 0); m_outputBuffer.write(buffer, n); // there's data to write m_flushed = false; } // make sure we're waiting to write if (wasEmpty) { setJob(newJob()); } } void TCPSocket::flush() { Lock lock(&m_mutex); while (m_flushed == false) { m_flushed.wait(); } } void TCPSocket::shutdownInput() { bool useNewJob = false; { Lock lock(&m_mutex); // shutdown socket for reading try { ARCH->closeSocketForRead(m_socket); } catch (XArchNetwork&) { // ignore } // shutdown buffer for reading if (m_readable) { sendEvent(m_events->forIStream().inputShutdown()); onInputShutdown(); useNewJob = true; } } if (useNewJob) { setJob(newJob()); } } void TCPSocket::shutdownOutput() { bool useNewJob = false; { Lock lock(&m_mutex); // shutdown socket for writing try { ARCH->closeSocketForWrite(m_socket); } catch (XArchNetwork&) { // ignore } // shutdown buffer for writing if (m_writable) { sendEvent(m_events->forIStream().outputShutdown()); onOutputShutdown(); useNewJob = true; } } if (useNewJob) { setJob(newJob()); } } bool TCPSocket::isReady() const { Lock lock(&m_mutex); return (m_inputBuffer.getSize() > 0); } bool TCPSocket::isFatal() const { // TCP sockets aren't ever left in a fatal state. LOG((CLOG_ERR "isFatal() not valid for non-secure connections")); return false; } UInt32 TCPSocket::getSize() const { Lock lock(&m_mutex); return m_inputBuffer.getSize(); } void TCPSocket::connect(const NetworkAddress& addr) { { Lock lock(&m_mutex); // fail on attempts to reconnect if (m_socket == NULL || m_connected) { sendConnectionFailedEvent("busy"); return; } try { if (ARCH->connectSocket(m_socket, addr.getAddress())) { sendEvent(m_events->forIDataSocket().connected()); onConnected(); } else { // connection is in progress m_writable = true; } } catch (XArchNetwork& e) { throw XSocketConnect(e.what()); } } setJob(newJob()); } void TCPSocket::init() { // default state m_connected = false; m_readable = false; m_writable = false; try { // turn off Nagle algorithm. we send lots of very short messages // that should be sent without (much) delay. for example, the // mouse motion messages are much less useful if they're delayed. ARCH->setNoDelayOnSocket(m_socket, true); } catch (XArchNetwork& e) { try { ARCH->closeSocket(m_socket); m_socket = NULL; } catch (XArchNetwork&) { // ignore } throw XSocketCreate(e.what()); } } TCPSocket::EJobResult TCPSocket::doRead() { UInt8 buffer[4096]; memset(buffer, 0, sizeof(buffer)); size_t bytesRead = 0; bytesRead = (int) ARCH->readSocket(m_socket, buffer, sizeof(buffer)); if (bytesRead > 0) { bool wasEmpty = (m_inputBuffer.getSize() == 0); // slurp up as much as possible do { m_inputBuffer.write(buffer, bytesRead); bytesRead = ARCH->readSocket(m_socket, buffer, sizeof(buffer)); } while (bytesRead > 0); // send input ready if input buffer was empty if (wasEmpty) { sendEvent(m_events->forIStream().inputReady()); } } else { // remote write end of stream hungup. our input side // has therefore shutdown but don't flush our buffer // since there's still data to be read. sendEvent(m_events->forIStream().inputShutdown()); if (!m_writable && m_inputBuffer.getSize() == 0) { sendEvent(m_events->forISocket().disconnected()); m_connected = false; } m_readable = false; return kNew; } return kRetry; } TCPSocket::EJobResult TCPSocket::doWrite() { // write data UInt32 bufferSize = 0; int bytesWrote = 0; bufferSize = m_outputBuffer.getSize(); const void* buffer = m_outputBuffer.peek(bufferSize); bytesWrote = (UInt32)ARCH->writeSocket(m_socket, buffer, bufferSize); if (bytesWrote > 0) { discardWrittenData(bytesWrote); return kNew; } return kRetry; } void TCPSocket::setJob(ISocketMultiplexerJob* job) { // multiplexer will delete the old job if (job == NULL) { m_socketMultiplexer->removeSocket(this); } else { m_socketMultiplexer->addSocket(this, job); } } ISocketMultiplexerJob* TCPSocket::newJob() { // note -- must have m_mutex locked on entry if (m_socket == NULL) { return NULL; } else if (!m_connected) { assert(!m_readable); if (!(m_readable || m_writable)) { return NULL; } return new TSocketMultiplexerMethodJob( this, &TCPSocket::serviceConnecting, m_socket, m_readable, m_writable); } else { if (!(m_readable || (m_writable && (m_outputBuffer.getSize() > 0)))) { return NULL; } return new TSocketMultiplexerMethodJob( this, &TCPSocket::serviceConnected, m_socket, m_readable, m_writable && (m_outputBuffer.getSize() > 0)); } } void TCPSocket::sendConnectionFailedEvent(const char* msg) { ConnectionFailedInfo* info = new ConnectionFailedInfo(msg); m_events->addEvent(Event(m_events->forIDataSocket().connectionFailed(), getEventTarget(), info, Event::kDontFreeData)); } void TCPSocket::sendEvent(Event::Type type) { m_events->addEvent(Event(type, getEventTarget(), NULL)); } void TCPSocket::discardWrittenData(int bytesWrote) { m_outputBuffer.pop(bytesWrote); if (m_outputBuffer.getSize() == 0) { sendEvent(m_events->forIStream().outputFlushed()); m_flushed = true; m_flushed.broadcast(); } } void TCPSocket::onConnected() { m_connected = true; m_readable = true; m_writable = true; } void TCPSocket::onInputShutdown() { m_inputBuffer.pop(m_inputBuffer.getSize()); m_readable = false; } void TCPSocket::onOutputShutdown() { m_outputBuffer.pop(m_outputBuffer.getSize()); m_writable = false; // we're now flushed m_flushed = true; m_flushed.broadcast(); } void TCPSocket::onDisconnected() { // disconnected onInputShutdown(); onOutputShutdown(); m_connected = false; } ISocketMultiplexerJob* TCPSocket::serviceConnecting(ISocketMultiplexerJob* job, bool, bool write, bool error) { Lock lock(&m_mutex); // should only check for errors if error is true but checking a new // socket (and a socket that's connecting should be new) for errors // should be safe and Mac OS X appears to have a bug where a // non-blocking stream socket that fails to connect immediately is // reported by select as being writable (i.e. connected) even when // the connection has failed. this is easily demonstrated on OS X // 10.3.4 by starting a synergy client and telling to connect to // another system that's not running a synergy server. it will // claim to have connected then quickly disconnect (i guess because // read returns 0 bytes). unfortunately, synergy attempts to // reconnect immediately, the process repeats and we end up // spinning the CPU. luckily, OS X does set SO_ERROR on the // socket correctly when the connection has failed so checking for // errors works. (curiously, sometimes OS X doesn't report // connection refused. when that happens it at least doesn't // report the socket as being writable so synergy is able to time // out the attempt.) if (error || true) { try { // connection may have failed or succeeded ARCH->throwErrorOnSocket(m_socket); } catch (XArchNetwork& e) { sendConnectionFailedEvent(e.what()); onDisconnected(); return newJob(); } } if (write) { sendEvent(m_events->forIDataSocket().connected()); onConnected(); return newJob(); } return job; } ISocketMultiplexerJob* TCPSocket::serviceConnected(ISocketMultiplexerJob* job, bool read, bool write, bool error) { Lock lock(&m_mutex); if (error) { sendEvent(m_events->forISocket().disconnected()); onDisconnected(); return newJob(); } EJobResult result = kRetry; if (write) { try { result = doWrite(); } catch (XArchNetworkShutdown&) { // remote read end of stream hungup. our output side // has therefore shutdown. onOutputShutdown(); sendEvent(m_events->forIStream().outputShutdown()); if (!m_readable && m_inputBuffer.getSize() == 0) { sendEvent(m_events->forISocket().disconnected()); m_connected = false; } result = kNew; } catch (XArchNetworkDisconnected&) { // stream hungup onDisconnected(); sendEvent(m_events->forISocket().disconnected()); result = kNew; } catch (XArchNetwork& e) { // other write error LOG((CLOG_WARN "error writing socket: %s", e.what())); onDisconnected(); sendEvent(m_events->forIStream().outputError()); sendEvent(m_events->forISocket().disconnected()); result = kNew; } } if (read && m_readable) { try { result = doRead(); } catch (XArchNetworkDisconnected&) { // stream hungup sendEvent(m_events->forISocket().disconnected()); onDisconnected(); result = kNew; } catch (XArchNetwork& e) { // ignore other read error LOG((CLOG_WARN "error reading socket: %s", e.what())); } } return result == kBreak ? NULL : result == kNew ? newJob() : job; } synergy-1.8.8-stable/src/lib/net/TCPSocket.h000066400000000000000000000057601305627404700206130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "net/IDataSocket.h" #include "io/StreamBuffer.h" #include "mt/CondVar.h" #include "mt/Mutex.h" #include "arch/IArchNetwork.h" class Mutex; class Thread; class ISocketMultiplexerJob; class IEventQueue; class SocketMultiplexer; //! TCP data socket /*! A data socket using TCP. */ class TCPSocket : public IDataSocket { public: TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer); TCPSocket(IEventQueue* events, SocketMultiplexer* socketMultiplexer, ArchSocket socket); virtual ~TCPSocket(); // ISocket overrides virtual void bind(const NetworkAddress&); virtual void close(); virtual void* getEventTarget() const; // IStream overrides virtual UInt32 read(void* buffer, UInt32 n); virtual void write(const void* buffer, UInt32 n); virtual void flush(); virtual void shutdownInput(); virtual void shutdownOutput(); virtual bool isReady() const; virtual bool isFatal() const; virtual UInt32 getSize() const; // IDataSocket overrides virtual void connect(const NetworkAddress&); virtual ISocketMultiplexerJob* newJob(); protected: enum EJobResult { kBreak = -1, //!< Break the Job chain kRetry, //!< Retry the same job kNew //!< Require a new job }; ArchSocket getSocket() { return m_socket; } IEventQueue* getEvents() { return m_events; } virtual EJobResult doRead(); virtual EJobResult doWrite(); void setJob(ISocketMultiplexerJob*); bool isReadable() { return m_readable; } bool isWritable() { return m_writable; } Mutex& getMutex() { return m_mutex; } void sendEvent(Event::Type); void discardWrittenData(int bytesWrote); private: void init(); void sendConnectionFailedEvent(const char*); void onConnected(); void onInputShutdown(); void onOutputShutdown(); void onDisconnected(); ISocketMultiplexerJob* serviceConnecting(ISocketMultiplexerJob*, bool, bool, bool); ISocketMultiplexerJob* serviceConnected(ISocketMultiplexerJob*, bool, bool, bool); protected: bool m_readable; bool m_writable; bool m_connected; IEventQueue* m_events; StreamBuffer m_inputBuffer; StreamBuffer m_outputBuffer; private: Mutex m_mutex; ArchSocket m_socket; CondVar m_flushed; SocketMultiplexer* m_socketMultiplexer; }; synergy-1.8.8-stable/src/lib/net/TCPSocketFactory.cpp000066400000000000000000000033331305627404700224700ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "net/TCPSocketFactory.h" #include "net/TCPSocket.h" #include "net/TCPListenSocket.h" #include "net/SecureSocket.h" #include "net/SecureListenSocket.h" #include "arch/Arch.h" #include "base/Log.h" // // TCPSocketFactory // TCPSocketFactory::TCPSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer) : m_events(events), m_socketMultiplexer(socketMultiplexer) { // do nothing } TCPSocketFactory::~TCPSocketFactory() { // do nothing } IDataSocket* TCPSocketFactory::create(bool secure) const { if (secure) { SecureSocket* secureSocket = new SecureSocket(m_events, m_socketMultiplexer); secureSocket->initSsl (false); return secureSocket; } else { return new TCPSocket(m_events, m_socketMultiplexer); } } IListenSocket* TCPSocketFactory::createListen(bool secure) const { IListenSocket* socket = NULL; if (secure) { socket = new SecureListenSocket(m_events, m_socketMultiplexer); } else { socket = new TCPListenSocket(m_events, m_socketMultiplexer); } return socket; } synergy-1.8.8-stable/src/lib/net/TCPSocketFactory.h000066400000000000000000000023431305627404700221350ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "net/ISocketFactory.h" class IEventQueue; class SocketMultiplexer; //! Socket factory for TCP sockets class TCPSocketFactory : public ISocketFactory { public: TCPSocketFactory(IEventQueue* events, SocketMultiplexer* socketMultiplexer); virtual ~TCPSocketFactory(); // ISocketFactory overrides virtual IDataSocket* create(bool secure) const; virtual IListenSocket* createListen(bool secure) const; private: IEventQueue* m_events; SocketMultiplexer* m_socketMultiplexer; }; synergy-1.8.8-stable/src/lib/net/TSocketMultiplexerMethodJob.h000066400000000000000000000051201305627404700244050ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "net/ISocketMultiplexerJob.h" #include "arch/Arch.h" //! Use a method as a socket multiplexer job /*! A socket multiplexer job class that invokes a member function. */ template class TSocketMultiplexerMethodJob : public ISocketMultiplexerJob { public: typedef ISocketMultiplexerJob* (T::*Method)(ISocketMultiplexerJob*, bool, bool, bool); //! run() invokes \c object->method(arg) TSocketMultiplexerMethodJob(T* object, Method method, ArchSocket socket, bool readable, bool writeable); virtual ~TSocketMultiplexerMethodJob(); // IJob overrides virtual ISocketMultiplexerJob* run(bool readable, bool writable, bool error); virtual ArchSocket getSocket() const; virtual bool isReadable() const; virtual bool isWritable() const; private: T* m_object; Method m_method; ArchSocket m_socket; bool m_readable; bool m_writable; void* m_arg; }; template inline TSocketMultiplexerMethodJob::TSocketMultiplexerMethodJob(T* object, Method method, ArchSocket socket, bool readable, bool writable) : m_object(object), m_method(method), m_socket(ARCH->copySocket(socket)), m_readable(readable), m_writable(writable) { // do nothing } template inline TSocketMultiplexerMethodJob::~TSocketMultiplexerMethodJob() { ARCH->closeSocket(m_socket); } template inline ISocketMultiplexerJob* TSocketMultiplexerMethodJob::run(bool read, bool write, bool error) { if (m_object != NULL) { return (m_object->*m_method)(this, read, write, error); } return NULL; } template inline ArchSocket TSocketMultiplexerMethodJob::getSocket() const { return m_socket; } template inline bool TSocketMultiplexerMethodJob::isReadable() const { return m_readable; } template inline bool TSocketMultiplexerMethodJob::isWritable() const { return m_writable; } synergy-1.8.8-stable/src/lib/net/XSocket.cpp000066400000000000000000000045151305627404700207240ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "net/XSocket.h" #include "base/String.h" // // XSocketAddress // XSocketAddress::XSocketAddress(EError error, const String& hostname, int port) _NOEXCEPT : m_error(error), m_hostname(hostname), m_port(port) { // do nothing } XSocketAddress::EError XSocketAddress::getError() const throw() { return m_error; } String XSocketAddress::getHostname() const throw() { return m_hostname; } int XSocketAddress::getPort() const throw() { return m_port; } String XSocketAddress::getWhat() const throw() { static const char* s_errorID[] = { "XSocketAddressUnknown", "XSocketAddressNotFound", "XSocketAddressNoAddress", "XSocketAddressUnsupported", "XSocketAddressBadPort" }; static const char* s_errorMsg[] = { "unknown error for: %{1}:%{2}", "address not found for: %{1}", "no address for: %{1}", "unsupported address for: %{1}", "invalid port" // m_port may not be set to the bad port }; return format(s_errorID[m_error], s_errorMsg[m_error], m_hostname.c_str(), synergy::string::sprintf("%d", m_port).c_str()); } // // XSocketIOClose // String XSocketIOClose::getWhat() const throw() { return format("XSocketIOClose", "close: %{1}", what()); } // // XSocketBind // String XSocketBind::getWhat() const throw() { return format("XSocketBind", "cannot bind address: %{1}", what()); } // // XSocketConnect // String XSocketConnect::getWhat() const throw() { return format("XSocketConnect", "cannot connect socket: %{1}", what()); } // // XSocketCreate // String XSocketCreate::getWhat() const throw() { return format("XSocketCreate", "cannot create socket: %{1}", what()); } synergy-1.8.8-stable/src/lib/net/XSocket.h000066400000000000000000000050121305627404700203620ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "io/XIO.h" #include "base/XBase.h" #include "base/String.h" #include "common/basic_types.h" //! Generic socket exception XBASE_SUBCLASS(XSocket, XBase); //! Socket bad address exception /*! Thrown when attempting to create an invalid network address. */ class XSocketAddress : public XSocket { public: //! Failure codes enum EError { kUnknown, //!< Unknown error kNotFound, //!< The hostname is unknown kNoAddress, //!< The hostname is valid but has no IP address kUnsupported, //!< The hostname is valid but has no supported address kBadPort //!< The port is invalid }; XSocketAddress(EError, const String& hostname, int port) _NOEXCEPT; virtual ~XSocketAddress() _NOEXCEPT { } //! @name accessors //@{ //! Get the error code EError getError() const throw(); //! Get the hostname String getHostname() const throw(); //! Get the port int getPort() const throw(); //@} protected: // XBase overrides virtual String getWhat() const throw(); private: EError m_error; String m_hostname; int m_port; }; //! I/O closing exception /*! Thrown if a stream cannot be closed. */ XBASE_SUBCLASS_FORMAT(XSocketIOClose, XIOClose); //! Socket cannot bind address exception /*! Thrown when a socket cannot be bound to an address. */ XBASE_SUBCLASS_FORMAT(XSocketBind, XSocket); //! Socket address in use exception /*! Thrown when a socket cannot be bound to an address because the address is already in use. */ XBASE_SUBCLASS(XSocketAddressInUse, XSocketBind); //! Cannot connect socket exception /*! Thrown when a socket cannot connect to a remote endpoint. */ XBASE_SUBCLASS_FORMAT(XSocketConnect, XSocket); //! Cannot create socket exception /*! Thrown when a socket cannot be created (by the operating system). */ XBASE_SUBCLASS_FORMAT(XSocketCreate, XSocket); synergy-1.8.8-stable/src/lib/platform/000077500000000000000000000000001305627404700176715ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/platform/CMakeLists.txt000066400000000000000000000030251305627404700224310ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . if (WIN32) file(GLOB headers "MSWindows*.h") file(GLOB sources "MSWindows*.cpp") elseif (APPLE) file(GLOB headers "OSX*.h" "IOSX*.h") file(GLOB sources "OSX*.cpp" "IOSX*.cpp" "OSX*.m" "OSX*.mm") elseif (UNIX) file(GLOB headers "XWindows*.h") file(GLOB sources "XWindows*.cpp") endif() if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ../../../ext/gtest-1.6.0/include ) if (UNIX) include_directories( ../../.. ) endif() if (APPLE) list(APPEND inc /System/Library/Frameworks ) endif() include_directories(${inc}) add_library(platform STATIC ${sources}) target_link_libraries(platform client ${libs}) if (UNIX) target_link_libraries(platform io net ipc synergy client ${libs}) endif() if (APPLE) find_library(COCOA_LIBRARY Cocoa) target_link_libraries(platform ${COCOA_LIBRARY}) endif() synergy-1.8.8-stable/src/lib/platform/IMSWindowsClipboardFacade.h000066400000000000000000000021051305627404700247470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef IMWINDOWSCLIPBOARDFACADE #define IMWINDOWSCLIPBOARDFACADE #include "common/IInterface.h" #define WIN32_LEAN_AND_MEAN #include class IMSWindowsClipboardConverter; class IMSWindowsClipboardFacade : public IInterface { public: virtual void write(HANDLE win32Data, UINT win32Format) = 0; virtual ~IMSWindowsClipboardFacade() { } }; #endifsynergy-1.8.8-stable/src/lib/platform/IOSXKeyResource.cpp000066400000000000000000000074041305627404700233450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/IOSXKeyResource.h" #include KeyID IOSXKeyResource::getKeyID(UInt8 c) { if (c == 0) { return kKeyNone; } else if (c >= 32 && c < 127) { // ASCII return static_cast(c); } else { // handle special keys switch (c) { case 0x01: return kKeyHome; case 0x02: return kKeyKP_Enter; case 0x03: return kKeyKP_Enter; case 0x04: return kKeyEnd; case 0x05: return kKeyHelp; case 0x08: return kKeyBackSpace; case 0x09: return kKeyTab; case 0x0b: return kKeyPageUp; case 0x0c: return kKeyPageDown; case 0x0d: return kKeyReturn; case 0x10: // OS X maps all the function keys (F1, etc) to this one key. // we can't determine the right key here so we have to do it // some other way. return kKeyNone; case 0x1b: return kKeyEscape; case 0x1c: return kKeyLeft; case 0x1d: return kKeyRight; case 0x1e: return kKeyUp; case 0x1f: return kKeyDown; case 0x7f: return kKeyDelete; case 0x06: case 0x07: case 0x0a: case 0x0e: case 0x0f: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: case 0x18: case 0x19: case 0x1a: // discard other control characters return kKeyNone; default: // not special or unknown break; } // create string with character char str[2]; str[0] = static_cast(c); str[1] = 0; // get current keyboard script TISInputSourceRef isref = TISCopyCurrentKeyboardInputSource(); CFArrayRef langs = (CFArrayRef) TISGetInputSourceProperty(isref, kTISPropertyInputSourceLanguages); CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding( (CFStringRef)CFArrayGetValueAtIndex(langs, 0)); // convert to unicode CFStringRef cfString = CFStringCreateWithCStringNoCopy( kCFAllocatorDefault, str, encoding, kCFAllocatorNull); // sometimes CFStringCreate...() returns NULL (e.g. Apple Korean // encoding with char value 214). if it did then make no key, // otherwise CFStringCreateMutableCopy() will crash. if (cfString == NULL) { return kKeyNone; } // convert to precomposed CFMutableStringRef mcfString = CFStringCreateMutableCopy(kCFAllocatorDefault, 0, cfString); CFRelease(cfString); CFStringNormalize(mcfString, kCFStringNormalizationFormC); // check result int unicodeLength = CFStringGetLength(mcfString); if (unicodeLength == 0) { CFRelease(mcfString); return kKeyNone; } if (unicodeLength > 1) { // FIXME -- more than one character, we should handle this CFRelease(mcfString); return kKeyNone; } // get unicode character UniChar uc = CFStringGetCharacterAtIndex(mcfString, 0); CFRelease(mcfString); // convert to KeyID return static_cast(uc); } } KeyID IOSXKeyResource::unicharToKeyID(UniChar c) { switch (c) { case 3: return kKeyKP_Enter; case 8: return kKeyBackSpace; case 9: return kKeyTab; case 13: return kKeyReturn; case 27: return kKeyEscape; case 127: return kKeyDelete; default: if (c < 32) { return kKeyNone; } return static_cast(c); } } synergy-1.8.8-stable/src/lib/platform/IOSXKeyResource.h000066400000000000000000000024071305627404700230100ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/KeyState.h" class IOSXKeyResource : public IInterface { public: virtual bool isValid() const = 0; virtual UInt32 getNumModifierCombinations() const = 0; virtual UInt32 getNumTables() const = 0; virtual UInt32 getNumButtons() const = 0; virtual UInt32 getTableForModifier(UInt32 mask) const = 0; virtual KeyID getKey(UInt32 table, UInt32 button) const = 0; // Convert a character in the current script to the equivalent KeyID static KeyID getKeyID(UInt8); // Convert a unicode character to the equivalent KeyID. static KeyID unicharToKeyID(UniChar); }; synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboard.cpp000066400000000000000000000133521305627404700241130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsClipboard.h" #include "platform/MSWindowsClipboardTextConverter.h" #include "platform/MSWindowsClipboardUTF16Converter.h" #include "platform/MSWindowsClipboardBitmapConverter.h" #include "platform/MSWindowsClipboardHTMLConverter.h" #include "platform/MSWindowsClipboardFacade.h" #include "arch/win32/ArchMiscWindows.h" #include "base/Log.h" // // MSWindowsClipboard // UINT MSWindowsClipboard::s_ownershipFormat = 0; MSWindowsClipboard::MSWindowsClipboard(HWND window) : m_window(window), m_time(0), m_facade(new MSWindowsClipboardFacade()), m_deleteFacade(true) { // add converters, most desired first m_converters.push_back(new MSWindowsClipboardUTF16Converter); m_converters.push_back(new MSWindowsClipboardBitmapConverter); m_converters.push_back(new MSWindowsClipboardHTMLConverter); } MSWindowsClipboard::~MSWindowsClipboard() { clearConverters(); // dependency injection causes confusion over ownership, so we need // logic to decide whether or not we delete the facade. there must // be a more elegant way of doing this. if (m_deleteFacade) delete m_facade; } void MSWindowsClipboard::setFacade(IMSWindowsClipboardFacade& facade) { delete m_facade; m_facade = &facade; m_deleteFacade = false; } bool MSWindowsClipboard::emptyUnowned() { LOG((CLOG_DEBUG "empty clipboard")); // empty the clipboard (and take ownership) if (!EmptyClipboard()) { // unable to cause this in integ tests, but this error has never // actually been reported by users. LOG((CLOG_DEBUG "failed to grab clipboard")); return false; } return true; } bool MSWindowsClipboard::empty() { if (!emptyUnowned()) { return false; } // mark clipboard as being owned by synergy HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, 1); SetClipboardData(getOwnershipFormat(), data); return true; } void MSWindowsClipboard::add(EFormat format, const String& data) { LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format)); // convert data to win32 form for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) { IMSWindowsClipboardConverter* converter = *index; // skip converters for other formats if (converter->getFormat() == format) { HANDLE win32Data = converter->fromIClipboard(data); if (win32Data != NULL) { UINT win32Format = converter->getWin32Format(); m_facade->write(win32Data, win32Format); } } } } bool MSWindowsClipboard::open(Time time) const { LOG((CLOG_DEBUG "open clipboard")); if (!OpenClipboard(m_window)) { // unable to cause this in integ tests; but this can happen! // * http://symless.com/pm/issues/86 // * http://symless.com/pm/issues/1256 // logging improved to see if we can catch more info next time. LOG((CLOG_WARN "failed to open clipboard: %d", GetLastError())); return false; } m_time = time; return true; } void MSWindowsClipboard::close() const { LOG((CLOG_DEBUG "close clipboard")); CloseClipboard(); } IClipboard::Time MSWindowsClipboard::getTime() const { return m_time; } bool MSWindowsClipboard::has(EFormat format) const { for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) { IMSWindowsClipboardConverter* converter = *index; if (converter->getFormat() == format) { if (IsClipboardFormatAvailable(converter->getWin32Format())) { return true; } } } return false; } String MSWindowsClipboard::get(EFormat format) const { // find the converter for the first clipboard format we can handle IMSWindowsClipboardConverter* converter = NULL; for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) { converter = *index; if (converter->getFormat() == format) { break; } converter = NULL; } // if no converter then we don't recognize any formats if (converter == NULL) { LOG((CLOG_WARN "no converter for format %d", format)); return String(); } // get a handle to the clipboard data HANDLE win32Data = GetClipboardData(converter->getWin32Format()); if (win32Data == NULL) { // nb: can't cause this using integ tests; this is only caused when // the selected converter returns an invalid format -- which you // cannot cause using public functions. return String(); } // convert return converter->toIClipboard(win32Data); } void MSWindowsClipboard::clearConverters() { for (ConverterList::iterator index = m_converters.begin(); index != m_converters.end(); ++index) { delete *index; } m_converters.clear(); } bool MSWindowsClipboard::isOwnedBySynergy() { // create ownership format if we haven't yet if (s_ownershipFormat == 0) { s_ownershipFormat = RegisterClipboardFormat(TEXT("SynergyOwnership")); } return (IsClipboardFormatAvailable(getOwnershipFormat()) != 0); } UINT MSWindowsClipboard::getOwnershipFormat() { // create ownership format if we haven't yet if (s_ownershipFormat == 0) { s_ownershipFormat = RegisterClipboardFormat(TEXT("SynergyOwnership")); } // return the format return s_ownershipFormat; } synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboard.h000066400000000000000000000072111305627404700235550ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/MSWindowsClipboardFacade.h" #include "synergy/IClipboard.h" #include "common/stdvector.h" #define WIN32_LEAN_AND_MEAN #include class IMSWindowsClipboardConverter; class IMSWindowsClipboardFacade; //! Microsoft windows clipboard implementation class MSWindowsClipboard : public IClipboard { public: MSWindowsClipboard(HWND window); MSWindowsClipboard(HWND window, IMSWindowsClipboardFacade &facade); virtual ~MSWindowsClipboard(); //! Empty clipboard without ownership /*! Take ownership of the clipboard and clear all data from it. This must be called between a successful open() and close(). Return false if the clipboard ownership could not be taken; the clipboard should not be emptied in this case. Unlike empty(), isOwnedBySynergy() will return false when emptied this way. This is useful when synergy wants to put data on clipboard but pretend (to itself) that some other app did it. When using empty(), synergy assumes the data came from the server and doesn't need to be sent back. emptyUnowned() makes synergy send the data to the server. */ bool emptyUnowned(); //! Test if clipboard is owned by synergy static bool isOwnedBySynergy(); // IClipboard overrides virtual bool empty(); virtual void add(EFormat, const String& data); virtual bool open(Time) const; virtual void close() const; virtual Time getTime() const; virtual bool has(EFormat) const; virtual String get(EFormat) const; void setFacade(IMSWindowsClipboardFacade& facade); private: void clearConverters(); UINT convertFormatToWin32(EFormat) const; HANDLE convertTextToWin32(const String& data) const; String convertTextFromWin32(HANDLE) const; static UINT getOwnershipFormat(); private: typedef std::vector ConverterList; HWND m_window; mutable Time m_time; ConverterList m_converters; static UINT s_ownershipFormat; IMSWindowsClipboardFacade* m_facade; bool m_deleteFacade; }; //! Clipboard format converter interface /*! This interface defines the methods common to all win32 clipboard format converters. */ class IMSWindowsClipboardConverter : public IInterface { public: // accessors // return the clipboard format this object converts from/to virtual IClipboard::EFormat getFormat() const = 0; // return the atom representing the win32 clipboard format that // this object converts from/to virtual UINT getWin32Format() const = 0; // convert from the IClipboard format to the win32 clipboard format. // the input data must be in the IClipboard format returned by // getFormat(). the return data will be in the win32 clipboard // format returned by getWin32Format(), allocated by GlobalAlloc(). virtual HANDLE fromIClipboard(const String&) const = 0; // convert from the win32 clipboard format to the IClipboard format // (i.e., the reverse of fromIClipboard()). virtual String toIClipboard(HANDLE data) const = 0; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardAnyTextConverter.cpp000066400000000000000000000065651305627404700273300ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsClipboardAnyTextConverter.h" // // MSWindowsClipboardAnyTextConverter // MSWindowsClipboardAnyTextConverter::MSWindowsClipboardAnyTextConverter() { // do nothing } MSWindowsClipboardAnyTextConverter::~MSWindowsClipboardAnyTextConverter() { // do nothing } IClipboard::EFormat MSWindowsClipboardAnyTextConverter::getFormat() const { return IClipboard::kText; } HANDLE MSWindowsClipboardAnyTextConverter::fromIClipboard(const String& data) const { // convert linefeeds and then convert to desired encoding String text = doFromIClipboard(convertLinefeedToWin32(data)); UInt32 size = (UInt32)text.size(); // copy to memory handle HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, size); if (gData != NULL) { // get a pointer to the allocated memory char* dst = (char*)GlobalLock(gData); if (dst != NULL) { memcpy(dst, text.data(), size); GlobalUnlock(gData); } else { GlobalFree(gData); gData = NULL; } } return gData; } String MSWindowsClipboardAnyTextConverter::toIClipboard(HANDLE data) const { // get datator const char* src = (const char*)GlobalLock(data); UInt32 srcSize = (UInt32)GlobalSize(data); if (src == NULL || srcSize <= 1) { return String(); } // convert text String text = doToIClipboard(String(src, srcSize)); // release handle GlobalUnlock(data); // convert newlines return convertLinefeedToUnix(text); } String MSWindowsClipboardAnyTextConverter::convertLinefeedToWin32( const String& src) const { // note -- we assume src is a valid UTF-8 string // count newlines in string UInt32 numNewlines = 0; UInt32 n = (UInt32)src.size(); for (const char* scan = src.c_str(); n > 0; ++scan, --n) { if (*scan == '\n') { ++numNewlines; } } if (numNewlines == 0) { return src; } // allocate new string String dst; dst.reserve(src.size() + numNewlines); // copy string, converting newlines n = (UInt32)src.size(); for (const char* scan = src.c_str(); n > 0; ++scan, --n) { if (scan[0] == '\n') { dst += '\r'; } dst += scan[0]; } return dst; } String MSWindowsClipboardAnyTextConverter::convertLinefeedToUnix( const String& src) const { // count newlines in string UInt32 numNewlines = 0; UInt32 n = (UInt32)src.size(); for (const char* scan = src.c_str(); n > 0; ++scan, --n) { if (scan[0] == '\r' && scan[1] == '\n') { ++numNewlines; } } if (numNewlines == 0) { return src; } // allocate new string String dst; dst.reserve(src.size()); // copy string, converting newlines n = (UInt32)src.size(); for (const char* scan = src.c_str(); n > 0; ++scan, --n) { if (scan[0] != '\r' || scan[1] != '\n') { dst += scan[0]; } } return dst; } synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardAnyTextConverter.h000066400000000000000000000035721305627404700267700ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/MSWindowsClipboard.h" //! Convert to/from some text encoding class MSWindowsClipboardAnyTextConverter : public IMSWindowsClipboardConverter { public: MSWindowsClipboardAnyTextConverter(); virtual ~MSWindowsClipboardAnyTextConverter(); // IMSWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual UINT getWin32Format() const = 0; virtual HANDLE fromIClipboard(const String&) const; virtual String toIClipboard(HANDLE) const; protected: //! Convert from IClipboard format /*! Do UTF-8 conversion only. Memory handle allocation and linefeed conversion is done by this class. doFromIClipboard() must include the nul terminator in the returned string (not including the String's nul terminator). */ virtual String doFromIClipboard(const String&) const = 0; //! Convert to IClipboard format /*! Do UTF-8 conversion only. Memory handle allocation and linefeed conversion is done by this class. */ virtual String doToIClipboard(const String&) const = 0; private: String convertLinefeedToWin32(const String&) const; String convertLinefeedToUnix(const String&) const; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardBitmapConverter.cpp000066400000000000000000000102551305627404700271370ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsClipboardBitmapConverter.h" #include "base/Log.h" // // MSWindowsClipboardBitmapConverter // MSWindowsClipboardBitmapConverter::MSWindowsClipboardBitmapConverter() { // do nothing } MSWindowsClipboardBitmapConverter::~MSWindowsClipboardBitmapConverter() { // do nothing } IClipboard::EFormat MSWindowsClipboardBitmapConverter::getFormat() const { return IClipboard::kBitmap; } UINT MSWindowsClipboardBitmapConverter::getWin32Format() const { return CF_DIB; } HANDLE MSWindowsClipboardBitmapConverter::fromIClipboard(const String& data) const { // copy to memory handle HGLOBAL gData = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, data.size()); if (gData != NULL) { // get a pointer to the allocated memory char* dst = (char*)GlobalLock(gData); if (dst != NULL) { memcpy(dst, data.data(), data.size()); GlobalUnlock(gData); } else { GlobalFree(gData); gData = NULL; } } return gData; } String MSWindowsClipboardBitmapConverter::toIClipboard(HANDLE data) const { // get datator LPVOID src = GlobalLock(data); if (src == NULL) { return String(); } UInt32 srcSize = (UInt32)GlobalSize(data); // check image type const BITMAPINFO* bitmap = static_cast(src); LOG((CLOG_INFO "bitmap: %dx%d %d", bitmap->bmiHeader.biWidth, bitmap->bmiHeader.biHeight, (int)bitmap->bmiHeader.biBitCount)); if (bitmap->bmiHeader.biPlanes == 1 && (bitmap->bmiHeader.biBitCount == 24 || bitmap->bmiHeader.biBitCount == 32) && bitmap->bmiHeader.biCompression == BI_RGB) { // already in canonical form String image(static_cast(src), srcSize); GlobalUnlock(data); return image; } // create a destination DIB section LOG((CLOG_INFO "convert image from: depth=%d comp=%d", bitmap->bmiHeader.biBitCount, bitmap->bmiHeader.biCompression)); void* raw; BITMAPINFOHEADER info; LONG w = bitmap->bmiHeader.biWidth; LONG h = bitmap->bmiHeader.biHeight; info.biSize = sizeof(BITMAPINFOHEADER); info.biWidth = w; info.biHeight = h; info.biPlanes = 1; info.biBitCount = 32; info.biCompression = BI_RGB; info.biSizeImage = 0; info.biXPelsPerMeter = 1000; info.biYPelsPerMeter = 1000; info.biClrUsed = 0; info.biClrImportant = 0; HDC dc = GetDC(NULL); HBITMAP dst = CreateDIBSection(dc, (BITMAPINFO*)&info, DIB_RGB_COLORS, &raw, NULL, 0); // find the start of the pixel data const char* srcBits = (const char*)bitmap + bitmap->bmiHeader.biSize; if (bitmap->bmiHeader.biBitCount >= 16) { if (bitmap->bmiHeader.biCompression == BI_BITFIELDS && (bitmap->bmiHeader.biBitCount == 16 || bitmap->bmiHeader.biBitCount == 32)) { srcBits += 3 * sizeof(DWORD); } } else if (bitmap->bmiHeader.biClrUsed != 0) { srcBits += bitmap->bmiHeader.biClrUsed * sizeof(RGBQUAD); } else { //http://msdn.microsoft.com/en-us/library/ke55d167(VS.80).aspx srcBits += (1i64 << bitmap->bmiHeader.biBitCount) * sizeof(RGBQUAD); } // copy source image to destination image HDC dstDC = CreateCompatibleDC(dc); HGDIOBJ oldBitmap = SelectObject(dstDC, dst); SetDIBitsToDevice(dstDC, 0, 0, w, h, 0, 0, 0, h, srcBits, bitmap, DIB_RGB_COLORS); SelectObject(dstDC, oldBitmap); DeleteDC(dstDC); GdiFlush(); // extract data String image((const char*)&info, info.biSize); image.append((const char*)raw, 4 * w * h); // clean up GDI DeleteObject(dst); ReleaseDC(NULL, dc); // release handle GlobalUnlock(data); return image; } synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardBitmapConverter.h000066400000000000000000000023331305627404700266020ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/MSWindowsClipboard.h" //! Convert to/from some text encoding class MSWindowsClipboardBitmapConverter : public IMSWindowsClipboardConverter { public: MSWindowsClipboardBitmapConverter(); virtual ~MSWindowsClipboardBitmapConverter(); // IMSWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual UINT getWin32Format() const; virtual HANDLE fromIClipboard(const String&) const; virtual String toIClipboard(HANDLE) const; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardFacade.cpp000066400000000000000000000021131305627404700251700ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsClipboardFacade.h" #include "platform/MSWindowsClipboard.h" void MSWindowsClipboardFacade::write(HANDLE win32Data, UINT win32Format) { if (SetClipboardData(win32Format, win32Data) == NULL) { // free converted data if we couldn't put it on // the clipboard. // nb: couldn't cause this in integ tests. GlobalFree(win32Data); } } synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardFacade.h000066400000000000000000000017041305627404700246420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/IMSWindowsClipboardFacade.h" #include "synergy/IClipboard.h" class MSWindowsClipboardFacade : public IMSWindowsClipboardFacade { public: virtual void write(HANDLE win32Data, UINT win32Format); }; synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardHTMLConverter.cpp000066400000000000000000000064761305627404700265010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsClipboardHTMLConverter.h" #include "base/String.h" // // MSWindowsClipboardHTMLConverter // MSWindowsClipboardHTMLConverter::MSWindowsClipboardHTMLConverter() { m_format = RegisterClipboardFormat("HTML Format"); } MSWindowsClipboardHTMLConverter::~MSWindowsClipboardHTMLConverter() { // do nothing } IClipboard::EFormat MSWindowsClipboardHTMLConverter::getFormat() const { return IClipboard::kHTML; } UINT MSWindowsClipboardHTMLConverter::getWin32Format() const { return m_format; } String MSWindowsClipboardHTMLConverter::doFromIClipboard(const String& data) const { // prepare to CF_HTML format prefix and suffix String prefix("Version:0.9\r\nStartHTML:0000000105\r\n" "EndHTML:ZZZZZZZZZZ\r\n" "StartFragment:XXXXXXXXXX\r\nEndFragment:YYYYYYYYYY\r\n" ""); String suffix("\r\n"); // Get byte offsets for header UInt32 StartFragment = (UInt32)prefix.size(); UInt32 EndFragment = StartFragment + (UInt32)data.size(); // StartHTML is constant by the design of the prefix UInt32 EndHTML = EndFragment + (UInt32)suffix.size(); prefix.replace(prefix.find("XXXXXXXXXX"), 10, synergy::string::sprintf("%010u", StartFragment)); prefix.replace(prefix.find("YYYYYYYYYY"), 10, synergy::string::sprintf("%010u", EndFragment)); prefix.replace(prefix.find("ZZZZZZZZZZ"), 10, synergy::string::sprintf("%010u", EndHTML)); // concatenate prefix += data; prefix += suffix; return prefix; } String MSWindowsClipboardHTMLConverter::doToIClipboard(const String& data) const { // get fragment start/end args String startArg = findArg(data, "StartFragment"); String endArg = findArg(data, "EndFragment"); if (startArg.empty() || endArg.empty()) { return String(); } // convert args to integers SInt32 start = (SInt32)atoi(startArg.c_str()); SInt32 end = (SInt32)atoi(endArg.c_str()); if (start <= 0 || end <= 0 || start >= end) { return String(); } // extract the fragment return data.substr(start, end - start); } String MSWindowsClipboardHTMLConverter::findArg( const String& data, const String& name) const { String::size_type i = data.find(name); if (i == String::npos) { return String(); } i = data.find_first_of(":\r\n", i); if (i == String::npos || data[i] != ':') { return String(); } i = data.find_first_of("0123456789\r\n", i + 1); if (i == String::npos || data[i] == '\r' || data[i] == '\n') { return String(); } String::size_type j = data.find_first_not_of("0123456789", i); if (j == String::npos) { j = data.size(); } return data.substr(i, j - i); } synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardHTMLConverter.h000066400000000000000000000026271305627404700261400ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/MSWindowsClipboardAnyTextConverter.h" //! Convert to/from HTML encoding class MSWindowsClipboardHTMLConverter : public MSWindowsClipboardAnyTextConverter { public: MSWindowsClipboardHTMLConverter(); virtual ~MSWindowsClipboardHTMLConverter(); // IMSWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual UINT getWin32Format() const; protected: // MSWindowsClipboardAnyTextConverter overrides virtual String doFromIClipboard(const String&) const; virtual String doToIClipboard(const String&) const; private: String findArg(const String& data, const String& name) const; private: UINT m_format; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardTextConverter.cpp000066400000000000000000000030311305627404700266410ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsClipboardTextConverter.h" #include "base/Unicode.h" // // MSWindowsClipboardTextConverter // MSWindowsClipboardTextConverter::MSWindowsClipboardTextConverter() { // do nothing } MSWindowsClipboardTextConverter::~MSWindowsClipboardTextConverter() { // do nothing } UINT MSWindowsClipboardTextConverter::getWin32Format() const { return CF_TEXT; } String MSWindowsClipboardTextConverter::doFromIClipboard(const String& data) const { // convert and add nul terminator return Unicode::UTF8ToText(data) += '\0'; } String MSWindowsClipboardTextConverter::doToIClipboard(const String& data) const { // convert and truncate at first nul terminator String dst = Unicode::textToUTF8(data); String::size_type n = dst.find('\0'); if (n != String::npos) { dst.erase(n); } return dst; } synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardTextConverter.h000066400000000000000000000023771305627404700263220ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/MSWindowsClipboardAnyTextConverter.h" //! Convert to/from locale text encoding class MSWindowsClipboardTextConverter : public MSWindowsClipboardAnyTextConverter { public: MSWindowsClipboardTextConverter(); virtual ~MSWindowsClipboardTextConverter(); // IMSWindowsClipboardConverter overrides virtual UINT getWin32Format() const; protected: // MSWindowsClipboardAnyTextConverter overrides virtual String doFromIClipboard(const String&) const; virtual String doToIClipboard(const String&) const; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardUTF16Converter.cpp000066400000000000000000000030621305627404700265260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsClipboardUTF16Converter.h" #include "base/Unicode.h" // // MSWindowsClipboardUTF16Converter // MSWindowsClipboardUTF16Converter::MSWindowsClipboardUTF16Converter() { // do nothing } MSWindowsClipboardUTF16Converter::~MSWindowsClipboardUTF16Converter() { // do nothing } UINT MSWindowsClipboardUTF16Converter::getWin32Format() const { return CF_UNICODETEXT; } String MSWindowsClipboardUTF16Converter::doFromIClipboard(const String& data) const { // convert and add nul terminator return Unicode::UTF8ToUTF16(data).append(sizeof(wchar_t), 0); } String MSWindowsClipboardUTF16Converter::doToIClipboard(const String& data) const { // convert and strip nul terminator String dst = Unicode::UTF16ToUTF8(data); String::size_type n = dst.find('\0'); if (n != String::npos) { dst.erase(n); } return dst; } synergy-1.8.8-stable/src/lib/platform/MSWindowsClipboardUTF16Converter.h000066400000000000000000000023751305627404700262010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/MSWindowsClipboardAnyTextConverter.h" //! Convert to/from UTF-16 encoding class MSWindowsClipboardUTF16Converter : public MSWindowsClipboardAnyTextConverter { public: MSWindowsClipboardUTF16Converter(); virtual ~MSWindowsClipboardUTF16Converter(); // IMSWindowsClipboardConverter overrides virtual UINT getWin32Format() const; protected: // MSWindowsClipboardAnyTextConverter overrides virtual String doFromIClipboard(const String&) const; virtual String doToIClipboard(const String&) const; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsDebugOutputter.cpp000066400000000000000000000024221305627404700251720ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsDebugOutputter.h" #define WIN32_LEAN_AND_MEAN #include #include MSWindowsDebugOutputter::MSWindowsDebugOutputter() { } MSWindowsDebugOutputter::~MSWindowsDebugOutputter() { } void MSWindowsDebugOutputter::open(const char* title) { } void MSWindowsDebugOutputter::close() { } void MSWindowsDebugOutputter::show(bool showIfEmpty) { } bool MSWindowsDebugOutputter::write(ELevel level, const char* msg) { OutputDebugString((std::string(msg) + "\n").c_str()); return true; } void MSWindowsDebugOutputter::flush() { } synergy-1.8.8-stable/src/lib/platform/MSWindowsDebugOutputter.h000066400000000000000000000023471305627404700246450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/ILogOutputter.h" //! Write log to debugger /*! This outputter writes output to the debugger. In Visual Studio, this can be seen in the Output window. */ class MSWindowsDebugOutputter : public ILogOutputter { public: MSWindowsDebugOutputter(); virtual ~MSWindowsDebugOutputter(); // ILogOutputter overrides virtual void open(const char* title); virtual void close(); virtual void show(bool showIfEmpty); virtual bool write(ELevel level, const char* message); virtual void flush(); }; synergy-1.8.8-stable/src/lib/platform/MSWindowsDesks.cpp000066400000000000000000000622321305627404700232660ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsDesks.h" #include "synwinhk/synwinhk.h" #include "platform/MSWindowsScreen.h" #include "synergy/IScreenSaver.h" #include "synergy/XScreen.h" #include "mt/Lock.h" #include "mt/Thread.h" #include "arch/win32/ArchMiscWindows.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "base/IJob.h" #include "base/TMethodEventJob.h" #include "base/TMethodJob.h" #include "base/IEventQueue.h" #include // these are only defined when WINVER >= 0x0500 #if !defined(SPI_GETMOUSESPEED) #define SPI_GETMOUSESPEED 112 #endif #if !defined(SPI_SETMOUSESPEED) #define SPI_SETMOUSESPEED 113 #endif #if !defined(SPI_GETSCREENSAVERRUNNING) #define SPI_GETSCREENSAVERRUNNING 114 #endif // 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 0x0080 #define MOUSEEVENTF_XUP 0x0100 #define XBUTTON1 0x0001 #define XBUTTON2 0x0002 #endif #if !defined(VK_XBUTTON1) #define VK_XBUTTON1 0x05 #define VK_XBUTTON2 0x06 #endif // ; #define SYNERGY_MSG_SWITCH SYNERGY_HOOK_LAST_MSG + 1 // ; #define SYNERGY_MSG_ENTER SYNERGY_HOOK_LAST_MSG + 2 // ; #define SYNERGY_MSG_LEAVE SYNERGY_HOOK_LAST_MSG + 3 // wParam = flags, HIBYTE(lParam) = virtual key, LOBYTE(lParam) = scan code #define SYNERGY_MSG_FAKE_KEY SYNERGY_HOOK_LAST_MSG + 4 // flags, XBUTTON id #define SYNERGY_MSG_FAKE_BUTTON SYNERGY_HOOK_LAST_MSG + 5 // x; y #define SYNERGY_MSG_FAKE_MOVE SYNERGY_HOOK_LAST_MSG + 6 // xDelta; yDelta #define SYNERGY_MSG_FAKE_WHEEL SYNERGY_HOOK_LAST_MSG + 7 // POINT*; #define SYNERGY_MSG_CURSOR_POS SYNERGY_HOOK_LAST_MSG + 8 // IKeyState*; #define SYNERGY_MSG_SYNC_KEYS SYNERGY_HOOK_LAST_MSG + 9 // install; #define SYNERGY_MSG_SCREENSAVER SYNERGY_HOOK_LAST_MSG + 10 // dx; dy #define SYNERGY_MSG_FAKE_REL_MOVE SYNERGY_HOOK_LAST_MSG + 11 // enable; #define SYNERGY_MSG_FAKE_INPUT SYNERGY_HOOK_LAST_MSG + 12 // // MSWindowsDesks // MSWindowsDesks::MSWindowsDesks( bool isPrimary, bool noHooks, HINSTANCE hookLibrary, const IScreenSaver* screensaver, IEventQueue* events, IJob* updateKeys, bool stopOnDeskSwitch) : m_isPrimary(isPrimary), m_noHooks(noHooks), m_isOnScreen(m_isPrimary), m_x(0), m_y(0), m_w(0), m_h(0), m_xCenter(0), m_yCenter(0), m_multimon(false), m_timer(NULL), m_screensaver(screensaver), m_screensaverNotify(false), m_activeDesk(NULL), m_activeDeskName(), m_mutex(), m_deskReady(&m_mutex, false), m_updateKeys(updateKeys), m_events(events), m_stopOnDeskSwitch(stopOnDeskSwitch) { if (hookLibrary != NULL) queryHookLibrary(hookLibrary); m_cursor = createBlankCursor(); m_deskClass = createDeskWindowClass(m_isPrimary); m_keyLayout = GetKeyboardLayout(GetCurrentThreadId()); resetOptions(); } MSWindowsDesks::~MSWindowsDesks() { disable(); destroyClass(m_deskClass); destroyCursor(m_cursor); delete m_updateKeys; } void MSWindowsDesks::enable() { m_threadID = GetCurrentThreadId(); // set the active desk and (re)install the hooks checkDesk(); // install the desk timer. this timer periodically checks // which desk is active and reinstalls the hooks as necessary. // we wouldn't need this if windows notified us of a desktop // change but as far as i can tell it doesn't. m_timer = m_events->newTimer(0.2, NULL); m_events->adoptHandler(Event::kTimer, m_timer, new TMethodEventJob( this, &MSWindowsDesks::handleCheckDesk)); updateKeys(); } void MSWindowsDesks::disable() { // remove timer if (m_timer != NULL) { m_events->removeHandler(Event::kTimer, m_timer); m_events->deleteTimer(m_timer); m_timer = NULL; } // destroy desks removeDesks(); m_isOnScreen = m_isPrimary; } void MSWindowsDesks::enter() { sendMessage(SYNERGY_MSG_ENTER, 0, 0); } void MSWindowsDesks::leave(HKL keyLayout) { sendMessage(SYNERGY_MSG_LEAVE, (WPARAM)keyLayout, 0); } void MSWindowsDesks::resetOptions() { m_leaveForegroundOption = false; } void MSWindowsDesks::setOptions(const OptionsList& options) { for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { if (options[i] == kOptionWin32KeepForeground) { m_leaveForegroundOption = (options[i + 1] != 0); LOG((CLOG_DEBUG1 "%s the foreground window", m_leaveForegroundOption ? "don\'t grab" : "grab")); } } } void MSWindowsDesks::updateKeys() { sendMessage(SYNERGY_MSG_SYNC_KEYS, 0, 0); } void MSWindowsDesks::setShape(SInt32 x, SInt32 y, SInt32 width, SInt32 height, SInt32 xCenter, SInt32 yCenter, bool isMultimon) { m_x = x; m_y = y; m_w = width; m_h = height; m_xCenter = xCenter; m_yCenter = yCenter; m_multimon = isMultimon; } void MSWindowsDesks::installScreensaverHooks(bool install) { if (m_isPrimary && m_screensaverNotify != install) { m_screensaverNotify = install; sendMessage(SYNERGY_MSG_SCREENSAVER, install, 0); } } void MSWindowsDesks::fakeInputBegin() { sendMessage(SYNERGY_MSG_FAKE_INPUT, 1, 0); } void MSWindowsDesks::fakeInputEnd() { sendMessage(SYNERGY_MSG_FAKE_INPUT, 0, 0); } void MSWindowsDesks::getCursorPos(SInt32& x, SInt32& y) const { POINT pos; sendMessage(SYNERGY_MSG_CURSOR_POS, reinterpret_cast(&pos), 0); x = pos.x; y = pos.y; } void MSWindowsDesks::fakeKeyEvent( KeyButton button, UINT virtualKey, bool press, bool /*isAutoRepeat*/) const { // synthesize event DWORD flags = 0; if (((button & 0x100u) != 0)) { flags |= KEYEVENTF_EXTENDEDKEY; } if (!press) { flags |= KEYEVENTF_KEYUP; } sendMessage(SYNERGY_MSG_FAKE_KEY, flags, MAKEWORD(static_cast(button & 0xffu), static_cast(virtualKey & 0xffu))); } void MSWindowsDesks::fakeMouseButton(ButtonID button, bool press) { // the system will swap the meaning of left/right for us if // the user has configured a left-handed mouse but we don't // want it to swap since we want the handedness of the // server's mouse. so pre-swap for a left-handed mouse. if (GetSystemMetrics(SM_SWAPBUTTON)) { switch (button) { case kButtonLeft: button = kButtonRight; break; case kButtonRight: button = kButtonLeft; break; } } // map button id to button flag and button data DWORD data = 0; DWORD flags; switch (button) { case kButtonLeft: flags = press ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; break; case kButtonMiddle: flags = press ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP; break; case kButtonRight: flags = press ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; break; case kButtonExtra0 + 0: data = XBUTTON1; flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; break; case kButtonExtra0 + 1: data = XBUTTON2; flags = press ? MOUSEEVENTF_XDOWN : MOUSEEVENTF_XUP; break; default: return; } // do it sendMessage(SYNERGY_MSG_FAKE_BUTTON, flags, data); } void MSWindowsDesks::fakeMouseMove(SInt32 x, SInt32 y) const { sendMessage(SYNERGY_MSG_FAKE_MOVE, static_cast(x), static_cast(y)); } void MSWindowsDesks::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const { sendMessage(SYNERGY_MSG_FAKE_REL_MOVE, static_cast(dx), static_cast(dy)); } void MSWindowsDesks::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const { sendMessage(SYNERGY_MSG_FAKE_WHEEL, xDelta, yDelta); } void MSWindowsDesks::sendMessage(UINT msg, WPARAM wParam, LPARAM lParam) const { if (m_activeDesk != NULL && m_activeDesk->m_window != NULL) { PostThreadMessage(m_activeDesk->m_threadID, msg, wParam, lParam); waitForDesk(); } } void MSWindowsDesks::queryHookLibrary(HINSTANCE hookLibrary) { // look up functions if (m_isPrimary && !m_noHooks) { m_install = (InstallFunc)GetProcAddress(hookLibrary, "install"); m_uninstall = (UninstallFunc)GetProcAddress(hookLibrary, "uninstall"); m_installScreensaver = (InstallScreenSaverFunc)GetProcAddress( hookLibrary, "installScreenSaver"); m_uninstallScreensaver = (UninstallScreenSaverFunc)GetProcAddress( hookLibrary, "uninstallScreenSaver"); if (m_install == NULL || m_uninstall == NULL || m_installScreensaver == NULL || m_uninstallScreensaver == NULL) { LOG((CLOG_ERR "Invalid hook library")); throw XScreenOpenFailure(); } } else { m_install = NULL; m_uninstall = NULL; m_installScreensaver = NULL; m_uninstallScreensaver = NULL; } } HCURSOR MSWindowsDesks::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(MSWindowsScreen::getWindowInstance(), 0, 0, cw, ch, cursorAND, cursorXOR); delete[] cursorXOR; delete[] cursorAND; return c; } void MSWindowsDesks::destroyCursor(HCURSOR cursor) const { if (cursor != NULL) { DestroyCursor(cursor); } } ATOM MSWindowsDesks::createDeskWindowClass(bool isPrimary) const { WNDCLASSEX classInfo; classInfo.cbSize = sizeof(classInfo); classInfo.style = CS_DBLCLKS | CS_NOCLOSE; classInfo.lpfnWndProc = isPrimary ? &MSWindowsDesks::primaryDeskProc : &MSWindowsDesks::secondaryDeskProc; classInfo.cbClsExtra = 0; classInfo.cbWndExtra = 0; classInfo.hInstance = MSWindowsScreen::getWindowInstance(); classInfo.hIcon = NULL; classInfo.hCursor = m_cursor; classInfo.hbrBackground = NULL; classInfo.lpszMenuName = NULL; classInfo.lpszClassName = "SynergyDesk"; classInfo.hIconSm = NULL; return RegisterClassEx(&classInfo); } void MSWindowsDesks::destroyClass(ATOM windowClass) const { if (windowClass != 0) { UnregisterClass(reinterpret_cast(windowClass), MSWindowsScreen::getWindowInstance()); } } HWND MSWindowsDesks::createWindow(ATOM windowClass, const char* name) const { HWND window = CreateWindowEx(WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW, reinterpret_cast(windowClass), name, WS_POPUP, 0, 0, 1, 1, NULL, NULL, MSWindowsScreen::getWindowInstance(), NULL); if (window == NULL) { LOG((CLOG_ERR "failed to create window: %d", GetLastError())); throw XScreenOpenFailure(); } return window; } void MSWindowsDesks::destroyWindow(HWND hwnd) const { if (hwnd != NULL) { DestroyWindow(hwnd); } } LRESULT CALLBACK MSWindowsDesks::primaryDeskProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hwnd, msg, wParam, lParam); } LRESULT CALLBACK MSWindowsDesks::secondaryDeskProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { // would like to detect any local user input and hide the hider // window but for now we just detect mouse motion. bool hide = false; switch (msg) { case WM_MOUSEMOVE: if (LOWORD(lParam) != 0 || HIWORD(lParam) != 0) { hide = true; } break; } if (hide && IsWindowVisible(hwnd)) { ReleaseCapture(); SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW); } return DefWindowProc(hwnd, msg, wParam, lParam); } void MSWindowsDesks::deskMouseMove(SInt32 x, SInt32 y) const { // when using absolute positioning with mouse_event(), // the normalized device coordinates range over only // the primary screen. SInt32 w = GetSystemMetrics(SM_CXSCREEN); SInt32 h = GetSystemMetrics(SM_CYSCREEN); mouse_event(MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, (DWORD)((65535.0f * x) / (w - 1) + 0.5f), (DWORD)((65535.0f * y) / (h - 1) + 0.5f), 0, 0); } void MSWindowsDesks::deskMouseRelativeMove(SInt32 dx, SInt32 dy) const { // relative moves are subject to cursor acceleration which we don't // want.so we disable acceleration, do the relative move, then // restore acceleration. there's a slight chance we'll end up in // the wrong place if the user moves the cursor using this system's // mouse while simultaneously moving the mouse on the server // system. that defeats the purpose of synergy so we'll assume // that won't happen. even if it does, the next mouse move will // correct the position. // save mouse speed & acceleration int oldSpeed[4]; bool accelChanged = SystemParametersInfo(SPI_GETMOUSE,0, oldSpeed, 0) && SystemParametersInfo(SPI_GETMOUSESPEED, 0, oldSpeed + 3, 0); // use 1:1 motion if (accelChanged) { int newSpeed[4] = { 0, 0, 0, 1 }; accelChanged = SystemParametersInfo(SPI_SETMOUSE, 0, newSpeed, 0) || SystemParametersInfo(SPI_SETMOUSESPEED, 0, newSpeed + 3, 0); } // move relative to mouse position mouse_event(MOUSEEVENTF_MOVE, dx, dy, 0, 0); // restore mouse speed & acceleration if (accelChanged) { SystemParametersInfo(SPI_SETMOUSE, 0, oldSpeed, 0); SystemParametersInfo(SPI_SETMOUSESPEED, 0, oldSpeed + 3, 0); } } void MSWindowsDesks::deskEnter(Desk* desk) { if (!m_isPrimary) { ReleaseCapture(); } ShowCursor(TRUE); SetWindowPos(desk->m_window, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_HIDEWINDOW); // restore the foreground window // XXX -- this raises the window to the top of the Z-order. we // want it to stay wherever it was to properly support X-mouse // (mouse over activation) but i've no idea how to do that. // the obvious workaround of using SetWindowPos() to move it back // after being raised doesn't work. DWORD thisThread = GetWindowThreadProcessId(desk->m_window, NULL); DWORD thatThread = GetWindowThreadProcessId(desk->m_foregroundWindow, NULL); AttachThreadInput(thatThread, thisThread, TRUE); SetForegroundWindow(desk->m_foregroundWindow); AttachThreadInput(thatThread, thisThread, FALSE); EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE); desk->m_foregroundWindow = NULL; } void MSWindowsDesks::deskLeave(Desk* desk, HKL keyLayout) { ShowCursor(FALSE); if (m_isPrimary) { // map a window to hide the cursor and to use whatever keyboard // layout we choose rather than the keyboard layout of the last // active window. int x, y, w, h; if (desk->m_lowLevel) { // with a low level hook the cursor will never budge so // just a 1x1 window is sufficient. x = m_xCenter; y = m_yCenter; w = 1; h = 1; } else { // with regular hooks the cursor will jitter as it's moved // by the user then back to the center by us. to be sure // we never lose it, cover all the monitors with the window. x = m_x; y = m_y; w = m_w; h = m_h; } SetWindowPos(desk->m_window, HWND_TOP, x, y, w, h, SWP_NOACTIVATE | SWP_SHOWWINDOW); // if not using low-level hooks we have to also activate the // window to ensure we don't lose keyboard focus. // FIXME -- see if this can be avoided. if so then always // disable the window (see handling of SYNERGY_MSG_SWITCH). if (!desk->m_lowLevel) { SetActiveWindow(desk->m_window); } // if using low-level hooks then disable the foreground window // so it can't mess up any of our keyboard events. the console // program, for example, will cause characters to be reported as // unshifted, regardless of the shift key state. interestingly // we do see the shift key go down and up. // // note that we must enable the window to activate it and we // need to disable the window on deskEnter. else { desk->m_foregroundWindow = getForegroundWindow(); if (desk->m_foregroundWindow != NULL) { EnableWindow(desk->m_window, TRUE); SetActiveWindow(desk->m_window); DWORD thisThread = GetWindowThreadProcessId(desk->m_window, NULL); DWORD thatThread = GetWindowThreadProcessId(desk->m_foregroundWindow, NULL); AttachThreadInput(thatThread, thisThread, TRUE); SetForegroundWindow(desk->m_window); AttachThreadInput(thatThread, thisThread, FALSE); } } // switch to requested keyboard layout ActivateKeyboardLayout(keyLayout, 0); } else { // move hider window under the cursor center, raise, and show it SetWindowPos(desk->m_window, HWND_TOP, m_xCenter, m_yCenter, 1, 1, SWP_NOACTIVATE | SWP_SHOWWINDOW); // watch for mouse motion. if we see any then we hide the // hider window so the user can use the physically attached // mouse if desired. we'd rather not capture the mouse but // we aren't notified when the mouse leaves our window. SetCapture(desk->m_window); // warp the mouse to the cursor center LOG((CLOG_DEBUG2 "warping cursor to center: %+d,%+d", m_xCenter, m_yCenter)); deskMouseMove(m_xCenter, m_yCenter); } } void MSWindowsDesks::deskThread(void* vdesk) { MSG msg; // use given desktop for this thread Desk* desk = static_cast(vdesk); desk->m_threadID = GetCurrentThreadId(); desk->m_window = NULL; desk->m_foregroundWindow = NULL; if (desk->m_desk != NULL && SetThreadDesktop(desk->m_desk) != 0) { // create a message queue PeekMessage(&msg, NULL, 0,0, PM_NOREMOVE); // create a window. we use this window to hide the cursor. try { desk->m_window = createWindow(m_deskClass, "SynergyDesk"); LOG((CLOG_DEBUG "desk %s window is 0x%08x", desk->m_name.c_str(), desk->m_window)); } catch (...) { // ignore LOG((CLOG_DEBUG "can't create desk window for %s", desk->m_name.c_str())); } } // tell main thread that we're ready { Lock lock(&m_mutex); m_deskReady = true; m_deskReady.broadcast(); } while (GetMessage(&msg, NULL, 0, 0)) { switch (msg.message) { default: TranslateMessage(&msg); DispatchMessage(&msg); continue; case SYNERGY_MSG_SWITCH: if (m_isPrimary && !m_noHooks) { m_uninstall(); if (m_screensaverNotify) { m_uninstallScreensaver(); m_installScreensaver(); } switch (m_install()) { case kHOOK_FAILED: // we won't work on this desk desk->m_lowLevel = false; break; case kHOOK_OKAY: desk->m_lowLevel = false; break; case kHOOK_OKAY_LL: desk->m_lowLevel = true; break; } // a window on the primary screen with low-level hooks // should never activate. if (desk->m_window) EnableWindow(desk->m_window, desk->m_lowLevel ? FALSE : TRUE); } break; case SYNERGY_MSG_ENTER: m_isOnScreen = true; deskEnter(desk); break; case SYNERGY_MSG_LEAVE: m_isOnScreen = false; m_keyLayout = (HKL)msg.wParam; deskLeave(desk, m_keyLayout); break; case SYNERGY_MSG_FAKE_KEY: keybd_event(HIBYTE(msg.lParam), LOBYTE(msg.lParam), (DWORD)msg.wParam, 0); break; case SYNERGY_MSG_FAKE_BUTTON: if (msg.wParam != 0) { mouse_event((DWORD)msg.wParam, 0, 0, (DWORD)msg.lParam, 0); } break; case SYNERGY_MSG_FAKE_MOVE: deskMouseMove(static_cast(msg.wParam), static_cast(msg.lParam)); break; case SYNERGY_MSG_FAKE_REL_MOVE: deskMouseRelativeMove(static_cast(msg.wParam), static_cast(msg.lParam)); break; case SYNERGY_MSG_FAKE_WHEEL: // XXX -- add support for x-axis scrolling if (msg.lParam != 0) { mouse_event(MOUSEEVENTF_WHEEL, 0, 0, (DWORD)msg.lParam, 0); } break; case SYNERGY_MSG_CURSOR_POS: { POINT* pos = reinterpret_cast(msg.wParam); if (!GetCursorPos(pos)) { pos->x = m_xCenter; pos->y = m_yCenter; } break; } case SYNERGY_MSG_SYNC_KEYS: m_updateKeys->run(); break; case SYNERGY_MSG_SCREENSAVER: if (!m_noHooks) { if (msg.wParam != 0) { m_installScreensaver(); } else { m_uninstallScreensaver(); } } break; case SYNERGY_MSG_FAKE_INPUT: keybd_event(SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY, SYNERGY_HOOK_FAKE_INPUT_SCANCODE, msg.wParam ? 0 : KEYEVENTF_KEYUP, 0); break; } // notify that message was processed Lock lock(&m_mutex); m_deskReady = true; m_deskReady.broadcast(); } // clean up deskEnter(desk); if (desk->m_window != NULL) { DestroyWindow(desk->m_window); } if (desk->m_desk != NULL) { closeDesktop(desk->m_desk); } } MSWindowsDesks::Desk* MSWindowsDesks::addDesk(const String& name, HDESK hdesk) { Desk* desk = new Desk; desk->m_name = name; desk->m_desk = hdesk; desk->m_targetID = GetCurrentThreadId(); desk->m_thread = new Thread(new TMethodJob( this, &MSWindowsDesks::deskThread, desk)); waitForDesk(); m_desks.insert(std::make_pair(name, desk)); return desk; } void MSWindowsDesks::removeDesks() { for (Desks::iterator index = m_desks.begin(); index != m_desks.end(); ++index) { Desk* desk = index->second; PostThreadMessage(desk->m_threadID, WM_QUIT, 0, 0); desk->m_thread->wait(); delete desk->m_thread; delete desk; } m_desks.clear(); m_activeDesk = NULL; m_activeDeskName = ""; } void MSWindowsDesks::checkDesk() { // get current desktop. if we already know about it then return. Desk* desk; HDESK hdesk = openInputDesktop(); String name = getDesktopName(hdesk); Desks::const_iterator index = m_desks.find(name); if (index == m_desks.end()) { desk = addDesk(name, hdesk); // hold on to hdesk until thread exits so the desk can't // be removed by the system } else { closeDesktop(hdesk); desk = index->second; } // if we are told to shut down on desk switch, and this is not the // first switch, then shut down. if (m_stopOnDeskSwitch && m_activeDesk != NULL && name != m_activeDeskName) { LOG((CLOG_DEBUG "shutting down because of desk switch to \"%s\"", name.c_str())); m_events->addEvent(Event(Event::kQuit)); return; } // if active desktop changed then tell the old and new desk threads // about the change. don't switch desktops when the screensaver is // active becaue we'd most likely switch to the screensaver desktop // which would have the side effect of forcing the screensaver to // stop. if (name != m_activeDeskName && !m_screensaver->isActive()) { // show cursor on previous desk bool wasOnScreen = m_isOnScreen; if (!wasOnScreen) { sendMessage(SYNERGY_MSG_ENTER, 0, 0); } // check for desk accessibility change. we don't get events // from an inaccessible desktop so when we switch from an // inaccessible desktop to an accessible one we have to // update the keyboard state. LOG((CLOG_DEBUG "switched to desk \"%s\"", name.c_str())); bool syncKeys = false; bool isAccessible = isDeskAccessible(desk); if (isDeskAccessible(m_activeDesk) != isAccessible) { if (isAccessible) { LOG((CLOG_DEBUG "desktop is now accessible")); syncKeys = true; } else { LOG((CLOG_DEBUG "desktop is now inaccessible")); } } // switch desk m_activeDesk = desk; m_activeDeskName = name; sendMessage(SYNERGY_MSG_SWITCH, 0, 0); // hide cursor on new desk if (!wasOnScreen) { sendMessage(SYNERGY_MSG_LEAVE, (WPARAM)m_keyLayout, 0); } // update keys if necessary if (syncKeys) { updateKeys(); } } else if (name != m_activeDeskName) { // screen saver might have started PostThreadMessage(m_threadID, SYNERGY_MSG_SCREEN_SAVER, TRUE, 0); } } bool MSWindowsDesks::isDeskAccessible(const Desk* desk) const { return (desk != NULL && desk->m_desk != NULL); } void MSWindowsDesks::waitForDesk() const { MSWindowsDesks* self = const_cast(this); Lock lock(&m_mutex); while (!(bool)m_deskReady) { m_deskReady.wait(); } self->m_deskReady = false; } void MSWindowsDesks::handleCheckDesk(const Event&, void*) { checkDesk(); // also check if screen saver is running if on a modern OS and // this is the primary screen. if (m_isPrimary) { BOOL running; SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, FALSE); PostThreadMessage(m_threadID, SYNERGY_MSG_SCREEN_SAVER, running, 0); } } HDESK MSWindowsDesks::openInputDesktop() { return OpenInputDesktop( DF_ALLOWOTHERACCOUNTHOOK, TRUE, DESKTOP_CREATEWINDOW | DESKTOP_HOOKCONTROL | GENERIC_WRITE); } void MSWindowsDesks::closeDesktop(HDESK desk) { if (desk != NULL) { CloseDesktop(desk); } } String MSWindowsDesks::getDesktopName(HDESK desk) { if (desk == NULL) { return String(); } else { DWORD size; GetUserObjectInformation(desk, UOI_NAME, NULL, 0, &size); TCHAR* name = (TCHAR*)alloca(size + sizeof(TCHAR)); GetUserObjectInformation(desk, UOI_NAME, name, size, &size); String result(name); return result; } } HWND MSWindowsDesks::getForegroundWindow() const { // Ideally we'd return NULL as much as possible, only returning // the actual foreground window when we know it's going to mess // up our keyboard input. For now we'll just let the user // decide. if (m_leaveForegroundOption) { return NULL; } return GetForegroundWindow(); } synergy-1.8.8-stable/src/lib/platform/MSWindowsDesks.h000066400000000000000000000201641305627404700227310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synwinhk/synwinhk.h" #include "synergy/key_types.h" #include "synergy/mouse_types.h" #include "synergy/option_types.h" #include "mt/CondVar.h" #include "mt/Mutex.h" #include "base/String.h" #include "common/stdmap.h" #define WIN32_LEAN_AND_MEAN #include class Event; class EventQueueTimer; class Thread; class IJob; class IScreenSaver; class IEventQueue; //! Microsoft Windows desk handling /*! Desks in Microsoft Windows are only remotely like desktops on X11 systems. A desk is another virtual surface for windows but desks impose serious restrictions: a thread can interact with only one desk at a time, you can't switch desks if the thread has any hooks installed or owns any windows, windows cannot exist on multiple desks at once, etc. Basically, they're useless except for running the login window or the screensaver, which is what they're used for. Synergy must deal with them mainly because of the login window and screensaver but users can create their own desks and synergy should work on those too. This class encapsulates all the desk nastiness. Clients of this object don't have to know anything about desks. */ class MSWindowsDesks { public: //! Constructor /*! \p isPrimary is true iff the desk is for a primary screen. \p screensaver points to a screensaver object and it's used only to check if the screensaver is active. The \p updateKeys job is adopted and is called when the key state should be updated in a thread attached to the current desk. \p hookLibrary must be a handle to the hook library. */ MSWindowsDesks( bool isPrimary, bool noHooks, HINSTANCE hookLibrary, const IScreenSaver* screensaver, IEventQueue* events, IJob* updateKeys, bool stopOnDeskSwitch); ~MSWindowsDesks(); //! @name manipulators //@{ //! Enable desk tracking /*! Enables desk tracking. While enabled, this object checks to see if the desk has changed and ensures that the hooks are installed on the new desk. \c setShape should be called at least once before calling \c enable. */ void enable(); //! Disable desk tracking /*! Disables desk tracking. \sa enable. */ void disable(); //! Notify of entering a desk /*! Prepares a desk for when the cursor enters it. */ void enter(); //! Notify of leaving a desk /*! Prepares a desk for when the cursor leaves it. */ void leave(HKL keyLayout); //! Notify of options changes /*! Resets all options to their default values. */ void resetOptions(); //! Notify of options changes /*! Set options to given values. Ignores unknown options and doesn't modify options that aren't given in \c options. */ void setOptions(const OptionsList& options); //! Update the key state /*! Causes the key state to get updated to reflect the physical keyboard state and current keyboard mapping. */ void updateKeys(); //! Tell desk about new size /*! This tells the desks that the display size has changed. */ void setShape(SInt32 x, SInt32 y, SInt32 width, SInt32 height, SInt32 xCenter, SInt32 yCenter, bool isMultimon); //! Install/uninstall screensaver hooks /*! If \p install is true then the screensaver hooks are installed and, if desk tracking is enabled, updated whenever the desk changes. If \p install is false then the screensaver hooks are uninstalled. */ void installScreensaverHooks(bool install); //! Start ignoring user input /*! Starts ignoring user input so we don't pick up our own synthesized events. */ void fakeInputBegin(); //! Stop ignoring user input /*! Undoes whatever \c fakeInputBegin() did. */ void fakeInputEnd(); //@} //! @name accessors //@{ //! Get cursor position /*! Return the current position of the cursor in \c x and \c y. */ void getCursorPos(SInt32& x, SInt32& y) const; //! Fake key press/release /*! Synthesize a press or release of key \c button. */ void fakeKeyEvent(KeyButton button, UINT virtualKey, bool press, bool isAutoRepeat) const; //! Fake mouse press/release /*! Synthesize a press or release of mouse button \c id. */ void fakeMouseButton(ButtonID id, bool press); //! Fake mouse move /*! Synthesize a mouse move to the absolute coordinates \c x,y. */ void fakeMouseMove(SInt32 x, SInt32 y) const; //! Fake mouse move /*! Synthesize a mouse move to the relative coordinates \c dx,dy. */ void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; //! Fake mouse wheel /*! Synthesize a mouse wheel event of amount \c delta in direction \c axis. */ void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; //@} private: class Desk { public: String m_name; Thread* m_thread; DWORD m_threadID; DWORD m_targetID; HDESK m_desk; HWND m_window; HWND m_foregroundWindow; bool m_lowLevel; }; typedef std::map Desks; // initialization and shutdown operations void queryHookLibrary(HINSTANCE hookLibrary); HCURSOR createBlankCursor() const; void destroyCursor(HCURSOR cursor) const; ATOM createDeskWindowClass(bool isPrimary) const; void destroyClass(ATOM windowClass) const; HWND createWindow(ATOM windowClass, const char* name) const; void destroyWindow(HWND) const; // message handlers void deskMouseMove(SInt32 x, SInt32 y) const; void deskMouseRelativeMove(SInt32 dx, SInt32 dy) const; void deskEnter(Desk* desk); void deskLeave(Desk* desk, HKL keyLayout); void deskThread(void* vdesk); // desk switch checking and handling Desk* addDesk(const String& name, HDESK hdesk); void removeDesks(); void checkDesk(); bool isDeskAccessible(const Desk* desk) const; void handleCheckDesk(const Event& event, void*); // communication with desk threads void waitForDesk() const; void sendMessage(UINT, WPARAM, LPARAM) const; // work around for messed up keyboard events from low-level hooks HWND getForegroundWindow() const; // desk API wrappers HDESK openInputDesktop(); void closeDesktop(HDESK); String getDesktopName(HDESK); // our desk window procs static LRESULT CALLBACK primaryDeskProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK secondaryDeskProc(HWND, UINT, WPARAM, LPARAM); private: // true if screen is being used as a primary screen, false otherwise bool m_isPrimary; // true if hooks are not to be installed (useful for debugging) bool m_noHooks; // true if mouse has entered the screen bool m_isOnScreen; // our resources ATOM m_deskClass; HCURSOR m_cursor; // screen shape stuff SInt32 m_x, m_y; SInt32 m_w, m_h; SInt32 m_xCenter, m_yCenter; // true if system appears to have multiple monitors bool m_multimon; // the timer used to check for desktop switching EventQueueTimer* m_timer; // screen saver stuff DWORD m_threadID; const IScreenSaver* m_screensaver; bool m_screensaverNotify; // the current desk and it's name Desk* m_activeDesk; String m_activeDeskName; // one desk per desktop and a cond var to communicate with it Mutex m_mutex; CondVar m_deskReady; Desks m_desks; // hook library stuff InstallFunc m_install; UninstallFunc m_uninstall; InstallScreenSaverFunc m_installScreensaver; UninstallScreenSaverFunc m_uninstallScreensaver; // keyboard stuff IJob* m_updateKeys; HKL m_keyLayout; // options bool m_leaveForegroundOption; IEventQueue* m_events; // true if program should stop on desk switch. bool m_stopOnDeskSwitch; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsDropTarget.cpp000066400000000000000000000074251305627404700242730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsDropTarget.h" #include "base/Log.h" #include "common/common.h" #include #include void getDropData(IDataObject *pDataObject); MSWindowsDropTarget* MSWindowsDropTarget::s_instance = NULL; MSWindowsDropTarget::MSWindowsDropTarget() : m_refCount(1), m_allowDrop(false) { s_instance = this; } MSWindowsDropTarget::~MSWindowsDropTarget() { } MSWindowsDropTarget& MSWindowsDropTarget::instance() { assert(s_instance != NULL); return *s_instance; } HRESULT MSWindowsDropTarget::DragEnter(IDataObject* dataObject, DWORD keyState, POINTL point, DWORD* effect) { // check if data object contain drop m_allowDrop = queryDataObject(dataObject); if (m_allowDrop) { getDropData(dataObject); } *effect = DROPEFFECT_NONE; return S_OK; } HRESULT MSWindowsDropTarget::DragOver(DWORD keyState, POINTL point, DWORD* effect) { *effect = DROPEFFECT_NONE; return S_OK; } HRESULT MSWindowsDropTarget::DragLeave(void) { return S_OK; } HRESULT MSWindowsDropTarget::Drop(IDataObject* dataObject, DWORD keyState, POINTL point, DWORD* effect) { *effect = DROPEFFECT_NONE; return S_OK; } bool MSWindowsDropTarget::queryDataObject(IDataObject* dataObject) { // check if it supports CF_HDROP using a HGLOBAL FORMATETC fmtetc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; return dataObject->QueryGetData(&fmtetc) == S_OK ? true : false; } void MSWindowsDropTarget::setDraggingFilename(char* const filename) { m_dragFilename = filename; } std::string MSWindowsDropTarget::getDraggingFilename() { return m_dragFilename; } void MSWindowsDropTarget::clearDraggingFilename() { m_dragFilename.clear(); } void getDropData(IDataObject* dataObject) { // construct a FORMATETC object FORMATETC fmtEtc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }; STGMEDIUM stgMed; // See if the dataobject contains any DROP stored as a HGLOBAL if (dataObject->QueryGetData(&fmtEtc) == S_OK) { if (dataObject->GetData(&fmtEtc, &stgMed) == S_OK) { // get data here PVOID data = GlobalLock(stgMed.hGlobal); // data object global handler contains: // DROPFILESfilename1 filename2 two spaces as the end // TODO: get multiple filenames wchar_t* wcData = (wchar_t*)((LPBYTE)data + sizeof(DROPFILES)); // convert wchar to char char* filename = new char[wcslen(wcData) + 1]; filename[wcslen(wcData)] = '\0'; wcstombs(filename, wcData, wcslen(wcData)); MSWindowsDropTarget::instance().setDraggingFilename(filename); GlobalUnlock(stgMed.hGlobal); // release the data using the COM API ReleaseStgMedium(&stgMed); delete[] filename; } } } HRESULT __stdcall MSWindowsDropTarget::QueryInterface (REFIID iid, void ** object) { if (iid == IID_IDropTarget || iid == IID_IUnknown) { AddRef(); *object = this; return S_OK; } else { *object = 0; return E_NOINTERFACE; } } ULONG __stdcall MSWindowsDropTarget::AddRef(void) { return InterlockedIncrement(&m_refCount); } ULONG __stdcall MSWindowsDropTarget::Release(void) { LONG count = InterlockedDecrement(&m_refCount); if (count == 0) { delete this; return 0; } else { return count; } } synergy-1.8.8-stable/src/lib/platform/MSWindowsDropTarget.h000066400000000000000000000033531305627404700237340ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #define WIN32_LEAN_AND_MEAN #include #include class MSWindowsScreen; class MSWindowsDropTarget : public IDropTarget { public: MSWindowsDropTarget(); ~MSWindowsDropTarget(); // IUnknown implementation HRESULT __stdcall QueryInterface(REFIID iid, void** object); ULONG __stdcall AddRef(void); ULONG __stdcall Release(void); // IDropTarget implementation HRESULT __stdcall DragEnter(IDataObject* dataObject, DWORD keyState, POINTL point, DWORD* effect); HRESULT __stdcall DragOver(DWORD keyState, POINTL point, DWORD* effect); HRESULT __stdcall DragLeave(void); HRESULT __stdcall Drop(IDataObject* dataObject, DWORD keyState, POINTL point, DWORD* effect); void setDraggingFilename(char* const); std::string getDraggingFilename(); void clearDraggingFilename(); static MSWindowsDropTarget& instance(); private: bool queryDataObject(IDataObject* dataObject); long m_refCount; bool m_allowDrop; std::string m_dragFilename; static MSWindowsDropTarget* s_instance; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsEventQueueBuffer.cpp000066400000000000000000000072551305627404700254410ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsEventQueueBuffer.h" #include "arch/win32/ArchMiscWindows.h" #include "mt/Thread.h" #include "base/IEventQueue.h" // // EventQueueTimer // class EventQueueTimer { }; // // MSWindowsEventQueueBuffer // MSWindowsEventQueueBuffer::MSWindowsEventQueueBuffer(IEventQueue* events) : m_events(events) { // remember thread. we'll be posting messages to it. m_thread = GetCurrentThreadId(); // create a message type for custom events m_userEvent = RegisterWindowMessage("SYNERGY_USER_EVENT"); // get message type for daemon quit m_daemonQuit = ArchMiscWindows::getDaemonQuitMessage(); // make sure this thread has a message queue MSG dummy; PeekMessage(&dummy, NULL, WM_USER, WM_USER, PM_NOREMOVE); } MSWindowsEventQueueBuffer::~MSWindowsEventQueueBuffer() { // do nothing } void MSWindowsEventQueueBuffer::waitForEvent(double timeout) { // check if messages are available first. if we don't do this then // MsgWaitForMultipleObjects() will block even if the queue isn't // empty if the messages in the queue were there before the last // call to GetMessage()/PeekMessage(). if (HIWORD(GetQueueStatus(QS_ALLINPUT)) != 0) { return; } // convert timeout DWORD t; if (timeout < 0.0) { t = INFINITE; } else { t = (DWORD)(1000.0 * timeout); } // wait for a message. we cannot be interrupted by thread // cancellation but that's okay because we're run in the main // thread and we never cancel that thread. HANDLE dummy[1]; MsgWaitForMultipleObjects(0, dummy, FALSE, t, QS_ALLINPUT); } IEventQueueBuffer::Type MSWindowsEventQueueBuffer::getEvent(Event& event, UInt32& dataID) { // peek at messages first. waiting for QS_ALLINPUT will return // if a message has been sent to our window but GetMessage will // dispatch that message behind our backs and block. PeekMessage // will also dispatch behind our backs but won't block. if (!PeekMessage(&m_event, NULL, 0, 0, PM_NOREMOVE) && !PeekMessage(&m_event, (HWND)-1, 0, 0, PM_NOREMOVE)) { return kNone; } // BOOL. yeah, right. BOOL result = GetMessage(&m_event, NULL, 0, 0); if (result == -1) { return kNone; } else if (result == 0) { event = Event(Event::kQuit); return kSystem; } else if (m_daemonQuit != 0 && m_event.message == m_daemonQuit) { event = Event(Event::kQuit); return kSystem; } else if (m_event.message == m_userEvent) { dataID = static_cast(m_event.wParam); return kUser; } else { event = Event(Event::kSystem, m_events->getSystemTarget(), &m_event); return kSystem; } } bool MSWindowsEventQueueBuffer::addEvent(UInt32 dataID) { return (PostThreadMessage(m_thread, m_userEvent, static_cast(dataID), 0) != 0); } bool MSWindowsEventQueueBuffer::isEmpty() const { return (HIWORD(GetQueueStatus(QS_ALLINPUT)) == 0); } EventQueueTimer* MSWindowsEventQueueBuffer::newTimer(double, bool) const { return new EventQueueTimer; } void MSWindowsEventQueueBuffer::deleteTimer(EventQueueTimer* timer) const { delete timer; } synergy-1.8.8-stable/src/lib/platform/MSWindowsEventQueueBuffer.h000066400000000000000000000027661305627404700251100ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/IEventQueueBuffer.h" #define WIN32_LEAN_AND_MEAN #include class IEventQueue; //! Event queue buffer for Win32 class MSWindowsEventQueueBuffer : public IEventQueueBuffer { public: MSWindowsEventQueueBuffer(IEventQueue* events); virtual ~MSWindowsEventQueueBuffer(); // IEventQueueBuffer overrides virtual void init() { } virtual void waitForEvent(double timeout); virtual Type getEvent(Event& event, UInt32& dataID); virtual bool addEvent(UInt32 dataID); virtual bool isEmpty() const; virtual EventQueueTimer* newTimer(double duration, bool oneShot) const; virtual void deleteTimer(EventQueueTimer*) const; private: DWORD m_thread; UINT m_userEvent; MSG m_event; UINT m_daemonQuit; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsHook.cpp000066400000000000000000000056001305627404700231110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsHook.h" #include "synergy/XScreen.h" #include "base/Log.h" static const char* g_name = "synwinhk"; MSWindowsHook::MSWindowsHook() : m_initFunc(NULL), m_cleanupFunc(NULL), m_setSidesFunc(NULL), m_setZoneFunc(NULL), m_setModeFunc(NULL), m_instance(NULL) { } MSWindowsHook::~MSWindowsHook() { cleanup(); if (m_instance != NULL) { FreeLibrary(m_instance); } } void MSWindowsHook::loadLibrary() { // load library m_instance = LoadLibrary(g_name); if (m_instance == NULL) { LOG((CLOG_ERR "failed to load hook library, %s.dll is missing or invalid", g_name)); throw XScreenOpenFailure(); } // look up functions m_setSidesFunc = (SetSidesFunc)GetProcAddress(m_instance, "setSides"); m_setZoneFunc = (SetZoneFunc)GetProcAddress(m_instance, "setZone"); m_setModeFunc = (SetModeFunc)GetProcAddress(m_instance, "setMode"); m_initFunc = (InitFunc)GetProcAddress(m_instance, "init"); m_cleanupFunc = (CleanupFunc)GetProcAddress(m_instance, "cleanup"); if (m_setSidesFunc == NULL || m_setZoneFunc == NULL || m_setModeFunc == NULL || m_initFunc == NULL || m_cleanupFunc == NULL) { LOG((CLOG_ERR "failed to load hook function, %s.dll could be out of date", g_name)); throw XScreenOpenFailure(); } // initialize library if (init(GetCurrentThreadId()) == 0) { LOG((CLOG_ERR "failed to init %s.dll, another program may be using it", g_name)); LOG((CLOG_INFO "restarting your computer may solve this error")); throw XScreenOpenFailure(); } } HINSTANCE MSWindowsHook::getInstance() const { return m_instance; } int MSWindowsHook::init(DWORD threadID) { if (m_initFunc == NULL) { return NULL; } return m_initFunc(threadID); } int MSWindowsHook::cleanup() { if (m_cleanupFunc == NULL) { return NULL; } return m_cleanupFunc(); } void MSWindowsHook::setSides(UInt32 sides) { if (m_setSidesFunc == NULL) { return; } m_setSidesFunc(sides); } void MSWindowsHook::setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize) { if (m_setZoneFunc == NULL) { return; } m_setZoneFunc(x, y, w, h, jumpZoneSize); } void MSWindowsHook::setMode(EHookMode mode) { if (m_setModeFunc == NULL) { return; } m_setModeFunc(mode); } synergy-1.8.8-stable/src/lib/platform/MSWindowsHook.h000066400000000000000000000025641305627404700225640ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synwinhk/synwinhk.h" #define WIN32_LEAN_AND_MEAN #include //! Loads and provides functions for the Windows hook class MSWindowsHook { public: MSWindowsHook(); virtual ~MSWindowsHook(); void loadLibrary(); HINSTANCE getInstance() const; int init(DWORD threadID); int cleanup(); void setSides(UInt32 sides); void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize); void setMode(EHookMode mode); private: InitFunc m_initFunc; CleanupFunc m_cleanupFunc; SetSidesFunc m_setSidesFunc; SetZoneFunc m_setZoneFunc; SetModeFunc m_setModeFunc; HINSTANCE m_instance; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsKeyState.cpp000066400000000000000000001264141305627404700237510ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsKeyState.h" #include "platform/MSWindowsDesks.h" #include "mt/Thread.h" #include "arch/win32/ArchMiscWindows.h" #include "base/FunctionJob.h" #include "base/Log.h" #include "base/String.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" // extended mouse buttons #if !defined(VK_XBUTTON1) #define VK_XBUTTON1 0x05 #define VK_XBUTTON2 0x06 #endif // // MSWindowsKeyState // // map virtual keys to synergy key enumeration const KeyID MSWindowsKeyState::s_virtualKey[] = { /* 0x000 */ { kKeyNone }, // reserved /* 0x001 */ { kKeyNone }, // VK_LBUTTON /* 0x002 */ { kKeyNone }, // VK_RBUTTON /* 0x003 */ { kKeyNone }, // VK_CANCEL /* 0x004 */ { kKeyNone }, // VK_MBUTTON /* 0x005 */ { kKeyNone }, // VK_XBUTTON1 /* 0x006 */ { kKeyNone }, // VK_XBUTTON2 /* 0x007 */ { kKeyNone }, // undefined /* 0x008 */ { kKeyBackSpace }, // VK_BACK /* 0x009 */ { kKeyTab }, // VK_TAB /* 0x00a */ { kKeyNone }, // undefined /* 0x00b */ { kKeyNone }, // undefined /* 0x00c */ { kKeyClear }, // VK_CLEAR /* 0x00d */ { kKeyReturn }, // VK_RETURN /* 0x00e */ { kKeyNone }, // undefined /* 0x00f */ { kKeyNone }, // undefined /* 0x010 */ { kKeyShift_L }, // VK_SHIFT /* 0x011 */ { kKeyControl_L }, // VK_CONTROL /* 0x012 */ { kKeyAlt_L }, // VK_MENU /* 0x013 */ { kKeyPause }, // VK_PAUSE /* 0x014 */ { kKeyCapsLock }, // VK_CAPITAL /* 0x015 */ { kKeyKana }, // VK_HANGUL, VK_KANA /* 0x016 */ { kKeyNone }, // undefined /* 0x017 */ { kKeyNone }, // VK_JUNJA /* 0x018 */ { kKeyNone }, // VK_FINAL /* 0x019 */ { kKeyKanzi }, // VK_HANJA, VK_KANJI /* 0x01a */ { kKeyNone }, // undefined /* 0x01b */ { kKeyEscape }, // VK_ESCAPE /* 0x01c */ { kKeyHenkan }, // VK_CONVERT /* 0x01d */ { kKeyNone }, // VK_NONCONVERT /* 0x01e */ { kKeyNone }, // VK_ACCEPT /* 0x01f */ { kKeyNone }, // VK_MODECHANGE /* 0x020 */ { kKeyNone }, // VK_SPACE /* 0x021 */ { kKeyKP_PageUp }, // VK_PRIOR /* 0x022 */ { kKeyKP_PageDown },// VK_NEXT /* 0x023 */ { kKeyKP_End }, // VK_END /* 0x024 */ { kKeyKP_Home }, // VK_HOME /* 0x025 */ { kKeyKP_Left }, // VK_LEFT /* 0x026 */ { kKeyKP_Up }, // VK_UP /* 0x027 */ { kKeyKP_Right }, // VK_RIGHT /* 0x028 */ { kKeyKP_Down }, // VK_DOWN /* 0x029 */ { kKeySelect }, // VK_SELECT /* 0x02a */ { kKeyNone }, // VK_PRINT /* 0x02b */ { kKeyExecute }, // VK_EXECUTE /* 0x02c */ { kKeyPrint }, // VK_SNAPSHOT /* 0x02d */ { kKeyKP_Insert }, // VK_INSERT /* 0x02e */ { kKeyKP_Delete }, // VK_DELETE /* 0x02f */ { kKeyHelp }, // VK_HELP /* 0x030 */ { kKeyNone }, // VK_0 /* 0x031 */ { kKeyNone }, // VK_1 /* 0x032 */ { kKeyNone }, // VK_2 /* 0x033 */ { kKeyNone }, // VK_3 /* 0x034 */ { kKeyNone }, // VK_4 /* 0x035 */ { kKeyNone }, // VK_5 /* 0x036 */ { kKeyNone }, // VK_6 /* 0x037 */ { kKeyNone }, // VK_7 /* 0x038 */ { kKeyNone }, // VK_8 /* 0x039 */ { kKeyNone }, // VK_9 /* 0x03a */ { kKeyNone }, // undefined /* 0x03b */ { kKeyNone }, // undefined /* 0x03c */ { kKeyNone }, // undefined /* 0x03d */ { kKeyNone }, // undefined /* 0x03e */ { kKeyNone }, // undefined /* 0x03f */ { kKeyNone }, // undefined /* 0x040 */ { kKeyNone }, // undefined /* 0x041 */ { kKeyNone }, // VK_A /* 0x042 */ { kKeyNone }, // VK_B /* 0x043 */ { kKeyNone }, // VK_C /* 0x044 */ { kKeyNone }, // VK_D /* 0x045 */ { kKeyNone }, // VK_E /* 0x046 */ { kKeyNone }, // VK_F /* 0x047 */ { kKeyNone }, // VK_G /* 0x048 */ { kKeyNone }, // VK_H /* 0x049 */ { kKeyNone }, // VK_I /* 0x04a */ { kKeyNone }, // VK_J /* 0x04b */ { kKeyNone }, // VK_K /* 0x04c */ { kKeyNone }, // VK_L /* 0x04d */ { kKeyNone }, // VK_M /* 0x04e */ { kKeyNone }, // VK_N /* 0x04f */ { kKeyNone }, // VK_O /* 0x050 */ { kKeyNone }, // VK_P /* 0x051 */ { kKeyNone }, // VK_Q /* 0x052 */ { kKeyNone }, // VK_R /* 0x053 */ { kKeyNone }, // VK_S /* 0x054 */ { kKeyNone }, // VK_T /* 0x055 */ { kKeyNone }, // VK_U /* 0x056 */ { kKeyNone }, // VK_V /* 0x057 */ { kKeyNone }, // VK_W /* 0x058 */ { kKeyNone }, // VK_X /* 0x059 */ { kKeyNone }, // VK_Y /* 0x05a */ { kKeyNone }, // VK_Z /* 0x05b */ { kKeySuper_L }, // VK_LWIN /* 0x05c */ { kKeySuper_R }, // VK_RWIN /* 0x05d */ { kKeyMenu }, // VK_APPS /* 0x05e */ { kKeyNone }, // undefined /* 0x05f */ { kKeySleep }, // VK_SLEEP /* 0x060 */ { kKeyKP_0 }, // VK_NUMPAD0 /* 0x061 */ { kKeyKP_1 }, // VK_NUMPAD1 /* 0x062 */ { kKeyKP_2 }, // VK_NUMPAD2 /* 0x063 */ { kKeyKP_3 }, // VK_NUMPAD3 /* 0x064 */ { kKeyKP_4 }, // VK_NUMPAD4 /* 0x065 */ { kKeyKP_5 }, // VK_NUMPAD5 /* 0x066 */ { kKeyKP_6 }, // VK_NUMPAD6 /* 0x067 */ { kKeyKP_7 }, // VK_NUMPAD7 /* 0x068 */ { kKeyKP_8 }, // VK_NUMPAD8 /* 0x069 */ { kKeyKP_9 }, // VK_NUMPAD9 /* 0x06a */ { kKeyKP_Multiply },// VK_MULTIPLY /* 0x06b */ { kKeyKP_Add }, // VK_ADD /* 0x06c */ { kKeyKP_Separator },// VK_SEPARATOR /* 0x06d */ { kKeyKP_Subtract },// VK_SUBTRACT /* 0x06e */ { kKeyKP_Decimal }, // VK_DECIMAL /* 0x06f */ { kKeyNone }, // VK_DIVIDE /* 0x070 */ { kKeyF1 }, // VK_F1 /* 0x071 */ { kKeyF2 }, // VK_F2 /* 0x072 */ { kKeyF3 }, // VK_F3 /* 0x073 */ { kKeyF4 }, // VK_F4 /* 0x074 */ { kKeyF5 }, // VK_F5 /* 0x075 */ { kKeyF6 }, // VK_F6 /* 0x076 */ { kKeyF7 }, // VK_F7 /* 0x077 */ { kKeyF8 }, // VK_F8 /* 0x078 */ { kKeyF9 }, // VK_F9 /* 0x079 */ { kKeyF10 }, // VK_F10 /* 0x07a */ { kKeyF11 }, // VK_F11 /* 0x07b */ { kKeyF12 }, // VK_F12 /* 0x07c */ { kKeyF13 }, // VK_F13 /* 0x07d */ { kKeyF14 }, // VK_F14 /* 0x07e */ { kKeyF15 }, // VK_F15 /* 0x07f */ { kKeyF16 }, // VK_F16 /* 0x080 */ { kKeyF17 }, // VK_F17 /* 0x081 */ { kKeyF18 }, // VK_F18 /* 0x082 */ { kKeyF19 }, // VK_F19 /* 0x083 */ { kKeyF20 }, // VK_F20 /* 0x084 */ { kKeyF21 }, // VK_F21 /* 0x085 */ { kKeyF22 }, // VK_F22 /* 0x086 */ { kKeyF23 }, // VK_F23 /* 0x087 */ { kKeyF24 }, // VK_F24 /* 0x088 */ { kKeyNone }, // unassigned /* 0x089 */ { kKeyNone }, // unassigned /* 0x08a */ { kKeyNone }, // unassigned /* 0x08b */ { kKeyNone }, // unassigned /* 0x08c */ { kKeyNone }, // unassigned /* 0x08d */ { kKeyNone }, // unassigned /* 0x08e */ { kKeyNone }, // unassigned /* 0x08f */ { kKeyNone }, // unassigned /* 0x090 */ { kKeyNumLock }, // VK_NUMLOCK /* 0x091 */ { kKeyScrollLock }, // VK_SCROLL /* 0x092 */ { kKeyNone }, // unassigned /* 0x093 */ { kKeyNone }, // unassigned /* 0x094 */ { kKeyNone }, // unassigned /* 0x095 */ { kKeyNone }, // unassigned /* 0x096 */ { kKeyNone }, // unassigned /* 0x097 */ { kKeyNone }, // unassigned /* 0x098 */ { kKeyNone }, // unassigned /* 0x099 */ { kKeyNone }, // unassigned /* 0x09a */ { kKeyNone }, // unassigned /* 0x09b */ { kKeyNone }, // unassigned /* 0x09c */ { kKeyNone }, // unassigned /* 0x09d */ { kKeyNone }, // unassigned /* 0x09e */ { kKeyNone }, // unassigned /* 0x09f */ { kKeyNone }, // unassigned /* 0x0a0 */ { kKeyShift_L }, // VK_LSHIFT /* 0x0a1 */ { kKeyShift_R }, // VK_RSHIFT /* 0x0a2 */ { kKeyControl_L }, // VK_LCONTROL /* 0x0a3 */ { kKeyControl_R }, // VK_RCONTROL /* 0x0a4 */ { kKeyAlt_L }, // VK_LMENU /* 0x0a5 */ { kKeyAlt_R }, // VK_RMENU /* 0x0a6 */ { kKeyNone }, // VK_BROWSER_BACK /* 0x0a7 */ { kKeyNone }, // VK_BROWSER_FORWARD /* 0x0a8 */ { kKeyNone }, // VK_BROWSER_REFRESH /* 0x0a9 */ { kKeyNone }, // VK_BROWSER_STOP /* 0x0aa */ { kKeyNone }, // VK_BROWSER_SEARCH /* 0x0ab */ { kKeyNone }, // VK_BROWSER_FAVORITES /* 0x0ac */ { kKeyNone }, // VK_BROWSER_HOME /* 0x0ad */ { kKeyNone }, // VK_VOLUME_MUTE /* 0x0ae */ { kKeyNone }, // VK_VOLUME_DOWN /* 0x0af */ { kKeyNone }, // VK_VOLUME_UP /* 0x0b0 */ { kKeyNone }, // VK_MEDIA_NEXT_TRACK /* 0x0b1 */ { kKeyNone }, // VK_MEDIA_PREV_TRACK /* 0x0b2 */ { kKeyNone }, // VK_MEDIA_STOP /* 0x0b3 */ { kKeyNone }, // VK_MEDIA_PLAY_PAUSE /* 0x0b4 */ { kKeyNone }, // VK_LAUNCH_MAIL /* 0x0b5 */ { kKeyNone }, // VK_LAUNCH_MEDIA_SELECT /* 0x0b6 */ { kKeyNone }, // VK_LAUNCH_APP1 /* 0x0b7 */ { kKeyNone }, // VK_LAUNCH_APP2 /* 0x0b8 */ { kKeyNone }, // unassigned /* 0x0b9 */ { kKeyNone }, // unassigned /* 0x0ba */ { kKeyNone }, // OEM specific /* 0x0bb */ { kKeyNone }, // OEM specific /* 0x0bc */ { kKeyNone }, // OEM specific /* 0x0bd */ { kKeyNone }, // OEM specific /* 0x0be */ { kKeyNone }, // OEM specific /* 0x0bf */ { kKeyNone }, // OEM specific /* 0x0c0 */ { kKeyNone }, // OEM specific /* 0x0c1 */ { kKeyNone }, // unassigned /* 0x0c2 */ { kKeyNone }, // unassigned /* 0x0c3 */ { kKeyNone }, // unassigned /* 0x0c4 */ { kKeyNone }, // unassigned /* 0x0c5 */ { kKeyNone }, // unassigned /* 0x0c6 */ { kKeyNone }, // unassigned /* 0x0c7 */ { kKeyNone }, // unassigned /* 0x0c8 */ { kKeyNone }, // unassigned /* 0x0c9 */ { kKeyNone }, // unassigned /* 0x0ca */ { kKeyNone }, // unassigned /* 0x0cb */ { kKeyNone }, // unassigned /* 0x0cc */ { kKeyNone }, // unassigned /* 0x0cd */ { kKeyNone }, // unassigned /* 0x0ce */ { kKeyNone }, // unassigned /* 0x0cf */ { kKeyNone }, // unassigned /* 0x0d0 */ { kKeyNone }, // unassigned /* 0x0d1 */ { kKeyNone }, // unassigned /* 0x0d2 */ { kKeyNone }, // unassigned /* 0x0d3 */ { kKeyNone }, // unassigned /* 0x0d4 */ { kKeyNone }, // unassigned /* 0x0d5 */ { kKeyNone }, // unassigned /* 0x0d6 */ { kKeyNone }, // unassigned /* 0x0d7 */ { kKeyNone }, // unassigned /* 0x0d8 */ { kKeyNone }, // unassigned /* 0x0d9 */ { kKeyNone }, // unassigned /* 0x0da */ { kKeyNone }, // unassigned /* 0x0db */ { kKeyNone }, // OEM specific /* 0x0dc */ { kKeyNone }, // OEM specific /* 0x0dd */ { kKeyNone }, // OEM specific /* 0x0de */ { kKeyNone }, // OEM specific /* 0x0df */ { kKeyNone }, // OEM specific /* 0x0e0 */ { kKeyNone }, // OEM specific /* 0x0e1 */ { kKeyNone }, // OEM specific /* 0x0e2 */ { kKeyNone }, // OEM specific /* 0x0e3 */ { kKeyNone }, // OEM specific /* 0x0e4 */ { kKeyNone }, // OEM specific /* 0x0e5 */ { kKeyNone }, // unassigned /* 0x0e6 */ { kKeyNone }, // OEM specific /* 0x0e7 */ { kKeyNone }, // unassigned /* 0x0e8 */ { kKeyNone }, // unassigned /* 0x0e9 */ { kKeyNone }, // OEM specific /* 0x0ea */ { kKeyNone }, // OEM specific /* 0x0eb */ { kKeyNone }, // OEM specific /* 0x0ec */ { kKeyNone }, // OEM specific /* 0x0ed */ { kKeyNone }, // OEM specific /* 0x0ee */ { kKeyNone }, // OEM specific /* 0x0ef */ { kKeyNone }, // OEM specific /* 0x0f0 */ { kKeyNone }, // OEM specific /* 0x0f1 */ { kKeyNone }, // OEM specific /* 0x0f2 */ { kKeyHiraganaKatakana }, // VK_OEM_COPY /* 0x0f3 */ { kKeyZenkaku }, // VK_OEM_AUTO /* 0x0f4 */ { kKeyZenkaku }, // VK_OEM_ENLW /* 0x0f5 */ { kKeyNone }, // OEM specific /* 0x0f6 */ { kKeyNone }, // VK_ATTN /* 0x0f7 */ { kKeyNone }, // VK_CRSEL /* 0x0f8 */ { kKeyNone }, // VK_EXSEL /* 0x0f9 */ { kKeyNone }, // VK_EREOF /* 0x0fa */ { kKeyNone }, // VK_PLAY /* 0x0fb */ { kKeyNone }, // VK_ZOOM /* 0x0fc */ { kKeyNone }, // reserved /* 0x0fd */ { kKeyNone }, // VK_PA1 /* 0x0fe */ { kKeyNone }, // VK_OEM_CLEAR /* 0x0ff */ { kKeyNone }, // reserved /* 0x100 */ { kKeyNone }, // reserved /* 0x101 */ { kKeyNone }, // VK_LBUTTON /* 0x102 */ { kKeyNone }, // VK_RBUTTON /* 0x103 */ { kKeyBreak }, // VK_CANCEL /* 0x104 */ { kKeyNone }, // VK_MBUTTON /* 0x105 */ { kKeyNone }, // VK_XBUTTON1 /* 0x106 */ { kKeyNone }, // VK_XBUTTON2 /* 0x107 */ { kKeyNone }, // undefined /* 0x108 */ { kKeyNone }, // VK_BACK /* 0x109 */ { kKeyNone }, // VK_TAB /* 0x10a */ { kKeyNone }, // undefined /* 0x10b */ { kKeyNone }, // undefined /* 0x10c */ { kKeyClear }, // VK_CLEAR /* 0x10d */ { kKeyKP_Enter }, // VK_RETURN /* 0x10e */ { kKeyNone }, // undefined /* 0x10f */ { kKeyNone }, // undefined /* 0x110 */ { kKeyShift_R }, // VK_SHIFT /* 0x111 */ { kKeyControl_R }, // VK_CONTROL /* 0x112 */ { kKeyAlt_R }, // VK_MENU /* 0x113 */ { kKeyNone }, // VK_PAUSE /* 0x114 */ { kKeyNone }, // VK_CAPITAL /* 0x115 */ { kKeyHangul }, // VK_HANGUL /* 0x116 */ { kKeyNone }, // undefined /* 0x117 */ { kKeyNone }, // VK_JUNJA /* 0x118 */ { kKeyNone }, // VK_FINAL /* 0x119 */ { kKeyHanja }, // VK_HANJA /* 0x11a */ { kKeyNone }, // undefined /* 0x11b */ { kKeyNone }, // VK_ESCAPE /* 0x11c */ { kKeyNone }, // VK_CONVERT /* 0x11d */ { kKeyNone }, // VK_NONCONVERT /* 0x11e */ { kKeyNone }, // VK_ACCEPT /* 0x11f */ { kKeyNone }, // VK_MODECHANGE /* 0x120 */ { kKeyNone }, // VK_SPACE /* 0x121 */ { kKeyPageUp }, // VK_PRIOR /* 0x122 */ { kKeyPageDown }, // VK_NEXT /* 0x123 */ { kKeyEnd }, // VK_END /* 0x124 */ { kKeyHome }, // VK_HOME /* 0x125 */ { kKeyLeft }, // VK_LEFT /* 0x126 */ { kKeyUp }, // VK_UP /* 0x127 */ { kKeyRight }, // VK_RIGHT /* 0x128 */ { kKeyDown }, // VK_DOWN /* 0x129 */ { kKeySelect }, // VK_SELECT /* 0x12a */ { kKeyNone }, // VK_PRINT /* 0x12b */ { kKeyExecute }, // VK_EXECUTE /* 0x12c */ { kKeyPrint }, // VK_SNAPSHOT /* 0x12d */ { kKeyInsert }, // VK_INSERT /* 0x12e */ { kKeyDelete }, // VK_DELETE /* 0x12f */ { kKeyHelp }, // VK_HELP /* 0x130 */ { kKeyNone }, // VK_0 /* 0x131 */ { kKeyNone }, // VK_1 /* 0x132 */ { kKeyNone }, // VK_2 /* 0x133 */ { kKeyNone }, // VK_3 /* 0x134 */ { kKeyNone }, // VK_4 /* 0x135 */ { kKeyNone }, // VK_5 /* 0x136 */ { kKeyNone }, // VK_6 /* 0x137 */ { kKeyNone }, // VK_7 /* 0x138 */ { kKeyNone }, // VK_8 /* 0x139 */ { kKeyNone }, // VK_9 /* 0x13a */ { kKeyNone }, // undefined /* 0x13b */ { kKeyNone }, // undefined /* 0x13c */ { kKeyNone }, // undefined /* 0x13d */ { kKeyNone }, // undefined /* 0x13e */ { kKeyNone }, // undefined /* 0x13f */ { kKeyNone }, // undefined /* 0x140 */ { kKeyNone }, // undefined /* 0x141 */ { kKeyNone }, // VK_A /* 0x142 */ { kKeyNone }, // VK_B /* 0x143 */ { kKeyNone }, // VK_C /* 0x144 */ { kKeyNone }, // VK_D /* 0x145 */ { kKeyNone }, // VK_E /* 0x146 */ { kKeyNone }, // VK_F /* 0x147 */ { kKeyNone }, // VK_G /* 0x148 */ { kKeyNone }, // VK_H /* 0x149 */ { kKeyNone }, // VK_I /* 0x14a */ { kKeyNone }, // VK_J /* 0x14b */ { kKeyNone }, // VK_K /* 0x14c */ { kKeyNone }, // VK_L /* 0x14d */ { kKeyNone }, // VK_M /* 0x14e */ { kKeyNone }, // VK_N /* 0x14f */ { kKeyNone }, // VK_O /* 0x150 */ { kKeyNone }, // VK_P /* 0x151 */ { kKeyNone }, // VK_Q /* 0x152 */ { kKeyNone }, // VK_R /* 0x153 */ { kKeyNone }, // VK_S /* 0x154 */ { kKeyNone }, // VK_T /* 0x155 */ { kKeyNone }, // VK_U /* 0x156 */ { kKeyNone }, // VK_V /* 0x157 */ { kKeyNone }, // VK_W /* 0x158 */ { kKeyNone }, // VK_X /* 0x159 */ { kKeyNone }, // VK_Y /* 0x15a */ { kKeyNone }, // VK_Z /* 0x15b */ { kKeySuper_L }, // VK_LWIN /* 0x15c */ { kKeySuper_R }, // VK_RWIN /* 0x15d */ { kKeyMenu }, // VK_APPS /* 0x15e */ { kKeyNone }, // undefined /* 0x15f */ { kKeyNone }, // VK_SLEEP /* 0x160 */ { kKeyNone }, // VK_NUMPAD0 /* 0x161 */ { kKeyNone }, // VK_NUMPAD1 /* 0x162 */ { kKeyNone }, // VK_NUMPAD2 /* 0x163 */ { kKeyNone }, // VK_NUMPAD3 /* 0x164 */ { kKeyNone }, // VK_NUMPAD4 /* 0x165 */ { kKeyNone }, // VK_NUMPAD5 /* 0x166 */ { kKeyNone }, // VK_NUMPAD6 /* 0x167 */ { kKeyNone }, // VK_NUMPAD7 /* 0x168 */ { kKeyNone }, // VK_NUMPAD8 /* 0x169 */ { kKeyNone }, // VK_NUMPAD9 /* 0x16a */ { kKeyNone }, // VK_MULTIPLY /* 0x16b */ { kKeyNone }, // VK_ADD /* 0x16c */ { kKeyKP_Separator },// VK_SEPARATOR /* 0x16d */ { kKeyNone }, // VK_SUBTRACT /* 0x16e */ { kKeyNone }, // VK_DECIMAL /* 0x16f */ { kKeyKP_Divide }, // VK_DIVIDE /* 0x170 */ { kKeyNone }, // VK_F1 /* 0x171 */ { kKeyNone }, // VK_F2 /* 0x172 */ { kKeyNone }, // VK_F3 /* 0x173 */ { kKeyNone }, // VK_F4 /* 0x174 */ { kKeyNone }, // VK_F5 /* 0x175 */ { kKeyNone }, // VK_F6 /* 0x176 */ { kKeyNone }, // VK_F7 /* 0x177 */ { kKeyNone }, // VK_F8 /* 0x178 */ { kKeyNone }, // VK_F9 /* 0x179 */ { kKeyNone }, // VK_F10 /* 0x17a */ { kKeyNone }, // VK_F11 /* 0x17b */ { kKeyNone }, // VK_F12 /* 0x17c */ { kKeyF13 }, // VK_F13 /* 0x17d */ { kKeyF14 }, // VK_F14 /* 0x17e */ { kKeyF15 }, // VK_F15 /* 0x17f */ { kKeyF16 }, // VK_F16 /* 0x180 */ { kKeyF17 }, // VK_F17 /* 0x181 */ { kKeyF18 }, // VK_F18 /* 0x182 */ { kKeyF19 }, // VK_F19 /* 0x183 */ { kKeyF20 }, // VK_F20 /* 0x184 */ { kKeyF21 }, // VK_F21 /* 0x185 */ { kKeyF22 }, // VK_F22 /* 0x186 */ { kKeyF23 }, // VK_F23 /* 0x187 */ { kKeyF24 }, // VK_F24 /* 0x188 */ { kKeyNone }, // unassigned /* 0x189 */ { kKeyNone }, // unassigned /* 0x18a */ { kKeyNone }, // unassigned /* 0x18b */ { kKeyNone }, // unassigned /* 0x18c */ { kKeyNone }, // unassigned /* 0x18d */ { kKeyNone }, // unassigned /* 0x18e */ { kKeyNone }, // unassigned /* 0x18f */ { kKeyNone }, // unassigned /* 0x190 */ { kKeyNumLock }, // VK_NUMLOCK /* 0x191 */ { kKeyNone }, // VK_SCROLL /* 0x192 */ { kKeyNone }, // unassigned /* 0x193 */ { kKeyNone }, // unassigned /* 0x194 */ { kKeyNone }, // unassigned /* 0x195 */ { kKeyNone }, // unassigned /* 0x196 */ { kKeyNone }, // unassigned /* 0x197 */ { kKeyNone }, // unassigned /* 0x198 */ { kKeyNone }, // unassigned /* 0x199 */ { kKeyNone }, // unassigned /* 0x19a */ { kKeyNone }, // unassigned /* 0x19b */ { kKeyNone }, // unassigned /* 0x19c */ { kKeyNone }, // unassigned /* 0x19d */ { kKeyNone }, // unassigned /* 0x19e */ { kKeyNone }, // unassigned /* 0x19f */ { kKeyNone }, // unassigned /* 0x1a0 */ { kKeyShift_L }, // VK_LSHIFT /* 0x1a1 */ { kKeyShift_R }, // VK_RSHIFT /* 0x1a2 */ { kKeyControl_L }, // VK_LCONTROL /* 0x1a3 */ { kKeyControl_R }, // VK_RCONTROL /* 0x1a4 */ { kKeyAlt_L }, // VK_LMENU /* 0x1a5 */ { kKeyAlt_R }, // VK_RMENU /* 0x1a6 */ { kKeyWWWBack }, // VK_BROWSER_BACK /* 0x1a7 */ { kKeyWWWForward }, // VK_BROWSER_FORWARD /* 0x1a8 */ { kKeyWWWRefresh }, // VK_BROWSER_REFRESH /* 0x1a9 */ { kKeyWWWStop }, // VK_BROWSER_STOP /* 0x1aa */ { kKeyWWWSearch }, // VK_BROWSER_SEARCH /* 0x1ab */ { kKeyWWWFavorites },// VK_BROWSER_FAVORITES /* 0x1ac */ { kKeyWWWHome }, // VK_BROWSER_HOME /* 0x1ad */ { kKeyAudioMute }, // VK_VOLUME_MUTE /* 0x1ae */ { kKeyAudioDown }, // VK_VOLUME_DOWN /* 0x1af */ { kKeyAudioUp }, // VK_VOLUME_UP /* 0x1b0 */ { kKeyAudioNext }, // VK_MEDIA_NEXT_TRACK /* 0x1b1 */ { kKeyAudioPrev }, // VK_MEDIA_PREV_TRACK /* 0x1b2 */ { kKeyAudioStop }, // VK_MEDIA_STOP /* 0x1b3 */ { kKeyAudioPlay }, // VK_MEDIA_PLAY_PAUSE /* 0x1b4 */ { kKeyAppMail }, // VK_LAUNCH_MAIL /* 0x1b5 */ { kKeyAppMedia }, // VK_LAUNCH_MEDIA_SELECT /* 0x1b6 */ { kKeyAppUser1 }, // VK_LAUNCH_APP1 /* 0x1b7 */ { kKeyAppUser2 }, // VK_LAUNCH_APP2 /* 0x1b8 */ { kKeyNone }, // unassigned /* 0x1b9 */ { kKeyNone }, // unassigned /* 0x1ba */ { kKeyNone }, // OEM specific /* 0x1bb */ { kKeyNone }, // OEM specific /* 0x1bc */ { kKeyNone }, // OEM specific /* 0x1bd */ { kKeyNone }, // OEM specific /* 0x1be */ { kKeyNone }, // OEM specific /* 0x1bf */ { kKeyNone }, // OEM specific /* 0x1c0 */ { kKeyNone }, // OEM specific /* 0x1c1 */ { kKeyNone }, // unassigned /* 0x1c2 */ { kKeyNone }, // unassigned /* 0x1c3 */ { kKeyNone }, // unassigned /* 0x1c4 */ { kKeyNone }, // unassigned /* 0x1c5 */ { kKeyNone }, // unassigned /* 0x1c6 */ { kKeyNone }, // unassigned /* 0x1c7 */ { kKeyNone }, // unassigned /* 0x1c8 */ { kKeyNone }, // unassigned /* 0x1c9 */ { kKeyNone }, // unassigned /* 0x1ca */ { kKeyNone }, // unassigned /* 0x1cb */ { kKeyNone }, // unassigned /* 0x1cc */ { kKeyNone }, // unassigned /* 0x1cd */ { kKeyNone }, // unassigned /* 0x1ce */ { kKeyNone }, // unassigned /* 0x1cf */ { kKeyNone }, // unassigned /* 0x1d0 */ { kKeyNone }, // unassigned /* 0x1d1 */ { kKeyNone }, // unassigned /* 0x1d2 */ { kKeyNone }, // unassigned /* 0x1d3 */ { kKeyNone }, // unassigned /* 0x1d4 */ { kKeyNone }, // unassigned /* 0x1d5 */ { kKeyNone }, // unassigned /* 0x1d6 */ { kKeyNone }, // unassigned /* 0x1d7 */ { kKeyNone }, // unassigned /* 0x1d8 */ { kKeyNone }, // unassigned /* 0x1d9 */ { kKeyNone }, // unassigned /* 0x1da */ { kKeyNone }, // unassigned /* 0x1db */ { kKeyNone }, // OEM specific /* 0x1dc */ { kKeyNone }, // OEM specific /* 0x1dd */ { kKeyNone }, // OEM specific /* 0x1de */ { kKeyNone }, // OEM specific /* 0x1df */ { kKeyNone }, // OEM specific /* 0x1e0 */ { kKeyNone }, // OEM specific /* 0x1e1 */ { kKeyNone }, // OEM specific /* 0x1e2 */ { kKeyNone }, // OEM specific /* 0x1e3 */ { kKeyNone }, // OEM specific /* 0x1e4 */ { kKeyNone }, // OEM specific /* 0x1e5 */ { kKeyNone }, // unassigned /* 0x1e6 */ { kKeyNone }, // OEM specific /* 0x1e7 */ { kKeyNone }, // unassigned /* 0x1e8 */ { kKeyNone }, // unassigned /* 0x1e9 */ { kKeyNone }, // OEM specific /* 0x1ea */ { kKeyNone }, // OEM specific /* 0x1eb */ { kKeyNone }, // OEM specific /* 0x1ec */ { kKeyNone }, // OEM specific /* 0x1ed */ { kKeyNone }, // OEM specific /* 0x1ee */ { kKeyNone }, // OEM specific /* 0x1ef */ { kKeyNone }, // OEM specific /* 0x1f0 */ { kKeyNone }, // OEM specific /* 0x1f1 */ { kKeyNone }, // OEM specific /* 0x1f2 */ { kKeyNone }, // VK_OEM_COPY /* 0x1f3 */ { kKeyNone }, // VK_OEM_AUTO /* 0x1f4 */ { kKeyNone }, // VK_OEM_ENLW /* 0x1f5 */ { kKeyNone }, // OEM specific /* 0x1f6 */ { kKeyNone }, // VK_ATTN /* 0x1f7 */ { kKeyNone }, // VK_CRSEL /* 0x1f8 */ { kKeyNone }, // VK_EXSEL /* 0x1f9 */ { kKeyNone }, // VK_EREOF /* 0x1fa */ { kKeyNone }, // VK_PLAY /* 0x1fb */ { kKeyNone }, // VK_ZOOM /* 0x1fc */ { kKeyNone }, // reserved /* 0x1fd */ { kKeyNone }, // VK_PA1 /* 0x1fe */ { kKeyNone }, // VK_OEM_CLEAR /* 0x1ff */ { kKeyNone } // reserved }; struct Win32Modifiers { public: UINT m_vk; KeyModifierMask m_mask; }; static const Win32Modifiers s_modifiers[] = { { VK_SHIFT, KeyModifierShift }, { VK_LSHIFT, KeyModifierShift }, { VK_RSHIFT, KeyModifierShift }, { VK_CONTROL, KeyModifierControl }, { VK_LCONTROL, KeyModifierControl }, { VK_RCONTROL, KeyModifierControl }, { VK_MENU, KeyModifierAlt }, { VK_LMENU, KeyModifierAlt }, { VK_RMENU, KeyModifierAlt }, { VK_LWIN, KeyModifierSuper }, { VK_RWIN, KeyModifierSuper } }; MSWindowsKeyState::MSWindowsKeyState( MSWindowsDesks* desks, void* eventTarget, IEventQueue* events) : KeyState(events), m_eventTarget(eventTarget), m_desks(desks), m_keyLayout(GetKeyboardLayout(0)), m_fixTimer(NULL), m_lastDown(0), m_useSavedModifiers(false), m_savedModifiers(0), m_originalSavedModifiers(0), m_events(events) { init(); } MSWindowsKeyState::MSWindowsKeyState( MSWindowsDesks* desks, void* eventTarget, IEventQueue* events, synergy::KeyMap& keyMap) : KeyState(events, keyMap), m_eventTarget(eventTarget), m_desks(desks), m_keyLayout(GetKeyboardLayout(0)), m_fixTimer(NULL), m_lastDown(0), m_useSavedModifiers(false), m_savedModifiers(0), m_originalSavedModifiers(0), m_events(events) { init(); } MSWindowsKeyState::~MSWindowsKeyState() { disable(); } void MSWindowsKeyState::init() { // look up symbol that's available on winNT family but not win95 HMODULE userModule = GetModuleHandle("user32.dll"); m_ToUnicodeEx = (ToUnicodeEx_t)GetProcAddress(userModule, "ToUnicodeEx"); } void MSWindowsKeyState::disable() { if (m_fixTimer != NULL) { m_events->removeHandler(Event::kTimer, m_fixTimer); m_events->deleteTimer(m_fixTimer); m_fixTimer = NULL; } m_lastDown = 0; } KeyButton MSWindowsKeyState::virtualKeyToButton(UINT virtualKey) const { return m_virtualKeyToButton[virtualKey & 0xffu]; } void MSWindowsKeyState::setKeyLayout(HKL keyLayout) { m_keyLayout = keyLayout; } bool MSWindowsKeyState::testAutoRepeat(bool press, bool isRepeat, KeyButton button) { if (!isRepeat) { isRepeat = (press && m_lastDown != 0 && button == m_lastDown); } if (press) { m_lastDown = button; } else { m_lastDown = 0; } return isRepeat; } void MSWindowsKeyState::saveModifiers() { m_savedModifiers = getActiveModifiers(); m_originalSavedModifiers = m_savedModifiers; } void MSWindowsKeyState::useSavedModifiers(bool enable) { if (enable != m_useSavedModifiers) { m_useSavedModifiers = enable; if (!m_useSavedModifiers) { // transfer any modifier state changes to KeyState's state KeyModifierMask mask = m_originalSavedModifiers ^ m_savedModifiers; getActiveModifiersRValue() = (getActiveModifiers() & ~mask) | (m_savedModifiers & mask); } } } KeyID MSWindowsKeyState::mapKeyFromEvent(WPARAM charAndVirtKey, LPARAM info, KeyModifierMask* maskOut) const { static const KeyModifierMask s_controlAlt = KeyModifierControl | KeyModifierAlt; // extract character, virtual key, and if we didn't use AltGr char c = (char)((charAndVirtKey & 0xff00u) >> 8); UINT vkCode = (charAndVirtKey & 0xffu); bool noAltGr = ((charAndVirtKey & 0xff0000u) != 0); // handle some keys via table lookup KeyID id = getKeyID(vkCode, (KeyButton)((info >> 16) & 0x1ffu)); // check if not in table; map character to key id if (id == kKeyNone && c != 0) { if ((c & 0x80u) == 0) { // ASCII id = static_cast(c) & 0xffu; } else { // character is not really ASCII. instead it's some // character in the current ANSI code page. try to // convert that to a Unicode character. if we fail // then use the single byte character as is. char src = c; wchar_t unicode; if (MultiByteToWideChar(CP_THREAD_ACP, MB_PRECOMPOSED, &src, 1, &unicode, 1) > 0) { id = static_cast(unicode); } else { id = static_cast(c) & 0xffu; } } } // set modifier mask if (maskOut != NULL) { KeyModifierMask active = getActiveModifiers(); if (!noAltGr && (active & s_controlAlt) == s_controlAlt) { // if !noAltGr then we're only interested in matching the // key, not the AltGr. AltGr is down (i.e. control and alt // are down) but we don't want the client to have to match // that so we clear it. active &= ~s_controlAlt; } if (id == kKeyHangul) { // If shift-space is used to change input mode, clear shift modifier. active &= ~KeyModifierShift; } *maskOut = active; } return id; } bool MSWindowsKeyState::didGroupsChange() const { GroupList groups; return (getGroups(groups) && groups != m_groups); } UINT MSWindowsKeyState::mapKeyToVirtualKey(KeyID key) const { if (key == kKeyNone) { return 0; } KeyToVKMap::const_iterator i = m_keyToVKMap.find(key); if (i == m_keyToVKMap.end()) { return 0; } else { return i->second; } } void MSWindowsKeyState::onKey(KeyButton button, bool down, KeyModifierMask newState) { KeyState::onKey(button, down, newState); } void MSWindowsKeyState::sendKeyEvent(void* target, bool press, bool isAutoRepeat, KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button) { if (press || isAutoRepeat) { // send key if (press && !isAutoRepeat) { KeyState::sendKeyEvent(target, true, false, key, mask, 1, button); if (count > 0) { --count; } } if (count >= 1) { KeyState::sendKeyEvent(target, true, true, key, mask, count, button); } } else { // do key up KeyState::sendKeyEvent(target, false, false, key, mask, 1, button); } } void MSWindowsKeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button) { KeyState::fakeKeyDown(id, mask, button); } bool MSWindowsKeyState::fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) { return KeyState::fakeKeyRepeat(id, mask, count, button); } bool MSWindowsKeyState::fakeCtrlAltDel() { // to fake ctrl+alt+del on the NT family we broadcast a suitable // hotkey to all windows on the winlogon desktop. however, the // current thread must be on that desktop to do the broadcast // and we can't switch just any thread because some own windows // or hooks. so start a new thread to do the real work. HANDLE hEvtSendSas = OpenEvent(EVENT_MODIFY_STATE, FALSE, "Global\\SendSAS"); if (hEvtSendSas) { LOG((CLOG_DEBUG "found the SendSAS event - signaling my launcher to simulate ctrl+alt+del")); SetEvent(hEvtSendSas); CloseHandle(hEvtSendSas); } else { Thread cad(new FunctionJob(&MSWindowsKeyState::ctrlAltDelThread)); cad.wait(); } return true; } void MSWindowsKeyState::ctrlAltDelThread(void*) { // get the Winlogon desktop at whatever privilege we can HDESK desk = OpenDesktop("Winlogon", 0, FALSE, MAXIMUM_ALLOWED); if (desk != NULL) { if (SetThreadDesktop(desk)) { PostMessage(HWND_BROADCAST, WM_HOTKEY, 0, MAKELPARAM(MOD_CONTROL | MOD_ALT, VK_DELETE)); } else { LOG((CLOG_DEBUG "can't switch to Winlogon desk: %d", GetLastError())); } CloseDesktop(desk); } else { LOG((CLOG_DEBUG "can't open Winlogon desk: %d", GetLastError())); } } KeyModifierMask MSWindowsKeyState::pollActiveModifiers() const { KeyModifierMask state = 0; // get non-toggle modifiers from our own shadow key state for (size_t i = 0; i < sizeof(s_modifiers) / sizeof(s_modifiers[0]); ++i) { KeyButton button = virtualKeyToButton(s_modifiers[i].m_vk); if (button != 0 && isKeyDown(button)) { state |= s_modifiers[i].m_mask; } } // we can get toggle modifiers from the system if ((GetKeyState(VK_CAPITAL) & 0x01) != 0) { state |= KeyModifierCapsLock; } if ((GetKeyState(VK_NUMLOCK) & 0x01) != 0) { state |= KeyModifierNumLock; } if ((GetKeyState(VK_SCROLL) & 0x01) != 0) { state |= KeyModifierScrollLock; } return state; } SInt32 MSWindowsKeyState::pollActiveGroup() const { // determine the thread that'll receive this event HWND targetWindow = GetForegroundWindow(); DWORD targetThread = GetWindowThreadProcessId(targetWindow, NULL); // get keyboard layout for the thread HKL hkl = GetKeyboardLayout(targetThread); if (!hkl) { // GetKeyboardLayout failed. Maybe targetWindow is a console window. // We're getting the keyboard layout of the desktop instead. targetWindow = GetDesktopWindow(); targetThread = GetWindowThreadProcessId(targetWindow, NULL); hkl = GetKeyboardLayout(targetThread); } // get group GroupMap::const_iterator i = m_groupMap.find(hkl); if (i == m_groupMap.end()) { LOG((CLOG_DEBUG1 "can't find keyboard layout %08x", hkl)); return 0; } return i->second; } void MSWindowsKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const { BYTE keyState[256]; if (!GetKeyboardState(keyState)) { LOG((CLOG_ERR "GetKeyboardState returned false on pollPressedKeys")); return; } for (KeyButton i = 1; i < 256; ++i) { if ((keyState[i] & 0x80) != 0) { KeyButton keyButton = virtualKeyToButton(i); if (keyButton != 0) { pressedKeys.insert(keyButton); } } } } void MSWindowsKeyState::getKeyMap(synergy::KeyMap& keyMap) { // update keyboard groups if (getGroups(m_groups)) { m_groupMap.clear(); SInt32 numGroups = (SInt32)m_groups.size(); for (SInt32 g = 0; g < numGroups; ++g) { m_groupMap[m_groups[g]] = g; } } HKL activeLayout = GetKeyboardLayout(0); // clear table memset(m_virtualKeyToButton, 0, sizeof(m_virtualKeyToButton)); m_keyToVKMap.clear(); synergy::KeyMap::KeyItem item; SInt32 numGroups = (SInt32)m_groups.size(); for (SInt32 g = 0; g < numGroups; ++g) { item.m_group = g; ActivateKeyboardLayout(m_groups[g], 0); // clear tables memset(m_buttonToVK, 0, sizeof(m_buttonToVK)); memset(m_buttonToNumpadVK, 0, sizeof(m_buttonToNumpadVK)); // map buttons (scancodes) to virtual keys for (KeyButton i = 1; i < 256; ++i) { UINT vk = MapVirtualKey(i, 1); if (vk == 0) { // unmapped continue; } // deal with certain virtual keys specially switch (vk) { case VK_SHIFT: // this is important for sending the correct modifier to the // client, a patch from bug #242 (right shift broken for ms // remote desktop) removed this to just use left shift, which // caused bug #2799 (right shift broken for osx). // we must not repeat this same mistake and must fix platform // specific bugs in code that only affects that platform. if (MapVirtualKey(VK_RSHIFT, 0) == i) { vk = VK_RSHIFT; } else { vk = VK_LSHIFT; } break; case VK_CONTROL: vk = VK_LCONTROL; break; case VK_MENU: vk = VK_LMENU; break; case VK_NUMLOCK: vk = VK_PAUSE; break; case VK_NUMPAD0: case VK_NUMPAD1: case VK_NUMPAD2: case VK_NUMPAD3: case VK_NUMPAD4: case VK_NUMPAD5: case VK_NUMPAD6: case VK_NUMPAD7: case VK_NUMPAD8: case VK_NUMPAD9: case VK_DECIMAL: // numpad keys are saved in their own table m_buttonToNumpadVK[i] = vk; continue; case VK_LWIN: case VK_RWIN: break; case VK_RETURN: case VK_PRIOR: case VK_NEXT: case VK_END: case VK_HOME: case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN: case VK_INSERT: case VK_DELETE: // also add extended key for these m_buttonToVK[i | 0x100u] = vk; break; } if (m_buttonToVK[i] == 0) { m_buttonToVK[i] = vk; } } // now map virtual keys to buttons. multiple virtual keys may map // to a single button. if the virtual key matches the one in // m_buttonToVK then we use the button as is. if not then it's // either a numpad key and we use the button as is or it's an // extended button. for (UINT i = 1; i < 255; ++i) { // skip virtual keys we don't want switch (i) { case VK_LBUTTON: case VK_RBUTTON: case VK_MBUTTON: case VK_XBUTTON1: case VK_XBUTTON2: case VK_SHIFT: case VK_CONTROL: case VK_MENU: continue; } // get the button KeyButton button = static_cast(MapVirtualKey(i, 0)); if (button == 0) { continue; } // deal with certain virtual keys specially switch (i) { case VK_NUMPAD0: case VK_NUMPAD1: case VK_NUMPAD2: case VK_NUMPAD3: case VK_NUMPAD4: case VK_NUMPAD5: case VK_NUMPAD6: case VK_NUMPAD7: case VK_NUMPAD8: case VK_NUMPAD9: case VK_DECIMAL: m_buttonToNumpadVK[button] = i; break; default: // add extended key if virtual keys don't match if (m_buttonToVK[button] != i) { m_buttonToVK[button | 0x100u] = i; } break; } } // set virtual key to button table if (activeLayout == m_groups[g]) { for (KeyButton i = 0; i < 512; ++i) { if (m_buttonToVK[i] != 0) { if (m_virtualKeyToButton[m_buttonToVK[i]] == 0) { m_virtualKeyToButton[m_buttonToVK[i]] = i; } } if (m_buttonToNumpadVK[i] != 0) { if (m_virtualKeyToButton[m_buttonToNumpadVK[i]] == 0) { m_virtualKeyToButton[m_buttonToNumpadVK[i]] = i; } } } } // add numpad keys for (KeyButton i = 0; i < 512; ++i) { if (m_buttonToNumpadVK[i] != 0) { item.m_id = getKeyID(m_buttonToNumpadVK[i], i); item.m_button = i; item.m_required = KeyModifierNumLock; item.m_sensitive = KeyModifierNumLock | KeyModifierShift; item.m_generates = 0; item.m_client = m_buttonToNumpadVK[i]; addKeyEntry(keyMap, item); } } // add other keys BYTE keys[256]; memset(keys, 0, sizeof(keys)); for (KeyButton i = 0; i < 512; ++i) { if (m_buttonToVK[i] != 0) { // initialize item item.m_id = getKeyID(m_buttonToVK[i], i); item.m_button = i; item.m_required = 0; item.m_sensitive = 0; item.m_client = m_buttonToVK[i]; // get flags for modifier keys synergy::KeyMap::initModifierKey(item); if (item.m_id == 0) { // translate virtual key to a character with and without // shift, caps lock, and AltGr. struct Modifier { UINT m_vk1; UINT m_vk2; BYTE m_state; KeyModifierMask m_mask; }; static const Modifier modifiers[] = { { VK_SHIFT, VK_SHIFT, 0x80u, KeyModifierShift }, { VK_CAPITAL, VK_CAPITAL, 0x01u, KeyModifierCapsLock }, { VK_CONTROL, VK_MENU, 0x80u, KeyModifierControl | KeyModifierAlt } }; static const size_t s_numModifiers = sizeof(modifiers) / sizeof(modifiers[0]); static const size_t s_numCombinations = 1 << s_numModifiers; KeyID id[s_numCombinations]; bool anyFound = false; KeyButton button = static_cast(i & 0xffu); for (size_t j = 0; j < s_numCombinations; ++j) { for (size_t k = 0; k < s_numModifiers; ++k) { //if ((j & (1 << k)) != 0) { // http://msdn.microsoft.com/en-us/library/ke55d167.aspx if ((j & (1i64 << k)) != 0) { keys[modifiers[k].m_vk1] = modifiers[k].m_state; keys[modifiers[k].m_vk2] = modifiers[k].m_state; } else { keys[modifiers[k].m_vk1] = 0; keys[modifiers[k].m_vk2] = 0; } } id[j] = getIDForKey(item, button, m_buttonToVK[i], keys, m_groups[g]); if (id[j] != 0) { anyFound = true; } } if (anyFound) { // determine what modifiers we're sensitive to. // we're sensitive if the KeyID changes when the // modifier does. item.m_sensitive = 0; for (size_t k = 0; k < s_numModifiers; ++k) { for (size_t j = 0; j < s_numCombinations; ++j) { //if (id[j] != id[j ^ (1u << k)]) { // http://msdn.microsoft.com/en-us/library/ke55d167.aspx if (id[j] != id[j ^ (1ui64 << k)]) { item.m_sensitive |= modifiers[k].m_mask; break; } } } // save each key. the map will automatically discard // duplicates, like an unshift and shifted version of // a key that's insensitive to shift. for (size_t j = 0; j < s_numCombinations; ++j) { item.m_id = id[j]; item.m_required = 0; for (size_t k = 0; k < s_numModifiers; ++k) { if ((j & (1i64 << k)) != 0) { item.m_required |= modifiers[k].m_mask; } } addKeyEntry(keyMap, item); } } } else { // found in table switch (m_buttonToVK[i]) { case VK_TAB: // add kKeyLeftTab, too item.m_id = kKeyLeftTab; item.m_required |= KeyModifierShift; item.m_sensitive |= KeyModifierShift; addKeyEntry(keyMap, item); item.m_id = kKeyTab; item.m_required &= ~KeyModifierShift; break; case VK_CANCEL: item.m_required |= KeyModifierControl; item.m_sensitive |= KeyModifierControl; break; case VK_SNAPSHOT: item.m_sensitive |= KeyModifierAlt; if ((i & 0x100u) == 0) { // non-extended snapshot key requires alt item.m_required |= KeyModifierAlt; } break; } addKeyEntry(keyMap, item); } } } } // restore keyboard layout ActivateKeyboardLayout(activeLayout, 0); } void MSWindowsKeyState::fakeKey(const Keystroke& keystroke) { switch (keystroke.m_type) { case Keystroke::kButton: { LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up")); KeyButton button = keystroke.m_data.m_button.m_button; // windows doesn't send key ups for key repeats if (keystroke.m_data.m_button.m_repeat && !keystroke.m_data.m_button.m_press) { LOG((CLOG_DEBUG1 " discard key repeat release")); break; } // get the virtual key for the button UINT vk = keystroke.m_data.m_button.m_client; // special handling of VK_SNAPSHOT if (vk == VK_SNAPSHOT) { if ((getActiveModifiers() & KeyModifierAlt) != 0) { // snapshot active window button = 1; } else { // snapshot full screen button = 0; } } // synthesize event m_desks->fakeKeyEvent(button, vk, keystroke.m_data.m_button.m_press, keystroke.m_data.m_button.m_repeat); break; } case Keystroke::kGroup: // we don't restore the group. we'd like to but we can't be // sure the restoring group change will be processed after the // key events. if (!keystroke.m_data.m_group.m_restore) { if (keystroke.m_data.m_group.m_absolute) { LOG((CLOG_DEBUG1 " group %d", keystroke.m_data.m_group.m_group)); setWindowGroup(keystroke.m_data.m_group.m_group); } else { LOG((CLOG_DEBUG1 " group %+d", keystroke.m_data.m_group.m_group)); setWindowGroup(getEffectiveGroup(pollActiveGroup(), keystroke.m_data.m_group.m_group)); } } break; } } KeyModifierMask& MSWindowsKeyState::getActiveModifiersRValue() { if (m_useSavedModifiers) { return m_savedModifiers; } else { return KeyState::getActiveModifiersRValue(); } } bool MSWindowsKeyState::getGroups(GroupList& groups) const { // get keyboard layouts UInt32 newNumLayouts = GetKeyboardLayoutList(0, NULL); if (newNumLayouts == 0) { LOG((CLOG_DEBUG1 "can't get keyboard layouts")); return false; } HKL* newLayouts = new HKL[newNumLayouts]; newNumLayouts = GetKeyboardLayoutList(newNumLayouts, newLayouts); if (newNumLayouts == 0) { LOG((CLOG_DEBUG1 "can't get keyboard layouts")); delete[] newLayouts; return false; } groups.clear(); groups.insert(groups.end(), newLayouts, newLayouts + newNumLayouts); delete[] newLayouts; return true; } void MSWindowsKeyState::setWindowGroup(SInt32 group) { HWND targetWindow = GetForegroundWindow(); bool sysCharSet = true; // XXX -- determine if m_groups[group] can be used with the system // character set. PostMessage(targetWindow, WM_INPUTLANGCHANGEREQUEST, sysCharSet ? 1 : 0, (LPARAM)m_groups[group]); // XXX -- use a short delay to let the target window process the message // before it sees the keyboard events. i'm not sure why this is // necessary since the messages should arrive in order. if we don't // delay, though, some of our keyboard events may disappear. Sleep(100); } KeyID MSWindowsKeyState::getKeyID(UINT virtualKey, KeyButton button) const { // Some virtual keycodes have same values. // VK_HANGUL == VK_KANA, VK_HANJA == NK_KANJI // which are used to change the input mode of IME. // But they have different X11 keysym. So we should distinguish them. if ((LOWORD(m_keyLayout) & 0xffffu) == 0x0412u) { // 0x0412 : Korean Locale ID if (virtualKey == VK_HANGUL || virtualKey == VK_HANJA) { // If shift-space is used to change the input mode, // the extented bit is not set. So add it to get right key id. button |= 0x100u; } } if ((button & 0x100u) != 0) { virtualKey += 0x100u; } return s_virtualKey[virtualKey]; } UINT MSWindowsKeyState::mapButtonToVirtualKey(KeyButton button) const { return m_buttonToVK[button]; } KeyID MSWindowsKeyState::getIDForKey(synergy::KeyMap::KeyItem& item, KeyButton button, UINT virtualKey, PBYTE keyState, HKL hkl) const { WCHAR unicode[2]; int n = m_ToUnicodeEx( virtualKey, button, keyState, unicode, sizeof(unicode) / sizeof(unicode[0]), 0, hkl); KeyID id = static_cast(unicode[0]); switch (n) { case -1: return synergy::KeyMap::getDeadKey(id); default: case 0: // unmapped return kKeyNone; case 1: return id; case 2: // left over dead key in buffer. this used to recurse, // but apparently this causes a stack overflow, so just // return no key instead. return kKeyNone; } } void MSWindowsKeyState::addKeyEntry(synergy::KeyMap& keyMap, synergy::KeyMap::KeyItem& item) { keyMap.addKeyEntry(item); if (item.m_group == 0) { m_keyToVKMap[item.m_id] = static_cast(item.m_client); } } synergy-1.8.8-stable/src/lib/platform/MSWindowsKeyState.h000066400000000000000000000153431305627404700234140ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/KeyState.h" #include "base/String.h" #include "common/stdvector.h" #define WIN32_LEAN_AND_MEAN #include class Event; class EventQueueTimer; class MSWindowsDesks; class IEventQueue; //! Microsoft Windows key mapper /*! This class maps KeyIDs to keystrokes. */ class MSWindowsKeyState : public KeyState { public: MSWindowsKeyState(MSWindowsDesks* desks, void* eventTarget, IEventQueue* events); MSWindowsKeyState(MSWindowsDesks* desks, void* eventTarget, IEventQueue* events, synergy::KeyMap& keyMap); virtual ~MSWindowsKeyState(); //! @name manipulators //@{ //! Handle screen disabling /*! Called when screen is disabled. This is needed to deal with platform brokenness. */ void disable(); //! Set the active keyboard layout /*! Uses \p keyLayout when querying the keyboard. */ void setKeyLayout(HKL keyLayout); //! Test and set autorepeat state /*! Returns true if the given button is autorepeating and updates internal state. */ bool testAutoRepeat(bool press, bool isRepeat, KeyButton); //! Remember modifier state /*! Records the current non-toggle modifier state. */ void saveModifiers(); //! Set effective modifier state /*! Temporarily sets the non-toggle modifier state to those saved by the last call to \c saveModifiers if \p enable is \c true. Restores the modifier state to the current modifier state if \p enable is \c false. This is for synthesizing keystrokes on the primary screen when the cursor is on a secondary screen. When on a secondary screen we capture all non-toggle modifier state, track the state internally and do not pass it on. So if Alt+F1 synthesizes Alt+X we need to synthesize not just X but also Alt, despite the fact that our internal modifier state indicates Alt is down, because local apps never saw the Alt down event. */ void useSavedModifiers(bool enable); //@} //! @name accessors //@{ //! Map a virtual key to a button /*! Returns the button for the \p virtualKey. */ KeyButton virtualKeyToButton(UINT virtualKey) const; //! Map key event to a key /*! Converts a key event into a KeyID and the shadow modifier state to a modifier mask. */ KeyID mapKeyFromEvent(WPARAM charAndVirtKey, LPARAM info, KeyModifierMask* maskOut) const; //! Check if keyboard groups have changed /*! Returns true iff the number or order of the keyboard groups have changed since the last call to updateKeys(). */ bool didGroupsChange() const; //! Map key to virtual key /*! Returns the virtual key for key \p key or 0 if there's no such virtual key. */ UINT mapKeyToVirtualKey(KeyID key) const; //! Map virtual key and button to KeyID /*! Returns the KeyID for virtual key \p virtualKey and button \p button (button should include the extended key bit), or kKeyNone if there is no such key. */ KeyID getKeyID(UINT virtualKey, KeyButton button) const; //! Map button to virtual key /*! Returns the virtual key for button \p button (button should include the extended key bit), or kKeyNone if there is no such key. */ UINT mapButtonToVirtualKey(KeyButton button) const; //@} // IKeyState overrides virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button); virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button); virtual bool fakeCtrlAltDel(); virtual KeyModifierMask pollActiveModifiers() const; virtual SInt32 pollActiveGroup() const; virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const; // KeyState overrides virtual void onKey(KeyButton button, bool down, KeyModifierMask newState); virtual void sendKeyEvent(void* target, bool press, bool isAutoRepeat, KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button); // Unit test accessors KeyButton getLastDown() const { return m_lastDown; } void setLastDown(KeyButton value) { m_lastDown = value; } KeyModifierMask getSavedModifiers() const { return m_savedModifiers; } void setSavedModifiers(KeyModifierMask value) { m_savedModifiers = value; } protected: // KeyState overrides virtual void getKeyMap(synergy::KeyMap& keyMap); virtual void fakeKey(const Keystroke& keystroke); virtual KeyModifierMask& getActiveModifiersRValue(); private: typedef std::vector GroupList; // send ctrl+alt+del hotkey event on NT family static void ctrlAltDelThread(void*); bool getGroups(GroupList&) const; void setWindowGroup(SInt32 group); KeyID getIDForKey(synergy::KeyMap::KeyItem& item, KeyButton button, UINT virtualKey, PBYTE keyState, HKL hkl) const; void addKeyEntry(synergy::KeyMap& keyMap, synergy::KeyMap::KeyItem& item); void init(); private: // not implemented MSWindowsKeyState(const MSWindowsKeyState&); MSWindowsKeyState& operator=(const MSWindowsKeyState&); private: typedef std::map GroupMap; typedef std::map KeyToVKMap; void* m_eventTarget; MSWindowsDesks* m_desks; HKL m_keyLayout; UINT m_buttonToVK[512]; UINT m_buttonToNumpadVK[512]; KeyButton m_virtualKeyToButton[256]; KeyToVKMap m_keyToVKMap; IEventQueue* m_events; // the timer used to check for fixing key state EventQueueTimer* m_fixTimer; // the groups (keyboard layouts) GroupList m_groups; GroupMap m_groupMap; // the last button that we generated a key down event for. this // is zero if the last key event was a key up. we use this to // synthesize key repeats since the low level keyboard hook can't // tell us if an event is a key repeat. KeyButton m_lastDown; // modifier tracking bool m_useSavedModifiers; KeyModifierMask m_savedModifiers; KeyModifierMask m_originalSavedModifiers; // pointer to ToUnicodeEx. on win95 family this will be NULL. typedef int (WINAPI *ToUnicodeEx_t)(UINT wVirtKey, UINT wScanCode, PBYTE lpKeyState, LPWSTR pwszBuff, int cchBuff, UINT wFlags, HKL dwhkl); ToUnicodeEx_t m_ToUnicodeEx; static const KeyID s_virtualKey[]; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsScreen.cpp000066400000000000000000001407111305627404700234330ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsScreen.h" #include "platform/MSWindowsDropTarget.h" #include "client/Client.h" #include "platform/MSWindowsClipboard.h" #include "platform/MSWindowsDesks.h" #include "platform/MSWindowsEventQueueBuffer.h" #include "platform/MSWindowsKeyState.h" #include "platform/MSWindowsScreenSaver.h" #include "synergy/Clipboard.h" #include "synergy/KeyMap.h" #include "synergy/XScreen.h" #include "synergy/App.h" #include "synergy/ArgsBase.h" #include "synergy/ClientApp.h" #include "mt/Lock.h" #include "mt/Thread.h" #include "arch/win32/ArchMiscWindows.h" #include "arch/Arch.h" #include "base/FunctionJob.h" #include "base/Log.h" #include "base/String.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include "base/TMethodJob.h" #include #include #include #include // // add backwards compatible multihead support (and suppress bogus warning). // this isn't supported on MinGW yet AFAICT. // #if defined(_MSC_VER) #pragma warning(push) #pragma warning(disable: 4706) // assignment within conditional #define COMPILE_MULTIMON_STUBS #include #pragma warning(pop) #endif // 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 0x0080 #define MOUSEEVENTF_XUP 0x0100 #define XBUTTON1 0x0001 #define XBUTTON2 0x0002 #endif #if !defined(VK_XBUTTON1) #define VK_XBUTTON1 0x05 #define VK_XBUTTON2 0x06 #endif // WM_POWERBROADCAST stuff #if !defined(PBT_APMRESUMEAUTOMATIC) #define PBT_APMRESUMEAUTOMATIC 0x0012 #endif // // MSWindowsScreen // HINSTANCE MSWindowsScreen::s_windowInstance = NULL; MSWindowsScreen* MSWindowsScreen::s_screen = NULL; MSWindowsScreen::MSWindowsScreen( bool isPrimary, bool noHooks, bool stopOnDeskSwitch, IEventQueue* events) : PlatformScreen(events), m_isPrimary(isPrimary), m_noHooks(noHooks), m_isOnScreen(m_isPrimary), m_class(0), m_x(0), m_y(0), m_w(0), m_h(0), m_xCenter(0), m_yCenter(0), m_multimon(false), m_xCursor(0), m_yCursor(0), m_sequenceNumber(0), m_mark(0), m_markReceived(0), m_fixTimer(NULL), m_keyLayout(NULL), m_screensaver(NULL), m_screensaverNotify(false), m_screensaverActive(false), m_window(NULL), m_nextClipboardWindow(NULL), m_ownClipboard(false), m_desks(NULL), m_keyState(NULL), m_hasMouse(GetSystemMetrics(SM_MOUSEPRESENT) != 0), m_showingMouse(false), m_events(events), m_dropWindow(NULL), m_dropWindowSize(20) { assert(s_windowInstance != NULL); assert(s_screen == NULL); s_screen = this; try { if (m_isPrimary && !m_noHooks) { m_hook.loadLibrary(); } m_screensaver = new MSWindowsScreenSaver(); m_desks = new MSWindowsDesks( m_isPrimary, m_noHooks, m_hook.getInstance(), m_screensaver, m_events, new TMethodJob( this, &MSWindowsScreen::updateKeysCB), stopOnDeskSwitch); m_keyState = new MSWindowsKeyState(m_desks, getEventTarget(), m_events); updateScreenShape(); m_class = createWindowClass(); m_window = createWindow(m_class, "Synergy"); forceShowCursor(); 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)); // SHGetFolderPath is deprecated in vista, but use it for xp support. char desktopPath[MAX_PATH]; if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktopPath))) { m_desktopPath = String(desktopPath); LOG((CLOG_DEBUG "using desktop for drop target: %s", m_desktopPath.c_str())); } else { LOG((CLOG_ERR "failed to get desktop path, no drop target available, error=%d", GetLastError())); } OleInitialize(0); m_dropWindow = createDropWindow(m_class, "DropWindow"); m_dropTarget = new MSWindowsDropTarget(); RegisterDragDrop(m_dropWindow, m_dropTarget); } catch (...) { delete m_keyState; delete m_desks; delete m_screensaver; destroyWindow(m_window); destroyClass(m_class); s_screen = NULL; throw; } // install event handlers m_events->adoptHandler(Event::kSystem, m_events->getSystemTarget(), new TMethodEventJob(this, &MSWindowsScreen::handleSystemEvent)); // install the platform event queue m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events)); } MSWindowsScreen::~MSWindowsScreen() { assert(s_screen != NULL); disable(); m_events->adoptBuffer(NULL); m_events->removeHandler(Event::kSystem, m_events->getSystemTarget()); delete m_keyState; delete m_desks; delete m_screensaver; destroyWindow(m_window); destroyClass(m_class); RevokeDragDrop(m_dropWindow); m_dropTarget->Release(); OleUninitialize(); destroyWindow(m_dropWindow); s_screen = NULL; } void MSWindowsScreen::init(HINSTANCE windowInstance) { assert(s_windowInstance == NULL); assert(windowInstance != NULL); s_windowInstance = windowInstance; } HINSTANCE MSWindowsScreen::getWindowInstance() { return s_windowInstance; } void MSWindowsScreen::enable() { assert(m_isOnScreen == m_isPrimary); // we need to poll some things to fix them m_fixTimer = m_events->newTimer(1.0, NULL); m_events->adoptHandler(Event::kTimer, m_fixTimer, new TMethodEventJob(this, &MSWindowsScreen::handleFixes)); // install our clipboard snooper m_nextClipboardWindow = SetClipboardViewer(m_window); // track the active desk and (re)install the hooks m_desks->enable(); if (m_isPrimary) { // set jump zones m_hook.setZone(m_x, m_y, m_w, m_h, getJumpZoneSize()); // watch jump zones m_hook.setMode(kHOOK_WATCH_JUMP_ZONE); } 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. ArchMiscWindows::addBusyState(ArchMiscWindows::kSYSTEM); } } void MSWindowsScreen::disable() { // stop tracking the active desk m_desks->disable(); if (m_isPrimary) { // disable hooks m_hook.setMode(kHOOK_DISABLE); // enable special key sequences on win95 family enableSpecialKeys(true); } else { // allow the system to enter power saving mode ArchMiscWindows::removeBusyState(ArchMiscWindows::kSYSTEM | ArchMiscWindows::kDISPLAY); } // tell key state m_keyState->disable(); // stop snooping the clipboard ChangeClipboardChain(m_window, m_nextClipboardWindow); m_nextClipboardWindow = NULL; // uninstall fix timer if (m_fixTimer != NULL) { m_events->removeHandler(Event::kTimer, m_fixTimer); m_events->deleteTimer(m_fixTimer); m_fixTimer = NULL; } m_isOnScreen = m_isPrimary; forceShowCursor(); } void MSWindowsScreen::enter() { m_desks->enter(); if (m_isPrimary) { // enable special key sequences on win95 family enableSpecialKeys(true); // watch jump zones m_hook.setMode(kHOOK_WATCH_JUMP_ZONE); // all messages prior to now are invalid nextMark(); m_primaryKeyDownList.clear(); } else { // Entering a secondary screen. Ensure that no screensaver is active // and that the screen is not in powersave mode. ArchMiscWindows::wakeupDisplay(); if (m_screensaver != NULL && m_screensaverActive) { m_screensaver->deactivate(); m_screensaverActive = 0; } } // now on screen m_isOnScreen = true; forceShowCursor(); } bool MSWindowsScreen::leave() { // 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 m_keyState->setKeyLayout(m_keyLayout); // tell desk that we're leaving and tell it the keyboard layout m_desks->leave(m_keyLayout); if (m_isPrimary) { // warp to center LOG((CLOG_DEBUG1 "warping cursor to center: %+d, %+d", m_xCenter, m_yCenter)); warpCursor(m_xCenter, m_yCenter); // disable special key sequences on win95 family enableSpecialKeys(false); // all messages prior to now are invalid nextMark(); // remember the modifier state. this is the modifier state // reflected in the internal keyboard state. m_keyState->saveModifiers(); m_hook.setMode(kHOOK_RELAY_EVENTS); m_primaryKeyDownList.clear(); for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { if (m_keyState->isKeyDown(i)) { m_primaryKeyDownList.push_back(i); LOG((CLOG_DEBUG1 "key button %d is down before leaving to another screen", i)); } } } // now off screen m_isOnScreen = false; forceShowCursor(); if (isDraggingStarted() && !m_isPrimary) { m_sendDragThread = new Thread( new TMethodJob( this, &MSWindowsScreen::sendDragThread)); } return true; } void MSWindowsScreen::sendDragThread(void*) { String& draggingFilename = getDraggingFilename(); size_t size = draggingFilename.size(); if (draggingFilename.empty() == false) { ClientApp& app = ClientApp::instance(); Client* client = app.getClientPtr(); UInt32 fileCount = 1; LOG((CLOG_DEBUG "send dragging info to server: %s", draggingFilename.c_str())); client->sendDragInfo(fileCount, draggingFilename, size); LOG((CLOG_DEBUG "send dragging file to server")); client->sendFileToServer(draggingFilename.c_str()); } m_draggingStarted = false; } bool MSWindowsScreen::setClipboard(ClipboardID, const IClipboard* src) { MSWindowsClipboard dst(m_window); if (src != NULL) { // save clipboard data return Clipboard::copy(&dst, src); } else { // assert clipboard ownership if (!dst.open(0)) { return false; } dst.empty(); dst.close(); return true; } } void MSWindowsScreen::checkClipboards() { // 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. if (m_ownClipboard && !MSWindowsClipboard::isOwnedBySynergy()) { LOG((CLOG_DEBUG "clipboard changed: lost ownership and no notification received")); m_ownClipboard = false; sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardClipboard); sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardSelection); } } void MSWindowsScreen::openScreensaver(bool notify) { assert(m_screensaver != NULL); m_screensaverNotify = notify; if (m_screensaverNotify) { m_desks->installScreensaverHooks(true); } else if (m_screensaver) { m_screensaver->disable(); } } void MSWindowsScreen::closeScreensaver() { if (m_screensaver != NULL) { if (m_screensaverNotify) { m_desks->installScreensaverHooks(false); } else { m_screensaver->enable(); } } m_screensaverNotify = false; } void MSWindowsScreen::screensaver(bool activate) { assert(m_screensaver != NULL); if (m_screensaver==NULL) return; if (activate) { m_screensaver->activate(); } else { m_screensaver->deactivate(); } } void MSWindowsScreen::resetOptions() { m_desks->resetOptions(); } void MSWindowsScreen::setOptions(const OptionsList& options) { m_desks->setOptions(options); } void MSWindowsScreen::setSequenceNumber(UInt32 seqNum) { m_sequenceNumber = seqNum; } bool MSWindowsScreen::isPrimary() const { return m_isPrimary; } void* MSWindowsScreen::getEventTarget() const { return const_cast(this); } bool MSWindowsScreen::getClipboard(ClipboardID, IClipboard* dst) const { MSWindowsClipboard src(m_window); Clipboard::copy(dst, &src); return true; } void MSWindowsScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { assert(m_class != 0); x = m_x; y = m_y; w = m_w; h = m_h; } void MSWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const { m_desks->getCursorPos(x, y); } void MSWindowsScreen::reconfigure(UInt32 activeSides) { assert(m_isPrimary); LOG((CLOG_DEBUG "active sides: %x", activeSides)); m_hook.setSides(activeSides); } void MSWindowsScreen::warpCursor(SInt32 x, SInt32 y) { // 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 } // save position to compute delta of next motion saveMousePosition(x, y); } void MSWindowsScreen::saveMousePosition(SInt32 x, SInt32 y) { m_xCursor = x; m_yCursor = y; LOG((CLOG_DEBUG5 "saved mouse position for next delta: %+d,%+d", x,y)); } UInt32 MSWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) { // only allow certain modifiers if ((mask & ~(KeyModifierShift | KeyModifierControl | KeyModifierAlt | KeyModifierSuper)) != 0) { // this should be a warning, but this can confuse users, // as this warning happens almost always. LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); return 0; } // fail if no keys if (key == kKeyNone && mask == 0) { return 0; } // convert to win32 UINT modifiers = 0; if ((mask & KeyModifierShift) != 0) { modifiers |= MOD_SHIFT; } if ((mask & KeyModifierControl) != 0) { modifiers |= MOD_CONTROL; } if ((mask & KeyModifierAlt) != 0) { modifiers |= MOD_ALT; } if ((mask & KeyModifierSuper) != 0) { modifiers |= MOD_WIN; } UINT vk = m_keyState->mapKeyToVirtualKey(key); if (key != kKeyNone && vk == 0) { // can't map key // this should be a warning, but this can confuse users, // as this warning happens almost always. LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); return 0; } // choose hotkey id UInt32 id; if (!m_oldHotKeyIDs.empty()) { id = m_oldHotKeyIDs.back(); m_oldHotKeyIDs.pop_back(); } else { //id = m_hotKeys.size() + 1; id = (UInt32)m_hotKeys.size() + 1; } // if this hot key has modifiers only then we'll handle it specially bool err; if (key == kKeyNone) { // check if already registered err = (m_hotKeyToIDMap.count(HotKeyItem(vk, modifiers)) > 0); } else { // register with OS err = (RegisterHotKey(NULL, id, modifiers, vk) == 0); } if (!err) { m_hotKeys.insert(std::make_pair(id, HotKeyItem(vk, modifiers))); m_hotKeyToIDMap[HotKeyItem(vk, modifiers)] = id; } else { m_oldHotKeyIDs.push_back(id); m_hotKeys.erase(id); LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", synergy::KeyMap::formatKey(key, mask).c_str(), key, mask)); return 0; } LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", synergy::KeyMap::formatKey(key, mask).c_str(), key, mask, id)); return id; } void MSWindowsScreen::unregisterHotKey(UInt32 id) { // look up hotkey HotKeyMap::iterator i = m_hotKeys.find(id); if (i == m_hotKeys.end()) { return; } // unregister with OS bool err; if (i->second.getVirtualKey() != 0) { err = !UnregisterHotKey(NULL, id); } else { err = false; } if (err) { LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); } else { LOG((CLOG_DEBUG "unregistered hotkey id=%d", id)); } // discard hot key from map and record old id for reuse m_hotKeyToIDMap.erase(i->second); m_hotKeys.erase(i); m_oldHotKeyIDs.push_back(id); } void MSWindowsScreen::fakeInputBegin() { assert(m_isPrimary); if (!m_isOnScreen) { m_keyState->useSavedModifiers(true); } m_desks->fakeInputBegin(); } void MSWindowsScreen::fakeInputEnd() { assert(m_isPrimary); m_desks->fakeInputEnd(); if (!m_isOnScreen) { m_keyState->useSavedModifiers(false); } } SInt32 MSWindowsScreen::getJumpZoneSize() const { return 1; } bool MSWindowsScreen::isAnyMouseButtonDown(UInt32& buttonID) const { static const char* buttonToName[] = { "", "Left Button", "Middle Button", "Right Button", "X Button 1", "X Button 2" }; for (UInt32 i = 1; i < sizeof(m_buttons) / sizeof(m_buttons[0]); ++i) { if (m_buttons[i]) { buttonID = i; LOG((CLOG_DEBUG "locked by \"%s\"", buttonToName[i])); return true; } } return false; } void MSWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const { x = m_xCenter; y = m_yCenter; } void MSWindowsScreen::fakeMouseButton(ButtonID id, bool press) { m_desks->fakeMouseButton(id, press); if (id == kButtonLeft) { if (press) { m_buttons[kButtonLeft] = true; } else { m_buttons[kButtonLeft] = false; m_fakeDraggingStarted = false; m_draggingStarted = false; } } } void MSWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) { m_desks->fakeMouseMove(x, y); if (m_buttons[kButtonLeft]) { m_draggingStarted = true; } } void MSWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const { m_desks->fakeMouseRelativeMove(dx, dy); } void MSWindowsScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const { m_desks->fakeMouseWheel(xDelta, yDelta); } void MSWindowsScreen::updateKeys() { m_desks->updateKeys(); } void MSWindowsScreen::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button) { PlatformScreen::fakeKeyDown(id, mask, button); updateForceShowCursor(); } bool MSWindowsScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) { bool result = PlatformScreen::fakeKeyRepeat(id, mask, count, button); updateForceShowCursor(); return result; } bool MSWindowsScreen::fakeKeyUp(KeyButton button) { bool result = PlatformScreen::fakeKeyUp(button); updateForceShowCursor(); return result; } void MSWindowsScreen::fakeAllKeysUp() { PlatformScreen::fakeAllKeysUp(); updateForceShowCursor(); } HCURSOR MSWindowsScreen::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_windowInstance, 0, 0, cw, ch, cursorAND, cursorXOR); delete[] cursorXOR; delete[] cursorAND; return c; } void MSWindowsScreen::destroyCursor(HCURSOR cursor) const { if (cursor != NULL) { DestroyCursor(cursor); } } ATOM MSWindowsScreen::createWindowClass() const { WNDCLASSEX classInfo; classInfo.cbSize = sizeof(classInfo); classInfo.style = CS_DBLCLKS | CS_NOCLOSE; classInfo.lpfnWndProc = &MSWindowsScreen::wndProc; classInfo.cbClsExtra = 0; classInfo.cbWndExtra = 0; classInfo.hInstance = s_windowInstance; classInfo.hIcon = NULL; classInfo.hCursor = NULL; classInfo.hbrBackground = NULL; classInfo.lpszMenuName = NULL; classInfo.lpszClassName = "Synergy"; classInfo.hIconSm = NULL; return RegisterClassEx(&classInfo); } void MSWindowsScreen::destroyClass(ATOM windowClass) const { if (windowClass != 0) { UnregisterClass(reinterpret_cast(windowClass), s_windowInstance); } } HWND MSWindowsScreen::createWindow(ATOM windowClass, const char* name) const { HWND window = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_TOOLWINDOW, reinterpret_cast(windowClass), name, WS_POPUP, 0, 0, 1, 1, NULL, NULL, s_windowInstance, NULL); if (window == NULL) { LOG((CLOG_ERR "failed to create window: %d", GetLastError())); throw XScreenOpenFailure(); } return window; } HWND MSWindowsScreen::createDropWindow(ATOM windowClass, const char* name) const { HWND window = CreateWindowEx( WS_EX_TOPMOST | WS_EX_TRANSPARENT | WS_EX_ACCEPTFILES, reinterpret_cast(m_class), name, WS_POPUP, 0, 0, m_dropWindowSize, m_dropWindowSize, NULL, NULL, s_windowInstance, NULL); if (window == NULL) { LOG((CLOG_ERR "failed to create drop window: %d", GetLastError())); throw XScreenOpenFailure(); } return window; } void MSWindowsScreen::destroyWindow(HWND hwnd) const { if (hwnd != NULL) { DestroyWindow(hwnd); } } void MSWindowsScreen::sendEvent(Event::Type type, void* data) { m_events->addEvent(Event(type, getEventTarget(), data)); } void MSWindowsScreen::sendClipboardEvent(Event::Type type, ClipboardID id) { ClipboardInfo* info = (ClipboardInfo*)malloc(sizeof(ClipboardInfo)); if (info == NULL) { LOG((CLOG_ERR "malloc failed on %s:%s", __FILE__, __LINE__ )); return; } info->m_id = id; info->m_sequenceNumber = m_sequenceNumber; sendEvent(type, info); } void MSWindowsScreen::handleSystemEvent(const Event& event, void*) { MSG* msg = static_cast(event.getData()); assert(msg != NULL); if (ArchMiscWindows::processDialog(msg)) { return; } if (onPreDispatch(msg->hwnd, msg->message, msg->wParam, msg->lParam)) { return; } TranslateMessage(msg); DispatchMessage(msg); } void MSWindowsScreen::updateButtons() { int numButtons = GetSystemMetrics(SM_CMOUSEBUTTONS); m_buttons[kButtonNone] = false; m_buttons[kButtonLeft] = (GetKeyState(VK_LBUTTON) < 0); m_buttons[kButtonRight] = (GetKeyState(VK_RBUTTON) < 0); m_buttons[kButtonMiddle] = (GetKeyState(VK_MBUTTON) < 0); m_buttons[kButtonExtra0 + 0] = (numButtons >= 4) && (GetKeyState(VK_XBUTTON1) < 0); m_buttons[kButtonExtra0 + 1] = (numButtons >= 5) && (GetKeyState(VK_XBUTTON2) < 0); } IKeyState* MSWindowsScreen::getKeyState() const { return m_keyState; } bool MSWindowsScreen::onPreDispatch(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { // handle event switch (message) { case SYNERGY_MSG_SCREEN_SAVER: return onScreensaver(wParam != 0); case SYNERGY_MSG_DEBUG: LOG((CLOG_DEBUG1 "hook: 0x%08x 0x%08x", wParam, lParam)); return true; } if (m_isPrimary) { return onPreDispatchPrimary(hwnd, message, wParam, lParam); } return false; } bool MSWindowsScreen::onPreDispatchPrimary(HWND, UINT message, WPARAM wParam, LPARAM lParam) { LOG((CLOG_DEBUG5 "handling pre-dispatch primary")); // handle event switch (message) { case SYNERGY_MSG_MARK: return onMark(static_cast(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(wParam), static_cast(lParam)); case SYNERGY_MSG_MOUSE_WHEEL: // XXX -- support x-axis scrolling return onMouseWheel(0, static_cast(wParam)); case SYNERGY_MSG_PRE_WARP: { // save position to compute delta of next motion saveMousePosition(static_cast(wParam), static_cast(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; case WM_HOTKEY: // we discard these messages. we'll catch the hot key in the // regular key event handling, where we can detect both key // press and release. we only register the hot key so no other // app will act on the key combination. break; } return false; } bool MSWindowsScreen::onEvent(HWND, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* result) { switch (msg) { case WM_DRAWCLIPBOARD: // first pass on the message if (m_nextClipboardWindow != NULL) { SendMessage(m_nextClipboardWindow, msg, wParam, lParam); } // 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) { SendMessage(m_nextClipboardWindow, msg, wParam, lParam); } return true; case WM_DISPLAYCHANGE: return onDisplayChange(); case WM_POWERBROADCAST: switch (wParam) { case PBT_APMRESUMEAUTOMATIC: case PBT_APMRESUMECRITICAL: case PBT_APMRESUMESUSPEND: m_events->addEvent(Event(m_events->forIScreen().resume(), getEventTarget(), NULL, Event::kDeliverImmediately)); break; case PBT_APMSUSPEND: m_events->addEvent(Event(m_events->forIScreen().suspend(), getEventTarget(), NULL, Event::kDeliverImmediately)); break; } *result = TRUE; return true; case WM_DEVICECHANGE: forceShowCursor(); break; case WM_SETTINGCHANGE: if (wParam == SPI_SETMOUSEKEYS) { forceShowCursor(); } break; } return false; } bool MSWindowsScreen::onMark(UInt32 mark) { m_markReceived = mark; return true; } bool MSWindowsScreen::onKey(WPARAM wParam, LPARAM lParam) { static const KeyModifierMask s_ctrlAlt = KeyModifierControl | KeyModifierAlt; LOG((CLOG_DEBUG1 "event: Key char=%d, vk=0x%02x, nagr=%d, lParam=0x%08x", (wParam & 0xff00u) >> 8, wParam & 0xffu, (wParam & 0x10000u) ? 1 : 0, lParam)); // get event info KeyButton button = (KeyButton)((lParam & 0x01ff0000) >> 16); bool down = ((lParam & 0x80000000u) == 0x00000000u); bool wasDown = isKeyDown(button); KeyModifierMask oldState = pollActiveModifiers(); // check for autorepeat if (m_keyState->testAutoRepeat(down, (lParam & 0x40000000u) == 1, button)) { lParam |= 0x40000000u; } // if the button is zero then guess what the button should be. // these are badly synthesized key events and logitech software // that maps mouse buttons to keys is known to do this. // alternatively, we could just throw these events out. if (button == 0) { button = m_keyState->virtualKeyToButton(wParam & 0xffu); if (button == 0) { return true; } wasDown = isKeyDown(button); } // record keyboard state m_keyState->onKey(button, down, oldState); if (!down && m_isPrimary && !m_isOnScreen) { PrimaryKeyDownList::iterator find = std::find(m_primaryKeyDownList.begin(), m_primaryKeyDownList.end(), button); if (find != m_primaryKeyDownList.end()) { LOG((CLOG_DEBUG1 "release key button %d on primary", *find)); m_hook.setMode(kHOOK_WATCH_JUMP_ZONE); fakeLocalKey(*find, false); m_primaryKeyDownList.erase(find); m_hook.setMode(kHOOK_RELAY_EVENTS); return true; } } // windows doesn't tell us the modifier key state on mouse or key // events so we have to figure it out. most apps would use // GetKeyState() or even GetAsyncKeyState() for that but we can't // because our hook doesn't pass on key events for several modifiers. // it can't otherwise the system would interpret them normally on // the primary screen even when on a secondary screen. so tapping // alt would activate menus and tapping the windows key would open // the start menu. if you don't pass those events on in the hook // then GetKeyState() understandably doesn't reflect the effect of // the event. curiously, neither does GetAsyncKeyState(), which is // surprising. // // so anyway, we have to track the modifier state ourselves for // at least those modifiers we don't pass on. pollActiveModifiers() // does that but we have to update the keyboard state before calling // pollActiveModifiers() to get the right answer. but the only way // to set the modifier state or to set the up/down state of a key // is via onKey(). so we have to call onKey() twice. KeyModifierMask state = pollActiveModifiers(); m_keyState->onKey(button, down, state); // check for hot keys if (oldState != state) { // modifier key was pressed/released if (onHotKey(0, lParam)) { return true; } } else { // non-modifier was pressed/released if (onHotKey(wParam, lParam)) { return true; } } // stop sending modifier keys over and over again if (isModifierRepeat(oldState, state, wParam)) { return true; } // ignore message if posted prior to last mark change if (!ignore()) { // check for ctrl+alt+del. we do not want to pass that to the // client. the user can use ctrl+alt+pause to emulate it. UINT virtKey = (wParam & 0xffu); if (virtKey == VK_DELETE && (state & s_ctrlAlt) == s_ctrlAlt) { LOG((CLOG_DEBUG "discard ctrl+alt+del")); return true; } // check for ctrl+alt+del emulation if ((virtKey == VK_PAUSE || virtKey == VK_CANCEL) && (state & s_ctrlAlt) == s_ctrlAlt) { LOG((CLOG_DEBUG "emulate ctrl+alt+del")); // switch wParam and lParam to be as if VK_DELETE was // pressed or released. when mapping the key we require that // we not use AltGr (the 0x10000 flag in wParam) and we not // use the keypad delete key (the 0x01000000 flag in lParam). wParam = VK_DELETE | 0x00010000u; lParam &= 0xfe000000; lParam |= m_keyState->virtualKeyToButton(wParam & 0xffu) << 16; lParam |= 0x01000001; } // process key KeyModifierMask mask; KeyID key = m_keyState->mapKeyFromEvent(wParam, lParam, &mask); button = static_cast((lParam & 0x01ff0000u) >> 16); if (key != kKeyNone) { // do it m_keyState->sendKeyEvent(getEventTarget(), ((lParam & 0x80000000u) == 0), ((lParam & 0x40000000u) != 0), key, mask, (SInt32)(lParam & 0xffff), button); } else { LOG((CLOG_DEBUG1 "cannot map key")); } } return true; } bool MSWindowsScreen::onHotKey(WPARAM wParam, LPARAM lParam) { // get the key info KeyModifierMask state = getActiveModifiers(); UINT virtKey = (wParam & 0xffu); UINT modifiers = 0; if ((state & KeyModifierShift) != 0) { modifiers |= MOD_SHIFT; } if ((state & KeyModifierControl) != 0) { modifiers |= MOD_CONTROL; } if ((state & KeyModifierAlt) != 0) { modifiers |= MOD_ALT; } if ((state & KeyModifierSuper) != 0) { modifiers |= MOD_WIN; } // find the hot key id HotKeyToIDMap::const_iterator i = m_hotKeyToIDMap.find(HotKeyItem(virtKey, modifiers)); if (i == m_hotKeyToIDMap.end()) { return false; } // find what kind of event Event::Type type; if ((lParam & 0x80000000u) == 0u) { if ((lParam & 0x40000000u) != 0u) { // ignore key repeats but it counts as a hot key return true; } type = m_events->forIPrimaryScreen().hotKeyDown(); } else { type = m_events->forIPrimaryScreen().hotKeyUp(); } // generate event m_events->addEvent(Event(type, getEventTarget(), HotKeyInfo::alloc(i->second))); return true; } bool MSWindowsScreen::onMouseButton(WPARAM wParam, LPARAM lParam) { // get which button bool pressed = mapPressFromEvent(wParam, lParam); ButtonID button = mapButtonFromEvent(wParam, lParam); // keep our shadow key state up to date if (button >= kButtonLeft && button <= kButtonExtra0 + 1) { if (pressed) { m_buttons[button] = true; if (button == kButtonLeft) { m_draggingFilename.clear(); LOG((CLOG_DEBUG2 "dragging filename is cleared")); } } else { m_buttons[button] = false; if (m_draggingStarted && button == kButtonLeft) { m_draggingStarted = false; } } } // ignore message if posted prior to last mark change if (!ignore()) { KeyModifierMask mask = m_keyState->getActiveModifiers(); if (pressed) { LOG((CLOG_DEBUG1 "event: button press button=%d", button)); if (button != kButtonNone) { sendEvent(m_events->forIPrimaryScreen().buttonDown(), ButtonInfo::alloc(button, mask)); } } else { LOG((CLOG_DEBUG1 "event: button release button=%d", button)); if (button != kButtonNone) { sendEvent(m_events->forIPrimaryScreen().buttonUp(), ButtonInfo::alloc(button, mask)); } } } return true; } // here's how mouse movements are sent across the network to a client: // 1. synergy checks the mouse position on server screen // 2. records the delta (current x,y minus last x,y) // 3. records the current x,y as "last" (so we can calc delta next time) // 4. on the server, puts the cursor back to the center of the screen // - remember the cursor is hidden on the server at this point // - this actually records the current x,y as "last" a second time (it seems) // 5. sends the delta movement to the client (could be +1,+1 or -1,+4 for example) bool MSWindowsScreen::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; LOG((CLOG_DEBUG3 "mouse move - motion delta: %+d=(%+d - %+d),%+d=(%+d - %+d)", x, mx, m_xCursor, 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 saveMousePosition(mx, my); if (m_isOnScreen) { // motion on primary screen sendEvent( m_events->forIPrimaryScreen().motionOnPrimary(), MotionInfo::alloc(m_xCursor, m_yCursor)); if (m_buttons[kButtonLeft] == true && m_draggingStarted == false) { m_draggingStarted = true; } } else { // the motion is on the secondary screen, so we warp mouse back to // center on the server screen. if we don't do this, then the mouse // will always try to return to the original entry point on the // secondary screen. LOG((CLOG_DEBUG5 "warping server cursor to center: %+d,%+d", m_xCenter, m_yCenter)); 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 delta motion: %+d,%+d", x, y)); } else { // send motion sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), MotionInfo::alloc(x, y)); } } return true; } bool MSWindowsScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta) { // ignore message if posted prior to last mark change if (!ignore()) { LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta)); sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(xDelta, yDelta)); } return true; } bool MSWindowsScreen::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_screensaverActive && m_screensaver->checkStarted(SYNERGY_MSG_SCREEN_SAVER, FALSE, 0)) { m_screensaverActive = true; sendEvent(m_events->forIPrimaryScreen().screensaverActivated()); // enable display power down ArchMiscWindows::removeBusyState(ArchMiscWindows::kDISPLAY); } } else { if (m_screensaverActive) { m_screensaverActive = false; sendEvent(m_events->forIPrimaryScreen().screensaverDeactivated()); // disable display power down ArchMiscWindows::addBusyState(ArchMiscWindows::kDISPLAY); } } return true; } bool MSWindowsScreen::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) { LOG((CLOG_DEBUG1 "warping cursor to center: %+d, %+d", m_xCenter, m_yCenter)); warpCursor(m_xCenter, m_yCenter); } // tell hook about resize if on screen else { m_hook.setZone(m_x, m_y, m_w, m_h, getJumpZoneSize()); } } // send new screen info sendEvent(m_events->forIScreen().shapeChanged()); LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_multimon ? "(multi-monitor)" : "")); } return true; } bool MSWindowsScreen::onClipboardChange() { // now notify client that somebody changed the clipboard (unless // we're the owner). if (!MSWindowsClipboard::isOwnedBySynergy()) { if (m_ownClipboard) { LOG((CLOG_DEBUG "clipboard changed: lost ownership")); m_ownClipboard = false; sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardClipboard); sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardSelection); } } else if (!m_ownClipboard) { LOG((CLOG_DEBUG "clipboard changed: synergy owned")); m_ownClipboard = true; } return true; } void MSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y) { // send an event that we can recognize before the mouse warp PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_PRE_WARP, x, y); // warp mouse. hopefully this inserts a mouse motion event // between the previous message and the following message. SetCursorPos(x, y); // check to see if the mouse pos was set correctly POINT cursorPos; GetCursorPos(&cursorPos); // there is a bug or round error in SetCursorPos and GetCursorPos on // a high DPI setting. The check here is for Vista/7 login screen. // since this feature is mainly for client, so only check on client. if (!isPrimary()) { if ((cursorPos.x != x) && (cursorPos.y != y)) { LOG((CLOG_DEBUG "SetCursorPos did not work; using fakeMouseMove instead")); LOG((CLOG_DEBUG "cursor pos %d, %d expected pos %d, %d", cursorPos.x, cursorPos.y, x, y)); // when at Vista/7 login screen, SetCursorPos does not work (which could be // an MS security feature). instead we can use fakeMouseMove, which calls // mouse_event. // IMPORTANT: as of implementing this function, it has an annoying side // effect; instead of the mouse returning to the correct exit point, it // returns to the center of the screen. this could have something to do with // the center screen warping technique used (see comments for onMouseMove // definition). fakeMouseMove(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 PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_POST_WARP, 0, 0); } void MSWindowsScreen::nextMark() { // next mark ++m_mark; // mark point in message queue where the mark was changed PostThreadMessage(GetCurrentThreadId(), SYNERGY_MSG_MARK, m_mark, 0); } bool MSWindowsScreen::ignore() const { return (m_mark != m_markReceived); } void MSWindowsScreen::updateScreenShape() { // get shape and center m_w = GetSystemMetrics(SM_CXVIRTUALSCREEN); m_h = GetSystemMetrics(SM_CYVIRTUALSCREEN); m_x = GetSystemMetrics(SM_XVIRTUALSCREEN); m_y = GetSystemMetrics(SM_YVIRTUALSCREEN); 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)); // tell the desks m_desks->setShape(m_x, m_y, m_w, m_h, m_xCenter, m_yCenter, m_multimon); } void MSWindowsScreen::handleFixes(const Event&, void*) { // fix clipboard chain fixClipboardViewer(); // update keys if keyboard layouts have changed if (m_keyState->didGroupsChange()) { updateKeys(); } } void MSWindowsScreen::fixClipboardViewer() { // XXX -- disable this code for now. somehow it can cause an infinite // recursion in the WM_DRAWCLIPBOARD handler. either we're sending // the message to our own window or some window farther down the chain // forwards the message to our window or a window farther up the chain. // i'm not sure how that could happen. the m_nextClipboardWindow = NULL // was not in the code that infinite loops and may fix the bug but i // doubt it. /* ChangeClipboardChain(m_window, m_nextClipboardWindow); m_nextClipboardWindow = NULL; m_nextClipboardWindow = SetClipboardViewer(m_window); */ } void MSWindowsScreen::enableSpecialKeys(bool enable) const { } ButtonID MSWindowsScreen::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: if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 4) { return kButtonExtra0 + 0; } break; case XBUTTON2: if (GetSystemMetrics(SM_CMOUSEBUTTONS) >= 5) { return kButtonExtra0 + 1; } break; } return kButtonNone; default: return kButtonNone; } } bool MSWindowsScreen::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; } } void MSWindowsScreen::updateKeysCB(void*) { // record which keys we think are down bool down[IKeyState::kNumButtons]; bool sendFixes = (isPrimary() && !m_isOnScreen); if (sendFixes) { for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { down[i] = m_keyState->isKeyDown(i); } } // update layouts if necessary if (m_keyState->didGroupsChange()) { PlatformScreen::updateKeyMap(); } // now update the keyboard state PlatformScreen::updateKeyState(); // now see which keys we thought were down but now think are up. // send key releases for these keys to the active client. if (sendFixes) { KeyModifierMask mask = pollActiveModifiers(); for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { if (down[i] && !m_keyState->isKeyDown(i)) { m_keyState->sendKeyEvent(getEventTarget(), false, false, kKeyNone, mask, 1, i); } } } } void MSWindowsScreen::forceShowCursor() { // check for mouse m_hasMouse = (GetSystemMetrics(SM_MOUSEPRESENT) != 0); // decide if we should show the mouse bool showMouse = (!m_hasMouse && !m_isPrimary && m_isOnScreen); // show/hide the mouse if (showMouse != m_showingMouse) { if (showMouse) { m_oldMouseKeys.cbSize = sizeof(m_oldMouseKeys); m_gotOldMouseKeys = (SystemParametersInfo(SPI_GETMOUSEKEYS, m_oldMouseKeys.cbSize, &m_oldMouseKeys, 0) != 0); if (m_gotOldMouseKeys) { m_mouseKeys = m_oldMouseKeys; m_showingMouse = true; updateForceShowCursor(); } } else { if (m_gotOldMouseKeys) { SystemParametersInfo(SPI_SETMOUSEKEYS, m_oldMouseKeys.cbSize, &m_oldMouseKeys, SPIF_SENDCHANGE); m_showingMouse = false; } } } } void MSWindowsScreen::updateForceShowCursor() { DWORD oldFlags = m_mouseKeys.dwFlags; // turn on MouseKeys m_mouseKeys.dwFlags = MKF_AVAILABLE | MKF_MOUSEKEYSON; // make sure MouseKeys is active in whatever state the NumLock is // not currently in. if ((m_keyState->getActiveModifiers() & KeyModifierNumLock) != 0) { m_mouseKeys.dwFlags |= MKF_REPLACENUMBERS; } // update MouseKeys if (oldFlags != m_mouseKeys.dwFlags) { SystemParametersInfo(SPI_SETMOUSEKEYS, m_mouseKeys.cbSize, &m_mouseKeys, SPIF_SENDCHANGE); } } LRESULT CALLBACK MSWindowsScreen::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); } return result; } void MSWindowsScreen::fakeLocalKey(KeyButton button, bool press) const { INPUT input; input.type = INPUT_KEYBOARD; input.ki.wVk = m_keyState->mapButtonToVirtualKey(button); DWORD pressFlag = press ? KEYEVENTF_EXTENDEDKEY : KEYEVENTF_KEYUP; input.ki.dwFlags = pressFlag; input.ki.time = 0; input.ki.dwExtraInfo = 0; SendInput(1,&input,sizeof(input)); } // // MSWindowsScreen::HotKeyItem // MSWindowsScreen::HotKeyItem::HotKeyItem(UINT keycode, UINT mask) : m_keycode(keycode), m_mask(mask) { // do nothing } UINT MSWindowsScreen::HotKeyItem::getVirtualKey() const { return m_keycode; } bool MSWindowsScreen::HotKeyItem::operator<(const HotKeyItem& x) const { return (m_keycode < x.m_keycode || (m_keycode == x.m_keycode && m_mask < x.m_mask)); } void MSWindowsScreen::fakeDraggingFiles(DragFileList fileList) { // possible design flaw: this function stops a "not implemented" // exception from being thrown. } String& MSWindowsScreen::getDraggingFilename() { if (m_draggingStarted) { m_dropTarget->clearDraggingFilename(); m_draggingFilename.clear(); int halfSize = m_dropWindowSize / 2; SInt32 xPos = m_isPrimary ? m_xCursor : m_xCenter; SInt32 yPos = m_isPrimary ? m_yCursor : m_yCenter; xPos = (xPos - halfSize) < 0 ? 0 : xPos - halfSize; yPos = (yPos - halfSize) < 0 ? 0 : yPos - halfSize; SetWindowPos( m_dropWindow, HWND_TOPMOST, xPos, yPos, m_dropWindowSize, m_dropWindowSize, SWP_SHOWWINDOW); // TODO: fake these keys properly fakeKeyDown(kKeyEscape, 8192, 1); fakeKeyUp(1); fakeMouseButton(kButtonLeft, false); String filename; DOUBLE timeout = ARCH->time() + .5f; while (ARCH->time() < timeout) { ARCH->sleep(.05f); filename = m_dropTarget->getDraggingFilename(); if (!filename.empty()) { break; } } ShowWindow(m_dropWindow, SW_HIDE); if (!filename.empty()) { if (DragInformation::isFileValid(filename)) { m_draggingFilename = filename; } else { LOG((CLOG_DEBUG "drag file name is invalid: %s", filename.c_str())); } } if (m_draggingFilename.empty()) { LOG((CLOG_DEBUG "failed to get drag file name from OLE")); } } return m_draggingFilename; } const String& MSWindowsScreen::getDropTarget() const { return m_desktopPath; } bool MSWindowsScreen::isModifierRepeat(KeyModifierMask oldState, KeyModifierMask state, WPARAM wParam) const { bool result = false; if (oldState == state && state != 0) { UINT virtKey = (wParam & 0xffu); if ((state & KeyModifierShift) != 0 && (virtKey == VK_LSHIFT || virtKey == VK_RSHIFT)) { result = true; } if ((state & KeyModifierControl) != 0 && (virtKey == VK_LCONTROL || virtKey == VK_RCONTROL)) { result = true; } if ((state & KeyModifierAlt) != 0 && (virtKey == VK_LMENU || virtKey == VK_RMENU)) { result = true; } if ((state & KeyModifierSuper) != 0 && (virtKey == VK_LWIN || virtKey == VK_RWIN)) { result = true; } } return result; } synergy-1.8.8-stable/src/lib/platform/MSWindowsScreen.h000066400000000000000000000237641305627404700231100ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/MSWindowsHook.h" #include "synergy/PlatformScreen.h" #include "synergy/DragInformation.h" #include "synwinhk/synwinhk.h" #include "mt/CondVar.h" #include "mt/Mutex.h" #include "base/String.h" #define WIN32_LEAN_AND_MEAN #include class EventQueueTimer; class MSWindowsDesks; class MSWindowsKeyState; class MSWindowsScreenSaver; class Thread; class MSWindowsDropTarget; //! Implementation of IPlatformScreen for Microsoft Windows class MSWindowsScreen : public PlatformScreen { public: MSWindowsScreen( bool isPrimary, bool noHooks, bool stopOnDeskSwitch, IEventQueue* events); virtual ~MSWindowsScreen(); //! @name manipulators //@{ //! Initialize /*! Saves the application's HINSTANCE. This \b must be called by WinMain with the HINSTANCE it was passed. */ static void init(HINSTANCE); //@} //! @name accessors //@{ //! Get instance /*! Returns the application instance handle passed to init(). */ static HINSTANCE getWindowInstance(); //@} // IScreen overrides virtual void* getEventTarget() const; virtual bool getClipboard(ClipboardID id, IClipboard*) const; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const; virtual void getCursorPos(SInt32& x, SInt32& y) const; // IPrimaryScreen overrides virtual void reconfigure(UInt32 activeSides); virtual void warpCursor(SInt32 x, SInt32 y); virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); virtual void unregisterHotKey(UInt32 id); virtual void fakeInputBegin(); virtual void fakeInputEnd(); virtual SInt32 getJumpZoneSize() const; virtual bool isAnyMouseButtonDown(UInt32& buttonID) const; virtual void getCursorCenter(SInt32& x, SInt32& y) const; // ISecondaryScreen overrides virtual void fakeMouseButton(ButtonID id, bool press); virtual void fakeMouseMove(SInt32 x, SInt32 y); virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; // IKeyState overrides virtual void updateKeys(); virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button); virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button); virtual bool fakeKeyUp(KeyButton button); virtual void fakeAllKeysUp(); // IPlatformScreen overrides virtual void enable(); virtual void disable(); virtual void enter(); virtual bool leave(); virtual bool setClipboard(ClipboardID, const IClipboard*); virtual void checkClipboards(); virtual void openScreensaver(bool notify); virtual void closeScreensaver(); virtual void screensaver(bool activate); virtual void resetOptions(); virtual void setOptions(const OptionsList& options); virtual void setSequenceNumber(UInt32); virtual bool isPrimary() const; virtual void fakeDraggingFiles(DragFileList fileList); virtual String& getDraggingFilename(); virtual const String& getDropTarget() const; protected: // IPlatformScreen overrides virtual void handleSystemEvent(const Event&, void*); virtual void updateButtons(); virtual IKeyState* getKeyState() const; // simulate a local key to the system directly void fakeLocalKey(KeyButton button, bool press) const; private: // initialization and shutdown operations HCURSOR createBlankCursor() const; void destroyCursor(HCURSOR cursor) const; ATOM createWindowClass() const; ATOM createDeskWindowClass(bool isPrimary) const; void destroyClass(ATOM windowClass) const; HWND createWindow(ATOM windowClass, const char* name) const; HWND createDropWindow(ATOM windowClass, const char* name) const; void destroyWindow(HWND) const; // convenience function to send events public: // HACK void sendEvent(Event::Type type, void* = NULL); private: // HACK void sendClipboardEvent(Event::Type type, ClipboardID id); // handle message before it gets dispatched. returns true iff // the message should not be dispatched. bool onPreDispatch(HWND, UINT, WPARAM, LPARAM); // handle message before it gets dispatched. returns true iff // the message should not be dispatched. bool onPreDispatchPrimary(HWND, UINT, WPARAM, LPARAM); // handle message. returns true iff handled and optionally sets // \c *result (which defaults to 0). bool onEvent(HWND, UINT, WPARAM, LPARAM, LRESULT* result); // message handlers bool onMark(UInt32 mark); bool onKey(WPARAM, LPARAM); bool onHotKey(WPARAM, LPARAM); bool onMouseButton(WPARAM, LPARAM); bool onMouseMove(SInt32 x, SInt32 y); bool onMouseWheel(SInt32 xDelta, SInt32 yDelta); bool onScreensaver(bool activated); bool onDisplayChange(); bool onClipboardChange(); // warp cursor without discarding queued events void warpCursorNoFlush(SInt32 x, SInt32 y); // discard posted messages void nextMark(); // test if event should be ignored bool ignore() const; // update screen size cache void updateScreenShape(); // fix timer callback void handleFixes(const Event&, void*); // fix the clipboard viewer chain void fixClipboardViewer(); // enable/disable special key combinations so we can catch/pass them void enableSpecialKeys(bool) const; // map a button event to a button ID ButtonID mapButtonFromEvent(WPARAM msg, LPARAM button) const; // map a button event to a press (true) or release (false) bool mapPressFromEvent(WPARAM msg, LPARAM button) const; // job to update the key state void updateKeysCB(void*); // determine whether the mouse is hidden by the system and force // it to be displayed if user has entered this secondary screen. void forceShowCursor(); // forceShowCursor uses MouseKeys to show the cursor. since we // don't actually want MouseKeys behavior we have to make sure // it applies when NumLock is in whatever state it's not in now. // this method does that. void updateForceShowCursor(); // our window proc static LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM); // save last position of mouse to compute next delta movement void saveMousePosition(SInt32 x, SInt32 y); // check if it is a modifier key repeating message bool isModifierRepeat(KeyModifierMask oldState, KeyModifierMask state, WPARAM wParam) const; // send drag info and data back to server void sendDragThread(void*); private: struct HotKeyItem { public: HotKeyItem(UINT vk, UINT modifiers); UINT getVirtualKey() const; bool operator<(const HotKeyItem&) const; private: UINT m_keycode; UINT m_mask; }; typedef std::map HotKeyMap; typedef std::vector HotKeyIDList; typedef std::map HotKeyToIDMap; typedef std::vector PrimaryKeyDownList; static HINSTANCE s_windowInstance; // true if screen is being used as a primary screen, false otherwise bool m_isPrimary; // true if hooks are not to be installed (useful for debugging) bool m_noHooks; // true if mouse has entered the screen bool m_isOnScreen; // our resources ATOM m_class; // screen shape stuff SInt32 m_x, m_y; SInt32 m_w, m_h; SInt32 m_xCenter, m_yCenter; // true if system appears to have multiple monitors bool m_multimon; // last mouse position SInt32 m_xCursor, m_yCursor; // last clipboard UInt32 m_sequenceNumber; // used to discard queued messages that are no longer needed UInt32 m_mark; UInt32 m_markReceived; // the main loop's thread id DWORD m_threadID; // timer for periodically checking stuff that requires polling EventQueueTimer* m_fixTimer; // the keyboard layout to use when off primary screen HKL m_keyLayout; // screen saver stuff MSWindowsScreenSaver* m_screensaver; bool m_screensaverNotify; bool m_screensaverActive; // clipboard stuff. our window is used mainly as a clipboard // owner and as a link in the clipboard viewer chain. HWND m_window; HWND m_nextClipboardWindow; bool m_ownClipboard; // one desk per desktop and a cond var to communicate with it MSWindowsDesks* m_desks; // keyboard stuff MSWindowsKeyState* m_keyState; // hot key stuff HotKeyMap m_hotKeys; HotKeyIDList m_oldHotKeyIDs; HotKeyToIDMap m_hotKeyToIDMap; // map of button state bool m_buttons[1 + kButtonExtra0 + 1]; // the system shows the mouse cursor when an internal display count // is >= 0. this count is maintained per application but there's // apparently a system wide count added to the application's count. // this system count is 0 if there's a mouse attached to the system // and -1 otherwise. the MouseKeys accessibility feature can modify // this system count by making the system appear to have a mouse. // // m_hasMouse is true iff there's a mouse attached to the system or // MouseKeys is simulating one. we track this so we can force the // cursor to be displayed when the user has entered this screen. // m_showingMouse is true when we're doing that. bool m_hasMouse; bool m_showingMouse; bool m_gotOldMouseKeys; MOUSEKEYS m_mouseKeys; MOUSEKEYS m_oldMouseKeys; MSWindowsHook m_hook; static MSWindowsScreen* s_screen; IEventQueue* m_events; String m_desktopPath; MSWindowsDropTarget* m_dropTarget; HWND m_dropWindow; const int m_dropWindowSize; Thread* m_sendDragThread; PrimaryKeyDownList m_primaryKeyDownList; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsScreenSaver.cpp000066400000000000000000000212261305627404700244330ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsScreenSaver.h" #include "platform/MSWindowsScreen.h" #include "mt/Thread.h" #include "arch/Arch.h" #include "arch/win32/ArchMiscWindows.h" #include "base/Log.h" #include "base/TMethodJob.h" #include #include #if !defined(SPI_GETSCREENSAVERRUNNING) #define SPI_GETSCREENSAVERRUNNING 114 #endif static const TCHAR* g_isSecureNT = "ScreenSaverIsSecure"; static const TCHAR* g_isSecure9x = "ScreenSaveUsePassword"; static const TCHAR* const g_pathScreenSaverIsSecure[] = { "Control Panel", "Desktop", NULL }; // // MSWindowsScreenSaver // MSWindowsScreenSaver::MSWindowsScreenSaver() : m_wasSecure(false), m_wasSecureAnInt(false), m_process(NULL), m_watch(NULL), m_threadID(0), m_active(false) { // check if screen saver is enabled SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0); } MSWindowsScreenSaver::~MSWindowsScreenSaver() { unwatchProcess(); } bool MSWindowsScreenSaver::checkStarted(UINT msg, WPARAM wParam, LPARAM lParam) { // if already started then say it didn't just start if (m_active) { return false; } // screen saver may have started. look for it and get // the process. if we can't find it then assume it // didn't really start. we wait a moment before // looking to give the screen saver a chance to start. // this shouldn't be a problem since we only get here // if the screen saver wants to kick in, meaning that // the system is idle or the user deliberately started // the screen saver. Sleep(250); // set parameters common to all screen saver handling m_threadID = GetCurrentThreadId(); m_msg = msg; m_wParam = wParam; m_lParam = lParam; // on the windows nt family we wait for the desktop to // change until it's neither the Screen-Saver desktop // nor a desktop we can't open (the login desktop). // since windows will send the request-to-start-screen- // saver message even when the screen saver is disabled // we first check that the screen saver is indeed active // before watching for it to stop. if (!isActive()) { LOG((CLOG_DEBUG2 "can't open screen saver desktop")); return false; } watchDesktop(); return true; } void MSWindowsScreenSaver::enable() { SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, 0); // restore password protection if (m_wasSecure) { setSecure(true, m_wasSecureAnInt); } // restore display power down ArchMiscWindows::removeBusyState(ArchMiscWindows::kDISPLAY); } void MSWindowsScreenSaver::disable() { SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0); SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, FALSE, 0, 0); // disable password protected screensaver m_wasSecure = isSecure(&m_wasSecureAnInt); if (m_wasSecure) { setSecure(false, m_wasSecureAnInt); } // disable display power down ArchMiscWindows::addBusyState(ArchMiscWindows::kDISPLAY); } void MSWindowsScreenSaver::activate() { // don't activate if already active if (!isActive()) { // activate HWND hwnd = GetForegroundWindow(); if (hwnd != NULL) { PostMessage(hwnd, WM_SYSCOMMAND, SC_SCREENSAVE, 0); } else { // no foreground window. pretend we got the event instead. DefWindowProc(NULL, WM_SYSCOMMAND, SC_SCREENSAVE, 0); } // restore power save when screen saver activates ArchMiscWindows::removeBusyState(ArchMiscWindows::kDISPLAY); } } void MSWindowsScreenSaver::deactivate() { bool killed = false; // NT runs screen saver in another desktop HDESK desktop = OpenDesktop("Screen-saver", 0, FALSE, DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS); if (desktop != NULL) { EnumDesktopWindows(desktop, &MSWindowsScreenSaver::killScreenSaverFunc, reinterpret_cast(&killed)); CloseDesktop(desktop); } // if above failed or wasn't tried, try the windows 95 way if (!killed) { // find screen saver window and close it HWND hwnd = FindWindow("WindowsScreenSaverClass", NULL); if (hwnd == NULL) { // win2k may use a different class hwnd = FindWindow("Default Screen Saver", NULL); } if (hwnd != NULL) { PostMessage(hwnd, WM_CLOSE, 0, 0); } } // force timer to restart SystemParametersInfo(SPI_GETSCREENSAVEACTIVE, 0, &m_wasEnabled, 0); SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, !m_wasEnabled, 0, SPIF_SENDWININICHANGE); SystemParametersInfo(SPI_SETSCREENSAVEACTIVE, m_wasEnabled, 0, SPIF_SENDWININICHANGE); // disable display power down ArchMiscWindows::removeBusyState(ArchMiscWindows::kDISPLAY); } bool MSWindowsScreenSaver::isActive() const { BOOL running; SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0); return (running != FALSE); } BOOL CALLBACK MSWindowsScreenSaver::killScreenSaverFunc(HWND hwnd, LPARAM arg) { if (IsWindowVisible(hwnd)) { HINSTANCE instance = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE); if (instance != MSWindowsScreen::getWindowInstance()) { PostMessage(hwnd, WM_CLOSE, 0, 0); *reinterpret_cast(arg) = true; } } return TRUE; } void MSWindowsScreenSaver::watchDesktop() { // stop watching previous process/desktop unwatchProcess(); // watch desktop in another thread LOG((CLOG_DEBUG "watching screen saver desktop")); m_active = true; m_watch = new Thread(new TMethodJob(this, &MSWindowsScreenSaver::watchDesktopThread)); } void MSWindowsScreenSaver::watchProcess(HANDLE process) { // stop watching previous process/desktop unwatchProcess(); // watch new process in another thread if (process != NULL) { LOG((CLOG_DEBUG "watching screen saver process")); m_process = process; m_active = true; m_watch = new Thread(new TMethodJob(this, &MSWindowsScreenSaver::watchProcessThread)); } } void MSWindowsScreenSaver::unwatchProcess() { if (m_watch != NULL) { LOG((CLOG_DEBUG "stopped watching screen saver process/desktop")); m_watch->cancel(); m_watch->wait(); delete m_watch; m_watch = NULL; m_active = false; } if (m_process != NULL) { CloseHandle(m_process); m_process = NULL; } } void MSWindowsScreenSaver::watchDesktopThread(void*) { DWORD reserved = 0; TCHAR* name = NULL; for (;;) { // wait a bit ARCH->sleep(0.2); BOOL running; SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, &running, 0); if (running) { continue; } // send screen saver deactivation message m_active = false; PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam); return; } } void MSWindowsScreenSaver::watchProcessThread(void*) { for (;;) { Thread::testCancel(); if (WaitForSingleObject(m_process, 50) == WAIT_OBJECT_0) { // process terminated LOG((CLOG_DEBUG "screen saver died")); // send screen saver deactivation message m_active = false; PostThreadMessage(m_threadID, m_msg, m_wParam, m_lParam); return; } } } void MSWindowsScreenSaver::setSecure(bool secure, bool saveSecureAsInt) { HKEY hkey = ArchMiscWindows::addKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure); if (hkey == NULL) { return; } if (saveSecureAsInt) { ArchMiscWindows::setValue(hkey, g_isSecureNT, secure ? 1 : 0); } else { ArchMiscWindows::setValue(hkey, g_isSecureNT, secure ? "1" : "0"); } ArchMiscWindows::closeKey(hkey); } bool MSWindowsScreenSaver::isSecure(bool* wasSecureFlagAnInt) const { // get the password protection setting key HKEY hkey = ArchMiscWindows::openKey(HKEY_CURRENT_USER, g_pathScreenSaverIsSecure); if (hkey == NULL) { return false; } // get the value. the value may be an int or a string, depending // on the version of windows. bool result; switch (ArchMiscWindows::typeOfValue(hkey, g_isSecureNT)) { default: result = false; break; case ArchMiscWindows::kUINT: { DWORD value = ArchMiscWindows::readValueInt(hkey, g_isSecureNT); *wasSecureFlagAnInt = true; result = (value != 0); break; } case ArchMiscWindows::kSTRING: { std::string value = ArchMiscWindows::readValueString(hkey, g_isSecureNT); *wasSecureFlagAnInt = false; result = (value != "0"); break; } } ArchMiscWindows::closeKey(hkey); return result; } synergy-1.8.8-stable/src/lib/platform/MSWindowsScreenSaver.h000066400000000000000000000044161305627404700241020ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/IScreenSaver.h" #include "base/String.h" #define WIN32_LEAN_AND_MEAN #include class Thread; //! Microsoft windows screen saver implementation class MSWindowsScreenSaver : public IScreenSaver { public: MSWindowsScreenSaver(); virtual ~MSWindowsScreenSaver(); //! @name manipulators //@{ //! Check if screen saver started /*! Check if the screen saver really started. Returns false if it hasn't, true otherwise. When the screen saver stops, \c msg will be posted to the current thread's message queue with the given parameters. */ bool checkStarted(UINT msg, WPARAM, LPARAM); //@} // IScreenSaver overrides virtual void enable(); virtual void disable(); virtual void activate(); virtual void deactivate(); virtual bool isActive() const; private: class FindScreenSaverInfo { public: HDESK m_desktop; HWND m_window; }; static BOOL CALLBACK killScreenSaverFunc(HWND hwnd, LPARAM lParam); void watchDesktop(); void watchProcess(HANDLE process); void unwatchProcess(); void watchDesktopThread(void*); void watchProcessThread(void*); void setSecure(bool secure, bool saveSecureAsInt); bool isSecure(bool* wasSecureAnInt) const; private: BOOL m_wasEnabled; bool m_wasSecure; bool m_wasSecureAnInt; HANDLE m_process; Thread* m_watch; DWORD m_threadID; UINT m_msg; WPARAM m_wParam; LPARAM m_lParam; // checkActive state. true if the screen saver is being watched // for deactivation (and is therefore active). bool m_active; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsSession.cpp000066400000000000000000000120101305627404700236250ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsSession.h" #include "arch/win32/XArchWindows.h" #include "synergy/XSynergy.h" #include "base/Log.h" #include MSWindowsSession::MSWindowsSession() : m_activeSessionId(-1) { } MSWindowsSession::~MSWindowsSession() { } bool MSWindowsSession::isProcessInSession(const char* name, PHANDLE process = NULL) { // first we need to take a snapshot of the running processes HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snapshot == INVALID_HANDLE_VALUE) { LOG((CLOG_ERR "could not get process snapshot")); throw XArch(new XArchEvalWindows()); } PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); // get the first process, and if we can't do that then it's // unlikely we can go any further BOOL gotEntry = Process32First(snapshot, &entry); if (!gotEntry) { LOG((CLOG_ERR "could not get first process entry")); throw XArch(new XArchEvalWindows()); } // used to record process names for debug info std::list nameList; // now just iterate until we can find winlogon.exe pid DWORD pid = 0; while(gotEntry) { // make sure we're not checking the system process if (entry.th32ProcessID != 0) { DWORD processSessionId; BOOL pidToSidRet = ProcessIdToSessionId( entry.th32ProcessID, &processSessionId); if (!pidToSidRet) { // if we can not acquire session associated with a specified process, // simply ignore it LOG((CLOG_ERR "could not get session id for process id %i", entry.th32ProcessID)); gotEntry = nextProcessEntry(snapshot, &entry); continue; } else { // only pay attention to processes in the active session if (processSessionId == m_activeSessionId) { // store the names so we can record them for debug nameList.push_back(entry.szExeFile); if (_stricmp(entry.szExeFile, name) == 0) { pid = entry.th32ProcessID; } } } } // now move on to the next entry (if we're not at the end) gotEntry = nextProcessEntry(snapshot, &entry); } std::string nameListJoin; for(std::list::iterator it = nameList.begin(); it != nameList.end(); it++) { nameListJoin.append(*it); nameListJoin.append(", "); } LOG((CLOG_DEBUG "processes in session %d: %s", m_activeSessionId, nameListJoin.c_str())); CloseHandle(snapshot); if (pid) { if (process != NULL) { // now get the process, which we'll use to get the process token. LOG((CLOG_DEBUG "found %s in session %i", name, m_activeSessionId)); *process = OpenProcess(MAXIMUM_ALLOWED, FALSE, pid); } return true; } else { LOG((CLOG_DEBUG "did not find %s in session %i", name, m_activeSessionId)); return false; } } HANDLE MSWindowsSession::getUserToken(LPSECURITY_ATTRIBUTES security) { HANDLE sourceToken; if (!WTSQueryUserToken(m_activeSessionId, &sourceToken)) { LOG((CLOG_ERR "could not get token from session %d", m_activeSessionId)); throw XArch(new XArchEvalWindows); } HANDLE newToken; if (!DuplicateTokenEx( sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security, SecurityImpersonation, TokenPrimary, &newToken)) { LOG((CLOG_ERR "could not duplicate token")); throw XArch(new XArchEvalWindows); } LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); return newToken; } BOOL MSWindowsSession::hasChanged() { return (m_activeSessionId != WTSGetActiveConsoleSessionId()); } void MSWindowsSession::updateActiveSession() { m_activeSessionId = WTSGetActiveConsoleSessionId(); } BOOL MSWindowsSession::nextProcessEntry(HANDLE snapshot, LPPROCESSENTRY32 entry) { BOOL gotEntry = Process32Next(snapshot, entry); if (!gotEntry) { DWORD err = GetLastError(); if (err != ERROR_NO_MORE_FILES) { // only worry about error if it's not the end of the snapshot LOG((CLOG_ERR "could not get next process entry")); throw XArch(new XArchEvalWindows()); } } return gotEntry; } String MSWindowsSession::getActiveDesktopName() { String result; try { HDESK hd = OpenInputDesktop(0, TRUE, GENERIC_READ); if (hd != NULL) { DWORD size; GetUserObjectInformation(hd, UOI_NAME, NULL, 0, &size); TCHAR* name = (TCHAR*)alloca(size + sizeof(TCHAR)); GetUserObjectInformation(hd, UOI_NAME, name, size, &size); result = name; CloseDesktop(hd); } } catch (std::exception error) { LOG((CLOG_ERR "failed to get active desktop name: %s", error.what())); } return result; } synergy-1.8.8-stable/src/lib/platform/MSWindowsSession.h000066400000000000000000000025401305627404700233010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" #define WIN32_LEAN_AND_MEAN #include #include class MSWindowsSession { public: MSWindowsSession(); ~MSWindowsSession(); //! /*! Returns true if the session ID has changed since updateActiveSession was called. */ BOOL hasChanged(); bool isProcessInSession(const char* name, PHANDLE process); HANDLE getUserToken(LPSECURITY_ATTRIBUTES security); DWORD getActiveSessionId() { return m_activeSessionId; } void updateActiveSession(); String getActiveDesktopName(); private: BOOL nextProcessEntry(HANDLE snapshot, LPPROCESSENTRY32 entry); private: DWORD m_activeSessionId; }; synergy-1.8.8-stable/src/lib/platform/MSWindowsUtil.cpp000066400000000000000000000037561305627404700231400ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsUtil.h" #include "base/String.h" #include // // MSWindowsUtil // String MSWindowsUtil::getString(HINSTANCE instance, DWORD id) { char buffer[1024]; int size = static_cast(sizeof(buffer) / sizeof(buffer[0])); char* msg = buffer; // load string int n = LoadString(instance, id, msg, size); msg[n] = '\0'; if (n < size) { return msg; } // not enough buffer space. keep trying larger buffers until // we get the whole string. msg = NULL; do { size <<= 1; delete[] msg; char* msg = new char[size]; n = LoadString(instance, id, msg, size); } while (n == size); msg[n] = '\0'; String result(msg); delete[] msg; return result; } String MSWindowsUtil::getErrorString(HINSTANCE hinstance, DWORD error, DWORD id) { char* buffer; if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, 0, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&buffer, 0, NULL) == 0) { String errorString = synergy::string::sprintf("%d", error); return synergy::string::format(getString(hinstance, id).c_str(), errorString.c_str()); } else { String result(buffer); LocalFree(buffer); return result; } } synergy-1.8.8-stable/src/lib/platform/MSWindowsUtil.h000066400000000000000000000023311305627404700225710ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" #define WINDOWS_LEAN_AND_MEAN #include class MSWindowsUtil { public: //! Get message string /*! Gets a string for \p id from the string table of \p instance. */ static String getString(HINSTANCE instance, DWORD id); //! Get error string /*! Gets a system error message for \p error. If the error cannot be found return the string for \p id, replacing ${1} with \p error. */ static String getErrorString(HINSTANCE, DWORD error, DWORD id); }; synergy-1.8.8-stable/src/lib/platform/MSWindowsWatchdog.cpp000066400000000000000000000354501305627404700237570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2009 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsWatchdog.h" #include "ipc/IpcLogOutputter.h" #include "ipc/IpcServer.h" #include "ipc/IpcMessage.h" #include "ipc/Ipc.h" #include "synergy/App.h" #include "synergy/ArgsBase.h" #include "mt/Thread.h" #include "arch/win32/ArchDaemonWindows.h" #include "arch/win32/XArchWindows.h" #include "arch/Arch.h" #include "base/log_outputters.h" #include "base/TMethodJob.h" #include "base/Log.h" #include "common/Version.h" #include #include #include #define MAXIMUM_WAIT_TIME 3 enum { kOutputBufferSize = 4096 }; typedef VOID (WINAPI *SendSas)(BOOL asUser); const char g_activeDesktop[] = {"activeDesktop:"}; MSWindowsWatchdog::MSWindowsWatchdog( bool autoDetectCommand, IpcServer& ipcServer, IpcLogOutputter& ipcLogOutputter) : m_thread(NULL), m_autoDetectCommand(autoDetectCommand), m_monitoring(true), m_commandChanged(false), m_stdOutWrite(NULL), m_stdOutRead(NULL), m_ipcServer(ipcServer), m_ipcLogOutputter(ipcLogOutputter), m_elevateProcess(false), m_processFailures(0), m_processRunning(false), m_fileLogOutputter(NULL), m_autoElevated(false), m_ready(false) { m_mutex = ARCH->newMutex(); m_condVar = ARCH->newCondVar(); } MSWindowsWatchdog::~MSWindowsWatchdog() { if (m_condVar != NULL) { ARCH->closeCondVar(m_condVar); } if (m_mutex != NULL) { ARCH->closeMutex(m_mutex); } } void MSWindowsWatchdog::startAsync() { m_thread = new Thread(new TMethodJob( this, &MSWindowsWatchdog::mainLoop, nullptr)); m_outputThread = new Thread(new TMethodJob( this, &MSWindowsWatchdog::outputLoop, nullptr)); } void MSWindowsWatchdog::stop() { m_monitoring = false; m_thread->wait(5); delete m_thread; m_outputThread->wait(5); delete m_outputThread; } HANDLE MSWindowsWatchdog::duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security) { HANDLE sourceToken; BOOL tokenRet = OpenProcessToken( process, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, &sourceToken); if (!tokenRet) { LOG((CLOG_ERR "could not open token, process handle: %d", process)); throw XArch(new XArchEvalWindows()); } LOG((CLOG_DEBUG "got token %i, duplicating", sourceToken)); HANDLE newToken; BOOL duplicateRet = DuplicateTokenEx( sourceToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, security, SecurityImpersonation, TokenPrimary, &newToken); if (!duplicateRet) { LOG((CLOG_ERR "could not duplicate token %i", sourceToken)); throw XArch(new XArchEvalWindows()); } LOG((CLOG_DEBUG "duplicated, new token: %i", newToken)); return newToken; } HANDLE MSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security) { // always elevate if we are at the vista/7 login screen. we could also // elevate for the uac dialog (consent.exe) but this would be pointless, // since synergy would re-launch as non-elevated after the desk switch, // and so would be unusable with the new elevated process taking focus. if (m_elevateProcess || m_autoElevated || m_session.isProcessInSession("logonui.exe", NULL)) { LOG((CLOG_DEBUG "getting elevated token, %s", (m_elevateProcess ? "elevation required" : "at login screen"))); HANDLE process; if (!m_session.isProcessInSession("winlogon.exe", &process)) { throw XMSWindowsWatchdogError("cannot get user token without winlogon.exe"); } return duplicateProcessToken(process, security); } else { LOG((CLOG_DEBUG "getting non-elevated token")); return m_session.getUserToken(security); } } void MSWindowsWatchdog::mainLoop(void*) { shutdownExistingProcesses(); SendSas sendSasFunc = NULL; HINSTANCE sasLib = LoadLibrary("sas.dll"); if (sasLib) { LOG((CLOG_DEBUG "found sas.dll")); sendSasFunc = (SendSas)GetProcAddress(sasLib, "SendSAS"); } SECURITY_ATTRIBUTES saAttr; saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = TRUE; saAttr.lpSecurityDescriptor = NULL; if (!CreatePipe(&m_stdOutRead, &m_stdOutWrite, &saAttr, 0)) { throw XArch(new XArchEvalWindows()); } ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); while (m_monitoring) { try { if (m_processRunning && getCommand().empty()) { LOG((CLOG_INFO "process started but command is empty, shutting down")); shutdownExistingProcesses(); m_processRunning = false; continue; } if (m_processFailures != 0) { // increasing backoff period, maximum of 10 seconds. int timeout = (m_processFailures * 2) < 10 ? (m_processFailures * 2) : 10; LOG((CLOG_INFO "backing off, wait=%ds, failures=%d", timeout, m_processFailures)); ARCH->sleep(timeout); } if (!getCommand().empty() && ((m_processFailures != 0) || m_session.hasChanged() || m_commandChanged)) { startProcess(); } if (m_processRunning && !isProcessActive()) { m_processFailures++; m_processRunning = false; LOG((CLOG_WARN "detected application not running, pid=%d", m_processInfo.dwProcessId)); } if (sendSasFunc != NULL) { HANDLE sendSasEvent = CreateEvent(NULL, FALSE, FALSE, "Global\\SendSAS"); if (sendSasEvent != NULL) { // use SendSAS event to wait for next session (timeout 1 second). if (WaitForSingleObject(sendSasEvent, 1000) == WAIT_OBJECT_0) { LOG((CLOG_DEBUG "calling SendSAS")); sendSasFunc(FALSE); } CloseHandle(sendSasEvent); continue; } } // if the sas event failed, wait by sleeping. ARCH->sleep(1); } catch (std::exception& e) { LOG((CLOG_ERR "failed to launch, error: %s", e.what())); m_processFailures++; m_processRunning = false; continue; } catch (...) { LOG((CLOG_ERR "failed to launch, unknown error.")); m_processFailures++; m_processRunning = false; continue; } } if (m_processRunning) { LOG((CLOG_DEBUG "terminated running process on exit")); shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20); } LOG((CLOG_DEBUG "watchdog main thread finished")); } bool MSWindowsWatchdog::isProcessActive() { DWORD exitCode; GetExitCodeProcess(m_processInfo.hProcess, &exitCode); return exitCode == STILL_ACTIVE; } void MSWindowsWatchdog::setFileLogOutputter(FileLogOutputter* outputter) { m_fileLogOutputter = outputter; } void MSWindowsWatchdog::startProcess() { if (m_command.empty()) { throw XMSWindowsWatchdogError("cannot start process, command is empty"); } m_commandChanged = false; if (m_processRunning) { LOG((CLOG_DEBUG "closing existing process to make way for new one")); shutdownProcess(m_processInfo.hProcess, m_processInfo.dwProcessId, 20); m_processRunning = false; } m_session.updateActiveSession(); SECURITY_ATTRIBUTES sa; ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); getActiveDesktop(&sa); ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES)); HANDLE userToken = getUserToken(&sa); m_elevateProcess = m_autoElevated ? m_autoElevated : m_elevateProcess; m_autoElevated = false; // patch by Jack Zhou and Henry Tung // set UIAccess to fix Windows 8 GUI interaction // http://symless.com/spit/issues/details/3338/#c70 DWORD uiAccess = 1; SetTokenInformation(userToken, TokenUIAccess, &uiAccess, sizeof(DWORD)); BOOL createRet = doStartProcess(m_command, userToken, &sa); if (!createRet) { LOG((CLOG_ERR "could not launch")); DWORD exitCode = 0; GetExitCodeProcess(m_processInfo.hProcess, &exitCode); LOG((CLOG_ERR "exit code: %d", exitCode)); throw XArch(new XArchEvalWindows); } else { // wait for program to fail. ARCH->sleep(1); if (!isProcessActive()) { throw XMSWindowsWatchdogError("process immediately stopped"); } m_processRunning = true; m_processFailures = 0; LOG((CLOG_DEBUG "started process, session=%i, elevated: %s, command=%s", m_session.getActiveSessionId(), m_elevateProcess ? "yes" : "no", m_command.c_str())); } } BOOL MSWindowsWatchdog::doStartProcess(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa) { // clear, as we're reusing process info struct ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION)); STARTUPINFO si; ZeroMemory(&si, sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.lpDesktop = "winsta0\\Default"; // TODO: maybe this should be \winlogon if we have logonui.exe? si.hStdError = m_stdOutWrite; si.hStdOutput = m_stdOutWrite; si.dwFlags |= STARTF_USESTDHANDLES; LPVOID environment; BOOL blockRet = CreateEnvironmentBlock(&environment, userToken, FALSE); if (!blockRet) { LOG((CLOG_ERR "could not create environment block")); throw XArch(new XArchEvalWindows); } DWORD creationFlags = NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT; // re-launch in current active user session LOG((CLOG_INFO "starting new process")); BOOL createRet = CreateProcessAsUser( userToken, NULL, LPSTR(command.c_str()), sa, NULL, TRUE, creationFlags, environment, NULL, &si, &m_processInfo); DestroyEnvironmentBlock(environment); CloseHandle(userToken); return createRet; } void MSWindowsWatchdog::setCommand(const std::string& command, bool elevate) { LOG((CLOG_INFO "service command updated")); m_command = command; m_elevateProcess = elevate; m_commandChanged = true; m_processFailures = 0; } std::string MSWindowsWatchdog::getCommand() const { if (!m_autoDetectCommand) { return m_command; } // seems like a fairly convoluted way to get the process name const char* launchName = App::instance().argsBase().m_pname; std::string args = ARCH->commandLine(); // build up a full command line std::stringstream cmdTemp; cmdTemp << launchName << args; std::string cmd = cmdTemp.str(); size_t i; std::string find = "--relaunch"; while ((i = cmd.find(find)) != std::string::npos) { cmd.replace(i, find.length(), ""); } return cmd; } void MSWindowsWatchdog::outputLoop(void*) { // +1 char for \0 CHAR buffer[kOutputBufferSize + 1]; while (m_monitoring) { DWORD bytesRead; BOOL success = ReadFile(m_stdOutRead, buffer, kOutputBufferSize, &bytesRead, NULL); // assume the process has gone away? slow down // the reads until another one turns up. if (!success || bytesRead == 0) { ARCH->sleep(1); } else { buffer[bytesRead] = '\0'; testOutput(buffer); m_ipcLogOutputter.write(kINFO, buffer); if (m_fileLogOutputter != NULL) { m_fileLogOutputter->write(kINFO, buffer); } } } } void MSWindowsWatchdog::shutdownProcess(HANDLE handle, DWORD pid, int timeout) { DWORD exitCode; GetExitCodeProcess(handle, &exitCode); if (exitCode != STILL_ACTIVE) { return; } IpcShutdownMessage shutdown; m_ipcServer.send(shutdown, kIpcClientNode); // wait for process to exit gracefully. double start = ARCH->time(); while (true) { GetExitCodeProcess(handle, &exitCode); if (exitCode != STILL_ACTIVE) { // yay, we got a graceful shutdown. there should be no hook in use errors! LOG((CLOG_INFO "process %d was shutdown gracefully", pid)); break; } else { double elapsed = (ARCH->time() - start); if (elapsed > timeout) { // if timeout reached, kill forcefully. // calling TerminateProcess on synergy is very bad! // it causes the hook DLL to stay loaded in some apps, // making it impossible to start synergy again. LOG((CLOG_WARN "shutdown timed out after %d secs, forcefully terminating", (int)elapsed)); TerminateProcess(handle, kExitSuccess); break; } ARCH->sleep(1); } } } void MSWindowsWatchdog::shutdownExistingProcesses() { // first we need to take a snapshot of the running processes HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (snapshot == INVALID_HANDLE_VALUE) { LOG((CLOG_ERR "could not get process snapshot")); throw XArch(new XArchEvalWindows); } PROCESSENTRY32 entry; entry.dwSize = sizeof(PROCESSENTRY32); // get the first process, and if we can't do that then it's // unlikely we can go any further BOOL gotEntry = Process32First(snapshot, &entry); if (!gotEntry) { LOG((CLOG_ERR "could not get first process entry")); throw XArch(new XArchEvalWindows); } // now just iterate until we can find winlogon.exe pid DWORD pid = 0; while (gotEntry) { // make sure we're not checking the system process if (entry.th32ProcessID != 0) { if (_stricmp(entry.szExeFile, "synergyc.exe") == 0 || _stricmp(entry.szExeFile, "synergys.exe") == 0) { HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID); shutdownProcess(handle, entry.th32ProcessID, 10); } } // now move on to the next entry (if we're not at the end) gotEntry = Process32Next(snapshot, &entry); if (!gotEntry) { DWORD err = GetLastError(); if (err != ERROR_NO_MORE_FILES) { // only worry about error if it's not the end of the snapshot LOG((CLOG_ERR "could not get subsiquent process entry")); throw XArch(new XArchEvalWindows); } } } CloseHandle(snapshot); m_processRunning = false; } void MSWindowsWatchdog::getActiveDesktop(LPSECURITY_ATTRIBUTES security) { String installedDir = ARCH->getInstalledDirectory(); if (!installedDir.empty()) { String syntoolCommand; syntoolCommand.append("\"").append(installedDir).append("\\").append("syntool").append("\""); syntoolCommand.append(" --get-active-desktop"); m_session.updateActiveSession(); bool elevateProcess = m_elevateProcess; m_elevateProcess = true; HANDLE userToken = getUserToken(security); m_elevateProcess = elevateProcess; BOOL createRet = doStartProcess(syntoolCommand, userToken, security); if (!createRet) { DWORD rc = GetLastError(); RevertToSelf(); } else { LOG((CLOG_DEBUG "launched syntool to check active desktop")); } ARCH->lockMutex(m_mutex); int waitTime = 0; while (!m_ready) { if (waitTime >= MAXIMUM_WAIT_TIME) { break; } ARCH->waitCondVar(m_condVar, m_mutex, 1.0); waitTime++; } m_ready = false; ARCH->unlockMutex(m_mutex); } } void MSWindowsWatchdog::testOutput(String buffer) { // HACK: check standard output seems hacky. size_t i = buffer.find(g_activeDesktop); if (i != String::npos) { size_t s = sizeof(g_activeDesktop); String defaultDesktop("Default"); String sub = buffer.substr(i + s - 1, defaultDesktop.size()); if (sub != defaultDesktop) { m_autoElevated = true; } ARCH->lockMutex(m_mutex); m_ready = true; ARCH->broadcastCondVar(m_condVar); ARCH->unlockMutex(m_mutex); } } synergy-1.8.8-stable/src/lib/platform/MSWindowsWatchdog.h000066400000000000000000000053321305627404700234200ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2009 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/MSWindowsSession.h" #include "synergy/XSynergy.h" #include "arch/IArchMultithread.h" #define WIN32_LEAN_AND_MEAN #include #include #include class Thread; class IpcLogOutputter; class IpcServer; class FileLogOutputter; class MSWindowsWatchdog { public: MSWindowsWatchdog( bool autoDetectCommand, IpcServer& ipcServer, IpcLogOutputter& ipcLogOutputter); virtual ~MSWindowsWatchdog(); void startAsync(); std::string getCommand() const; void setCommand(const std::string& command, bool elevate); void stop(); bool isProcessActive(); void setFileLogOutputter(FileLogOutputter* outputter); private: void mainLoop(void*); void outputLoop(void*); void shutdownProcess(HANDLE handle, DWORD pid, int timeout); void shutdownExistingProcesses(); HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security); HANDLE getUserToken(LPSECURITY_ATTRIBUTES security); void startProcess(); BOOL doStartProcess(String& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa); void sendSas(); void getActiveDesktop(LPSECURITY_ATTRIBUTES security); void testOutput(String buffer); private: Thread* m_thread; bool m_autoDetectCommand; std::string m_command; bool m_monitoring; bool m_commandChanged; HANDLE m_stdOutWrite; HANDLE m_stdOutRead; Thread* m_outputThread; IpcServer& m_ipcServer; IpcLogOutputter& m_ipcLogOutputter; bool m_elevateProcess; MSWindowsSession m_session; PROCESS_INFORMATION m_processInfo; int m_processFailures; bool m_processRunning; FileLogOutputter* m_fileLogOutputter; bool m_autoElevated; ArchMutex m_mutex; ArchCond m_condVar; bool m_ready; }; //! Relauncher error /*! An error occured in the process watchdog. */ class XMSWindowsWatchdogError : public XSynergy { public: XMSWindowsWatchdogError(const String& msg) : XSynergy(msg) { } // XBase overrides virtual String getWhat() const throw() { return what(); } }; synergy-1.8.8-stable/src/lib/platform/OSXClipboard.cpp000066400000000000000000000141271305627404700226730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXClipboard.h" #include "synergy/Clipboard.h" #include "platform/OSXClipboardUTF16Converter.h" #include "platform/OSXClipboardTextConverter.h" #include "platform/OSXClipboardBMPConverter.h" #include "platform/OSXClipboardHTMLConverter.h" #include "base/Log.h" #include "arch/XArch.h" // // OSXClipboard // OSXClipboard::OSXClipboard() : m_time(0), m_pboard(NULL) { m_converters.push_back(new OSXClipboardHTMLConverter); m_converters.push_back(new OSXClipboardBMPConverter); m_converters.push_back(new OSXClipboardUTF16Converter); m_converters.push_back(new OSXClipboardTextConverter); OSStatus createErr = PasteboardCreate(kPasteboardClipboard, &m_pboard); if (createErr != noErr) { LOG((CLOG_DEBUG "failed to create clipboard reference: error %i", createErr)); LOG((CLOG_ERR "unable to connect to pasteboard, clipboard sharing disabled", createErr)); m_pboard = NULL; return; } OSStatus syncErr = PasteboardSynchronize(m_pboard); if (syncErr != noErr) { LOG((CLOG_DEBUG "failed to syncronize clipboard: error %i", syncErr)); } } OSXClipboard::~OSXClipboard() { clearConverters(); } bool OSXClipboard::empty() { LOG((CLOG_DEBUG "emptying clipboard")); if (m_pboard == NULL) return false; OSStatus err = PasteboardClear(m_pboard); if (err != noErr) { LOG((CLOG_DEBUG "failed to clear clipboard: error %i", err)); return false; } return true; } bool OSXClipboard::synchronize() { if (m_pboard == NULL) return false; PasteboardSyncFlags flags = PasteboardSynchronize(m_pboard); LOG((CLOG_DEBUG2 "flags: %x", flags)); if (flags & kPasteboardModified) { return true; } return false; } void OSXClipboard::add(EFormat format, const String & data) { if (m_pboard == NULL) return; LOG((CLOG_DEBUG "add %d bytes to clipboard format: %d", data.size(), format)); if (format == IClipboard::kText) { LOG((CLOG_DEBUG " format of data to be added to clipboard was kText")); } else if (format == IClipboard::kBitmap) { LOG((CLOG_DEBUG " format of data to be added to clipboard was kBitmap")); } else if (format == IClipboard::kHTML) { LOG((CLOG_DEBUG " format of data to be added to clipboard was kHTML")); } for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) { IOSXClipboardConverter* converter = *index; // skip converters for other formats if (converter->getFormat() == format) { String osXData = converter->fromIClipboard(data); CFStringRef flavorType = converter->getOSXFormat(); CFDataRef dataRef = CFDataCreate(kCFAllocatorDefault, (UInt8 *)osXData.data(), osXData.size()); PasteboardPutItemFlavor( m_pboard, nullptr, flavorType, dataRef, kPasteboardFlavorNoFlags); LOG((CLOG_DEBUG "added %d bytes to clipboard format: %d", data.size(), format)); } } } bool OSXClipboard::open(Time time) const { if (m_pboard == NULL) return false; LOG((CLOG_DEBUG "opening clipboard")); m_time = time; return true; } void OSXClipboard::close() const { LOG((CLOG_DEBUG "closing clipboard")); /* not needed */ } IClipboard::Time OSXClipboard::getTime() const { return m_time; } bool OSXClipboard::has(EFormat format) const { if (m_pboard == NULL) return false; PasteboardItemID item; PasteboardGetItemIdentifier(m_pboard, (CFIndex) 1, &item); for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) { IOSXClipboardConverter* converter = *index; if (converter->getFormat() == format) { PasteboardFlavorFlags flags; CFStringRef type = converter->getOSXFormat(); OSStatus res; if ((res = PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags)) == noErr) { return true; } } } return false; } String OSXClipboard::get(EFormat format) const { CFStringRef type; PasteboardItemID item; String result; if (m_pboard == NULL) return result; PasteboardGetItemIdentifier(m_pboard, (CFIndex) 1, &item); // find the converter for the first clipboard format we can handle IOSXClipboardConverter* converter = NULL; for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) { converter = *index; PasteboardFlavorFlags flags; type = converter->getOSXFormat(); if (converter->getFormat() == format && PasteboardGetItemFlavorFlags(m_pboard, item, type, &flags) == noErr) { break; } converter = NULL; } // if no converter then we don't recognize any formats if (converter == NULL) { LOG((CLOG_DEBUG "Unable to find converter for data")); return result; } // get the clipboard data. CFDataRef buffer = NULL; try { OSStatus err = PasteboardCopyItemFlavorData(m_pboard, item, type, &buffer); if (err != noErr) { throw err; } result = String((char *) CFDataGetBytePtr(buffer), CFDataGetLength(buffer)); } catch (OSStatus err) { LOG((CLOG_DEBUG "exception thrown in OSXClipboard::get MacError (%d)", err)); } catch (...) { LOG((CLOG_DEBUG "unknown exception in OSXClipboard::get")); RETHROW_XTHREAD } if (buffer != NULL) CFRelease(buffer); return converter->toIClipboard(result); } void OSXClipboard::clearConverters() { if (m_pboard == NULL) return; for (ConverterList::iterator index = m_converters.begin(); index != m_converters.end(); ++index) { delete *index; } m_converters.clear(); } synergy-1.8.8-stable/src/lib/platform/OSXClipboard.h000066400000000000000000000047711305627404700223440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/IClipboard.h" #include #include class IOSXClipboardConverter; //! OS X clipboard implementation class OSXClipboard : public IClipboard { public: OSXClipboard(); virtual ~OSXClipboard(); //! Test if clipboard is owned by synergy static bool isOwnedBySynergy(); // IClipboard overrides virtual bool empty(); virtual void add(EFormat, const String& data); virtual bool open(Time) const; virtual void close() const; virtual Time getTime() const; virtual bool has(EFormat) const; virtual String get(EFormat) const; bool synchronize(); private: void clearConverters(); private: typedef std::vector ConverterList; mutable Time m_time; ConverterList m_converters; PasteboardRef m_pboard; }; //! Clipboard format converter interface /*! This interface defines the methods common to all Scrap book format */ class IOSXClipboardConverter : public IInterface { public: //! @name accessors //@{ //! Get clipboard format /*! Return the clipboard format this object converts from/to. */ virtual IClipboard::EFormat getFormat() const = 0; //! returns the scrap flavor type that this object converts from/to virtual CFStringRef getOSXFormat() const = 0; //! Convert from IClipboard format /*! Convert from the IClipboard format to the Carbon scrap format. The input data must be in the IClipboard format returned by getFormat(). The return data will be in the scrap format returned by getOSXFormat(). */ virtual String fromIClipboard(const String&) const = 0; //! Convert to IClipboard format /*! Convert from the carbon scrap format to the IClipboard format (i.e., the reverse of fromIClipboard()). */ virtual String toIClipboard(const String&) const = 0; //@} }; synergy-1.8.8-stable/src/lib/platform/OSXClipboardAnyBitmapConverter.cpp000066400000000000000000000024171305627404700263670ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * Patch by Ryan Chapman * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXClipboardAnyBitmapConverter.h" #include OSXClipboardAnyBitmapConverter::OSXClipboardAnyBitmapConverter() { // do nothing } OSXClipboardAnyBitmapConverter::~OSXClipboardAnyBitmapConverter() { // do nothing } IClipboard::EFormat OSXClipboardAnyBitmapConverter::getFormat() const { return IClipboard::kBitmap; } String OSXClipboardAnyBitmapConverter::fromIClipboard(const String& data) const { return doFromIClipboard(data); } String OSXClipboardAnyBitmapConverter::toIClipboard(const String& data) const { return doToIClipboard(data); } synergy-1.8.8-stable/src/lib/platform/OSXClipboardAnyBitmapConverter.h000066400000000000000000000027661305627404700260430ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * Patch by Ryan Chapman * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/OSXClipboard.h" //! Convert to/from some text encoding class OSXClipboardAnyBitmapConverter : public IOSXClipboardConverter { public: OSXClipboardAnyBitmapConverter(); virtual ~OSXClipboardAnyBitmapConverter(); // IOSXClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual CFStringRef getOSXFormat() const = 0; virtual String fromIClipboard(const String &) const; virtual String toIClipboard(const String &) const; protected: //! Convert from IClipboard format /*! Do UTF-8 conversion and linefeed conversion. */ virtual String doFromIClipboard(const String&) const = 0; //! Convert to IClipboard format /*! Do UTF-8 conversion and Linefeed conversion. */ virtual String doToIClipboard(const String&) const = 0; }; synergy-1.8.8-stable/src/lib/platform/OSXClipboardAnyTextConverter.cpp000066400000000000000000000037131305627404700260770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXClipboardAnyTextConverter.h" #include // // OSXClipboardAnyTextConverter // OSXClipboardAnyTextConverter::OSXClipboardAnyTextConverter() { // do nothing } OSXClipboardAnyTextConverter::~OSXClipboardAnyTextConverter() { // do nothing } IClipboard::EFormat OSXClipboardAnyTextConverter::getFormat() const { return IClipboard::kText; } String OSXClipboardAnyTextConverter::fromIClipboard(const String& data) const { // convert linefeeds and then convert to desired encoding return doFromIClipboard(convertLinefeedToMacOS(data)); } String OSXClipboardAnyTextConverter::toIClipboard(const String& data) const { // convert text then newlines return convertLinefeedToUnix(doToIClipboard(data)); } static bool isLF(char ch) { return (ch == '\n'); } static bool isCR(char ch) { return (ch == '\r'); } String OSXClipboardAnyTextConverter::convertLinefeedToMacOS(const String& src) { // note -- we assume src is a valid UTF-8 string String copy = src; std::replace_if(copy.begin(), copy.end(), isLF, '\r'); return copy; } String OSXClipboardAnyTextConverter::convertLinefeedToUnix(const String& src) { String copy = src; std::replace_if(copy.begin(), copy.end(), isCR, '\n'); return copy; } synergy-1.8.8-stable/src/lib/platform/OSXClipboardAnyTextConverter.h000066400000000000000000000031731305627404700255440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/OSXClipboard.h" //! Convert to/from some text encoding class OSXClipboardAnyTextConverter : public IOSXClipboardConverter { public: OSXClipboardAnyTextConverter(); virtual ~OSXClipboardAnyTextConverter(); // IOSXClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual CFStringRef getOSXFormat() const = 0; virtual String fromIClipboard(const String &) const; virtual String toIClipboard(const String &) const; protected: //! Convert from IClipboard format /*! Do UTF-8 conversion and linefeed conversion. */ virtual String doFromIClipboard(const String&) const = 0; //! Convert to IClipboard format /*! Do UTF-8 conversion and Linefeed conversion. */ virtual String doToIClipboard(const String&) const = 0; private: static String convertLinefeedToMacOS(const String&); static String convertLinefeedToUnix(const String&); }; synergy-1.8.8-stable/src/lib/platform/OSXClipboardBMPConverter.cpp000066400000000000000000000060751305627404700251250ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * Patch by Ryan Chapman * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXClipboardBMPConverter.h" #include "base/Log.h" // BMP file header structure struct CBMPHeader { public: UInt16 type; UInt32 size; UInt16 reserved1; UInt16 reserved2; UInt32 offset; }; // BMP is little-endian static inline UInt32 fromLEU32(const UInt8* data) { return static_cast(data[0]) | (static_cast(data[1]) << 8) | (static_cast(data[2]) << 16) | (static_cast(data[3]) << 24); } static void toLE(UInt8*& dst, char src) { dst[0] = static_cast(src); dst += 1; } static void toLE(UInt8*& dst, UInt16 src) { dst[0] = static_cast(src & 0xffu); dst[1] = static_cast((src >> 8) & 0xffu); dst += 2; } static void toLE(UInt8*& dst, UInt32 src) { dst[0] = static_cast(src & 0xffu); dst[1] = static_cast((src >> 8) & 0xffu); dst[2] = static_cast((src >> 16) & 0xffu); dst[3] = static_cast((src >> 24) & 0xffu); dst += 4; } OSXClipboardBMPConverter::OSXClipboardBMPConverter() { // do nothing } OSXClipboardBMPConverter::~OSXClipboardBMPConverter() { // do nothing } IClipboard::EFormat OSXClipboardBMPConverter::getFormat() const { return IClipboard::kBitmap; } CFStringRef OSXClipboardBMPConverter::getOSXFormat() const { // TODO: does this only work with Windows? return CFSTR("com.microsoft.bmp"); } String OSXClipboardBMPConverter::fromIClipboard(const String& bmp) const { LOG((CLOG_DEBUG1 "ENTER OSXClipboardBMPConverter::doFromIClipboard()")); // create BMP image UInt8 header[14]; UInt8* dst = header; toLE(dst, 'B'); toLE(dst, 'M'); toLE(dst, static_cast(14 + bmp.size())); toLE(dst, static_cast(0)); toLE(dst, static_cast(0)); toLE(dst, static_cast(14 + 40)); return String(reinterpret_cast(header), 14) + bmp; } String OSXClipboardBMPConverter::toIClipboard(const String& bmp) const { // make sure data is big enough for a BMP file if (bmp.size() <= 14 + 40) { return String(); } // check BMP file header const UInt8* rawBMPHeader = reinterpret_cast(bmp.data()); if (rawBMPHeader[0] != 'B' || rawBMPHeader[1] != 'M') { return String(); } // get offset to image data UInt32 offset = fromLEU32(rawBMPHeader + 10); // construct BMP if (offset == 14 + 40) { return bmp.substr(14); } else { return bmp.substr(14, 40) + bmp.substr(offset, bmp.size() - offset); } } synergy-1.8.8-stable/src/lib/platform/OSXClipboardBMPConverter.h000066400000000000000000000025721305627404700245700ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * Patch by Ryan Chapman * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/OSXClipboard.h" //! Convert to/from some text encoding class OSXClipboardBMPConverter : public IOSXClipboardConverter { public: OSXClipboardBMPConverter(); virtual ~OSXClipboardBMPConverter(); // IMSWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual CFStringRef getOSXFormat() const; // OSXClipboardAnyBMPConverter overrides virtual String fromIClipboard(const String&) const; virtual String toIClipboard(const String&) const; // generic encoding converter static String convertString(const String& data, CFStringEncoding fromEncoding, CFStringEncoding toEncoding); }; synergy-1.8.8-stable/src/lib/platform/OSXClipboardHTMLConverter.cpp000066400000000000000000000043421305627404700252460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * Patch by Ryan Chapman * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXClipboardHTMLConverter.h" #include "base/Unicode.h" OSXClipboardHTMLConverter::OSXClipboardHTMLConverter() { // do nothing } OSXClipboardHTMLConverter::~OSXClipboardHTMLConverter() { // do nothing } IClipboard::EFormat OSXClipboardHTMLConverter::getFormat() const { return IClipboard::kHTML; } CFStringRef OSXClipboardHTMLConverter::getOSXFormat() const { return CFSTR("public.html"); } String OSXClipboardHTMLConverter::convertString( const String& data, CFStringEncoding fromEncoding, CFStringEncoding toEncoding) { CFStringRef stringRef = CFStringCreateWithCString( kCFAllocatorDefault, data.c_str(), fromEncoding); if (stringRef == NULL) { return String(); } CFIndex buffSize; CFRange entireString = CFRangeMake(0, CFStringGetLength(stringRef)); CFStringGetBytes(stringRef, entireString, toEncoding, 0, false, NULL, 0, &buffSize); char* buffer = new char[buffSize]; if (buffer == NULL) { CFRelease(stringRef); return String(); } CFStringGetBytes(stringRef, entireString, toEncoding, 0, false, (UInt8*)buffer, buffSize, NULL); String result(buffer, buffSize); delete[] buffer; CFRelease(stringRef); return result; } String OSXClipboardHTMLConverter::doFromIClipboard(const String& data) const { return convertString(data, kCFStringEncodingUTF8, CFStringGetSystemEncoding()); } String OSXClipboardHTMLConverter::doToIClipboard(const String& data) const { return convertString(data, CFStringGetSystemEncoding(), kCFStringEncodingUTF8); } synergy-1.8.8-stable/src/lib/platform/OSXClipboardHTMLConverter.h000066400000000000000000000026171305627404700247160ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * Patch by Ryan Chapman * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "OSXClipboardAnyTextConverter.h" //! Convert to/from HTML encoding class OSXClipboardHTMLConverter : public OSXClipboardAnyTextConverter { public: OSXClipboardHTMLConverter(); virtual ~OSXClipboardHTMLConverter(); // IMSWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual CFStringRef getOSXFormat() const; protected: // OSXClipboardAnyTextConverter overrides virtual String doFromIClipboard(const String&) const; virtual String doToIClipboard(const String&) const; // generic encoding converter static String convertString(const String& data, CFStringEncoding fromEncoding, CFStringEncoding toEncoding); }; synergy-1.8.8-stable/src/lib/platform/OSXClipboardTextConverter.cpp000066400000000000000000000042731305627404700254310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXClipboardTextConverter.h" #include "base/Unicode.h" // // OSXClipboardTextConverter // OSXClipboardTextConverter::OSXClipboardTextConverter() { // do nothing } OSXClipboardTextConverter::~OSXClipboardTextConverter() { // do nothing } CFStringRef OSXClipboardTextConverter::getOSXFormat() const { return CFSTR("public.plain-text"); } String OSXClipboardTextConverter::convertString( const String& data, CFStringEncoding fromEncoding, CFStringEncoding toEncoding) { CFStringRef stringRef = CFStringCreateWithCString(kCFAllocatorDefault, data.c_str(), fromEncoding); if (stringRef == NULL) { return String(); } CFIndex buffSize; CFRange entireString = CFRangeMake(0, CFStringGetLength(stringRef)); CFStringGetBytes(stringRef, entireString, toEncoding, 0, false, NULL, 0, &buffSize); char* buffer = new char[buffSize]; if (buffer == NULL) { CFRelease(stringRef); return String(); } CFStringGetBytes(stringRef, entireString, toEncoding, 0, false, (UInt8*)buffer, buffSize, NULL); String result(buffer, buffSize); delete[] buffer; CFRelease(stringRef); return result; } String OSXClipboardTextConverter::doFromIClipboard(const String& data) const { return convertString(data, kCFStringEncodingUTF8, CFStringGetSystemEncoding()); } String OSXClipboardTextConverter::doToIClipboard(const String& data) const { return convertString(data, CFStringGetSystemEncoding(), kCFStringEncodingUTF8); } synergy-1.8.8-stable/src/lib/platform/OSXClipboardTextConverter.h000066400000000000000000000026011305627404700250670ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/OSXClipboardAnyTextConverter.h" //! Convert to/from locale text encoding class OSXClipboardTextConverter : public OSXClipboardAnyTextConverter { public: OSXClipboardTextConverter(); virtual ~OSXClipboardTextConverter(); // IOSXClipboardAnyTextConverter overrides virtual CFStringRef getOSXFormat() const; protected: // OSXClipboardAnyTextConverter overrides virtual String doFromIClipboard(const String&) const; virtual String doToIClipboard(const String&) const; // generic encoding converter static String convertString(const String& data, CFStringEncoding fromEncoding, CFStringEncoding toEncoding); }; synergy-1.8.8-stable/src/lib/platform/OSXClipboardUTF16Converter.cpp000066400000000000000000000026101305627404700253030ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXClipboardUTF16Converter.h" #include "base/Unicode.h" // // OSXClipboardUTF16Converter // OSXClipboardUTF16Converter::OSXClipboardUTF16Converter() { // do nothing } OSXClipboardUTF16Converter::~OSXClipboardUTF16Converter() { // do nothing } CFStringRef OSXClipboardUTF16Converter::getOSXFormat() const { return CFSTR("public.utf16-plain-text"); } String OSXClipboardUTF16Converter::doFromIClipboard(const String& data) const { // convert and add nul terminator return Unicode::UTF8ToUTF16(data); } String OSXClipboardUTF16Converter::doToIClipboard(const String& data) const { // convert and strip nul terminator return Unicode::UTF16ToUTF8(data); } synergy-1.8.8-stable/src/lib/platform/OSXClipboardUTF16Converter.h000066400000000000000000000023401305627404700247500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/OSXClipboardAnyTextConverter.h" //! Convert to/from UTF-16 encoding class OSXClipboardUTF16Converter : public OSXClipboardAnyTextConverter { public: OSXClipboardUTF16Converter(); virtual ~OSXClipboardUTF16Converter(); // IOSXClipboardAnyTextConverter overrides virtual CFStringRef getOSXFormat() const; protected: // OSXClipboardAnyTextConverter overrides virtual String doFromIClipboard(const String&) const; virtual String doToIClipboard(const String&) const; }; synergy-1.8.8-stable/src/lib/platform/OSXDragSimulator.h000066400000000000000000000017561305627404700232220ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" #import #if defined(__cplusplus) extern "C" { #endif void runCocoaApp(); void stopCocoaLoop(); void fakeDragging(const char* str, int cursorX, int cursorY); CFStringRef getCocoaDropTarget(); #if defined(__cplusplus) } #endif synergy-1.8.8-stable/src/lib/platform/OSXDragSimulator.m000066400000000000000000000051621305627404700232220ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #import "platform/OSXDragSimulator.h" #import "platform/OSXDragView.h" #import #import #import #if defined(MAC_OS_X_VERSION_10_7) NSWindow* g_dragWindow = NULL; OSXDragView* g_dragView = NULL; NSString* g_ext = NULL; void runCocoaApp() { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; [NSApplication sharedApplication]; NSWindow* window = [[NSWindow alloc] initWithContentRect: NSMakeRect(0, 0, 3, 3) styleMask: NSBorderlessWindowMask backing: NSBackingStoreBuffered defer: NO]; [window setTitle: @""]; [window setAlphaValue:0.1]; [window makeKeyAndOrderFront:nil]; OSXDragView* dragView = [[OSXDragView alloc] initWithFrame:NSMakeRect(0, 0, 3, 3)]; g_dragWindow = window; g_dragView = dragView; [window setContentView: dragView]; NSLog(@"starting cocoa loop"); [NSApp run]; NSLog(@"cocoa: release"); [pool release]; } void stopCocoaLoop() { [NSApp stop: g_dragWindow]; } void fakeDragging(const char* str, int cursorX, int cursorY) { g_ext = [NSString stringWithUTF8String:str]; dispatch_async(dispatch_get_main_queue(), ^{ NSRect screen = [[NSScreen mainScreen] frame]; NSLog ( @"screen size: witdh = %f height = %f", screen.size.width, screen.size.height); NSLog ( @"mouseLocation: %d %d", cursorX, cursorY); int newPosX = 0; int newPosY = 0; newPosX = cursorX - 1; newPosY = screen.size.height - cursorY - 1; NSRect rect = NSMakeRect(newPosX, newPosY, 3, 3); NSLog ( @"newPosX: %d", newPosX); NSLog ( @"newPosY: %d", newPosY); [g_dragWindow setFrame:rect display:NO]; [g_dragWindow makeKeyAndOrderFront:nil]; [NSApp activateIgnoringOtherApps:YES]; [g_dragView setFileExt:g_ext]; CGEventRef down = CGEventCreateMouseEvent(CGEventSourceCreate(kCGEventSourceStateHIDSystemState), kCGEventLeftMouseDown, CGPointMake(cursorX, cursorY), kCGMouseButtonLeft); CGEventPost(kCGHIDEventTap, down); }); } CFStringRef getCocoaDropTarget() { // HACK: sleep, wait for cocoa drop target updated first usleep(1000000); return [g_dragView getDropTarget]; } #endif synergy-1.8.8-stable/src/lib/platform/OSXDragView.h000066400000000000000000000017231305627404700221470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #import #ifdef MAC_OS_X_VERSION_10_7 @interface OSXDragView : NSView { NSMutableString* m_dropTarget; NSString* m_dragFileExt; } - (CFStringRef)getDropTarget; - (void)clearDropTarget; - (void)setFileExt:(NSString*) ext; @end #endif synergy-1.8.8-stable/src/lib/platform/OSXDragView.m000066400000000000000000000065131305627404700221560ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #import "platform/OSXDragView.h" #ifdef MAC_OS_X_VERSION_10_7 @implementation OSXDragView @dynamic draggingFormation; @dynamic animatesToDestination; @dynamic numberOfValidItemsForDrop; - (id) initWithFrame:(NSRect)frame { self = [super initWithFrame:frame]; m_dropTarget = [[NSMutableString alloc] initWithCapacity:0]; m_dragFileExt = [[NSMutableString alloc] initWithCapacity:0]; return self; } - (void) drawRect:(NSRect)dirtyRect { } - (BOOL) acceptsFirstMouse:(NSEvent *)theEvent { return YES; } - (void) mouseDown:(NSEvent *)theEvent { NSLog ( @"cocoa mouse down"); NSPoint dragPosition; NSRect imageLocation; dragPosition = [self convertPoint:[theEvent locationInWindow] fromView:nil]; dragPosition.x -= 16; dragPosition.y -= 16; imageLocation.origin = dragPosition; imageLocation.size = NSMakeSize(32,32); [self dragPromisedFilesOfTypes:[NSArray arrayWithObject:m_dragFileExt] fromRect:imageLocation source:self slideBack:NO event:theEvent]; } - (NSArray*) namesOfPromisedFilesDroppedAtDestination:(NSURL *)dropDestination { [m_dropTarget setString:@""]; [m_dropTarget appendString:dropDestination.path]; NSLog ( @"cocoa drop target: %@", m_dropTarget); return nil; } - (NSDragOperation) draggingSourceOperationMaskForLocal:(BOOL)flag { return NSDragOperationCopy; } - (CFStringRef) getDropTarget { NSMutableString* string; string = [[NSMutableString alloc] initWithCapacity:0]; [string appendString:m_dropTarget]; return (CFStringRef)string; } - (void) clearDropTarget { [m_dropTarget setString:@""]; } - (void) setFileExt:(NSString*) ext { [ext retain]; [m_dragFileExt release]; m_dragFileExt = ext; NSLog(@"drag file ext: %@", m_dragFileExt); } - (NSWindow *) draggingDestinationWindow { return nil; } - (NSDragOperation) draggingSourceOperationMask { return NSDragOperationCopy; } - (NSPoint)draggingLocation { NSPoint point; return point; } - (NSPoint)draggedImageLocation { NSPoint point; return point; } - (NSImage *)draggedImage { return nil; } - (NSPasteboard *)draggingPasteboard { return nil; } - (id)draggingSource { return nil; } - (NSInteger)draggingSequenceNumber { return 0; } - (void)slideDraggedImageTo:(NSPoint)screenPoint { } - (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context { return NSDragOperationCopy; } - (void)enumerateDraggingItemsWithOptions:(NSDraggingItemEnumerationOptions)enumOpts forView:(NSView *)view classes:(NSArray *)classArray searchOptions:(NSDictionary *)searchOptions usingBlock:(void (^)(NSDraggingItem *draggingItem, NSInteger idx, BOOL *stop))block { } @end #endif synergy-1.8.8-stable/src/lib/platform/OSXEventQueueBuffer.cpp000066400000000000000000000055201305627404700242110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXEventQueueBuffer.h" #include "base/Event.h" #include "base/IEventQueue.h" // // EventQueueTimer // class EventQueueTimer { }; // // OSXEventQueueBuffer // OSXEventQueueBuffer::OSXEventQueueBuffer(IEventQueue* events) : m_event(NULL), m_eventQueue(events), m_carbonEventQueue(NULL) { // do nothing } OSXEventQueueBuffer::~OSXEventQueueBuffer() { // release the last event if (m_event != NULL) { ReleaseEvent(m_event); } } void OSXEventQueueBuffer::init() { m_carbonEventQueue = GetCurrentEventQueue(); } void OSXEventQueueBuffer::waitForEvent(double timeout) { EventRef event; ReceiveNextEvent(0, NULL, timeout, false, &event); } IEventQueueBuffer::Type OSXEventQueueBuffer::getEvent(Event& event, UInt32& dataID) { // release the previous event if (m_event != NULL) { ReleaseEvent(m_event); m_event = NULL; } // get the next event OSStatus error = ReceiveNextEvent(0, NULL, 0.0, true, &m_event); // handle the event if (error == eventLoopQuitErr) { event = Event(Event::kQuit); return kSystem; } else if (error != noErr) { return kNone; } else { UInt32 eventClass = GetEventClass(m_event); switch (eventClass) { case 'Syne': dataID = GetEventKind(m_event); return kUser; default: event = Event(Event::kSystem, m_eventQueue->getSystemTarget(), &m_event); return kSystem; } } } bool OSXEventQueueBuffer::addEvent(UInt32 dataID) { EventRef event; OSStatus error = CreateEvent( kCFAllocatorDefault, 'Syne', dataID, 0, kEventAttributeNone, &event); if (error == noErr) { assert(m_carbonEventQueue != NULL); error = PostEventToQueue( m_carbonEventQueue, event, kEventPriorityStandard); ReleaseEvent(event); } return (error == noErr); } bool OSXEventQueueBuffer::isEmpty() const { EventRef event; OSStatus status = ReceiveNextEvent(0, NULL, 0.0, false, &event); return (status == eventLoopTimedOutErr); } EventQueueTimer* OSXEventQueueBuffer::newTimer(double, bool) const { return new EventQueueTimer; } void OSXEventQueueBuffer::deleteTimer(EventQueueTimer* timer) const { delete timer; } synergy-1.8.8-stable/src/lib/platform/OSXEventQueueBuffer.h000066400000000000000000000026701305627404700236610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/IEventQueueBuffer.h" #include class IEventQueue; //! Event queue buffer for OS X class OSXEventQueueBuffer : public IEventQueueBuffer { public: OSXEventQueueBuffer(IEventQueue* eventQueue); virtual ~OSXEventQueueBuffer(); // IEventQueueBuffer overrides virtual void init(); virtual void waitForEvent(double timeout); virtual Type getEvent(Event& event, UInt32& dataID); virtual bool addEvent(UInt32 dataID); virtual bool isEmpty() const; virtual EventQueueTimer* newTimer(double duration, bool oneShot) const; virtual void deleteTimer(EventQueueTimer*) const; private: EventRef m_event; IEventQueue* m_eventQueue; EventQueueRef m_carbonEventQueue; }; synergy-1.8.8-stable/src/lib/platform/OSXKeyState.cpp000066400000000000000000000572631305627404700225350ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXKeyState.h" #include "platform/OSXUchrKeyResource.h" #include "platform/OSXMediaKeySupport.h" #include "arch/Arch.h" #include "base/Log.h" #include #include // Note that some virtual keys codes appear more than once. The // first instance of a virtual key code maps to the KeyID that we // want to generate for that code. The others are for mapping // different KeyIDs to a single key code. static const UInt32 s_shiftVK = kVK_Shift; static const UInt32 s_controlVK = kVK_Control; static const UInt32 s_altVK = kVK_Option; static const UInt32 s_superVK = kVK_Command; static const UInt32 s_capsLockVK = kVK_CapsLock; static const UInt32 s_numLockVK = kVK_ANSI_KeypadClear; // 71 static const UInt32 s_brightnessUp = 144; static const UInt32 s_brightnessDown = 145; static const UInt32 s_missionControlVK = 160; static const UInt32 s_launchpadVK = 131; static const UInt32 s_osxNumLock = 1 << 16; struct KeyEntry { public: KeyID m_keyID; UInt32 m_virtualKey; }; static const KeyEntry s_controlKeys[] = { // cursor keys. if we don't do this we'll may still get these from // the keyboard resource but they may not correspond to the arrow // keys. { kKeyLeft, kVK_LeftArrow }, { kKeyRight, kVK_RightArrow }, { kKeyUp, kVK_UpArrow }, { kKeyDown, kVK_DownArrow }, { kKeyHome, kVK_Home }, { kKeyEnd, kVK_End }, { kKeyPageUp, kVK_PageUp }, { kKeyPageDown, kVK_PageDown }, { kKeyInsert, kVK_Help }, // Mac Keyboards have 'Help' on 'Insert' // function keys { kKeyF1, kVK_F1 }, { kKeyF2, kVK_F2 }, { kKeyF3, kVK_F3 }, { kKeyF4, kVK_F4 }, { kKeyF5, kVK_F5 }, { kKeyF6, kVK_F6 }, { kKeyF7, kVK_F7 }, { kKeyF8, kVK_F8 }, { kKeyF9, kVK_F9 }, { kKeyF10, kVK_F10 }, { kKeyF11, kVK_F11 }, { kKeyF12, kVK_F12 }, { kKeyF13, kVK_F13 }, { kKeyF14, kVK_F14 }, { kKeyF15, kVK_F15 }, { kKeyF16, kVK_F16 }, { kKeyKP_0, kVK_ANSI_Keypad0 }, { kKeyKP_1, kVK_ANSI_Keypad1 }, { kKeyKP_2, kVK_ANSI_Keypad2 }, { kKeyKP_3, kVK_ANSI_Keypad3 }, { kKeyKP_4, kVK_ANSI_Keypad4 }, { kKeyKP_5, kVK_ANSI_Keypad5 }, { kKeyKP_6, kVK_ANSI_Keypad6 }, { kKeyKP_7, kVK_ANSI_Keypad7 }, { kKeyKP_8, kVK_ANSI_Keypad8 }, { kKeyKP_9, kVK_ANSI_Keypad9 }, { kKeyKP_Decimal, kVK_ANSI_KeypadDecimal }, { kKeyKP_Equal, kVK_ANSI_KeypadEquals }, { kKeyKP_Multiply, kVK_ANSI_KeypadMultiply }, { kKeyKP_Add, kVK_ANSI_KeypadPlus }, { kKeyKP_Divide, kVK_ANSI_KeypadDivide }, { kKeyKP_Subtract, kVK_ANSI_KeypadMinus }, { kKeyKP_Enter, kVK_ANSI_KeypadEnter }, // virtual key 110 is fn+enter and i have no idea what that's supposed // to map to. also the enter key with numlock on is a modifier but i // don't know which. // modifier keys. OS X doesn't seem to support right handed versions // of modifier keys so we map them to the left handed versions. { kKeyShift_L, s_shiftVK }, { kKeyShift_R, s_shiftVK }, // 60 { kKeyControl_L, s_controlVK }, { kKeyControl_R, s_controlVK }, // 62 { kKeyAlt_L, s_altVK }, { kKeyAlt_R, s_altVK }, { kKeySuper_L, s_superVK }, { kKeySuper_R, s_superVK }, // 61 { kKeyMeta_L, s_superVK }, { kKeyMeta_R, s_superVK }, // 61 // toggle modifiers { kKeyNumLock, s_numLockVK }, { kKeyCapsLock, s_capsLockVK }, { kKeyMissionControl, s_missionControlVK }, { kKeyLaunchpad, s_launchpadVK }, { kKeyBrightnessUp, s_brightnessUp }, { kKeyBrightnessDown, s_brightnessDown } }; // // OSXKeyState // OSXKeyState::OSXKeyState(IEventQueue* events) : KeyState(events) { init(); } OSXKeyState::OSXKeyState(IEventQueue* events, synergy::KeyMap& keyMap) : KeyState(events, keyMap) { init(); } OSXKeyState::~OSXKeyState() { } void OSXKeyState::init() { m_deadKeyState = 0; m_shiftPressed = false; m_controlPressed = false; m_altPressed = false; m_superPressed = false; m_capsPressed = false; // build virtual key map for (size_t i = 0; i < sizeof(s_controlKeys) / sizeof(s_controlKeys[0]); ++i) { m_virtualKeyMap[s_controlKeys[i].m_virtualKey] = s_controlKeys[i].m_keyID; } } KeyModifierMask OSXKeyState::mapModifiersFromOSX(UInt32 mask) const { KeyModifierMask outMask = 0; if ((mask & kCGEventFlagMaskShift) != 0) { outMask |= KeyModifierShift; } if ((mask & kCGEventFlagMaskControl) != 0) { outMask |= KeyModifierControl; } if ((mask & kCGEventFlagMaskAlternate) != 0) { outMask |= KeyModifierAlt; } if ((mask & kCGEventFlagMaskCommand) != 0) { outMask |= KeyModifierSuper; } if ((mask & kCGEventFlagMaskAlphaShift) != 0) { outMask |= KeyModifierCapsLock; } if ((mask & kCGEventFlagMaskNumericPad) != 0) { outMask |= KeyModifierNumLock; } LOG((CLOG_DEBUG1 "mask=%04x outMask=%04x", mask, outMask)); return outMask; } KeyModifierMask OSXKeyState::mapModifiersToCarbon(UInt32 mask) const { KeyModifierMask outMask = 0; if ((mask & kCGEventFlagMaskShift) != 0) { outMask |= shiftKey; } if ((mask & kCGEventFlagMaskControl) != 0) { outMask |= controlKey; } if ((mask & kCGEventFlagMaskCommand) != 0) { outMask |= cmdKey; } if ((mask & kCGEventFlagMaskAlternate) != 0) { outMask |= optionKey; } if ((mask & kCGEventFlagMaskAlphaShift) != 0) { outMask |= alphaLock; } if ((mask & kCGEventFlagMaskNumericPad) != 0) { outMask |= s_osxNumLock; } return outMask; } KeyButton OSXKeyState::mapKeyFromEvent(KeyIDs& ids, KeyModifierMask* maskOut, CGEventRef event) const { ids.clear(); // map modifier key if (maskOut != NULL) { KeyModifierMask activeMask = getActiveModifiers(); activeMask &= ~KeyModifierAltGr; *maskOut = activeMask; } // get virtual key UInt32 vkCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); // handle up events UInt32 eventKind = CGEventGetType(event); if (eventKind == kCGEventKeyUp) { // the id isn't used. we just need the same button we used on // the key press. note that we don't use or reset the dead key // state; up events should not affect the dead key state. ids.push_back(kKeyNone); return mapVirtualKeyToKeyButton(vkCode); } // check for special keys VirtualKeyMap::const_iterator i = m_virtualKeyMap.find(vkCode); if (i != m_virtualKeyMap.end()) { m_deadKeyState = 0; ids.push_back(i->second); return mapVirtualKeyToKeyButton(vkCode); } // get keyboard info TISInputSourceRef currentKeyboardLayout = TISCopyCurrentKeyboardLayoutInputSource(); if (currentKeyboardLayout == NULL) { return kKeyNone; } // get the event modifiers and remove the command and control // keys. note if we used them though. // UCKeyTranslate expects old-style Carbon modifiers, so convert. UInt32 modifiers; modifiers = mapModifiersToCarbon(CGEventGetFlags(event)); static const UInt32 s_commandModifiers = cmdKey | controlKey | rightControlKey; bool isCommand = ((modifiers & s_commandModifiers) != 0); modifiers &= ~s_commandModifiers; // if we've used a command key then we want the glyph produced without // the option key (i.e. the base glyph). //if (isCommand) { modifiers &= ~optionKey; //} // choose action UInt16 action; if (eventKind==kCGEventKeyDown) { action = kUCKeyActionDown; } else if (CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat)==1) { action = kUCKeyActionAutoKey; } else { return 0; } // translate via uchr resource CFDataRef ref = (CFDataRef) TISGetInputSourceProperty(currentKeyboardLayout, kTISPropertyUnicodeKeyLayoutData); const UCKeyboardLayout* layout = (const UCKeyboardLayout*) CFDataGetBytePtr(ref); const bool layoutValid = (layout != NULL); if (layoutValid) { // translate key UniCharCount count; UniChar chars[2]; LOG((CLOG_DEBUG2 "modifiers: %08x", modifiers & 0xffu)); OSStatus status = UCKeyTranslate(layout, vkCode & 0xffu, action, (modifiers >> 8) & 0xffu, LMGetKbdType(), 0, &m_deadKeyState, sizeof(chars) / sizeof(chars[0]), &count, chars); // get the characters if (status == 0) { if (count != 0 || m_deadKeyState == 0) { m_deadKeyState = 0; for (UniCharCount i = 0; i < count; ++i) { ids.push_back(IOSXKeyResource::unicharToKeyID(chars[i])); } adjustAltGrModifier(ids, maskOut, isCommand); return mapVirtualKeyToKeyButton(vkCode); } return 0; } } return 0; } bool OSXKeyState::fakeCtrlAltDel() { // pass keys through unchanged return false; } bool OSXKeyState::fakeMediaKey(KeyID id) { return fakeNativeMediaKey(id);; } CGEventFlags OSXKeyState::getModifierStateAsOSXFlags() { CGEventFlags modifiers = 0; if (m_shiftPressed) { modifiers |= kCGEventFlagMaskShift; } if (m_controlPressed) { modifiers |= kCGEventFlagMaskControl; } if (m_altPressed) { modifiers |= kCGEventFlagMaskAlternate; } if (m_superPressed) { modifiers |= kCGEventFlagMaskCommand; } if (m_capsPressed) { modifiers |= kCGEventFlagMaskAlphaShift; } return modifiers; } KeyModifierMask OSXKeyState::pollActiveModifiers() const { // falsely assumed that the mask returned by GetCurrentKeyModifiers() // was the same as a CGEventFlags (which is what mapModifiersFromOSX // expects). patch by Marc UInt32 mask = GetCurrentKeyModifiers(); KeyModifierMask outMask = 0; if ((mask & shiftKey) != 0) { outMask |= KeyModifierShift; } if ((mask & controlKey) != 0) { outMask |= KeyModifierControl; } if ((mask & optionKey) != 0) { outMask |= KeyModifierAlt; } if ((mask & cmdKey) != 0) { outMask |= KeyModifierSuper; } if ((mask & alphaLock) != 0) { outMask |= KeyModifierCapsLock; } if ((mask & s_osxNumLock) != 0) { outMask |= KeyModifierNumLock; } LOG((CLOG_DEBUG1 "mask=%04x outMask=%04x", mask, outMask)); return outMask; } SInt32 OSXKeyState::pollActiveGroup() const { TISInputSourceRef keyboardLayout = TISCopyCurrentKeyboardLayoutInputSource(); CFDataRef id = (CFDataRef)TISGetInputSourceProperty( keyboardLayout, kTISPropertyInputSourceID); GroupMap::const_iterator i = m_groupMap.find(id); if (i != m_groupMap.end()) { return i->second; } LOG((CLOG_DEBUG "can't get the active group, use the first group instead")); return 0; } void OSXKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const { ::KeyMap km; GetKeys(km); const UInt8* m = reinterpret_cast(km); for (UInt32 i = 0; i < 16; ++i) { for (UInt32 j = 0; j < 8; ++j) { if ((m[i] & (1u << j)) != 0) { pressedKeys.insert(mapVirtualKeyToKeyButton(8 * i + j)); } } } } void OSXKeyState::getKeyMap(synergy::KeyMap& keyMap) { // update keyboard groups if (getGroups(m_groups)) { m_groupMap.clear(); SInt32 numGroups = (SInt32)m_groups.size(); for (SInt32 g = 0; g < numGroups; ++g) { CFDataRef id = (CFDataRef)TISGetInputSourceProperty( m_groups[g], kTISPropertyInputSourceID); m_groupMap[id] = g; } } UInt32 keyboardType = LMGetKbdType(); for (SInt32 g = 0, n = (SInt32)m_groups.size(); g < n; ++g) { // add special keys getKeyMapForSpecialKeys(keyMap, g); const void* resource; bool layoutValid = false; // add regular keys // try uchr resource first CFDataRef resourceRef = (CFDataRef)TISGetInputSourceProperty( m_groups[g], kTISPropertyUnicodeKeyLayoutData); layoutValid = resourceRef != NULL; if (layoutValid) resource = CFDataGetBytePtr(resourceRef); if (layoutValid) { OSXUchrKeyResource uchr(resource, keyboardType); if (uchr.isValid()) { LOG((CLOG_DEBUG1 "using uchr resource for group %d", g)); getKeyMap(keyMap, g, uchr); continue; } } LOG((CLOG_DEBUG1 "no keyboard resource for group %d", g)); } } static io_connect_t getEventDriver(void) { static mach_port_t sEventDrvrRef = 0; mach_port_t masterPort, service, iter; kern_return_t kr; if (!sEventDrvrRef) { // Get master device port kr = IOMasterPort(bootstrap_port, &masterPort); assert(KERN_SUCCESS == kr); kr = IOServiceGetMatchingServices(masterPort, IOServiceMatching(kIOHIDSystemClass), &iter); assert(KERN_SUCCESS == kr); service = IOIteratorNext(iter); assert(service); kr = IOServiceOpen(service, mach_task_self(), kIOHIDParamConnectType, &sEventDrvrRef); assert(KERN_SUCCESS == kr); IOObjectRelease(service); IOObjectRelease(iter); } return sEventDrvrRef; } void OSXKeyState::postHIDVirtualKey(const UInt8 virtualKeyCode, const bool postDown) { static UInt32 modifiers = 0; NXEventData event; IOGPoint loc = { 0, 0 }; UInt32 modifiersDelta = 0; bzero(&event, sizeof(NXEventData)); switch (virtualKeyCode) { case s_shiftVK: case s_superVK: case s_altVK: case s_controlVK: case s_capsLockVK: switch (virtualKeyCode) { case s_shiftVK: modifiersDelta = NX_SHIFTMASK; m_shiftPressed = postDown; break; case s_superVK: modifiersDelta = NX_COMMANDMASK; m_superPressed = postDown; break; case s_altVK: modifiersDelta = NX_ALTERNATEMASK; m_altPressed = postDown; break; case s_controlVK: modifiersDelta = NX_CONTROLMASK; m_controlPressed = postDown; break; case s_capsLockVK: modifiersDelta = NX_ALPHASHIFTMASK; m_capsPressed = postDown; break; } // update the modifier bit if (postDown) { modifiers |= modifiersDelta; } else { modifiers &= ~modifiersDelta; } kern_return_t kr; kr = IOHIDPostEvent(getEventDriver(), NX_FLAGSCHANGED, loc, &event, kNXEventDataVersion, modifiers, true); assert(KERN_SUCCESS == kr); break; default: event.key.repeat = false; event.key.keyCode = virtualKeyCode; event.key.origCharSet = event.key.charSet = NX_ASCIISET; event.key.origCharCode = event.key.charCode = 0; kr = IOHIDPostEvent(getEventDriver(), postDown ? NX_KEYDOWN : NX_KEYUP, loc, &event, kNXEventDataVersion, 0, false); assert(KERN_SUCCESS == kr); break; } } void OSXKeyState::fakeKey(const Keystroke& keystroke) { switch (keystroke.m_type) { case Keystroke::kButton: { KeyButton button = keystroke.m_data.m_button.m_button; bool keyDown = keystroke.m_data.m_button.m_press; CGKeyCode virtualKey = mapKeyButtonToVirtualKey(button); LOG((CLOG_DEBUG1 " button=0x%04x virtualKey=0x%04x keyDown=%s", button, virtualKey, keyDown ? "down" : "up")); postHIDVirtualKey(virtualKey, keyDown); break; } case Keystroke::kGroup: { SInt32 group = keystroke.m_data.m_group.m_group; if (keystroke.m_data.m_group.m_absolute) { LOG((CLOG_DEBUG1 " group %d", group)); setGroup(group); } else { LOG((CLOG_DEBUG1 " group %+d", group)); setGroup(getEffectiveGroup(pollActiveGroup(), group)); } break; } } } void OSXKeyState::getKeyMapForSpecialKeys(synergy::KeyMap& keyMap, SInt32 group) const { // special keys are insensitive to modifers and none are dead keys synergy::KeyMap::KeyItem item; for (size_t i = 0; i < sizeof(s_controlKeys) / sizeof(s_controlKeys[0]); ++i) { const KeyEntry& entry = s_controlKeys[i]; item.m_id = entry.m_keyID; item.m_group = group; item.m_button = mapVirtualKeyToKeyButton(entry.m_virtualKey); item.m_required = 0; item.m_sensitive = 0; item.m_dead = false; item.m_client = 0; synergy::KeyMap::initModifierKey(item); keyMap.addKeyEntry(item); if (item.m_lock) { // all locking keys are half duplex on OS X keyMap.addHalfDuplexButton(item.m_button); } } // note: we don't special case the number pad keys. querying the // mac keyboard returns the non-keypad version of those keys but // a KeyState always provides a mapping from keypad keys to // non-keypad keys so we'll be able to generate the characters // anyway. } bool OSXKeyState::getKeyMap(synergy::KeyMap& keyMap, SInt32 group, const IOSXKeyResource& r) const { if (!r.isValid()) { return false; } // space for all possible modifier combinations std::vector modifiers(r.getNumModifierCombinations()); // make space for the keys that any single button can synthesize std::vector > buttonKeys(r.getNumTables()); // iterate over each button synergy::KeyMap::KeyItem item; for (UInt32 i = 0; i < r.getNumButtons(); ++i) { item.m_button = mapVirtualKeyToKeyButton(i); // the KeyIDs we've already handled std::set keys; // convert the entry in each table for this button to a KeyID for (UInt32 j = 0; j < r.getNumTables(); ++j) { buttonKeys[j].first = r.getKey(j, i); buttonKeys[j].second = synergy::KeyMap::isDeadKey(buttonKeys[j].first); } // iterate over each character table for (UInt32 j = 0; j < r.getNumTables(); ++j) { // get the KeyID for the button/table KeyID id = buttonKeys[j].first; if (id == kKeyNone) { continue; } // if we've already handled the KeyID in the table then // move on to the next table if (keys.count(id) > 0) { continue; } keys.insert(id); // prepare item. the client state is 1 for dead keys. item.m_id = id; item.m_group = group; item.m_dead = buttonKeys[j].second; item.m_client = buttonKeys[j].second ? 1 : 0; synergy::KeyMap::initModifierKey(item); if (item.m_lock) { // all locking keys are half duplex on OS X keyMap.addHalfDuplexButton(i); } // collect the tables that map to the same KeyID. we know it // can't be any earlier tables because of the check above. std::set tables; tables.insert(static_cast(j)); for (UInt32 k = j + 1; k < r.getNumTables(); ++k) { if (buttonKeys[k].first == id) { tables.insert(static_cast(k)); } } // collect the modifier combinations that map to any of the // tables we just collected for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) { modifiers[k] = (tables.count(r.getTableForModifier(k)) > 0); } // figure out which modifiers the key is sensitive to. the // key is insensitive to a modifier if for every modifier mask // with the modifier bit unset in the modifiers we also find // the same mask with the bit set. // // we ignore a few modifiers that we know aren't important // for generating characters. in fact, we want to ignore any // characters generated by the control key. we don't map // those and instead expect the control modifier plus a key. UInt32 sensitive = 0; for (UInt32 k = 0; (1u << k) < r.getNumModifierCombinations(); ++k) { UInt32 bit = (1u << k); if ((bit << 8) == cmdKey || (bit << 8) == controlKey || (bit << 8) == rightControlKey) { continue; } for (UInt32 m = 0; m < r.getNumModifierCombinations(); ++m) { if (modifiers[m] != modifiers[m ^ bit]) { sensitive |= bit; break; } } } // find each required modifier mask. the key can be synthesized // using any of the masks. std::set required; for (UInt32 k = 0; k < r.getNumModifierCombinations(); ++k) { if ((k & sensitive) == k && modifiers[k & sensitive]) { required.insert(k); } } // now add a key entry for each key/required modifier pair. item.m_sensitive = mapModifiersFromOSX(sensitive << 16); for (std::set::iterator k = required.begin(); k != required.end(); ++k) { item.m_required = mapModifiersFromOSX(*k << 16); keyMap.addKeyEntry(item); } } } return true; } bool OSXKeyState::mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask, UInt32 &macVirtualKey, UInt32 &macModifierMask) const { // look up button for key KeyButton button = getButton(key, pollActiveGroup()); if (button == 0 && key != kKeyNone) { return false; } macVirtualKey = mapKeyButtonToVirtualKey(button); // calculate modifier mask macModifierMask = 0; if ((mask & KeyModifierShift) != 0) { macModifierMask |= shiftKey; } if ((mask & KeyModifierControl) != 0) { macModifierMask |= controlKey; } if ((mask & KeyModifierAlt) != 0) { macModifierMask |= cmdKey; } if ((mask & KeyModifierSuper) != 0) { macModifierMask |= optionKey; } if ((mask & KeyModifierCapsLock) != 0) { macModifierMask |= alphaLock; } if ((mask & KeyModifierNumLock) != 0) { macModifierMask |= s_osxNumLock; } return true; } void OSXKeyState::handleModifierKeys(void* target, KeyModifierMask oldMask, KeyModifierMask newMask) { // compute changed modifiers KeyModifierMask changed = (oldMask ^ newMask); // synthesize changed modifier keys if ((changed & KeyModifierShift) != 0) { handleModifierKey(target, s_shiftVK, kKeyShift_L, (newMask & KeyModifierShift) != 0, newMask); } if ((changed & KeyModifierControl) != 0) { handleModifierKey(target, s_controlVK, kKeyControl_L, (newMask & KeyModifierControl) != 0, newMask); } if ((changed & KeyModifierAlt) != 0) { handleModifierKey(target, s_altVK, kKeyAlt_L, (newMask & KeyModifierAlt) != 0, newMask); } if ((changed & KeyModifierSuper) != 0) { handleModifierKey(target, s_superVK, kKeySuper_L, (newMask & KeyModifierSuper) != 0, newMask); } if ((changed & KeyModifierCapsLock) != 0) { handleModifierKey(target, s_capsLockVK, kKeyCapsLock, (newMask & KeyModifierCapsLock) != 0, newMask); } if ((changed & KeyModifierNumLock) != 0) { handleModifierKey(target, s_numLockVK, kKeyNumLock, (newMask & KeyModifierNumLock) != 0, newMask); } } void OSXKeyState::handleModifierKey(void* target, UInt32 virtualKey, KeyID id, bool down, KeyModifierMask newMask) { KeyButton button = mapVirtualKeyToKeyButton(virtualKey); onKey(button, down, newMask); sendKeyEvent(target, down, false, id, newMask, 0, button); } bool OSXKeyState::getGroups(GroupList& groups) const { CFIndex n; bool gotLayouts = false; // get number of layouts CFStringRef keys[] = { kTISPropertyInputSourceCategory }; CFStringRef values[] = { kTISCategoryKeyboardInputSource }; CFDictionaryRef dict = CFDictionaryCreate(NULL, (const void **)keys, (const void **)values, 1, NULL, NULL); CFArrayRef kbds = TISCreateInputSourceList(dict, false); n = CFArrayGetCount(kbds); gotLayouts = (n != 0); if (!gotLayouts) { LOG((CLOG_DEBUG1 "can't get keyboard layouts")); return false; } // get each layout groups.clear(); for (CFIndex i = 0; i < n; ++i) { bool addToGroups = true; TISInputSourceRef keyboardLayout = (TISInputSourceRef)CFArrayGetValueAtIndex(kbds, i); if (addToGroups) groups.push_back(keyboardLayout); } return true; } void OSXKeyState::setGroup(SInt32 group) { TISSetInputMethodKeyboardLayoutOverride(m_groups[group]); } void OSXKeyState::checkKeyboardLayout() { // XXX -- should call this when notified that groups have changed. // if no notification for that then we should poll. GroupList groups; if (getGroups(groups) && groups != m_groups) { updateKeyMap(); updateKeyState(); } } void OSXKeyState::adjustAltGrModifier(const KeyIDs& ids, KeyModifierMask* mask, bool isCommand) const { if (!isCommand) { for (KeyIDs::const_iterator i = ids.begin(); i != ids.end(); ++i) { KeyID id = *i; if (id != kKeyNone && ((id < 0xe000u || id > 0xefffu) || (id >= kKeyKP_Equal && id <= kKeyKP_9))) { *mask |= KeyModifierAltGr; return; } } } } KeyButton OSXKeyState::mapVirtualKeyToKeyButton(UInt32 keyCode) { // 'A' maps to 0 so shift every id return static_cast(keyCode + KeyButtonOffset); } UInt32 OSXKeyState::mapKeyButtonToVirtualKey(KeyButton keyButton) { return static_cast(keyButton - KeyButtonOffset); } synergy-1.8.8-stable/src/lib/platform/OSXKeyState.h000066400000000000000000000130141305627404700221640ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/KeyState.h" #include "common/stdmap.h" #include "common/stdset.h" #include "common/stdvector.h" #include typedef TISInputSourceRef KeyLayout; class IOSXKeyResource; //! OS X key state /*! A key state for OS X. */ class OSXKeyState : public KeyState { public: typedef std::vector KeyIDs; OSXKeyState(IEventQueue* events); OSXKeyState(IEventQueue* events, synergy::KeyMap& keyMap); virtual ~OSXKeyState(); //! @name modifiers //@{ //! Handle modifier key change /*! Determines which modifier keys have changed and updates the modifier state and sends key events as appropriate. */ void handleModifierKeys(void* target, KeyModifierMask oldMask, KeyModifierMask newMask); //@} //! @name accessors //@{ //! Convert OS X modifier mask to synergy mask /*! Returns the synergy modifier mask corresponding to the OS X modifier mask in \p mask. */ KeyModifierMask mapModifiersFromOSX(UInt32 mask) const; //! Convert CG flags-style modifier mask to old-style Carbon /*! Still required in a few places for translation calls. */ KeyModifierMask mapModifiersToCarbon(UInt32 mask) const; //! Map key event to keys /*! Converts a key event into a sequence of KeyIDs and the shadow modifier state to a modifier mask. The KeyIDs list, in order, the characters generated by the key press/release. It returns the id of the button that was pressed or released, or 0 if the button doesn't map to a known KeyID. */ KeyButton mapKeyFromEvent(KeyIDs& ids, KeyModifierMask* maskOut, CGEventRef event) const; //! Map key and mask to native values /*! Calculates mac virtual key and mask for a key \p key and modifiers \p mask. Returns \c true if the key can be mapped, \c false otherwise. */ bool mapSynergyHotKeyToMac(KeyID key, KeyModifierMask mask, UInt32& macVirtualKey, UInt32& macModifierMask) const; //@} // IKeyState overrides virtual bool fakeCtrlAltDel(); virtual bool fakeMediaKey(KeyID id); virtual KeyModifierMask pollActiveModifiers() const; virtual SInt32 pollActiveGroup() const; virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const; CGEventFlags getModifierStateAsOSXFlags(); protected: // KeyState overrides virtual void getKeyMap(synergy::KeyMap& keyMap); virtual void fakeKey(const Keystroke& keystroke); private: class KeyResource; typedef std::vector GroupList; // Add hard coded special keys to a synergy::KeyMap. void getKeyMapForSpecialKeys( synergy::KeyMap& keyMap, SInt32 group) const; // Convert keyboard resource to a key map bool getKeyMap(synergy::KeyMap& keyMap, SInt32 group, const IOSXKeyResource& r) const; // Get the available keyboard groups bool getGroups(GroupList&) const; // Change active keyboard group to group void setGroup(SInt32 group); // Check if the keyboard layout has changed and update keyboard state // if so. void checkKeyboardLayout(); // Send an event for the given modifier key void handleModifierKey(void* target, UInt32 virtualKey, KeyID id, bool down, KeyModifierMask newMask); // Checks if any in \p ids is a glyph key and if \p isCommand is false. // If so it adds the AltGr modifier to \p mask. This allows OS X // servers to use the option key both as AltGr and as a modifier. If // option is acting as AltGr (i.e. it generates a glyph and there are // no command modifiers active) then we don't send the super modifier // to clients because they'd try to match it as a command modifier. void adjustAltGrModifier(const KeyIDs& ids, KeyModifierMask* mask, bool isCommand) const; // Maps an OS X virtual key id to a KeyButton. This simply remaps // the ids so we don't use KeyButton 0. static KeyButton mapVirtualKeyToKeyButton(UInt32 keyCode); // Maps a KeyButton to an OS X key code. This is the inverse of // mapVirtualKeyToKeyButton. static UInt32 mapKeyButtonToVirtualKey(KeyButton keyButton); void init(); // Post a key event to HID manager. It posts an event to HID client, a // much lower level than window manager which's the target from carbon // CGEventPost void postHIDVirtualKey(const UInt8 virtualKeyCode, const bool postDown); private: // OS X uses a physical key if 0 for the 'A' key. synergy reserves // KeyButton 0 so we offset all OS X physical key ids by this much // when used as a KeyButton and by minus this much to map a KeyButton // to a physical button. enum { KeyButtonOffset = 1 }; typedef std::map GroupMap; typedef std::map VirtualKeyMap; VirtualKeyMap m_virtualKeyMap; mutable UInt32 m_deadKeyState; GroupList m_groups; GroupMap m_groupMap; bool m_shiftPressed; bool m_controlPressed; bool m_altPressed; bool m_superPressed; bool m_capsPressed; }; synergy-1.8.8-stable/src/lib/platform/OSXMediaKeySupport.h000066400000000000000000000020271305627404700235220ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless. * * 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #import #import #include "synergy/key_types.h" #if defined(__cplusplus) extern "C" { #endif bool fakeNativeMediaKey(KeyID id); bool isMediaKeyEvent(CGEventRef event); bool getMediaKeyEventInfo(CGEventRef event, KeyID* keyId, bool* down, bool* isRepeat); #if defined(__cplusplus) } #endif synergy-1.8.8-stable/src/lib/platform/OSXMediaKeySupport.m000066400000000000000000000064421305627404700235340ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless. * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file COPYING that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #import "platform/OSXMediaKeySupport.h" #import #import int convertKeyIDToNXKeyType(KeyID id) { int type = -1; switch (id) { case kKeyAudioUp: type = NX_KEYTYPE_SOUND_UP; break; case kKeyAudioDown: type = NX_KEYTYPE_SOUND_DOWN; break; case kKeyBrightnessUp: type = NX_KEYTYPE_BRIGHTNESS_UP; break; case kKeyBrightnessDown: type = NX_KEYTYPE_BRIGHTNESS_DOWN; break; case kKeyAudioMute: type = NX_KEYTYPE_MUTE; break; case kKeyEject: type = NX_KEYTYPE_EJECT; break; case kKeyAudioPlay: type = NX_KEYTYPE_PLAY; break; case kKeyAudioNext: type = NX_KEYTYPE_NEXT; break; case kKeyAudioPrev: type = NX_KEYTYPE_PREVIOUS; break; default: break; } return type; } static KeyID convertNXKeyTypeToKeyID(uint32_t const type) { KeyID id = 0; switch (type) { case NX_KEYTYPE_SOUND_UP: id = kKeyAudioUp; break; case NX_KEYTYPE_SOUND_DOWN: id = kKeyAudioDown; break; case NX_KEYTYPE_MUTE: id = kKeyAudioMute; break; case NX_KEYTYPE_EJECT: id = kKeyEject; break; case NX_KEYTYPE_PLAY: id = kKeyAudioPlay; break; case NX_KEYTYPE_FAST: case NX_KEYTYPE_NEXT: id = kKeyAudioNext; break; case NX_KEYTYPE_REWIND: case NX_KEYTYPE_PREVIOUS: id = kKeyAudioPrev; break; default: break; } return id; } bool isMediaKeyEvent(CGEventRef event) { NSEvent* nsEvent = nil; @try { nsEvent = [NSEvent eventWithCGEvent: event]; if ([nsEvent subtype] != 8) { return false; } uint32_t const nxKeyId = ([nsEvent data1] & 0xFFFF0000) >> 16; if (convertNXKeyTypeToKeyID (nxKeyId)) { return true; } } @catch (NSException* e) { } return false; } bool getMediaKeyEventInfo(CGEventRef event, KeyID* const keyId, bool* const down, bool* const isRepeat) { NSEvent* nsEvent = nil; @try { nsEvent = [NSEvent eventWithCGEvent: event]; } @catch (NSException* e) { return false; } if (keyId) { *keyId = convertNXKeyTypeToKeyID (([nsEvent data1] & 0xFFFF0000) >> 16); } if (down) { *down = !([nsEvent data1] & 0x100); } if (isRepeat) { *isRepeat = [nsEvent data1] & 0x1; } return true; } bool fakeNativeMediaKey(KeyID id) { NSEvent* downRef = [NSEvent otherEventWithType:NSSystemDefined location: NSMakePoint(0, 0) modifierFlags:0xa00 timestamp:0 windowNumber:0 context:0 subtype:8 data1:(convertKeyIDToNXKeyType(id) << 16) | ((0xa) << 8) data2:-1]; CGEventRef downEvent = [downRef CGEvent]; NSEvent* upRef = [NSEvent otherEventWithType:NSSystemDefined location: NSMakePoint(0, 0) modifierFlags:0xa00 timestamp:0 windowNumber:0 context:0 subtype:8 data1:(convertKeyIDToNXKeyType(id) << 16) | ((0xb) << 8) data2:-1]; CGEventRef upEvent = [upRef CGEvent]; CGEventPost(0, downEvent); CGEventPost(0, upEvent); return true; } synergy-1.8.8-stable/src/lib/platform/OSXPasteboardPeeker.h000066400000000000000000000015761305627404700236650ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" #import #if defined(__cplusplus) extern "C" { #endif CFStringRef getDraggedFileURL(); #if defined(__cplusplus) } #endif synergy-1.8.8-stable/src/lib/platform/OSXPasteboardPeeker.m000066400000000000000000000021161305627404700236610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #import "platform/OSXPasteboardPeeker.h" #import #import #import CFStringRef getDraggedFileURL() { NSString* pbName = NSDragPboard; NSPasteboard* pboard = [NSPasteboard pasteboardWithName:pbName]; NSMutableString* string; string = [[NSMutableString alloc] initWithCapacity:0]; NSArray* files = [pboard propertyListForType:NSFilenamesPboardType]; for (id file in files) { [string appendString: (NSString*)file]; [string appendString: @"\0"]; } return (CFStringRef)string; } synergy-1.8.8-stable/src/lib/platform/OSXScreen.h000066400000000000000000000243461305627404700216640ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/OSXClipboard.h" #include "synergy/PlatformScreen.h" #include "synergy/DragInformation.h" #include "base/EventTypes.h" #include "common/stdmap.h" #include "common/stdvector.h" #include #include #include #include #include #include #include extern "C" { typedef int CGSConnectionID; CGError CGSSetConnectionProperty(CGSConnectionID cid, CGSConnectionID targetCID, CFStringRef key, CFTypeRef value); int _CGSDefaultConnection(); } template class CondVar; class EventQueueTimer; class Mutex; class Thread; class OSXKeyState; class OSXScreenSaver; class IEventQueue; class Mutex; //! Implementation of IPlatformScreen for OS X class OSXScreen : public PlatformScreen { public: OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCursor=true); virtual ~OSXScreen(); IEventQueue* getEvents() const { return m_events; } // IScreen overrides virtual void* getEventTarget() const; virtual bool getClipboard(ClipboardID id, IClipboard*) const; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const; virtual void getCursorPos(SInt32& x, SInt32& y) const; // IPrimaryScreen overrides virtual void reconfigure(UInt32 activeSides); virtual void warpCursor(SInt32 x, SInt32 y); virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); virtual void unregisterHotKey(UInt32 id); virtual void fakeInputBegin(); virtual void fakeInputEnd(); virtual SInt32 getJumpZoneSize() const; virtual bool isAnyMouseButtonDown(UInt32& buttonID) const; virtual void getCursorCenter(SInt32& x, SInt32& y) const; // ISecondaryScreen overrides virtual void fakeMouseButton(ButtonID id, bool press); virtual void fakeMouseMove(SInt32 x, SInt32 y); virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; // IPlatformScreen overrides virtual void enable(); virtual void disable(); virtual void enter(); virtual bool leave(); virtual bool setClipboard(ClipboardID, const IClipboard*); virtual void checkClipboards(); virtual void openScreensaver(bool notify); virtual void closeScreensaver(); virtual void screensaver(bool activate); virtual void resetOptions(); virtual void setOptions(const OptionsList& options); virtual void setSequenceNumber(UInt32); virtual bool isPrimary() const; virtual void fakeDraggingFiles(DragFileList fileList); virtual String& getDraggingFilename(); const String& getDropTarget() const { return m_dropTarget; } void waitForCarbonLoop() const; protected: // IPlatformScreen overrides virtual void handleSystemEvent(const Event&, void*); virtual void updateButtons(); virtual IKeyState* getKeyState() const; private: void updateScreenShape(); void updateScreenShape(const CGDirectDisplayID, const CGDisplayChangeSummaryFlags); void postMouseEvent(CGPoint&) const; // convenience function to send events void sendEvent(Event::Type type, void* = NULL) const; void sendClipboardEvent(Event::Type type, ClipboardID id) const; // message handlers bool onMouseMove(SInt32 mx, SInt32 my); // mouse button handler. pressed is true if this is a mousedown // event, false if it is a mouseup event. macButton is the index // of the button pressed using the mac button mapping. bool onMouseButton(bool pressed, UInt16 macButton); bool onMouseWheel(SInt32 xDelta, SInt32 yDelta) const; void constructMouseButtonEventMap(); bool onKey(CGEventRef event); void onMediaKey(CGEventRef event); bool onHotKey(EventRef event) const; // Added here to allow the carbon cursor hack to be called. void showCursor(); void hideCursor(); // map synergy mouse button to mac buttons ButtonID mapSynergyButtonToMac(UInt16) const; // map mac mouse button to synergy buttons ButtonID mapMacButtonToSynergy(UInt16) const; // map mac scroll wheel value to a synergy scroll wheel value SInt32 mapScrollWheelToSynergy(SInt32) const; // map synergy scroll wheel value to a mac scroll wheel value SInt32 mapScrollWheelFromSynergy(SInt32) const; // get the current scroll wheel speed double getScrollSpeed() const; // get the current scroll wheel speed double getScrollSpeedFactor() const; // enable/disable drag handling for buttons 3 and up void enableDragTimer(bool enable); // drag timer handler void handleDrag(const Event&, void*); // clipboard check timer handler void handleClipboardCheck(const Event&, void*); // Resolution switch callback static void displayReconfigurationCallback(CGDirectDisplayID, CGDisplayChangeSummaryFlags, void*); // fast user switch callback static pascal OSStatus userSwitchCallback(EventHandlerCallRef nextHandler, EventRef theEvent, void* inUserData); // sleep / wakeup support void watchSystemPowerThread(void*); static void testCanceled(CFRunLoopTimerRef timer, void*info); static void powerChangeCallback(void* refcon, io_service_t service, natural_t messageType, void* messageArgument); void handlePowerChangeRequest(natural_t messageType, void* messageArgument); void handleConfirmSleep(const Event& event, void*); // global hotkey operating mode static bool isGlobalHotKeyOperatingModeAvailable(); static void setGlobalHotKeysEnabled(bool enabled); static bool getGlobalHotKeysEnabled(); // Quartz event tap support static CGEventRef handleCGInputEvent(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon); static CGEventRef handleCGInputEventSecondary(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon); // convert CFString to char* static char* CFStringRefToUTF8String(CFStringRef aString); void getDropTargetThread(void*); private: struct HotKeyItem { public: HotKeyItem(UInt32, UInt32); HotKeyItem(EventHotKeyRef, UInt32, UInt32); EventHotKeyRef getRef() const; bool operator<(const HotKeyItem&) const; private: EventHotKeyRef m_ref; UInt32 m_keycode; UInt32 m_mask; }; enum EMouseButtonState { kMouseButtonUp = 0, kMouseButtonDragged, kMouseButtonDown, kMouseButtonStateMax }; class MouseButtonState { public: void set(UInt32 button, EMouseButtonState state); bool any(); void reset(); void overwrite(UInt32 buttons); bool test(UInt32 button) const; SInt8 getFirstButtonDown() const; private: std::bitset m_buttons; }; typedef std::map HotKeyMap; typedef std::vector HotKeyIDList; typedef std::map ModifierHotKeyMap; typedef std::map HotKeyToIDMap; // true if screen is being used as a primary screen, false otherwise bool m_isPrimary; // true if mouse has entered the screen bool m_isOnScreen; // the display CGDirectDisplayID m_displayID; // screen shape stuff SInt32 m_x, m_y; SInt32 m_w, m_h; SInt32 m_xCenter, m_yCenter; // mouse state mutable SInt32 m_xCursor, m_yCursor; mutable bool m_cursorPosValid; /* FIXME: this data structure is explicitly marked mutable due to a need to track the state of buttons since the remote side only lets us know of change events, and because the fakeMouseButton button method is marked 'const'. This is Evil, and this should be moved to a place where it need not be mutable as soon as possible. */ mutable MouseButtonState m_buttonState; typedef std::map MouseButtonEventMapType; std::vector MouseButtonEventMap; bool m_cursorHidden; SInt32 m_dragNumButtonsDown; Point m_dragLastPoint; EventQueueTimer* m_dragTimer; // keyboard stuff OSXKeyState* m_keyState; // clipboards OSXClipboard m_pasteboard; UInt32 m_sequenceNumber; // screen saver stuff OSXScreenSaver* m_screensaver; bool m_screensaverNotify; // clipboard stuff bool m_ownClipboard; EventQueueTimer* m_clipboardTimer; // window object that gets user input events when the server // has focus. WindowRef m_hiddenWindow; // window object that gets user input events when the server // does not have focus. WindowRef m_userInputWindow; // fast user switching EventHandlerRef m_switchEventHandlerRef; // sleep / wakeup Mutex* m_pmMutex; Thread* m_pmWatchThread; CondVar* m_pmThreadReady; CFRunLoopRef m_pmRunloop; io_connect_t m_pmRootPort; // hot key stuff HotKeyMap m_hotKeys; HotKeyIDList m_oldHotKeyIDs; ModifierHotKeyMap m_modifierHotKeys; UInt32 m_activeModifierHotKey; KeyModifierMask m_activeModifierHotKeyMask; HotKeyToIDMap m_hotKeyToIDMap; // global hotkey operating mode static bool s_testedForGHOM; static bool s_hasGHOM; // Quartz input event support CFMachPortRef m_eventTapPort; CFRunLoopSourceRef m_eventTapRLSR; // for double click coalescing. double m_lastClickTime; int m_clickState; SInt32 m_lastSingleClickXCursor; SInt32 m_lastSingleClickYCursor; // cursor will hide and show on enable and disable if true. bool m_autoShowHideCursor; IEventQueue* m_events; Thread* m_getDropTargetThread; String m_dropTarget; #if defined(MAC_OS_X_VERSION_10_7) Mutex* m_carbonLoopMutex; CondVar* m_carbonLoopReady; #endif class OSXScreenImpl* m_impl; }; synergy-1.8.8-stable/src/lib/platform/OSXScreen.mm000066400000000000000000001550771305627404700220540ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXScreen.h" #include "base/EventQueue.h" #include "client/Client.h" #include "platform/OSXClipboard.h" #include "platform/OSXEventQueueBuffer.h" #include "platform/OSXKeyState.h" #include "platform/OSXScreenSaver.h" #include "platform/OSXDragSimulator.h" #include "platform/OSXMediaKeySupport.h" #include "platform/OSXPasteboardPeeker.h" #include "synergy/Clipboard.h" #include "synergy/KeyMap.h" #include "synergy/ClientApp.h" #include "mt/CondVar.h" #include "mt/Lock.h" #include "mt/Mutex.h" #include "mt/Thread.h" #include "arch/XArch.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include "base/TMethodJob.h" #include #include #include #include #import // Set some enums for fast user switching if we're building with an SDK // from before such support was added. #if !defined(MAC_OS_X_VERSION_10_3) || \ (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_3) enum { kEventClassSystem = 'macs', kEventSystemUserSessionActivated = 10, kEventSystemUserSessionDeactivated = 11 }; #endif // This isn't in any Apple SDK that I know of as of yet. enum { kSynergyEventMouseScroll = 11, kSynergyMouseScrollAxisX = 'saxx', kSynergyMouseScrollAxisY = 'saxy' }; enum { kCarbonLoopWaitTimeout = 10 }; // TODO: upgrade deprecated function usage in these functions. void setZeroSuppressionInterval(); void avoidSupression(); void logCursorVisibility(); void avoidHesitatingCursor(); // // OSXScreen // bool OSXScreen::s_testedForGHOM = false; bool OSXScreen::s_hasGHOM = false; OSXScreen::OSXScreen(IEventQueue* events, bool isPrimary, bool autoShowHideCursor) : PlatformScreen(events), m_isPrimary(isPrimary), m_isOnScreen(m_isPrimary), m_cursorPosValid(false), MouseButtonEventMap(NumButtonIDs), m_cursorHidden(false), m_dragNumButtonsDown(0), m_dragTimer(NULL), m_keyState(NULL), m_sequenceNumber(0), m_screensaver(NULL), m_screensaverNotify(false), m_ownClipboard(false), m_clipboardTimer(NULL), m_hiddenWindow(NULL), m_userInputWindow(NULL), m_switchEventHandlerRef(0), m_pmMutex(new Mutex), m_pmWatchThread(NULL), m_pmThreadReady(new CondVar(m_pmMutex, false)), m_pmRootPort(0), m_activeModifierHotKey(0), m_activeModifierHotKeyMask(0), m_eventTapPort(nullptr), m_eventTapRLSR(nullptr), m_lastClickTime(0), m_clickState(1), m_lastSingleClickXCursor(0), m_lastSingleClickYCursor(0), m_autoShowHideCursor(autoShowHideCursor), m_events(events), m_getDropTargetThread(NULL), m_impl(NULL) { try { m_displayID = CGMainDisplayID(); updateScreenShape(m_displayID, 0); m_screensaver = new OSXScreenSaver(m_events, getEventTarget()); m_keyState = new OSXKeyState(m_events); // only needed when running as a server. if (m_isPrimary) { #if defined(MAC_OS_X_VERSION_10_9) // we can't pass options to show the dialog, this must be done by the gui. if (!AXIsProcessTrusted()) { throw XArch("assistive devices does not trust this process, allow it in system settings."); } #else // now deprecated in mavericks. if (!AXAPIEnabled()) { throw XArch("assistive devices is not enabled, enable it in system settings."); } #endif } // install display manager notification handler CGDisplayRegisterReconfigurationCallback(displayReconfigurationCallback, this); // install fast user switching event handler EventTypeSpec switchEventTypes[2]; switchEventTypes[0].eventClass = kEventClassSystem; switchEventTypes[0].eventKind = kEventSystemUserSessionDeactivated; switchEventTypes[1].eventClass = kEventClassSystem; switchEventTypes[1].eventKind = kEventSystemUserSessionActivated; EventHandlerUPP switchEventHandler = NewEventHandlerUPP(userSwitchCallback); InstallApplicationEventHandler(switchEventHandler, 2, switchEventTypes, this, &m_switchEventHandlerRef); DisposeEventHandlerUPP(switchEventHandler); constructMouseButtonEventMap(); // watch for requests to sleep m_events->adoptHandler(m_events->forOSXScreen().confirmSleep(), getEventTarget(), new TMethodEventJob(this, &OSXScreen::handleConfirmSleep)); // create thread for monitoring system power state. *m_pmThreadReady = false; #if defined(MAC_OS_X_VERSION_10_7) m_carbonLoopMutex = new Mutex(); m_carbonLoopReady = new CondVar(m_carbonLoopMutex, false); #endif LOG((CLOG_DEBUG "starting watchSystemPowerThread")); m_pmWatchThread = new Thread(new TMethodJob (this, &OSXScreen::watchSystemPowerThread)); } catch (...) { m_events->removeHandler(m_events->forOSXScreen().confirmSleep(), getEventTarget()); if (m_switchEventHandlerRef != 0) { RemoveEventHandler(m_switchEventHandlerRef); } CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); delete m_keyState; delete m_screensaver; throw; } // install event handlers m_events->adoptHandler(Event::kSystem, m_events->getSystemTarget(), new TMethodEventJob(this, &OSXScreen::handleSystemEvent)); // install the platform event queue m_events->adoptBuffer(new OSXEventQueueBuffer(m_events)); } OSXScreen::~OSXScreen() { disable(); m_events->adoptBuffer(NULL); m_events->removeHandler(Event::kSystem, m_events->getSystemTarget()); if (m_pmWatchThread) { // make sure the thread has setup the runloop. { Lock lock(m_pmMutex); while (!(bool)*m_pmThreadReady) { m_pmThreadReady->wait(); } } // now exit the thread's runloop and wait for it to exit LOG((CLOG_DEBUG "stopping watchSystemPowerThread")); CFRunLoopStop(m_pmRunloop); m_pmWatchThread->wait(); delete m_pmWatchThread; m_pmWatchThread = NULL; } delete m_pmThreadReady; delete m_pmMutex; m_events->removeHandler(m_events->forOSXScreen().confirmSleep(), getEventTarget()); RemoveEventHandler(m_switchEventHandlerRef); CGDisplayRemoveReconfigurationCallback(displayReconfigurationCallback, this); delete m_keyState; delete m_screensaver; #if defined(MAC_OS_X_VERSION_10_7) delete m_carbonLoopMutex; delete m_carbonLoopReady; #endif } void* OSXScreen::getEventTarget() const { return const_cast(this); } bool OSXScreen::getClipboard(ClipboardID, IClipboard* dst) const { Clipboard::copy(dst, &m_pasteboard); return true; } void OSXScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { x = m_x; y = m_y; w = m_w; h = m_h; } void OSXScreen::getCursorPos(SInt32& x, SInt32& y) const { CGEventRef event = CGEventCreate(NULL); CGPoint mouse = CGEventGetLocation(event); x = mouse.x; y = mouse.y; m_cursorPosValid = true; m_xCursor = x; m_yCursor = y; CFRelease(event); } void OSXScreen::reconfigure(UInt32) { // do nothing } void OSXScreen::warpCursor(SInt32 x, SInt32 y) { // move cursor without generating events CGPoint pos; pos.x = x; pos.y = y; CGWarpMouseCursorPosition(pos); // save new cursor position m_xCursor = x; m_yCursor = y; m_cursorPosValid = true; } void OSXScreen::fakeInputBegin() { // FIXME -- not implemented } void OSXScreen::fakeInputEnd() { // FIXME -- not implemented } SInt32 OSXScreen::getJumpZoneSize() const { return 1; } bool OSXScreen::isAnyMouseButtonDown(UInt32& buttonID) const { if (m_buttonState.test(0)) { buttonID = kButtonLeft; return true; } return (GetCurrentButtonState() != 0); } void OSXScreen::getCursorCenter(SInt32& x, SInt32& y) const { x = m_xCenter; y = m_yCenter; } UInt32 OSXScreen::registerHotKey(KeyID key, KeyModifierMask mask) { // get mac virtual key and modifier mask matching synergy key and mask UInt32 macKey, macMask; if (!m_keyState->mapSynergyHotKeyToMac(key, mask, macKey, macMask)) { LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); return 0; } // choose hotkey id UInt32 id; if (!m_oldHotKeyIDs.empty()) { id = m_oldHotKeyIDs.back(); m_oldHotKeyIDs.pop_back(); } else { id = m_hotKeys.size() + 1; } // if this hot key has modifiers only then we'll handle it specially EventHotKeyRef ref = NULL; bool okay; if (key == kKeyNone) { if (m_modifierHotKeys.count(mask) > 0) { // already registered okay = false; } else { m_modifierHotKeys[mask] = id; okay = true; } } else { EventHotKeyID hkid = { 'SNRG', (UInt32)id }; OSStatus status = RegisterEventHotKey(macKey, macMask, hkid, GetApplicationEventTarget(), 0, &ref); okay = (status == noErr); m_hotKeyToIDMap[HotKeyItem(macKey, macMask)] = id; } if (!okay) { m_oldHotKeyIDs.push_back(id); m_hotKeyToIDMap.erase(HotKeyItem(macKey, macMask)); LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", synergy::KeyMap::formatKey(key, mask).c_str(), key, mask)); return 0; } m_hotKeys.insert(std::make_pair(id, HotKeyItem(ref, macKey, macMask))); LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", synergy::KeyMap::formatKey(key, mask).c_str(), key, mask, id)); return id; } void OSXScreen::unregisterHotKey(UInt32 id) { // look up hotkey HotKeyMap::iterator i = m_hotKeys.find(id); if (i == m_hotKeys.end()) { return; } // unregister with OS bool okay; if (i->second.getRef() != NULL) { okay = (UnregisterEventHotKey(i->second.getRef()) == noErr); } else { okay = false; // XXX -- this is inefficient for (ModifierHotKeyMap::iterator j = m_modifierHotKeys.begin(); j != m_modifierHotKeys.end(); ++j) { if (j->second == id) { m_modifierHotKeys.erase(j); okay = true; break; } } } if (!okay) { LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); } else { LOG((CLOG_DEBUG "unregistered hotkey id=%d", id)); } // discard hot key from map and record old id for reuse m_hotKeyToIDMap.erase(i->second); m_hotKeys.erase(i); m_oldHotKeyIDs.push_back(id); if (m_activeModifierHotKey == id) { m_activeModifierHotKey = 0; m_activeModifierHotKeyMask = 0; } } void OSXScreen::constructMouseButtonEventMap() { const CGEventType source[NumButtonIDs][3] = { {kCGEventLeftMouseUp, kCGEventLeftMouseDragged, kCGEventLeftMouseDown}, {kCGEventRightMouseUp, kCGEventRightMouseDragged, kCGEventRightMouseDown}, {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown}, {kCGEventOtherMouseUp, kCGEventOtherMouseDragged, kCGEventOtherMouseDown} }; for (UInt16 button = 0; button < NumButtonIDs; button++) { MouseButtonEventMapType new_map; for (UInt16 state = (UInt32) kMouseButtonUp; state < kMouseButtonStateMax; state++) { CGEventType curEvent = source[button][state]; new_map[state] = curEvent; } MouseButtonEventMap[button] = new_map; } } void OSXScreen::postMouseEvent(CGPoint& pos) const { // check if cursor position is valid on the client display configuration // stkamp@users.sourceforge.net CGDisplayCount displayCount = 0; CGGetDisplaysWithPoint(pos, 0, NULL, &displayCount); if (displayCount == 0) { // cursor position invalid - clamp to bounds of last valid display. // find the last valid display using the last cursor position. displayCount = 0; CGDirectDisplayID displayID; CGGetDisplaysWithPoint(CGPointMake(m_xCursor, m_yCursor), 1, &displayID, &displayCount); if (displayCount != 0) { CGRect displayRect = CGDisplayBounds(displayID); if (pos.x < displayRect.origin.x) { pos.x = displayRect.origin.x; } else if (pos.x > displayRect.origin.x + displayRect.size.width - 1) { pos.x = displayRect.origin.x + displayRect.size.width - 1; } if (pos.y < displayRect.origin.y) { pos.y = displayRect.origin.y; } else if (pos.y > displayRect.origin.y + displayRect.size.height - 1) { pos.y = displayRect.origin.y + displayRect.size.height - 1; } } } CGEventType type = kCGEventMouseMoved; SInt8 button = m_buttonState.getFirstButtonDown(); if (button != -1) { MouseButtonEventMapType thisButtonType = MouseButtonEventMap[button]; type = thisButtonType[kMouseButtonDragged]; } CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, button); // Dragging events also need the click state CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState); // Fix for sticky keys CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); CGEventSetFlags(event, modifiers); // Set movement deltas to fix issues with certain 3D programs SInt64 deltaX = pos.x; deltaX -= m_xCursor; SInt64 deltaY = pos.y; deltaY -= m_yCursor; CGEventSetIntegerValueField(event, kCGMouseEventDeltaX, deltaX); CGEventSetIntegerValueField(event, kCGMouseEventDeltaY, deltaY); double deltaFX = deltaX; double deltaFY = deltaY; CGEventSetDoubleValueField(event, kCGMouseEventDeltaX, deltaFX); CGEventSetDoubleValueField(event, kCGMouseEventDeltaY, deltaFY); CGEventPost(kCGHIDEventTap, event); CFRelease(event); } void OSXScreen::fakeMouseButton(ButtonID id, bool press) { // Buttons are indexed from one, but the button down array is indexed from zero UInt32 index = mapSynergyButtonToMac(id) - kButtonLeft; if (index >= NumButtonIDs) { return; } CGPoint pos; if (!m_cursorPosValid) { SInt32 x, y; getCursorPos(x, y); } pos.x = m_xCursor; pos.y = m_yCursor; // variable used to detect mouse coordinate differences between // old & new mouse clicks. Used in double click detection. SInt32 xDiff = m_xCursor - m_lastSingleClickXCursor; SInt32 yDiff = m_yCursor - m_lastSingleClickYCursor; double diff = sqrt(xDiff * xDiff + yDiff * yDiff); // max sqrt(x^2 + y^2) difference allowed to double click // since we don't have double click distance in NX APIs // we define our own defaults. const double maxDiff = sqrt(2) + 0.0001; double clickTime = [NSEvent doubleClickInterval]; // As long as the click is within the time window and distance window // increase clickState (double click, triple click, etc) // This will allow for higher than triple click but the quartz documenation // does not specify that this should be limited to triple click if (press) { if ((ARCH->time() - m_lastClickTime) <= clickTime && diff <= maxDiff){ m_clickState++; } else { m_clickState = 1; } m_lastClickTime = ARCH->time(); } if (m_clickState == 1){ m_lastSingleClickXCursor = m_xCursor; m_lastSingleClickYCursor = m_yCursor; } EMouseButtonState state = press ? kMouseButtonDown : kMouseButtonUp; LOG((CLOG_DEBUG1 "faking mouse button id: %d press: %s", index, press ? "pressed" : "released")); MouseButtonEventMapType thisButtonMap = MouseButtonEventMap[index]; CGEventType type = thisButtonMap[state]; CGEventRef event = CGEventCreateMouseEvent(NULL, type, pos, index); CGEventSetIntegerValueField(event, kCGMouseEventClickState, m_clickState); // Fix for sticky keys CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); CGEventSetFlags(event, modifiers); m_buttonState.set(index, state); CGEventPost(kCGHIDEventTap, event); CFRelease(event); if (!press && (id == kButtonLeft)) { if (m_fakeDraggingStarted) { m_getDropTargetThread = new Thread(new TMethodJob( this, &OSXScreen::getDropTargetThread)); } m_draggingStarted = false; } } void OSXScreen::getDropTargetThread(void*) { #if defined(MAC_OS_X_VERSION_10_7) char* cstr = NULL; // wait for 5 secs for the drop destinaiton string to be filled. UInt32 timeout = ARCH->time() + 5; while (ARCH->time() < timeout) { CFStringRef cfstr = getCocoaDropTarget(); cstr = CFStringRefToUTF8String(cfstr); CFRelease(cfstr); if (cstr != NULL) { break; } ARCH->sleep(.1f); } if (cstr != NULL) { LOG((CLOG_DEBUG "drop target: %s", cstr)); m_dropTarget = cstr; } else { LOG((CLOG_ERR "failed to get drop target")); m_dropTarget.clear(); } #else LOG((CLOG_WARN "drag drop not supported")); #endif m_fakeDraggingStarted = false; } void OSXScreen::fakeMouseMove(SInt32 x, SInt32 y) { if (m_fakeDraggingStarted) { m_buttonState.set(0, kMouseButtonDown); } // index 0 means left mouse button if (m_buttonState.test(0)) { m_draggingStarted = true; } // synthesize event CGPoint pos; pos.x = x; pos.y = y; postMouseEvent(pos); // save new cursor position m_xCursor = static_cast(pos.x); m_yCursor = static_cast(pos.y); m_cursorPosValid = true; } void OSXScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const { // OS X does not appear to have a fake relative mouse move function. // simulate it by getting the current mouse position and adding to // that. this can yield the wrong answer but there's not much else // we can do. // get current position CGEventRef event = CGEventCreate(NULL); CGPoint oldPos = CGEventGetLocation(event); CFRelease(event); // synthesize event CGPoint pos; m_xCursor = static_cast(oldPos.x); m_yCursor = static_cast(oldPos.y); pos.x = oldPos.x + dx; pos.y = oldPos.y + dy; postMouseEvent(pos); // we now assume we don't know the current cursor position m_cursorPosValid = false; } void OSXScreen::fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const { if (xDelta != 0 || yDelta != 0) { // create a scroll event, post it and release it. not sure if kCGScrollEventUnitLine // is the right choice here over kCGScrollEventUnitPixel CGEventRef scrollEvent = CGEventCreateScrollWheelEvent( NULL, kCGScrollEventUnitLine, 2, mapScrollWheelFromSynergy(yDelta), -mapScrollWheelFromSynergy(xDelta)); // Fix for sticky keys CGEventFlags modifiers = m_keyState->getModifierStateAsOSXFlags(); CGEventSetFlags(scrollEvent, modifiers); CGEventPost(kCGHIDEventTap, scrollEvent); CFRelease(scrollEvent); } } void OSXScreen::showCursor() { LOG((CLOG_DEBUG "showing cursor")); CFStringRef propertyString = CFStringCreateWithCString( NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); CGSSetConnectionProperty( _CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanTrue); CFRelease(propertyString); CGError error = CGDisplayShowCursor(m_displayID); if (error != kCGErrorSuccess) { LOG((CLOG_ERR "failed to show cursor, error=%d", error)); } // appears to fix "mouse randomly not showing" bug CGAssociateMouseAndMouseCursorPosition(true); logCursorVisibility(); m_cursorHidden = false; } void OSXScreen::hideCursor() { LOG((CLOG_DEBUG "hiding cursor")); CFStringRef propertyString = CFStringCreateWithCString( NULL, "SetsCursorInBackground", kCFStringEncodingMacRoman); CGSSetConnectionProperty( _CGSDefaultConnection(), _CGSDefaultConnection(), propertyString, kCFBooleanTrue); CFRelease(propertyString); CGError error = CGDisplayHideCursor(m_displayID); if (error != kCGErrorSuccess) { LOG((CLOG_ERR "failed to hide cursor, error=%d", error)); } // appears to fix "mouse randomly not hiding" bug CGAssociateMouseAndMouseCursorPosition(true); logCursorVisibility(); m_cursorHidden = true; } void OSXScreen::enable() { // watch the clipboard m_clipboardTimer = m_events->newTimer(1.0, NULL); m_events->adoptHandler(Event::kTimer, m_clipboardTimer, new TMethodEventJob(this, &OSXScreen::handleClipboardCheck)); if (m_isPrimary) { // FIXME -- start watching jump zones // kCGEventTapOptionDefault = 0x00000000 (Missing in 10.4, so specified literally) m_eventTapPort = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 0, kCGEventMaskForAllEvents, handleCGInputEvent, this); } else { // FIXME -- prevent system from entering power save mode if (m_autoShowHideCursor) { hideCursor(); } // warp the mouse to the cursor center fakeMouseMove(m_xCenter, m_yCenter); // there may be a better way to do this, but we register an event handler even if we're // not on the primary display (acting as a client). This way, if a local event comes in // (either keyboard or mouse), we can make sure to show the cursor if we've hidden it. m_eventTapPort = CGEventTapCreate(kCGHIDEventTap, kCGHeadInsertEventTap, 0, kCGEventMaskForAllEvents, handleCGInputEventSecondary, this); } if (!m_eventTapPort) { LOG((CLOG_ERR "failed to create quartz event tap")); } m_eventTapRLSR = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTapPort, 0); if (!m_eventTapRLSR) { LOG((CLOG_ERR "failed to create a CFRunLoopSourceRef for the quartz event tap")); } CFRunLoopAddSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode); } void OSXScreen::disable() { if (m_autoShowHideCursor) { showCursor(); } // FIXME -- stop watching jump zones, stop capturing input if (m_eventTapRLSR) { CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_eventTapRLSR, kCFRunLoopDefaultMode); CFRelease(m_eventTapRLSR); m_eventTapRLSR = nullptr; } if (m_eventTapPort) { CGEventTapEnable(m_eventTapPort, false); CFRelease(m_eventTapPort); m_eventTapPort = nullptr; } // FIXME -- allow system to enter power saving mode // disable drag handling m_dragNumButtonsDown = 0; enableDragTimer(false); // uninstall clipboard timer if (m_clipboardTimer != NULL) { m_events->removeHandler(Event::kTimer, m_clipboardTimer); m_events->deleteTimer(m_clipboardTimer); m_clipboardTimer = NULL; } m_isOnScreen = m_isPrimary; } void OSXScreen::enter() { showCursor(); if (m_isPrimary) { setZeroSuppressionInterval(); } else { // reset buttons m_buttonState.reset(); // patch by Yutaka Tsutano // wakes the client screen // http://symless.com/spit/issues/details/3287#c12 io_registry_entry_t entry = IORegistryEntryFromPath( kIOMasterPortDefault, "IOService:/IOResources/IODisplayWrangler"); if (entry != MACH_PORT_NULL) { IORegistryEntrySetCFProperty(entry, CFSTR("IORequestIdle"), kCFBooleanFalse); IOObjectRelease(entry); } avoidSupression(); } // now on screen m_isOnScreen = true; } bool OSXScreen::leave() { hideCursor(); if (isDraggingStarted()) { String& fileList = getDraggingFilename(); if (!m_isPrimary) { if (fileList.empty() == false) { ClientApp& app = ClientApp::instance(); Client* client = app.getClientPtr(); DragInformation di; di.setFilename(fileList); DragFileList dragFileList; dragFileList.push_back(di); String info; UInt32 fileCount = DragInformation::setupDragInfo( dragFileList, info); client->sendDragInfo(fileCount, info, info.size()); LOG((CLOG_DEBUG "send dragging file to server")); // TODO: what to do with multiple file or even // a folder client->sendFileToServer(fileList.c_str()); } } m_draggingStarted = false; } if (m_isPrimary) { avoidHesitatingCursor(); } // now off screen m_isOnScreen = false; return true; } bool OSXScreen::setClipboard(ClipboardID, const IClipboard* src) { if (src != NULL) { LOG((CLOG_DEBUG "setting clipboard")); Clipboard::copy(&m_pasteboard, src); } return true; } void OSXScreen::checkClipboards() { LOG((CLOG_DEBUG2 "checking clipboard")); if (m_pasteboard.synchronize()) { LOG((CLOG_DEBUG "clipboard changed")); sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardClipboard); sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), kClipboardSelection); } } void OSXScreen::openScreensaver(bool notify) { m_screensaverNotify = notify; if (!m_screensaverNotify) { m_screensaver->disable(); } } void OSXScreen::closeScreensaver() { if (!m_screensaverNotify) { m_screensaver->enable(); } } void OSXScreen::screensaver(bool activate) { if (activate) { m_screensaver->activate(); } else { m_screensaver->deactivate(); } } void OSXScreen::resetOptions() { // no options } void OSXScreen::setOptions(const OptionsList&) { // no options } void OSXScreen::setSequenceNumber(UInt32 seqNum) { m_sequenceNumber = seqNum; } bool OSXScreen::isPrimary() const { return m_isPrimary; } void OSXScreen::sendEvent(Event::Type type, void* data) const { m_events->addEvent(Event(type, getEventTarget(), data)); } void OSXScreen::sendClipboardEvent(Event::Type type, ClipboardID id) const { ClipboardInfo* info = (ClipboardInfo*)malloc(sizeof(ClipboardInfo)); info->m_id = id; info->m_sequenceNumber = m_sequenceNumber; sendEvent(type, info); } void OSXScreen::handleSystemEvent(const Event& event, void*) { EventRef* carbonEvent = static_cast(event.getData()); assert(carbonEvent != NULL); UInt32 eventClass = GetEventClass(*carbonEvent); switch (eventClass) { case kEventClassMouse: switch (GetEventKind(*carbonEvent)) { case kSynergyEventMouseScroll: { OSStatus r; long xScroll; long yScroll; // get scroll amount r = GetEventParameter(*carbonEvent, kSynergyMouseScrollAxisX, typeSInt32, NULL, sizeof(xScroll), NULL, &xScroll); if (r != noErr) { xScroll = 0; } r = GetEventParameter(*carbonEvent, kSynergyMouseScrollAxisY, typeSInt32, NULL, sizeof(yScroll), NULL, &yScroll); if (r != noErr) { yScroll = 0; } if (xScroll != 0 || yScroll != 0) { onMouseWheel(-mapScrollWheelToSynergy(xScroll), mapScrollWheelToSynergy(yScroll)); } } } break; case kEventClassKeyboard: switch (GetEventKind(*carbonEvent)) { case kEventHotKeyPressed: case kEventHotKeyReleased: onHotKey(*carbonEvent); break; } break; case kEventClassWindow: // 2nd param was formerly GetWindowEventTarget(m_userInputWindow) which is 32-bit only, // however as m_userInputWindow is never initialized to anything we can take advantage of // the fact that GetWindowEventTarget(NULL) == NULL SendEventToEventTarget(*carbonEvent, NULL); switch (GetEventKind(*carbonEvent)) { case kEventWindowActivated: LOG((CLOG_DEBUG1 "window activated")); break; case kEventWindowDeactivated: LOG((CLOG_DEBUG1 "window deactivated")); break; case kEventWindowFocusAcquired: LOG((CLOG_DEBUG1 "focus acquired")); break; case kEventWindowFocusRelinquish: LOG((CLOG_DEBUG1 "focus released")); break; } break; default: SendEventToEventTarget(*carbonEvent, GetEventDispatcherTarget()); break; } } bool OSXScreen::onMouseMove(SInt32 mx, SInt32 my) { LOG((CLOG_DEBUG2 "mouse move %+d,%+d", mx, my)); SInt32 x = mx - m_xCursor; SInt32 y = my - m_yCursor; if ((x == 0 && y == 0) || (mx == m_xCenter && mx == m_yCenter)) { return true; } // save position to compute delta of next motion m_xCursor = mx; m_yCursor = my; if (m_isOnScreen) { // motion on primary screen sendEvent(m_events->forIPrimaryScreen().motionOnPrimary(), MotionInfo::alloc(m_xCursor, m_yCursor)); if (m_buttonState.test(0)) { m_draggingStarted = true; } } else { // motion on secondary screen. warp mouse back to // center. warpCursor(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 sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), MotionInfo::alloc(x, y)); } } return true; } bool OSXScreen::onMouseButton(bool pressed, UInt16 macButton) { // Buttons 2 and 3 are inverted on the mac ButtonID button = mapMacButtonToSynergy(macButton); if (pressed) { LOG((CLOG_DEBUG1 "event: button press button=%d", button)); if (button != kButtonNone) { KeyModifierMask mask = m_keyState->getActiveModifiers(); sendEvent(m_events->forIPrimaryScreen().buttonDown(), ButtonInfo::alloc(button, mask)); } } else { LOG((CLOG_DEBUG1 "event: button release button=%d", button)); if (button != kButtonNone) { KeyModifierMask mask = m_keyState->getActiveModifiers(); sendEvent(m_events->forIPrimaryScreen().buttonUp(), ButtonInfo::alloc(button, mask)); } } // handle drags with any button other than button 1 or 2 if (macButton > 2) { if (pressed) { // one more button if (m_dragNumButtonsDown++ == 0) { enableDragTimer(true); } } else { // one less button if (--m_dragNumButtonsDown == 0) { enableDragTimer(false); } } } if (macButton == kButtonLeft) { EMouseButtonState state = pressed ? kMouseButtonDown : kMouseButtonUp; m_buttonState.set(kButtonLeft - 1, state); if (pressed) { m_draggingFilename.clear(); LOG((CLOG_DEBUG2 "dragging file directory is cleared")); } else { if (m_fakeDraggingStarted) { m_getDropTargetThread = new Thread(new TMethodJob( this, &OSXScreen::getDropTargetThread)); } m_draggingStarted = false; } } return true; } bool OSXScreen::onMouseWheel(SInt32 xDelta, SInt32 yDelta) const { LOG((CLOG_DEBUG1 "event: button wheel delta=%+d,%+d", xDelta, yDelta)); sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(xDelta, yDelta)); return true; } void OSXScreen::handleClipboardCheck(const Event&, void*) { checkClipboards(); } void OSXScreen::displayReconfigurationCallback(CGDirectDisplayID displayID, CGDisplayChangeSummaryFlags flags, void* inUserData) { OSXScreen* screen = (OSXScreen*)inUserData; // Closing or opening the lid when an external monitor is // connected causes an kCGDisplayBeginConfigurationFlag event CGDisplayChangeSummaryFlags mask = kCGDisplayBeginConfigurationFlag | kCGDisplayMovedFlag | kCGDisplaySetModeFlag | kCGDisplayAddFlag | kCGDisplayRemoveFlag | kCGDisplayEnabledFlag | kCGDisplayDisabledFlag | kCGDisplayMirrorFlag | kCGDisplayUnMirrorFlag | kCGDisplayDesktopShapeChangedFlag; LOG((CLOG_DEBUG1 "event: display was reconfigured: %x %x %x", flags, mask, flags & mask)); if (flags & mask) { /* Something actually did change */ LOG((CLOG_DEBUG1 "event: screen changed shape; refreshing dimensions")); screen->updateScreenShape(displayID, flags); } } bool OSXScreen::onKey(CGEventRef event) { CGEventType eventKind = CGEventGetType(event); // get the key and active modifiers UInt32 virtualKey = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); CGEventFlags macMask = CGEventGetFlags(event); LOG((CLOG_DEBUG1 "event: Key event kind: %d, keycode=%d", eventKind, virtualKey)); // Special handling to track state of modifiers if (eventKind == kCGEventFlagsChanged) { // get old and new modifier state KeyModifierMask oldMask = getActiveModifiers(); KeyModifierMask newMask = m_keyState->mapModifiersFromOSX(macMask); m_keyState->handleModifierKeys(getEventTarget(), oldMask, newMask); // if the current set of modifiers exactly matches a modifiers-only // hot key then generate a hot key down event. if (m_activeModifierHotKey == 0) { if (m_modifierHotKeys.count(newMask) > 0) { m_activeModifierHotKey = m_modifierHotKeys[newMask]; m_activeModifierHotKeyMask = newMask; m_events->addEvent(Event(m_events->forIPrimaryScreen().hotKeyDown(), getEventTarget(), HotKeyInfo::alloc(m_activeModifierHotKey))); } } // if a modifiers-only hot key is active and should no longer be // then generate a hot key up event. else if (m_activeModifierHotKey != 0) { KeyModifierMask mask = (newMask & m_activeModifierHotKeyMask); if (mask != m_activeModifierHotKeyMask) { m_events->addEvent(Event(m_events->forIPrimaryScreen().hotKeyUp(), getEventTarget(), HotKeyInfo::alloc(m_activeModifierHotKey))); m_activeModifierHotKey = 0; m_activeModifierHotKeyMask = 0; } } return true; } // check for hot key. when we're on a secondary screen we disable // all hotkeys so we can capture the OS defined hot keys as regular // keystrokes but that means we don't get our own hot keys either. // so we check for a key/modifier match in our hot key map. if (!m_isOnScreen) { HotKeyToIDMap::const_iterator i = m_hotKeyToIDMap.find(HotKeyItem(virtualKey, m_keyState->mapModifiersToCarbon(macMask) & 0xff00u)); if (i != m_hotKeyToIDMap.end()) { UInt32 id = i->second; // determine event type Event::Type type; //UInt32 eventKind = GetEventKind(event); if (eventKind == kCGEventKeyDown) { type = m_events->forIPrimaryScreen().hotKeyDown(); } else if (eventKind == kCGEventKeyUp) { type = m_events->forIPrimaryScreen().hotKeyUp(); } else { return false; } m_events->addEvent(Event(type, getEventTarget(), HotKeyInfo::alloc(id))); return true; } } // decode event type bool down = (eventKind == kCGEventKeyDown); bool up = (eventKind == kCGEventKeyUp); bool isRepeat = (CGEventGetIntegerValueField(event, kCGKeyboardEventAutorepeat) == 1); // map event to keys KeyModifierMask mask; OSXKeyState::KeyIDs keys; KeyButton button = m_keyState->mapKeyFromEvent(keys, &mask, event); if (button == 0) { return false; } // check for AltGr in mask. if set we send neither the AltGr nor // the super modifiers to clients then remove AltGr before passing // the modifiers to onKey. KeyModifierMask sendMask = (mask & ~KeyModifierAltGr); if ((mask & KeyModifierAltGr) != 0) { sendMask &= ~KeyModifierSuper; } mask &= ~KeyModifierAltGr; // update button state if (down) { m_keyState->onKey(button, true, mask); } else if (up) { if (!m_keyState->isKeyDown(button)) { // up event for a dead key. throw it away. return false; } m_keyState->onKey(button, false, mask); } // send key events for (OSXKeyState::KeyIDs::const_iterator i = keys.begin(); i != keys.end(); ++i) { m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat, *i, sendMask, 1, button); } return true; } void OSXScreen::onMediaKey(CGEventRef event) { KeyID keyID; bool down; bool isRepeat; if (!getMediaKeyEventInfo (event, &keyID, &down, &isRepeat)) { LOG ((CLOG_ERR "Failed to decode media key event")); return; } LOG ((CLOG_DEBUG2 "Media key event: keyID=0x%02x, %s, repeat=%s", keyID, (down ? "down": "up"), (isRepeat ? "yes" : "no"))); KeyButton button = 0; KeyModifierMask mask = m_keyState->getActiveModifiers(); m_keyState->sendKeyEvent(getEventTarget(), down, isRepeat, keyID, mask, 1, button); } bool OSXScreen::onHotKey(EventRef event) const { // get the hotkey id EventHotKeyID hkid; GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(EventHotKeyID), NULL, &hkid); UInt32 id = hkid.id; // determine event type Event::Type type; UInt32 eventKind = GetEventKind(event); if (eventKind == kEventHotKeyPressed) { type = m_events->forIPrimaryScreen().hotKeyDown(); } else if (eventKind == kEventHotKeyReleased) { type = m_events->forIPrimaryScreen().hotKeyUp(); } else { return false; } m_events->addEvent(Event(type, getEventTarget(), HotKeyInfo::alloc(id))); return true; } ButtonID OSXScreen::mapSynergyButtonToMac(UInt16 button) const { switch (button) { case 1: return kButtonLeft; case 2: return kMacButtonMiddle; case 3: return kMacButtonRight; } return static_cast(button); } ButtonID OSXScreen::mapMacButtonToSynergy(UInt16 macButton) const { switch (macButton) { case 1: return kButtonLeft; case 2: return kButtonRight; case 3: return kButtonMiddle; } return static_cast(macButton); } SInt32 OSXScreen::mapScrollWheelToSynergy(SInt32 x) const { // return accelerated scrolling but not exponentially scaled as it is // on the mac. double d = (1.0 + getScrollSpeed()) * x / getScrollSpeedFactor(); return static_cast(120.0 * d); } SInt32 OSXScreen::mapScrollWheelFromSynergy(SInt32 x) const { // use server's acceleration with a little boost since other platforms // take one wheel step as a larger step than the mac does. return static_cast(3.0 * x / 120.0); } double OSXScreen::getScrollSpeed() const { double scaling = 0.0; CFPropertyListRef pref = ::CFPreferencesCopyValue( CFSTR("com.apple.scrollwheel.scaling") , kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost); if (pref != NULL) { CFTypeID id = CFGetTypeID(pref); if (id == CFNumberGetTypeID()) { CFNumberRef value = static_cast(pref); if (CFNumberGetValue(value, kCFNumberDoubleType, &scaling)) { if (scaling < 0.0) { scaling = 0.0; } } } CFRelease(pref); } return scaling; } double OSXScreen::getScrollSpeedFactor() const { return pow(10.0, getScrollSpeed()); } void OSXScreen::enableDragTimer(bool enable) { if (enable && m_dragTimer == NULL) { m_dragTimer = m_events->newTimer(0.01, NULL); m_events->adoptHandler(Event::kTimer, m_dragTimer, new TMethodEventJob(this, &OSXScreen::handleDrag)); CGEventRef event = CGEventCreate(NULL); CGPoint mouse = CGEventGetLocation(event); m_dragLastPoint.h = (short)mouse.x; m_dragLastPoint.v = (short)mouse.y; CFRelease(event); } else if (!enable && m_dragTimer != NULL) { m_events->removeHandler(Event::kTimer, m_dragTimer); m_events->deleteTimer(m_dragTimer); m_dragTimer = NULL; } } void OSXScreen::handleDrag(const Event&, void*) { CGEventRef event = CGEventCreate(NULL); CGPoint p = CGEventGetLocation(event); CFRelease(event); if ((short)p.x != m_dragLastPoint.h || (short)p.y != m_dragLastPoint.v) { m_dragLastPoint.h = (short)p.x; m_dragLastPoint.v = (short)p.y; onMouseMove((SInt32)p.x, (SInt32)p.y); } } void OSXScreen::updateButtons() { UInt32 buttons = GetCurrentButtonState(); m_buttonState.overwrite(buttons); } IKeyState* OSXScreen::getKeyState() const { return m_keyState; } void OSXScreen::updateScreenShape(const CGDirectDisplayID, const CGDisplayChangeSummaryFlags flags) { updateScreenShape(); } void OSXScreen::updateScreenShape() { // get info for each display CGDisplayCount displayCount = 0; if (CGGetActiveDisplayList(0, NULL, &displayCount) != CGDisplayNoErr) { return; } if (displayCount == 0) { return; } CGDirectDisplayID* displays = new CGDirectDisplayID[displayCount]; if (displays == NULL) { return; } if (CGGetActiveDisplayList(displayCount, displays, &displayCount) != CGDisplayNoErr) { delete[] displays; return; } // get smallest rect enclosing all display rects CGRect totalBounds = CGRectZero; for (CGDisplayCount i = 0; i < displayCount; ++i) { CGRect bounds = CGDisplayBounds(displays[i]); totalBounds = CGRectUnion(totalBounds, bounds); } // get shape of default screen m_x = (SInt32)totalBounds.origin.x; m_y = (SInt32)totalBounds.origin.y; m_w = (SInt32)totalBounds.size.width; m_h = (SInt32)totalBounds.size.height; // get center of default screen CGDirectDisplayID main = CGMainDisplayID(); const CGRect rect = CGDisplayBounds(main); m_xCenter = (rect.origin.x + rect.size.width) / 2; m_yCenter = (rect.origin.y + rect.size.height) / 2; delete[] displays; // We want to notify the peer screen whether we are primary screen or not sendEvent(m_events->forIScreen().shapeChanged()); LOG((CLOG_DEBUG "screen shape: center=%d,%d size=%dx%d on %u %s", m_x, m_y, m_w, m_h, displayCount, (displayCount == 1) ? "display" : "displays")); } #pragma mark - // // FAST USER SWITCH NOTIFICATION SUPPORT // // OSXScreen::userSwitchCallback(void*) // // gets called if a fast user switch occurs // pascal OSStatus OSXScreen::userSwitchCallback(EventHandlerCallRef nextHandler, EventRef theEvent, void* inUserData) { OSXScreen* screen = (OSXScreen*)inUserData; UInt32 kind = GetEventKind(theEvent); IEventQueue* events = screen->getEvents(); if (kind == kEventSystemUserSessionDeactivated) { LOG((CLOG_DEBUG "user session deactivated")); events->addEvent(Event(events->forIScreen().suspend(), screen->getEventTarget())); } else if (kind == kEventSystemUserSessionActivated) { LOG((CLOG_DEBUG "user session activated")); events->addEvent(Event(events->forIScreen().resume(), screen->getEventTarget())); } return (CallNextEventHandler(nextHandler, theEvent)); } #pragma mark - // // SLEEP/WAKEUP NOTIFICATION SUPPORT // // OSXScreen::watchSystemPowerThread(void*) // // main of thread monitoring system power (sleep/wakup) using a CFRunLoop // void OSXScreen::watchSystemPowerThread(void*) { io_object_t notifier; IONotificationPortRef notificationPortRef; CFRunLoopSourceRef runloopSourceRef = 0; m_pmRunloop = CFRunLoopGetCurrent(); // install system power change callback m_pmRootPort = IORegisterForSystemPower(this, ¬ificationPortRef, powerChangeCallback, ¬ifier); if (m_pmRootPort == 0) { LOG((CLOG_WARN "IORegisterForSystemPower failed")); } else { runloopSourceRef = IONotificationPortGetRunLoopSource(notificationPortRef); CFRunLoopAddSource(m_pmRunloop, runloopSourceRef, kCFRunLoopCommonModes); } // thread is ready { Lock lock(m_pmMutex); *m_pmThreadReady = true; m_pmThreadReady->signal(); } // if we were unable to initialize then exit. we must do this after // setting m_pmThreadReady to true otherwise the parent thread will // block waiting for it. if (m_pmRootPort == 0) { LOG((CLOG_WARN "failed to init watchSystemPowerThread")); return; } LOG((CLOG_DEBUG "started watchSystemPowerThread")); LOG((CLOG_DEBUG "waiting for event loop")); m_events->waitForReady(); #if defined(MAC_OS_X_VERSION_10_7) { Lock lockCarbon(m_carbonLoopMutex); if (*m_carbonLoopReady == false) { // we signalling carbon loop ready before starting // unless we know how to do it within the loop LOG((CLOG_DEBUG "signalling carbon loop ready")); *m_carbonLoopReady = true; m_carbonLoopReady->signal(); } } #endif // start the run loop LOG((CLOG_DEBUG "starting carbon loop")); CFRunLoopRun(); LOG((CLOG_DEBUG "carbon loop has stopped")); // cleanup if (notificationPortRef) { CFRunLoopRemoveSource(m_pmRunloop, runloopSourceRef, kCFRunLoopDefaultMode); CFRunLoopSourceInvalidate(runloopSourceRef); CFRelease(runloopSourceRef); } Lock lock(m_pmMutex); IODeregisterForSystemPower(¬ifier); m_pmRootPort = 0; LOG((CLOG_DEBUG "stopped watchSystemPowerThread")); } void OSXScreen::powerChangeCallback(void* refcon, io_service_t service, natural_t messageType, void* messageArg) { ((OSXScreen*)refcon)->handlePowerChangeRequest(messageType, messageArg); } void OSXScreen::handlePowerChangeRequest(natural_t messageType, void* messageArg) { // we've received a power change notification switch (messageType) { case kIOMessageSystemWillSleep: // OSXScreen has to handle this in the main thread so we have to // queue a confirm sleep event here. we actually don't allow the // system to sleep until the event is handled. m_events->addEvent(Event(m_events->forOSXScreen().confirmSleep(), getEventTarget(), messageArg, Event::kDontFreeData)); return; case kIOMessageSystemHasPoweredOn: LOG((CLOG_DEBUG "system wakeup")); m_events->addEvent(Event(m_events->forIScreen().resume(), getEventTarget())); break; default: break; } Lock lock(m_pmMutex); if (m_pmRootPort != 0) { IOAllowPowerChange(m_pmRootPort, (long)messageArg); } } void OSXScreen::handleConfirmSleep(const Event& event, void*) { long messageArg = (long)event.getData(); if (messageArg != 0) { Lock lock(m_pmMutex); if (m_pmRootPort != 0) { // deliver suspend event immediately. m_events->addEvent(Event(m_events->forIScreen().suspend(), getEventTarget(), NULL, Event::kDeliverImmediately)); LOG((CLOG_DEBUG "system will sleep")); IOAllowPowerChange(m_pmRootPort, messageArg); } } } #pragma mark - // // GLOBAL HOTKEY OPERATING MODE SUPPORT (10.3) // // CoreGraphics private API (OSX 10.3) // Source: http://ichiro.nnip.org/osx/Cocoa/GlobalHotkey.html // // We load the functions dynamically because they're not available in // older SDKs. We don't use weak linking because we want users of // older SDKs to build an app that works on newer systems and older // SDKs will not provide the symbols. // // FIXME: This is hosed as of OS 10.5; patches to repair this are // a good thing. // #if 0 #ifdef __cplusplus extern "C" { #endif typedef int CGSConnection; typedef enum { CGSGlobalHotKeyEnable = 0, CGSGlobalHotKeyDisable = 1, } CGSGlobalHotKeyOperatingMode; extern CGSConnection _CGSDefaultConnection(void) WEAK_IMPORT_ATTRIBUTE; extern CGError CGSGetGlobalHotKeyOperatingMode(CGSConnection connection, CGSGlobalHotKeyOperatingMode *mode) WEAK_IMPORT_ATTRIBUTE; extern CGError CGSSetGlobalHotKeyOperatingMode(CGSConnection connection, CGSGlobalHotKeyOperatingMode mode) WEAK_IMPORT_ATTRIBUTE; typedef CGSConnection (*_CGSDefaultConnection_t)(void); typedef CGError (*CGSGetGlobalHotKeyOperatingMode_t)(CGSConnection connection, CGSGlobalHotKeyOperatingMode *mode); typedef CGError (*CGSSetGlobalHotKeyOperatingMode_t)(CGSConnection connection, CGSGlobalHotKeyOperatingMode mode); static _CGSDefaultConnection_t s__CGSDefaultConnection; static CGSGetGlobalHotKeyOperatingMode_t s_CGSGetGlobalHotKeyOperatingMode; static CGSSetGlobalHotKeyOperatingMode_t s_CGSSetGlobalHotKeyOperatingMode; #ifdef __cplusplus } #endif #define LOOKUP(name_) \ s_ ## name_ = NULL; \ if (NSIsSymbolNameDefinedWithHint("_" #name_, "CoreGraphics")) { \ s_ ## name_ = (name_ ## _t)NSAddressOfSymbol( \ NSLookupAndBindSymbolWithHint( \ "_" #name_, "CoreGraphics")); \ } bool OSXScreen::isGlobalHotKeyOperatingModeAvailable() { if (!s_testedForGHOM) { s_testedForGHOM = true; LOOKUP(_CGSDefaultConnection); LOOKUP(CGSGetGlobalHotKeyOperatingMode); LOOKUP(CGSSetGlobalHotKeyOperatingMode); s_hasGHOM = (s__CGSDefaultConnection != NULL && s_CGSGetGlobalHotKeyOperatingMode != NULL && s_CGSSetGlobalHotKeyOperatingMode != NULL); } return s_hasGHOM; } void OSXScreen::setGlobalHotKeysEnabled(bool enabled) { if (isGlobalHotKeyOperatingModeAvailable()) { CGSConnection conn = s__CGSDefaultConnection(); CGSGlobalHotKeyOperatingMode mode; s_CGSGetGlobalHotKeyOperatingMode(conn, &mode); if (enabled && mode == CGSGlobalHotKeyDisable) { s_CGSSetGlobalHotKeyOperatingMode(conn, CGSGlobalHotKeyEnable); } else if (!enabled && mode == CGSGlobalHotKeyEnable) { s_CGSSetGlobalHotKeyOperatingMode(conn, CGSGlobalHotKeyDisable); } } } bool OSXScreen::getGlobalHotKeysEnabled() { CGSGlobalHotKeyOperatingMode mode; if (isGlobalHotKeyOperatingModeAvailable()) { CGSConnection conn = s__CGSDefaultConnection(); s_CGSGetGlobalHotKeyOperatingMode(conn, &mode); } else { mode = CGSGlobalHotKeyEnable; } return (mode == CGSGlobalHotKeyEnable); } #endif // // OSXScreen::HotKeyItem // OSXScreen::HotKeyItem::HotKeyItem(UInt32 keycode, UInt32 mask) : m_ref(NULL), m_keycode(keycode), m_mask(mask) { // do nothing } OSXScreen::HotKeyItem::HotKeyItem(EventHotKeyRef ref, UInt32 keycode, UInt32 mask) : m_ref(ref), m_keycode(keycode), m_mask(mask) { // do nothing } EventHotKeyRef OSXScreen::HotKeyItem::getRef() const { return m_ref; } bool OSXScreen::HotKeyItem::operator<(const HotKeyItem& x) const { return (m_keycode < x.m_keycode || (m_keycode == x.m_keycode && m_mask < x.m_mask)); } // Quartz event tap support for the secondary display. This makes sure that we // will show the cursor if a local event comes in while synergy has the cursor // off the screen. CGEventRef OSXScreen::handleCGInputEventSecondary( CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) { // this fix is really screwing with the correct show/hide behavior. it // should be tested better before reintroducing. return event; OSXScreen* screen = (OSXScreen*)refcon; if (screen->m_cursorHidden && type == kCGEventMouseMoved) { CGPoint pos = CGEventGetLocation(event); if (pos.x != screen->m_xCenter || pos.y != screen->m_yCenter) { LOG((CLOG_DEBUG "show cursor on secondary, type=%d pos=%d,%d", type, pos.x, pos.y)); screen->showCursor(); } } return event; } // Quartz event tap support CGEventRef OSXScreen::handleCGInputEvent(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) { OSXScreen* screen = (OSXScreen*)refcon; CGPoint pos; switch(type) { case kCGEventLeftMouseDown: case kCGEventRightMouseDown: case kCGEventOtherMouseDown: screen->onMouseButton(true, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1); break; case kCGEventLeftMouseUp: case kCGEventRightMouseUp: case kCGEventOtherMouseUp: screen->onMouseButton(false, CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) + 1); break; case kCGEventLeftMouseDragged: case kCGEventRightMouseDragged: case kCGEventOtherMouseDragged: case kCGEventMouseMoved: pos = CGEventGetLocation(event); screen->onMouseMove(pos.x, pos.y); // The system ignores our cursor-centering calls if // we don't return the event. This should be harmless, // but might register as slight movement to other apps // on the system. It hasn't been a problem before, though. return event; break; case kCGEventScrollWheel: screen->onMouseWheel(screen->mapScrollWheelToSynergy( CGEventGetIntegerValueField(event, kCGScrollWheelEventDeltaAxis2)), screen->mapScrollWheelToSynergy( CGEventGetIntegerValueField(event, kCGScrollWheelEventDeltaAxis1))); break; case kCGEventKeyDown: case kCGEventKeyUp: case kCGEventFlagsChanged: screen->onKey(event); break; case kCGEventTapDisabledByTimeout: // Re-enable our event-tap CGEventTapEnable(screen->m_eventTapPort, true); LOG((CLOG_INFO "quartz event tap was disabled by timeout, re-enabling")); break; case kCGEventTapDisabledByUserInput: LOG((CLOG_ERR "quartz event tap was disabled by user input")); break; case NX_NULLEVENT: break; case NX_SYSDEFINED: if (isMediaKeyEvent (event)) { LOG((CLOG_DEBUG2 "detected media key event")); screen->onMediaKey (event); } else { LOG((CLOG_DEBUG2 "ignoring unknown system defined event")); return event; } break; case NX_NUMPROCS: break; default: LOG((CLOG_WARN "unknown quartz event type: 0x%02x", type)); } if (screen->m_isOnScreen) { return event; } else { return NULL; } } void OSXScreen::MouseButtonState::set(UInt32 button, EMouseButtonState state) { bool newState = (state == kMouseButtonDown); m_buttons.set(button, newState); } bool OSXScreen::MouseButtonState::any() { return m_buttons.any(); } void OSXScreen::MouseButtonState::reset() { m_buttons.reset(); } void OSXScreen::MouseButtonState::overwrite(UInt32 buttons) { m_buttons = std::bitset(buttons); } bool OSXScreen::MouseButtonState::test(UInt32 button) const { return m_buttons.test(button); } SInt8 OSXScreen::MouseButtonState::getFirstButtonDown() const { if (m_buttons.any()) { for (unsigned short button = 0; button < m_buttons.size(); button++) { if (m_buttons.test(button)) { return button; } } } return -1; } char* OSXScreen::CFStringRefToUTF8String(CFStringRef aString) { if (aString == NULL) { return NULL; } CFIndex length = CFStringGetLength(aString); CFIndex maxSize = CFStringGetMaximumSizeForEncoding( length, kCFStringEncodingUTF8); char* buffer = (char*)malloc(maxSize); if (CFStringGetCString(aString, buffer, maxSize, kCFStringEncodingUTF8)) { return buffer; } return NULL; } void OSXScreen::fakeDraggingFiles(DragFileList fileList) { m_fakeDraggingStarted = true; String fileExt; if (fileList.size() == 1) { fileExt = DragInformation::getDragFileExtension( fileList.at(0).getFilename()); } #if defined(MAC_OS_X_VERSION_10_7) fakeDragging(fileExt.c_str(), m_xCursor, m_yCursor); #else LOG((CLOG_WARN "drag drop not supported")); #endif } String& OSXScreen::getDraggingFilename() { if (m_draggingStarted) { CFStringRef dragInfo = getDraggedFileURL(); char* info = NULL; info = CFStringRefToUTF8String(dragInfo); if (info == NULL) { m_draggingFilename.clear(); } else { LOG((CLOG_DEBUG "drag info: %s", info)); CFRelease(dragInfo); String fileList(info); m_draggingFilename = fileList; } // fake a escape key down and up then left mouse button up fakeKeyDown(kKeyEscape, 8192, 1); fakeKeyUp(1); fakeMouseButton(kButtonLeft, false); } return m_draggingFilename; } void OSXScreen::waitForCarbonLoop() const { #if defined(MAC_OS_X_VERSION_10_7) if (*m_carbonLoopReady) { LOG((CLOG_DEBUG "carbon loop already ready")); return; } Lock lock(m_carbonLoopMutex); LOG((CLOG_DEBUG "waiting for carbon loop")); double timeout = ARCH->time() + kCarbonLoopWaitTimeout; while (!m_carbonLoopReady->wait()) { if (ARCH->time() > timeout) { LOG((CLOG_DEBUG "carbon loop not ready, waiting again")); timeout = ARCH->time() + kCarbonLoopWaitTimeout; } } LOG((CLOG_DEBUG "carbon loop ready")); #endif } #pragma GCC diagnostic ignored "-Wdeprecated-declarations" void setZeroSuppressionInterval() { CGSetLocalEventsSuppressionInterval(0.0); } void avoidSupression() { // avoid suppression of local hardware events // stkamp@users.sourceforge.net CGSetLocalEventsFilterDuringSupressionState( kCGEventFilterMaskPermitAllEvents, kCGEventSupressionStateSupressionInterval); CGSetLocalEventsFilterDuringSupressionState( (kCGEventFilterMaskPermitLocalKeyboardEvents | kCGEventFilterMaskPermitSystemDefinedEvents), kCGEventSupressionStateRemoteMouseDrag); } void logCursorVisibility() { // CGCursorIsVisible is probably deprecated because its unreliable. if (!CGCursorIsVisible()) { LOG((CLOG_WARN "cursor may not be visible")); } } void avoidHesitatingCursor() { // This used to be necessary to get smooth mouse motion on other screens, // but now is just to avoid a hesitating cursor when transitioning to // the primary (this) screen. CGSetLocalEventsSuppressionInterval(0.0001); } #pragma GCC diagnostic error "-Wdeprecated-declarations" synergy-1.8.8-stable/src/lib/platform/OSXScreenSaver.cpp000066400000000000000000000126711305627404700232160ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #import "platform/OSXScreenSaver.h" #import "platform/OSXScreenSaverUtil.h" #import "synergy/IPrimaryScreen.h" #import "base/Log.h" #import "base/IEventQueue.h" #import #import // TODO: upgrade deprecated function usage in these functions. void getProcessSerialNumber(const char* name, ProcessSerialNumber& psn); bool testProcessName(const char* name, const ProcessSerialNumber& psn); // // OSXScreenSaver // OSXScreenSaver::OSXScreenSaver(IEventQueue* events, void* eventTarget) : m_eventTarget(eventTarget), m_enabled(true), m_events(events) { m_autoReleasePool = screenSaverUtilCreatePool(); m_screenSaverController = screenSaverUtilCreateController(); // install launch/termination event handlers EventTypeSpec launchEventTypes[2]; launchEventTypes[0].eventClass = kEventClassApplication; launchEventTypes[0].eventKind = kEventAppLaunched; launchEventTypes[1].eventClass = kEventClassApplication; launchEventTypes[1].eventKind = kEventAppTerminated; EventHandlerUPP launchTerminationEventHandler = NewEventHandlerUPP(launchTerminationCallback); InstallApplicationEventHandler(launchTerminationEventHandler, 2, launchEventTypes, this, &m_launchTerminationEventHandlerRef); DisposeEventHandlerUPP(launchTerminationEventHandler); m_screenSaverPSN.highLongOfPSN = 0; m_screenSaverPSN.lowLongOfPSN = 0; if (isActive()) { getProcessSerialNumber("ScreenSaverEngine", m_screenSaverPSN); } } OSXScreenSaver::~OSXScreenSaver() { RemoveEventHandler(m_launchTerminationEventHandlerRef); // screenSaverUtilReleaseController(m_screenSaverController); screenSaverUtilReleasePool(m_autoReleasePool); } void OSXScreenSaver::enable() { m_enabled = true; screenSaverUtilEnable(m_screenSaverController); } void OSXScreenSaver::disable() { m_enabled = false; screenSaverUtilDisable(m_screenSaverController); } void OSXScreenSaver::activate() { screenSaverUtilActivate(m_screenSaverController); } void OSXScreenSaver::deactivate() { screenSaverUtilDeactivate(m_screenSaverController, m_enabled); } bool OSXScreenSaver::isActive() const { return (screenSaverUtilIsActive(m_screenSaverController) != 0); } void OSXScreenSaver::processLaunched(ProcessSerialNumber psn) { if (testProcessName("ScreenSaverEngine", psn)) { m_screenSaverPSN = psn; LOG((CLOG_DEBUG1 "ScreenSaverEngine launched. Enabled=%d", m_enabled)); if (m_enabled) { m_events->addEvent( Event(m_events->forIPrimaryScreen().screensaverActivated(), m_eventTarget)); } } } void OSXScreenSaver::processTerminated(ProcessSerialNumber psn) { if (m_screenSaverPSN.highLongOfPSN == psn.highLongOfPSN && m_screenSaverPSN.lowLongOfPSN == psn.lowLongOfPSN) { LOG((CLOG_DEBUG1 "ScreenSaverEngine terminated. Enabled=%d", m_enabled)); if (m_enabled) { m_events->addEvent( Event(m_events->forIPrimaryScreen().screensaverDeactivated(), m_eventTarget)); } m_screenSaverPSN.highLongOfPSN = 0; m_screenSaverPSN.lowLongOfPSN = 0; } } pascal OSStatus OSXScreenSaver::launchTerminationCallback( EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) { OSStatus result; ProcessSerialNumber psn; EventParamType actualType; ByteCount actualSize; result = GetEventParameter(theEvent, kEventParamProcessID, typeProcessSerialNumber, &actualType, sizeof(psn), &actualSize, &psn); if ((result == noErr) && (actualSize > 0) && (actualType == typeProcessSerialNumber)) { OSXScreenSaver* screenSaver = (OSXScreenSaver*)userData; UInt32 eventKind = GetEventKind(theEvent); if (eventKind == kEventAppLaunched) { screenSaver->processLaunched(psn); } else if (eventKind == kEventAppTerminated) { screenSaver->processTerminated(psn); } } return (CallNextEventHandler(nextHandler, theEvent)); } #pragma GCC diagnostic ignored "-Wdeprecated-declarations" void getProcessSerialNumber(const char* name, ProcessSerialNumber& psn) { ProcessInfoRec procInfo; Str31 procName; // pascal string. first byte holds length. memset(&procInfo, 0, sizeof(procInfo)); procInfo.processName = procName; procInfo.processInfoLength = sizeof(ProcessInfoRec); ProcessSerialNumber checkPsn; OSErr err = GetNextProcess(&checkPsn); while (err == 0) { memset(procName, 0, sizeof(procName)); err = GetProcessInformation(&checkPsn, &procInfo); if (err != 0) { break; } if (strcmp(name, (const char*)&procName[1]) == 0) { psn = checkPsn; break; } err = GetNextProcess(&checkPsn); } } bool testProcessName(const char* name, const ProcessSerialNumber& psn) { CFStringRef processName; OSStatus err = CopyProcessName(&psn, &processName); return (err == 0 && CFEqual(CFSTR("ScreenSaverEngine"), processName)); } #pragma GCC diagnostic error "-Wdeprecated-declarations" synergy-1.8.8-stable/src/lib/platform/OSXScreenSaver.h000066400000000000000000000032701305627404700226560ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/IScreenSaver.h" #include class IEventQueue; //! OSX screen saver implementation class OSXScreenSaver : public IScreenSaver { public: OSXScreenSaver(IEventQueue* events, void* eventTarget); virtual ~OSXScreenSaver(); // IScreenSaver overrides virtual void enable(); virtual void disable(); virtual void activate(); virtual void deactivate(); virtual bool isActive() const; private: void processLaunched(ProcessSerialNumber psn); void processTerminated(ProcessSerialNumber psn); static pascal OSStatus launchTerminationCallback( EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); private: // the target for the events we generate void* m_eventTarget; bool m_enabled; void* m_screenSaverController; void* m_autoReleasePool; EventHandlerRef m_launchTerminationEventHandlerRef; ProcessSerialNumber m_screenSaverPSN; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/platform/OSXScreenSaverControl.h000066400000000000000000000030101305627404700242070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2009 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // ScreenSaver.framework private API // Class dumping by Alex Harper http://www.ragingmenace.com/ #import @protocol ScreenSaverControl - (double)screenSaverTimeRemaining; - (void)restartForUser:fp12; - (void)screenSaverStopNow; - (void)screenSaverStartNow; - (void)setScreenSaverCanRun:(char)fp12; - (BOOL)screenSaverCanRun; - (BOOL)screenSaverIsRunning; @end @interface ScreenSaverController:NSObject + controller; + monitor; + daemonConnectionName; + daemonPath; + enginePath; - init; - (void)dealloc; - (void)_connectionClosed:fp12; - (BOOL)screenSaverIsRunning; - (BOOL)screenSaverCanRun; - (void)setScreenSaverCanRun:(char)fp12; - (void)screenSaverStartNow; - (void)screenSaverStopNow; - (void)restartForUser:fp12; - (double)screenSaverTimeRemaining; @end synergy-1.8.8-stable/src/lib/platform/OSXScreenSaverUtil.h000066400000000000000000000023451305627404700235160ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/common.h" #if defined(__cplusplus) extern "C" { #endif void* screenSaverUtilCreatePool(); void screenSaverUtilReleasePool(void*); void* screenSaverUtilCreateController(); void screenSaverUtilReleaseController(void*); void screenSaverUtilEnable(void*); void screenSaverUtilDisable(void*); void screenSaverUtilActivate(void*); void screenSaverUtilDeactivate(void*, int isEnabled); int screenSaverUtilIsActive(void*); #if defined(__cplusplus) } #endif synergy-1.8.8-stable/src/lib/platform/OSXScreenSaverUtil.m000066400000000000000000000037161305627404700235260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2004 Chris Schoeneman, Nick Bolton, Sorin Sbarnea * * 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 LICENSE that should have accompanied this file. * * This package is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #import "platform/OSXScreenSaverUtil.h" #import "platform/OSXScreenSaverControl.h" #import // // screenSaverUtil functions // // Note: these helper functions exist only so we can avoid using ObjC++. // autoconf/automake don't know about ObjC++ and I don't know how to // teach them about it. // void* screenSaverUtilCreatePool() { return [[NSAutoreleasePool alloc] init]; } void screenSaverUtilReleasePool(void* pool) { [(NSAutoreleasePool*)pool release]; } void* screenSaverUtilCreateController() { return [[ScreenSaverController controller] retain]; } void screenSaverUtilReleaseController(void* controller) { [(ScreenSaverController*)controller release]; } void screenSaverUtilEnable(void* controller) { [(ScreenSaverController*)controller setScreenSaverCanRun:YES]; } void screenSaverUtilDisable(void* controller) { [(ScreenSaverController*)controller setScreenSaverCanRun:NO]; } void screenSaverUtilActivate(void* controller) { [(ScreenSaverController*)controller setScreenSaverCanRun:YES]; [(ScreenSaverController*)controller screenSaverStartNow]; } void screenSaverUtilDeactivate(void* controller, int isEnabled) { [(ScreenSaverController*)controller screenSaverStopNow]; [(ScreenSaverController*)controller setScreenSaverCanRun:isEnabled]; } int screenSaverUtilIsActive(void* controller) { return [(ScreenSaverController*)controller screenSaverIsRunning]; } synergy-1.8.8-stable/src/lib/platform/OSXUchrKeyResource.cpp000066400000000000000000000162521305627404700240570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXUchrKeyResource.h" #include // // OSXUchrKeyResource // OSXUchrKeyResource::OSXUchrKeyResource(const void* resource, UInt32 keyboardType) : m_m(NULL), m_cti(NULL), m_sdi(NULL), m_sri(NULL), m_st(NULL) { m_resource = static_cast(resource); if (m_resource == NULL) { return; } // find the keyboard info for the current keyboard type const UCKeyboardTypeHeader* th = NULL; const UCKeyboardLayout* r = m_resource; for (ItemCount i = 0; i < r->keyboardTypeCount; ++i) { if (keyboardType >= r->keyboardTypeList[i].keyboardTypeFirst && keyboardType <= r->keyboardTypeList[i].keyboardTypeLast) { th = r->keyboardTypeList + i; break; } if (r->keyboardTypeList[i].keyboardTypeFirst == 0) { // found the default. use it unless we find a match. th = r->keyboardTypeList + i; } } if (th == NULL) { // cannot find a suitable keyboard type return; } // get tables for keyboard type const UInt8* const base = reinterpret_cast(m_resource); m_m = reinterpret_cast(base + th->keyModifiersToTableNumOffset); m_cti = reinterpret_cast(base + th->keyToCharTableIndexOffset); m_sdi = reinterpret_cast(base + th->keySequenceDataIndexOffset); if (th->keyStateRecordsIndexOffset != 0) { m_sri = reinterpret_cast(base + th->keyStateRecordsIndexOffset); } if (th->keyStateTerminatorsOffset != 0) { m_st = reinterpret_cast(base + th->keyStateTerminatorsOffset); } // find the space key, but only if it can combine with dead keys. // a dead key followed by a space yields the non-dead version of // the dead key. m_spaceOutput = 0xffffu; UInt32 table = getTableForModifier(0); for (UInt32 button = 0, n = getNumButtons(); button < n; ++button) { KeyID id = getKey(table, button); if (id == 0x20) { UCKeyOutput c = reinterpret_cast(base + m_cti->keyToCharTableOffsets[table])[button]; if ((c & kUCKeyOutputTestForIndexMask) == kUCKeyOutputStateIndexMask) { m_spaceOutput = (c & kUCKeyOutputGetIndexMask); break; } } } } bool OSXUchrKeyResource::isValid() const { return (m_m != NULL); } UInt32 OSXUchrKeyResource::getNumModifierCombinations() const { // only 32 (not 256) because the righthanded modifier bits are ignored return 32; } UInt32 OSXUchrKeyResource::getNumTables() const { return m_cti->keyToCharTableCount; } UInt32 OSXUchrKeyResource::getNumButtons() const { return m_cti->keyToCharTableSize; } UInt32 OSXUchrKeyResource::getTableForModifier(UInt32 mask) const { if (mask >= m_m->modifiersCount) { return m_m->defaultTableNum; } else { return m_m->tableNum[mask]; } } KeyID OSXUchrKeyResource::getKey(UInt32 table, UInt32 button) const { assert(table < getNumTables()); assert(button < getNumButtons()); const UInt8* const base = reinterpret_cast(m_resource); const UCKeyOutput* cPtr = reinterpret_cast(base + m_cti->keyToCharTableOffsets[table]); const UCKeyOutput c = cPtr[button]; KeySequence keys; switch (c & kUCKeyOutputTestForIndexMask) { case kUCKeyOutputStateIndexMask: if (!getDeadKey(keys, c & kUCKeyOutputGetIndexMask)) { return kKeyNone; } break; case kUCKeyOutputSequenceIndexMask: default: if (!addSequence(keys, c)) { return kKeyNone; } break; } // XXX -- no support for multiple characters if (keys.size() != 1) { return kKeyNone; } return keys.front(); } bool OSXUchrKeyResource::getDeadKey( KeySequence& keys, UInt16 index) const { if (m_sri == NULL || index >= m_sri->keyStateRecordCount) { // XXX -- should we be using some other fallback? return false; } UInt16 state = 0; if (!getKeyRecord(keys, index, state)) { return false; } if (state == 0) { // not a dead key return true; } // no dead keys if we couldn't find the space key if (m_spaceOutput == 0xffffu) { return false; } // the dead key should not have put anything in the key list if (!keys.empty()) { return false; } // get the character generated by pressing the space key after the // dead key. if we're still in a compose state afterwards then we're // confused so we bail. if (!getKeyRecord(keys, m_spaceOutput, state) || state != 0) { return false; } // convert keys to their dead counterparts for (KeySequence::iterator i = keys.begin(); i != keys.end(); ++i) { *i = synergy::KeyMap::getDeadKey(*i); } return true; } bool OSXUchrKeyResource::getKeyRecord( KeySequence& keys, UInt16 index, UInt16& state) const { const UInt8* const base = reinterpret_cast(m_resource); const UCKeyStateRecord* sr = reinterpret_cast(base + m_sri->keyStateRecordOffsets[index]); const UCKeyStateEntryTerminal* kset = reinterpret_cast(sr->stateEntryData); UInt16 nextState = 0; bool found = false; if (state == 0) { found = true; nextState = sr->stateZeroNextState; if (!addSequence(keys, sr->stateZeroCharData)) { return false; } } else { // we have a next entry switch (sr->stateEntryFormat) { case kUCKeyStateEntryTerminalFormat: for (UInt16 j = 0; j < sr->stateEntryCount; ++j) { if (kset[j].curState == state) { if (!addSequence(keys, kset[j].charData)) { return false; } nextState = 0; found = true; break; } } break; case kUCKeyStateEntryRangeFormat: // XXX -- not supported yet break; default: // XXX -- unknown format return false; } } if (!found) { // use a terminator if (m_st != NULL && state < m_st->keyStateTerminatorCount) { if (!addSequence(keys, m_st->keyStateTerminators[state - 1])) { return false; } } nextState = sr->stateZeroNextState; if (!addSequence(keys, sr->stateZeroCharData)) { return false; } } // next state = nextState; return true; } bool OSXUchrKeyResource::addSequence( KeySequence& keys, UCKeyCharSeq c) const { if ((c & kUCKeyOutputTestForIndexMask) == kUCKeyOutputSequenceIndexMask) { UInt16 index = (c & kUCKeyOutputGetIndexMask); if (index < m_sdi->charSequenceCount && m_sdi->charSequenceOffsets[index] != m_sdi->charSequenceOffsets[index + 1]) { // XXX -- sequences not supported yet return false; } } if (c != 0xfffe && c != 0xffff) { KeyID id = unicharToKeyID(c); if (id != kKeyNone) { keys.push_back(id); } } return true; } synergy-1.8.8-stable/src/lib/platform/OSXUchrKeyResource.h000066400000000000000000000033671305627404700235270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/KeyState.h" #include "platform/IOSXKeyResource.h" #include typedef TISInputSourceRef KeyLayout; class OSXUchrKeyResource : public IOSXKeyResource { public: OSXUchrKeyResource(const void*, UInt32 keyboardType); // KeyResource overrides virtual bool isValid() const; virtual UInt32 getNumModifierCombinations() const; virtual UInt32 getNumTables() const; virtual UInt32 getNumButtons() const; virtual UInt32 getTableForModifier(UInt32 mask) const; virtual KeyID getKey(UInt32 table, UInt32 button) const; private: typedef std::vector KeySequence; bool getDeadKey(KeySequence& keys, UInt16 index) const; bool getKeyRecord(KeySequence& keys, UInt16 index, UInt16& state) const; bool addSequence(KeySequence& keys, UCKeyCharSeq c) const; private: const UCKeyboardLayout* m_resource; const UCKeyModifiersToTableNum* m_m; const UCKeyToCharTableIndex* m_cti; const UCKeySequenceDataIndex* m_sdi; const UCKeyStateRecordsIndex* m_sri; const UCKeyStateTerminators* m_st; UInt16 m_spaceOutput; }; synergy-1.8.8-stable/src/lib/platform/XWindowsClipboard.cpp000066400000000000000000001200471305627404700240030ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsClipboard.h" #include "platform/XWindowsClipboardTextConverter.h" #include "platform/XWindowsClipboardUCS2Converter.h" #include "platform/XWindowsClipboardUTF8Converter.h" #include "platform/XWindowsClipboardHTMLConverter.h" #include "platform/XWindowsClipboardBMPConverter.h" #include "platform/XWindowsUtil.h" #include "mt/Thread.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/Stopwatch.h" #include "common/stdvector.h" #include #include #include // // XWindowsClipboard // XWindowsClipboard::XWindowsClipboard(Display* display, Window window, ClipboardID id) : m_display(display), m_window(window), m_id(id), m_open(false), m_time(0), m_owner(false), m_timeOwned(0), m_timeLost(0) { // get some atoms m_atomTargets = XInternAtom(m_display, "TARGETS", False); m_atomMultiple = XInternAtom(m_display, "MULTIPLE", False); m_atomTimestamp = XInternAtom(m_display, "TIMESTAMP", False); m_atomInteger = XInternAtom(m_display, "INTEGER", False); m_atomAtom = XInternAtom(m_display, "ATOM", False); m_atomAtomPair = XInternAtom(m_display, "ATOM_PAIR", False); m_atomData = XInternAtom(m_display, "CLIP_TEMPORARY", False); m_atomINCR = XInternAtom(m_display, "INCR", False); m_atomMotifClipLock = XInternAtom(m_display, "_MOTIF_CLIP_LOCK", False); m_atomMotifClipHeader = XInternAtom(m_display, "_MOTIF_CLIP_HEADER", False); m_atomMotifClipAccess = XInternAtom(m_display, "_MOTIF_CLIP_LOCK_ACCESS_VALID", False); m_atomGDKSelection = XInternAtom(m_display, "GDK_SELECTION", False); // set selection atom based on clipboard id switch (id) { case kClipboardClipboard: m_selection = XInternAtom(m_display, "CLIPBOARD", False); break; case kClipboardSelection: default: m_selection = XA_PRIMARY; break; } // add converters, most desired first m_converters.push_back(new XWindowsClipboardHTMLConverter(m_display, "text/html")); m_converters.push_back(new XWindowsClipboardBMPConverter(m_display)); m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display, "text/plain;charset=UTF-8")); m_converters.push_back(new XWindowsClipboardUTF8Converter(m_display, "UTF8_STRING")); m_converters.push_back(new XWindowsClipboardUCS2Converter(m_display, "text/plain;charset=ISO-10646-UCS-2")); m_converters.push_back(new XWindowsClipboardUCS2Converter(m_display, "text/unicode")); m_converters.push_back(new XWindowsClipboardTextConverter(m_display, "text/plain")); m_converters.push_back(new XWindowsClipboardTextConverter(m_display, "STRING")); // we have no data clearCache(); } XWindowsClipboard::~XWindowsClipboard() { clearReplies(); clearConverters(); } void XWindowsClipboard::lost(Time time) { LOG((CLOG_DEBUG "lost clipboard %d ownership at %d", m_id, time)); if (m_owner) { m_owner = false; m_timeLost = time; clearCache(); } } void XWindowsClipboard::addRequest(Window owner, Window requestor, Atom target, ::Time time, Atom property) { // must be for our window and we must have owned the selection // at the given time. bool success = false; if (owner == m_window) { LOG((CLOG_DEBUG1 "request for clipboard %d, target %s by 0x%08x (property=%s)", m_selection, XWindowsUtil::atomToString(m_display, target).c_str(), requestor, XWindowsUtil::atomToString(m_display, property).c_str())); if (wasOwnedAtTime(time)) { if (target == m_atomMultiple) { // add a multiple request. property may not be None // according to ICCCM. if (property != None) { success = insertMultipleReply(requestor, time, property); } } else { addSimpleRequest(requestor, target, time, property); // addSimpleRequest() will have already handled failure success = true; } } else { LOG((CLOG_DEBUG1 "failed, not owned at time %d", time)); } } if (!success) { // send failure LOG((CLOG_DEBUG1 "failed")); insertReply(new Reply(requestor, target, time)); } // send notifications that are pending pushReplies(); } bool XWindowsClipboard::addSimpleRequest(Window requestor, Atom target, ::Time time, Atom property) { // obsolete requestors may supply a None property. in // that case we use the target as the property to store // the conversion. if (property == None) { property = target; } // handle targets String data; Atom type = None; int format = 0; if (target == m_atomTargets) { type = getTargetsData(data, &format); } else if (target == m_atomTimestamp) { type = getTimestampData(data, &format); } else { IXWindowsClipboardConverter* converter = getConverter(target); if (converter != NULL) { IClipboard::EFormat clipboardFormat = converter->getFormat(); if (m_added[clipboardFormat]) { try { data = converter->fromIClipboard(m_data[clipboardFormat]); format = converter->getDataSize(); type = converter->getAtom(); } catch (...) { // ignore -- cannot convert } } } } if (type != None) { // success LOG((CLOG_DEBUG1 "success")); insertReply(new Reply(requestor, target, time, property, data, type, format)); return true; } else { // failure LOG((CLOG_DEBUG1 "failed")); insertReply(new Reply(requestor, target, time)); return false; } } bool XWindowsClipboard::processRequest(Window requestor, ::Time /*time*/, Atom property) { ReplyMap::iterator index = m_replies.find(requestor); if (index == m_replies.end()) { // unknown requestor window return false; } LOG((CLOG_DEBUG1 "received property %s delete from 0x08%x", XWindowsUtil::atomToString(m_display, property).c_str(), requestor)); // find the property in the known requests. it should be the // first property but we'll check 'em all if we have to. ReplyList& replies = index->second; for (ReplyList::iterator index2 = replies.begin(); index2 != replies.end(); ++index2) { Reply* reply = *index2; if (reply->m_replied && reply->m_property == property) { // if reply is complete then remove it and start the // next one. pushReplies(index, replies, index2); return true; } } return false; } bool XWindowsClipboard::destroyRequest(Window requestor) { ReplyMap::iterator index = m_replies.find(requestor); if (index == m_replies.end()) { // unknown requestor window return false; } // destroy all replies for this window clearReplies(index->second); m_replies.erase(index); // note -- we don't stop watching the window for events because // we're called in response to the window being destroyed. return true; } Window XWindowsClipboard::getWindow() const { return m_window; } Atom XWindowsClipboard::getSelection() const { return m_selection; } bool XWindowsClipboard::empty() { assert(m_open); LOG((CLOG_DEBUG "empty clipboard %d", m_id)); // assert ownership of clipboard XSetSelectionOwner(m_display, m_selection, m_window, m_time); if (XGetSelectionOwner(m_display, m_selection) != m_window) { LOG((CLOG_DEBUG "failed to grab clipboard %d", m_id)); return false; } // clear all data. since we own the data now, the cache is up // to date. clearCache(); m_cached = true; // FIXME -- actually delete motif clipboard items? // FIXME -- do anything to motif clipboard properties? // save time m_timeOwned = m_time; m_timeLost = 0; // we're the owner now m_owner = true; LOG((CLOG_DEBUG "grabbed clipboard %d", m_id)); return true; } void XWindowsClipboard::add(EFormat format, const String& data) { assert(m_open); assert(m_owner); LOG((CLOG_DEBUG "add %d bytes to clipboard %d format: %d", data.size(), m_id, format)); m_data[format] = data; m_added[format] = true; // FIXME -- set motif clipboard item? } bool XWindowsClipboard::open(Time time) const { if (m_open) { LOG((CLOG_DEBUG "failed to open clipboard: already opened")); return false; } LOG((CLOG_DEBUG "open clipboard %d", m_id)); // assume not motif m_motif = false; // lock clipboard if (m_id == kClipboardClipboard) { if (!motifLockClipboard()) { return false; } // check if motif owns the selection. unlock motif clipboard // if it does not. m_motif = motifOwnsClipboard(); LOG((CLOG_DEBUG1 "motif does %sown clipboard", m_motif ? "" : "not ")); if (!m_motif) { motifUnlockClipboard(); } } // now open m_open = true; m_time = time; // be sure to flush the cache later if it's dirty m_checkCache = true; return true; } void XWindowsClipboard::close() const { assert(m_open); LOG((CLOG_DEBUG "close clipboard %d", m_id)); // unlock clipboard if (m_motif) { motifUnlockClipboard(); } m_motif = false; m_open = false; } IClipboard::Time XWindowsClipboard::getTime() const { checkCache(); return m_timeOwned; } bool XWindowsClipboard::has(EFormat format) const { assert(m_open); fillCache(); return m_added[format]; } String XWindowsClipboard::get(EFormat format) const { assert(m_open); fillCache(); return m_data[format]; } void XWindowsClipboard::clearConverters() { for (ConverterList::iterator index = m_converters.begin(); index != m_converters.end(); ++index) { delete *index; } m_converters.clear(); } IXWindowsClipboardConverter* XWindowsClipboard::getConverter(Atom target, bool onlyIfNotAdded) const { IXWindowsClipboardConverter* converter = NULL; for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) { converter = *index; if (converter->getAtom() == target) { break; } } if (converter == NULL) { LOG((CLOG_DEBUG1 " no converter for target %s", XWindowsUtil::atomToString(m_display, target).c_str())); return NULL; } // optionally skip already handled targets if (onlyIfNotAdded) { if (m_added[converter->getFormat()]) { LOG((CLOG_DEBUG1 " skipping handled format %d", converter->getFormat())); return NULL; } } return converter; } void XWindowsClipboard::checkCache() const { if (!m_checkCache) { return; } m_checkCache = false; // get the time the clipboard ownership was taken by the current // owner. if (m_motif) { m_timeOwned = motifGetTime(); } else { m_timeOwned = icccmGetTime(); } // if we can't get the time then use the time passed to us if (m_timeOwned == 0) { m_timeOwned = m_time; } // if the cache is dirty then flush it if (m_timeOwned != m_cacheTime) { clearCache(); } } void XWindowsClipboard::clearCache() const { const_cast(this)->doClearCache(); } void XWindowsClipboard::doClearCache() { m_checkCache = false; m_cached = false; for (SInt32 index = 0; index < kNumFormats; ++index) { m_data[index] = ""; m_added[index] = false; } } void XWindowsClipboard::fillCache() const { // get the selection data if not already cached checkCache(); if (!m_cached) { const_cast(this)->doFillCache(); } } void XWindowsClipboard::doFillCache() { if (m_motif) { motifFillCache(); } else { icccmFillCache(); } m_checkCache = false; m_cached = true; m_cacheTime = m_timeOwned; } void XWindowsClipboard::icccmFillCache() { LOG((CLOG_DEBUG "ICCCM fill clipboard %d", m_id)); // see if we can get the list of available formats from the selection. // if not then use a default list of formats. note that some clipboard // owners are broken and report TARGETS as the type of the TARGETS data // instead of the correct type ATOM; allow either. const Atom atomTargets = m_atomTargets; Atom target; String data; if (!icccmGetSelection(atomTargets, &target, &data) || (target != m_atomAtom && target != m_atomTargets)) { LOG((CLOG_DEBUG1 "selection doesn't support TARGETS")); data = ""; XWindowsUtil::appendAtomData(data, XA_STRING); } XWindowsUtil::convertAtomProperty(data); const Atom* targets = reinterpret_cast(data.data()); // TODO: Safe? const UInt32 numTargets = data.size() / sizeof(Atom); LOG((CLOG_DEBUG " available targets: %s", XWindowsUtil::atomsToString(m_display, targets, numTargets).c_str())); // try each converter in order (because they're in order of // preference). for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) { IXWindowsClipboardConverter* converter = *index; // skip already handled targets if (m_added[converter->getFormat()]) { continue; } // see if atom is in target list Atom target = None; // XXX -- just ask for the converter's target to see if it's // available rather than checking TARGETS. i've seen clipboard // owners that don't report all the targets they support. target = converter->getAtom(); /* for (UInt32 i = 0; i < numTargets; ++i) { if (converter->getAtom() == targets[i]) { target = targets[i]; break; } } */ if (target == None) { continue; } // get the data Atom actualTarget; String targetData; if (!icccmGetSelection(target, &actualTarget, &targetData)) { LOG((CLOG_DEBUG1 " no data for target %s", XWindowsUtil::atomToString(m_display, target).c_str())); continue; } // add to clipboard and note we've done it IClipboard::EFormat format = converter->getFormat(); m_data[format] = converter->toIClipboard(targetData); m_added[format] = true; LOG((CLOG_DEBUG "added format %d for target %s (%u %s)", format, XWindowsUtil::atomToString(m_display, target).c_str(), targetData.size(), targetData.size() == 1 ? "byte" : "bytes")); } } bool XWindowsClipboard::icccmGetSelection(Atom target, Atom* actualTarget, String* data) const { assert(actualTarget != NULL); assert(data != NULL); // request data conversion CICCCMGetClipboard getter(m_window, m_time, m_atomData); if (!getter.readClipboard(m_display, m_selection, target, actualTarget, data)) { LOG((CLOG_DEBUG1 "can't get data for selection target %s", XWindowsUtil::atomToString(m_display, target).c_str())); LOGC(getter.m_error, (CLOG_WARN "ICCCM violation by clipboard owner")); return false; } else if (*actualTarget == None) { LOG((CLOG_DEBUG1 "selection conversion failed for target %s", XWindowsUtil::atomToString(m_display, target).c_str())); return false; } return true; } IClipboard::Time XWindowsClipboard::icccmGetTime() const { Atom actualTarget; String data; if (icccmGetSelection(m_atomTimestamp, &actualTarget, &data) && actualTarget == m_atomInteger) { Time time = *reinterpret_cast(data.data()); LOG((CLOG_DEBUG1 "got ICCCM time %d", time)); return time; } else { // no timestamp LOG((CLOG_DEBUG1 "can't get ICCCM time")); return 0; } } bool XWindowsClipboard::motifLockClipboard() const { // fail if anybody owns the lock (even us, so this is non-recursive) Window lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock); if (lockOwner != None) { LOG((CLOG_DEBUG1 "motif lock owner 0x%08x", lockOwner)); return false; } // try to grab the lock // FIXME -- is this right? there's a race condition here -- // A grabs successfully, B grabs successfully, A thinks it // still has the grab until it gets a SelectionClear. Time time = XWindowsUtil::getCurrentTime(m_display, m_window); XSetSelectionOwner(m_display, m_atomMotifClipLock, m_window, time); lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock); if (lockOwner != m_window) { LOG((CLOG_DEBUG1 "motif lock owner 0x%08x", lockOwner)); return false; } LOG((CLOG_DEBUG1 "locked motif clipboard")); return true; } void XWindowsClipboard::motifUnlockClipboard() const { LOG((CLOG_DEBUG1 "unlocked motif clipboard")); // fail if we don't own the lock Window lockOwner = XGetSelectionOwner(m_display, m_atomMotifClipLock); if (lockOwner != m_window) { return; } // release lock Time time = XWindowsUtil::getCurrentTime(m_display, m_window); XSetSelectionOwner(m_display, m_atomMotifClipLock, None, time); } bool XWindowsClipboard::motifOwnsClipboard() const { // get the current selection owner // FIXME -- this can't be right. even if the window is destroyed // Motif will still have a valid clipboard. how can we tell if // some other client owns CLIPBOARD? Window owner = XGetSelectionOwner(m_display, m_selection); if (owner == None) { return false; } // get the Motif clipboard header property from the root window Atom target; SInt32 format; String data; Window root = RootWindow(m_display, DefaultScreen(m_display)); if (!XWindowsUtil::getWindowProperty(m_display, root, m_atomMotifClipHeader, &data, &target, &format, False)) { return false; } // check the owner window against the current clipboard owner if (data.size() >= sizeof(MotifClipHeader)) { MotifClipHeader header; std::memcpy (&header, data.data(), sizeof(header)); if ((header.m_id == kMotifClipHeader) && (static_cast(header.m_selectionOwner) == owner)) { return true; } } return false; } void XWindowsClipboard::motifFillCache() { LOG((CLOG_DEBUG "Motif fill clipboard %d", m_id)); // get the Motif clipboard header property from the root window Atom target; SInt32 format; String data; Window root = RootWindow(m_display, DefaultScreen(m_display)); if (!XWindowsUtil::getWindowProperty(m_display, root, m_atomMotifClipHeader, &data, &target, &format, False)) { return; } MotifClipHeader header; if (data.size() < sizeof(header)) { // check that the header is okay return; } std::memcpy (&header, data.data(), sizeof(header)); if (header.m_id != kMotifClipHeader || header.m_numItems < 1) { return; } // get the Motif item property from the root window char name[18 + 20]; sprintf(name, "_MOTIF_CLIP_ITEM_%d", header.m_item); Atom atomItem = XInternAtom(m_display, name, False); data = ""; if (!XWindowsUtil::getWindowProperty(m_display, root, atomItem, &data, &target, &format, False)) { return; } MotifClipItem item; if (data.size() < sizeof(item)) { // check that the item is okay return; } std::memcpy (&item, data.data(), sizeof(item)); if (item.m_id != kMotifClipItem || item.m_numFormats - item.m_numDeletedFormats < 1) { return; } // format list is after static item structure elements const SInt32 numFormats = item.m_numFormats - item.m_numDeletedFormats; const SInt32* formats = reinterpret_cast(item.m_size + static_cast(data.data())); // get the available formats typedef std::map MotifFormatMap; MotifFormatMap motifFormats; for (SInt32 i = 0; i < numFormats; ++i) { // get Motif format property from the root window sprintf(name, "_MOTIF_CLIP_ITEM_%d", formats[i]); Atom atomFormat = XInternAtom(m_display, name, False); String data; if (!XWindowsUtil::getWindowProperty(m_display, root, atomFormat, &data, &target, &format, False)) { continue; } // check that the format is okay MotifClipFormat motifFormat; if (data.size() < sizeof(motifFormat)) { continue; } std::memcpy (&motifFormat, data.data(), sizeof(motifFormat)); if (motifFormat.m_id != kMotifClipFormat || motifFormat.m_length < 0 || motifFormat.m_type == None || motifFormat.m_deleted != 0) { continue; } // save it motifFormats.insert(std::make_pair(motifFormat.m_type, data)); } //const UInt32 numMotifFormats = motifFormats.size(); // try each converter in order (because they're in order of // preference). for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) { IXWindowsClipboardConverter* converter = *index; // skip already handled targets if (m_added[converter->getFormat()]) { continue; } // see if atom is in target list MotifFormatMap::const_iterator index2 = motifFormats.find(converter->getAtom()); if (index2 == motifFormats.end()) { continue; } // get format MotifClipFormat motifFormat; std::memcpy (&motifFormat, index2->second.data(), sizeof(motifFormat)); const Atom target = motifFormat.m_type; // get the data (finally) Atom actualTarget; String targetData; if (!motifGetSelection(&motifFormat, &actualTarget, &targetData)) { LOG((CLOG_DEBUG1 " no data for target %s", XWindowsUtil::atomToString(m_display, target).c_str())); continue; } // add to clipboard and note we've done it IClipboard::EFormat format = converter->getFormat(); m_data[format] = converter->toIClipboard(targetData); m_added[format] = true; LOG((CLOG_DEBUG "added format %d for target %s", format, XWindowsUtil::atomToString(m_display, target).c_str())); } } bool XWindowsClipboard::motifGetSelection(const MotifClipFormat* format, Atom* actualTarget, String* data) const { // if the current clipboard owner and the owner indicated by the // motif clip header are the same then transfer via a property on // the root window, otherwise transfer as a normal ICCCM client. if (!motifOwnsClipboard()) { return icccmGetSelection(format->m_type, actualTarget, data); } // use motif way // FIXME -- this isn't right. it'll only work if the data is // already stored on the root window and only if it fits in a // property. motif has some scheme for transferring part by // part that i don't know. char name[18 + 20]; sprintf(name, "_MOTIF_CLIP_ITEM_%d", format->m_data); Atom target = XInternAtom(m_display, name, False); Window root = RootWindow(m_display, DefaultScreen(m_display)); return XWindowsUtil::getWindowProperty(m_display, root, target, data, actualTarget, NULL, False); } IClipboard::Time XWindowsClipboard::motifGetTime() const { return icccmGetTime(); } bool XWindowsClipboard::insertMultipleReply(Window requestor, ::Time time, Atom property) { // get the requested targets Atom target; SInt32 format; String data; if (!XWindowsUtil::getWindowProperty(m_display, requestor, property, &data, &target, &format, False)) { // can't get the requested targets return false; } // fail if the requested targets isn't of the correct form if (format != 32 || target != m_atomAtomPair) { return false; } // data is a list of atom pairs: target, property XWindowsUtil::convertAtomProperty(data); const Atom* targets = reinterpret_cast(data.data()); const UInt32 numTargets = data.size() / sizeof(Atom); // add replies for each target bool changed = false; for (UInt32 i = 0; i < numTargets; i += 2) { const Atom target = targets[i + 0]; const Atom property = targets[i + 1]; if (!addSimpleRequest(requestor, target, time, property)) { // note that we can't perform the requested conversion XWindowsUtil::replaceAtomData(data, i, None); changed = true; } } // update the targets property if we changed it if (changed) { XWindowsUtil::setWindowProperty(m_display, requestor, property, data.data(), data.size(), target, format); } // add reply for MULTIPLE request insertReply(new Reply(requestor, m_atomMultiple, time, property, String(), None, 32)); return true; } void XWindowsClipboard::insertReply(Reply* reply) { assert(reply != NULL); // note -- we must respond to requests in order if requestor,target,time // are the same, otherwise we can use whatever order we like with one // exception: each reply in a MULTIPLE reply must be handled in order // as well. those replies will almost certainly not share targets so // we can't simply use requestor,target,time as map index. // // instead we'll use just the requestor. that's more restrictive than // necessary but we're guaranteed to do things in the right order. // note that we could also include the time in the map index and still // ensure the right order. but since that'll just make it harder to // find the right reply when handling property notify events we stick // to just the requestor. const bool newWindow = (m_replies.count(reply->m_requestor) == 0); m_replies[reply->m_requestor].push_back(reply); // adjust requestor's event mask if we haven't done so already. we // want events in case the window is destroyed or any of its // properties change. if (newWindow) { // note errors while we adjust event masks bool error = false; { XWindowsUtil::ErrorLock lock(m_display, &error); // get and save the current event mask XWindowAttributes attr; XGetWindowAttributes(m_display, reply->m_requestor, &attr); m_eventMasks[reply->m_requestor] = attr.your_event_mask; // add the events we want XSelectInput(m_display, reply->m_requestor, attr.your_event_mask | StructureNotifyMask | PropertyChangeMask); } // if we failed then the window has already been destroyed if (error) { m_replies.erase(reply->m_requestor); delete reply; } } } void XWindowsClipboard::pushReplies() { // send the first reply for each window if that reply hasn't // been sent yet. for (ReplyMap::iterator index = m_replies.begin(); index != m_replies.end(); ) { assert(!index->second.empty()); ReplyList::iterator listit = index->second.begin(); while (listit != index->second.end()) { if (!(*listit)->m_replied) break; ++listit; } if (listit != index->second.end() && !(*listit)->m_replied) { pushReplies(index, index->second, listit); } else { ++index; } } } void XWindowsClipboard::pushReplies(ReplyMap::iterator& mapIndex, ReplyList& replies, ReplyList::iterator index) { Reply* reply = *index; while (sendReply(reply)) { // reply is complete. discard it and send the next reply, // if any. index = replies.erase(index); delete reply; if (index == replies.end()) { break; } reply = *index; } // if there are no more replies in the list then remove the list // and stop watching the requestor for events. if (replies.empty()) { XWindowsUtil::ErrorLock lock(m_display); Window requestor = mapIndex->first; XSelectInput(m_display, requestor, m_eventMasks[requestor]); m_replies.erase(mapIndex++); m_eventMasks.erase(requestor); } else { ++mapIndex; } } bool XWindowsClipboard::sendReply(Reply* reply) { assert(reply != NULL); // bail out immediately if reply is done if (reply->m_done) { LOG((CLOG_DEBUG1 "clipboard: finished reply to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property)); return true; } // start in failed state if property is None bool failed = (reply->m_property == None); if (!failed) { LOG((CLOG_DEBUG1 "clipboard: setting property on 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property)); // send using INCR if already sending incrementally or if reply // is too large, otherwise just send it. const UInt32 maxRequestSize = 3 * XMaxRequestSize(m_display); const bool useINCR = (reply->m_data.size() > maxRequestSize); // send INCR reply if incremental and we haven't replied yet if (useINCR && !reply->m_replied) { UInt32 size = reply->m_data.size(); if (!XWindowsUtil::setWindowProperty(m_display, reply->m_requestor, reply->m_property, &size, 4, m_atomINCR, 32)) { failed = true; } } // send more INCR reply or entire non-incremental reply else { // how much more data should we send? UInt32 size = reply->m_data.size() - reply->m_ptr; if (size > maxRequestSize) size = maxRequestSize; // send it if (!XWindowsUtil::setWindowProperty(m_display, reply->m_requestor, reply->m_property, reply->m_data.data() + reply->m_ptr, size, reply->m_type, reply->m_format)) { failed = true; } else { reply->m_ptr += size; // we've finished the reply if we just sent the zero // size incremental chunk or if we're not incremental. reply->m_done = (size == 0 || !useINCR); } } } // if we've failed then delete the property and say we're done. // if we haven't replied yet then we can send a failure notify, // otherwise we've failed in the middle of an incremental // transfer; i don't know how to cancel that so i'll just send // the final zero-length property. // FIXME -- how do you gracefully cancel an incremental transfer? if (failed) { LOG((CLOG_DEBUG1 "clipboard: sending failure to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property)); reply->m_done = true; if (reply->m_property != None) { XWindowsUtil::ErrorLock lock(m_display); XDeleteProperty(m_display, reply->m_requestor, reply->m_property); } if (!reply->m_replied) { sendNotify(reply->m_requestor, m_selection, reply->m_target, None, reply->m_time); // don't wait for any reply (because we're not expecting one) return true; } else { static const char dummy = 0; XWindowsUtil::setWindowProperty(m_display, reply->m_requestor, reply->m_property, &dummy, 0, reply->m_type, reply->m_format); // wait for delete notify return false; } } // send notification if we haven't yet if (!reply->m_replied) { LOG((CLOG_DEBUG1 "clipboard: sending notify to 0x%08x,%d,%d", reply->m_requestor, reply->m_target, reply->m_property)); reply->m_replied = true; // dump every property on the requestor window to the debug2 // log. we've seen what appears to be a bug in lesstif and // knowing the properties may help design a workaround, if // it becomes necessary. if (CLOG->getFilter() >= kDEBUG2) { XWindowsUtil::ErrorLock lock(m_display); int n; Atom* props = XListProperties(m_display, reply->m_requestor, &n); LOG((CLOG_DEBUG2 "properties of 0x%08x:", reply->m_requestor)); for (int i = 0; i < n; ++i) { Atom target; String data; char* name = XGetAtomName(m_display, props[i]); if (!XWindowsUtil::getWindowProperty(m_display, reply->m_requestor, props[i], &data, &target, NULL, False)) { LOG((CLOG_DEBUG2 " %s: ", name)); } else { // if there are any non-ascii characters in string // then print the binary data. static const char* hex = "0123456789abcdef"; for (String::size_type j = 0; j < data.size(); ++j) { if (data[j] < 32 || data[j] > 126) { String tmp; tmp.reserve(data.size() * 3); for (j = 0; j < data.size(); ++j) { unsigned char v = (unsigned char)data[j]; tmp += hex[v >> 16]; tmp += hex[v & 15]; tmp += ' '; } data = tmp; break; } } char* type = XGetAtomName(m_display, target); LOG((CLOG_DEBUG2 " %s (%s): %s", name, type, data.c_str())); if (type != NULL) { XFree(type); } } if (name != NULL) { XFree(name); } } if (props != NULL) { XFree(props); } } sendNotify(reply->m_requestor, m_selection, reply->m_target, reply->m_property, reply->m_time); } // wait for delete notify return false; } void XWindowsClipboard::clearReplies() { for (ReplyMap::iterator index = m_replies.begin(); index != m_replies.end(); ++index) { clearReplies(index->second); } m_replies.clear(); m_eventMasks.clear(); } void XWindowsClipboard::clearReplies(ReplyList& replies) { for (ReplyList::iterator index = replies.begin(); index != replies.end(); ++index) { delete *index; } replies.clear(); } void XWindowsClipboard::sendNotify(Window requestor, Atom selection, Atom target, Atom property, Time time) { XEvent event; event.xselection.type = SelectionNotify; event.xselection.display = m_display; event.xselection.requestor = requestor; event.xselection.selection = selection; event.xselection.target = target; event.xselection.property = property; event.xselection.time = time; XWindowsUtil::ErrorLock lock(m_display); XSendEvent(m_display, requestor, False, 0, &event); } bool XWindowsClipboard::wasOwnedAtTime(::Time time) const { // not owned if we've never owned the selection checkCache(); if (m_timeOwned == 0) { return false; } // if time is CurrentTime then return true if we still own the // selection and false if we do not. else if we still own the // selection then get the current time, otherwise use // m_timeLost as the end time. Time lost = m_timeLost; if (m_timeLost == 0) { if (time == CurrentTime) { return true; } else { lost = XWindowsUtil::getCurrentTime(m_display, m_window); } } else { if (time == CurrentTime) { return false; } } // compare time to range Time duration = lost - m_timeOwned; Time when = time - m_timeOwned; return (/*when >= 0 &&*/ when <= duration); } Atom XWindowsClipboard::getTargetsData(String& data, int* format) const { assert(format != NULL); // add standard targets XWindowsUtil::appendAtomData(data, m_atomTargets); XWindowsUtil::appendAtomData(data, m_atomMultiple); XWindowsUtil::appendAtomData(data, m_atomTimestamp); // add targets we can convert to for (ConverterList::const_iterator index = m_converters.begin(); index != m_converters.end(); ++index) { IXWindowsClipboardConverter* converter = *index; // skip formats we don't have if (m_added[converter->getFormat()]) { XWindowsUtil::appendAtomData(data, converter->getAtom()); } } *format = 32; return m_atomAtom; } Atom XWindowsClipboard::getTimestampData(String& data, int* format) const { assert(format != NULL); checkCache(); XWindowsUtil::appendTimeData(data, m_timeOwned); *format = 32; return m_atomInteger; } // // XWindowsClipboard::CICCCMGetClipboard // XWindowsClipboard::CICCCMGetClipboard::CICCCMGetClipboard( Window requestor, Time time, Atom property) : m_requestor(requestor), m_time(time), m_property(property), m_incr(false), m_failed(false), m_done(false), m_reading(false), m_data(NULL), m_actualTarget(NULL), m_error(false) { // do nothing } XWindowsClipboard::CICCCMGetClipboard::~CICCCMGetClipboard() { // do nothing } bool XWindowsClipboard::CICCCMGetClipboard::readClipboard(Display* display, Atom selection, Atom target, Atom* actualTarget, String* data) { assert(actualTarget != NULL); assert(data != NULL); LOG((CLOG_DEBUG1 "request selection=%s, target=%s, window=%x", XWindowsUtil::atomToString(display, selection).c_str(), XWindowsUtil::atomToString(display, target).c_str(), m_requestor)); m_atomNone = XInternAtom(display, "NONE", False); m_atomIncr = XInternAtom(display, "INCR", False); // save output pointers m_actualTarget = actualTarget; m_data = data; // assume failure *m_actualTarget = None; *m_data = ""; // delete target property XDeleteProperty(display, m_requestor, m_property); // select window for property changes XWindowAttributes attr; XGetWindowAttributes(display, m_requestor, &attr); XSelectInput(display, m_requestor, attr.your_event_mask | PropertyChangeMask); // request data conversion XConvertSelection(display, selection, target, m_property, m_requestor, m_time); // synchronize with server before we start following timeout countdown XSync(display, False); // Xlib inexplicably omits the ability to wait for an event with // a timeout. (it's inexplicable because there's no portable way // to do it.) we'll poll until we have what we're looking for or // a timeout expires. we use a timeout so we don't get locked up // by badly behaved selection owners. XEvent xevent; std::vector events; Stopwatch timeout(false); // timer not stopped, not triggered static const double s_timeout = 0.25; // FIXME -- is this too short? bool noWait = false; while (!m_done && !m_failed) { // fail if timeout has expired if (timeout.getTime() >= s_timeout) { m_failed = true; break; } // process events if any otherwise sleep if (noWait || XPending(display) > 0) { while (!m_done && !m_failed && (noWait || XPending(display) > 0)) { XNextEvent(display, &xevent); if (!processEvent(display, &xevent)) { // not processed so save it events.push_back(xevent); } else { // reset timer since we've made some progress timeout.reset(); // don't sleep anymore, just block waiting for events. // we're assuming here that the clipboard owner will // complete the protocol correctly. if we continue to // sleep we'll get very bad performance. noWait = true; } } } else { ARCH->sleep(0.01); } } // put unprocessed events back for (UInt32 i = events.size(); i > 0; --i) { XPutBackEvent(display, &events[i - 1]); } // restore mask XSelectInput(display, m_requestor, attr.your_event_mask); // return success or failure LOG((CLOG_DEBUG1 "request %s after %fs", m_failed ? "failed" : "succeeded", timeout.getTime())); return !m_failed; } bool XWindowsClipboard::CICCCMGetClipboard::processEvent( Display* display, XEvent* xevent) { // process event switch (xevent->type) { case DestroyNotify: if (xevent->xdestroywindow.window == m_requestor) { m_failed = true; return true; } // not interested return false; case SelectionNotify: if (xevent->xselection.requestor == m_requestor) { // done if we can't convert if (xevent->xselection.property == None || xevent->xselection.property == m_atomNone) { m_done = true; return true; } // proceed if conversion successful else if (xevent->xselection.property == m_property) { m_reading = true; break; } } // otherwise not interested return false; case PropertyNotify: // proceed if conversion successful and we're receiving more data if (xevent->xproperty.window == m_requestor && xevent->xproperty.atom == m_property && xevent->xproperty.state == PropertyNewValue) { if (!m_reading) { // we haven't gotten the SelectionNotify yet return true; } break; } // otherwise not interested return false; default: // not interested return false; } // get the data from the property Atom target; const String::size_type oldSize = m_data->size(); if (!XWindowsUtil::getWindowProperty(display, m_requestor, m_property, m_data, &target, NULL, True)) { // unable to read property m_failed = true; return true; } // note if incremental. if we're already incremental then the // selection owner is busted. if the INCR property has no size // then the selection owner is busted. if (target == m_atomIncr) { if (m_incr) { m_failed = true; m_error = true; } else if (m_data->size() == oldSize) { m_failed = true; m_error = true; } else { m_incr = true; // discard INCR data *m_data = ""; } } // handle incremental chunks else if (m_incr) { // if first incremental chunk then save target if (oldSize == 0) { LOG((CLOG_DEBUG1 " INCR first chunk, target %s", XWindowsUtil::atomToString(display, target).c_str())); *m_actualTarget = target; } // secondary chunks must have the same target else { if (target != *m_actualTarget) { LOG((CLOG_WARN " INCR target mismatch")); m_failed = true; m_error = true; } } // note if this is the final chunk if (m_data->size() == oldSize) { LOG((CLOG_DEBUG1 " INCR final chunk: %d bytes total", m_data->size())); m_done = true; } } // not incremental; save the target. else { LOG((CLOG_DEBUG1 " target %s", XWindowsUtil::atomToString(display, target).c_str())); *m_actualTarget = target; m_done = true; } // this event has been processed LOGC(!m_incr, (CLOG_DEBUG1 " got data, %d bytes", m_data->size())); return true; } // // XWindowsClipboard::Reply // XWindowsClipboard::Reply::Reply(Window requestor, Atom target, ::Time time) : m_requestor(requestor), m_target(target), m_time(time), m_property(None), m_replied(false), m_done(false), m_data(), m_type(None), m_format(32), m_ptr(0) { // do nothing } XWindowsClipboard::Reply::Reply(Window requestor, Atom target, ::Time time, Atom property, const String& data, Atom type, int format) : m_requestor(requestor), m_target(target), m_time(time), m_property(property), m_replied(false), m_done(false), m_data(data), m_type(type), m_format(format), m_ptr(0) { // do nothing } synergy-1.8.8-stable/src/lib/platform/XWindowsClipboard.h000066400000000000000000000234521305627404700234520ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/clipboard_types.h" #include "synergy/IClipboard.h" #include "common/stdmap.h" #include "common/stdlist.h" #include "common/stdvector.h" #if X_DISPLAY_MISSING # error X11 is required to build synergy #else # include #endif class IXWindowsClipboardConverter; //! X11 clipboard implementation class XWindowsClipboard : public IClipboard { public: /*! Use \c window as the window that owns or interacts with the clipboard identified by \c id. */ XWindowsClipboard(Display*, Window window, ClipboardID id); virtual ~XWindowsClipboard(); //! Notify clipboard was lost /*! Tells clipboard it lost ownership at the given time. */ void lost(Time); //! Add clipboard request /*! Adds a selection request to the request list. If the given owner window isn't this clipboard's window then this simply sends a failure event to the requestor. */ void addRequest(Window owner, Window requestor, Atom target, ::Time time, Atom property); //! Process clipboard request /*! Continues processing a selection request. Returns true if the request was handled, false if the request was unknown. */ bool processRequest(Window requestor, ::Time time, Atom property); //! Cancel clipboard request /*! Terminate a selection request. Returns true iff the request was known and handled. */ bool destroyRequest(Window requestor); //! Get window /*! Returns the clipboard's window (passed the c'tor). */ Window getWindow() const; //! Get selection atom /*! Returns the selection atom that identifies the clipboard to X11 (e.g. XA_PRIMARY). */ Atom getSelection() const; // IClipboard overrides virtual bool empty(); virtual void add(EFormat, const String& data); virtual bool open(Time) const; virtual void close() const; virtual Time getTime() const; virtual bool has(EFormat) const; virtual String get(EFormat) const; private: // remove all converters from our list void clearConverters(); // get the converter for a clipboard format. returns NULL if no // suitable converter. iff onlyIfNotAdded is true then also // return NULL if a suitable converter was found but we already // have data of the converter's clipboard format. IXWindowsClipboardConverter* getConverter(Atom target, bool onlyIfNotAdded = false) const; // convert target atom to clipboard format EFormat getFormat(Atom target) const; // add a non-MULTIPLE request. does not verify that the selection // was owned at the given time. returns true if the conversion // could be performed, false otherwise. in either case, the // reply is inserted. bool addSimpleRequest( Window requestor, Atom target, ::Time time, Atom property); // if not already checked then see if the cache is stale and, if so, // clear it. this has the side effect of updating m_timeOwned. void checkCache() const; // clear the cache, resetting the cached flag and the added flag for // each format. void clearCache() const; void doClearCache(); // cache all formats of the selection void fillCache() const; void doFillCache(); // // helper classes // // read an ICCCM conforming selection class CICCCMGetClipboard { public: CICCCMGetClipboard(Window requestor, Time time, Atom property); ~CICCCMGetClipboard(); // convert the given selection to the given type. returns // true iff the conversion was successful or the conversion // cannot be performed (in which case *actualTarget == None). bool readClipboard(Display* display, Atom selection, Atom target, Atom* actualTarget, String* data); private: bool processEvent(Display* display, XEvent* event); private: Window m_requestor; Time m_time; Atom m_property; bool m_incr; bool m_failed; bool m_done; // atoms needed for the protocol Atom m_atomNone; // NONE, not None Atom m_atomIncr; // true iff we've received the selection notify bool m_reading; // the converted selection data String* m_data; // the actual type of the data. if this is None then the // selection owner cannot convert to the requested type. Atom* m_actualTarget; public: // true iff the selection owner didn't follow ICCCM conventions bool m_error; }; // Motif structure IDs enum { kMotifClipFormat = 1, kMotifClipItem, kMotifClipHeader }; // _MOTIF_CLIP_HEADER structure class MotifClipHeader { public: SInt32 m_id; // kMotifClipHeader SInt32 m_pad1[3]; SInt32 m_item; SInt32 m_pad2[4]; SInt32 m_numItems; SInt32 m_pad3[3]; SInt32 m_selectionOwner; // a Window SInt32 m_pad4[2]; }; // Motif clip item structure class MotifClipItem { public: SInt32 m_id; // kMotifClipItem SInt32 m_pad1[5]; SInt32 m_size; SInt32 m_numFormats; SInt32 m_numDeletedFormats; SInt32 m_pad2[6]; }; // Motif clip format structure class MotifClipFormat { public: SInt32 m_id; // kMotifClipFormat SInt32 m_pad1[6]; SInt32 m_length; SInt32 m_data; SInt32 m_type; // an Atom SInt32 m_pad2[1]; SInt32 m_deleted; SInt32 m_pad3[4]; }; // stores data needed to respond to a selection request class Reply { public: Reply(Window, Atom target, ::Time); Reply(Window, Atom target, ::Time, Atom property, const String& data, Atom type, int format); public: // information about the request Window m_requestor; Atom m_target; ::Time m_time; Atom m_property; // true iff we've sent the notification for this reply bool m_replied; // true iff the reply has sent its last message bool m_done; // the data to send and its type and format String m_data; Atom m_type; int m_format; // index of next byte in m_data to send UInt32 m_ptr; }; typedef std::list ReplyList; typedef std::map ReplyMap; typedef std::map ReplyEventMask; // ICCCM interoperability methods void icccmFillCache(); bool icccmGetSelection(Atom target, Atom* actualTarget, String* data) const; Time icccmGetTime() const; // motif interoperability methods bool motifLockClipboard() const; void motifUnlockClipboard() const; bool motifOwnsClipboard() const; void motifFillCache(); bool motifGetSelection(const MotifClipFormat*, Atom* actualTarget, String* data) const; Time motifGetTime() const; // reply methods bool insertMultipleReply(Window, ::Time, Atom); void insertReply(Reply*); void pushReplies(); void pushReplies(ReplyMap::iterator&, ReplyList&, ReplyList::iterator); bool sendReply(Reply*); void clearReplies(); void clearReplies(ReplyList&); void sendNotify(Window requestor, Atom selection, Atom target, Atom property, Time time); bool wasOwnedAtTime(::Time) const; // data conversion methods Atom getTargetsData(String&, int* format) const; Atom getTimestampData(String&, int* format) const; private: typedef std::vector ConverterList; Display* m_display; Window m_window; ClipboardID m_id; Atom m_selection; mutable bool m_open; mutable Time m_time; bool m_owner; mutable Time m_timeOwned; Time m_timeLost; // true iff open and clipboard owned by a motif app mutable bool m_motif; // the added/cached clipboard data mutable bool m_checkCache; bool m_cached; Time m_cacheTime; bool m_added[kNumFormats]; String m_data[kNumFormats]; // conversion request replies ReplyMap m_replies; ReplyEventMask m_eventMasks; // clipboard format converters ConverterList m_converters; // atoms we'll need Atom m_atomTargets; Atom m_atomMultiple; Atom m_atomTimestamp; Atom m_atomInteger; Atom m_atomAtom; Atom m_atomAtomPair; Atom m_atomData; Atom m_atomINCR; Atom m_atomMotifClipLock; Atom m_atomMotifClipHeader; Atom m_atomMotifClipAccess; Atom m_atomGDKSelection; }; //! Clipboard format converter interface /*! This interface defines the methods common to all X11 clipboard format converters. */ class IXWindowsClipboardConverter : public IInterface { public: //! @name accessors //@{ //! Get clipboard format /*! Return the clipboard format this object converts from/to. */ virtual IClipboard::EFormat getFormat() const = 0; //! Get X11 format atom /*! Return the atom representing the X selection format that this object converts from/to. */ virtual Atom getAtom() const = 0; //! Get X11 property datum size /*! Return the size (in bits) of data elements returned by toIClipboard(). */ virtual int getDataSize() const = 0; //! Convert from IClipboard format /*! Convert from the IClipboard format to the X selection format. The input data must be in the IClipboard format returned by getFormat(). The return data will be in the X selection format returned by getAtom(). */ virtual String fromIClipboard(const String&) const = 0; //! Convert to IClipboard format /*! Convert from the X selection format to the IClipboard format (i.e., the reverse of fromIClipboard()). */ virtual String toIClipboard(const String&) const = 0; //@} }; synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardAnyBitmapConverter.cpp000066400000000000000000000123341305627404700274770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsClipboardAnyBitmapConverter.h" // BMP info header structure struct CBMPInfoHeader { public: UInt32 biSize; SInt32 biWidth; SInt32 biHeight; UInt16 biPlanes; UInt16 biBitCount; UInt32 biCompression; UInt32 biSizeImage; SInt32 biXPelsPerMeter; SInt32 biYPelsPerMeter; UInt32 biClrUsed; UInt32 biClrImportant; }; // BMP is little-endian static void toLE(UInt8*& dst, UInt16 src) { dst[0] = static_cast(src & 0xffu); dst[1] = static_cast((src >> 8) & 0xffu); dst += 2; } static void toLE(UInt8*& dst, SInt32 src) { dst[0] = static_cast(src & 0xffu); dst[1] = static_cast((src >> 8) & 0xffu); dst[2] = static_cast((src >> 16) & 0xffu); dst[3] = static_cast((src >> 24) & 0xffu); dst += 4; } static void toLE(UInt8*& dst, UInt32 src) { dst[0] = static_cast(src & 0xffu); dst[1] = static_cast((src >> 8) & 0xffu); dst[2] = static_cast((src >> 16) & 0xffu); dst[3] = static_cast((src >> 24) & 0xffu); dst += 4; } static inline UInt16 fromLEU16(const UInt8* data) { return static_cast(data[0]) | (static_cast(data[1]) << 8); } static inline SInt32 fromLES32(const UInt8* data) { return static_cast(static_cast(data[0]) | (static_cast(data[1]) << 8) | (static_cast(data[2]) << 16) | (static_cast(data[3]) << 24)); } static inline UInt32 fromLEU32(const UInt8* data) { return static_cast(data[0]) | (static_cast(data[1]) << 8) | (static_cast(data[2]) << 16) | (static_cast(data[3]) << 24); } // // XWindowsClipboardAnyBitmapConverter // XWindowsClipboardAnyBitmapConverter::XWindowsClipboardAnyBitmapConverter() { // do nothing } XWindowsClipboardAnyBitmapConverter::~XWindowsClipboardAnyBitmapConverter() { // do nothing } IClipboard::EFormat XWindowsClipboardAnyBitmapConverter::getFormat() const { return IClipboard::kBitmap; } int XWindowsClipboardAnyBitmapConverter::getDataSize() const { return 8; } String XWindowsClipboardAnyBitmapConverter::fromIClipboard(const String& bmp) const { // fill BMP info header with native-endian data CBMPInfoHeader infoHeader; const UInt8* rawBMPInfoHeader = reinterpret_cast(bmp.data()); infoHeader.biSize = fromLEU32(rawBMPInfoHeader + 0); infoHeader.biWidth = fromLES32(rawBMPInfoHeader + 4); infoHeader.biHeight = fromLES32(rawBMPInfoHeader + 8); infoHeader.biPlanes = fromLEU16(rawBMPInfoHeader + 12); infoHeader.biBitCount = fromLEU16(rawBMPInfoHeader + 14); infoHeader.biCompression = fromLEU32(rawBMPInfoHeader + 16); infoHeader.biSizeImage = fromLEU32(rawBMPInfoHeader + 20); infoHeader.biXPelsPerMeter = fromLES32(rawBMPInfoHeader + 24); infoHeader.biYPelsPerMeter = fromLES32(rawBMPInfoHeader + 28); infoHeader.biClrUsed = fromLEU32(rawBMPInfoHeader + 32); infoHeader.biClrImportant = fromLEU32(rawBMPInfoHeader + 36); // check that format is acceptable if (infoHeader.biSize != 40 || infoHeader.biWidth == 0 || infoHeader.biHeight == 0 || infoHeader.biPlanes != 0 || infoHeader.biCompression != 0 || (infoHeader.biBitCount != 24 && infoHeader.biBitCount != 32)) { return String(); } // convert to image format const UInt8* rawBMPPixels = rawBMPInfoHeader + 40; if (infoHeader.biBitCount == 24) { return doBGRFromIClipboard(rawBMPPixels, infoHeader.biWidth, infoHeader.biHeight); } else { return doBGRAFromIClipboard(rawBMPPixels, infoHeader.biWidth, infoHeader.biHeight); } } String XWindowsClipboardAnyBitmapConverter::toIClipboard(const String& image) const { // convert to raw BMP data UInt32 w, h, depth; String rawBMP = doToIClipboard(image, w, h, depth); if (rawBMP.empty() || w == 0 || h == 0 || (depth != 24 && depth != 32)) { return String(); } // fill BMP info header with little-endian data UInt8 infoHeader[40]; UInt8* dst = infoHeader; toLE(dst, static_cast(40)); toLE(dst, static_cast(w)); toLE(dst, static_cast(h)); toLE(dst, static_cast(1)); toLE(dst, static_cast(depth)); toLE(dst, static_cast(0)); // BI_RGB toLE(dst, static_cast(image.size())); toLE(dst, static_cast(2834)); // 72 dpi toLE(dst, static_cast(2834)); // 72 dpi toLE(dst, static_cast(0)); toLE(dst, static_cast(0)); // construct image return String(reinterpret_cast(infoHeader), sizeof(infoHeader)) + rawBMP; } synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardAnyBitmapConverter.h000066400000000000000000000036311305627404700271440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/XWindowsClipboard.h" //! Convert to/from some text encoding class XWindowsClipboardAnyBitmapConverter : public IXWindowsClipboardConverter { public: XWindowsClipboardAnyBitmapConverter(); virtual ~XWindowsClipboardAnyBitmapConverter(); // IXWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual Atom getAtom() const = 0; virtual int getDataSize() const; virtual String fromIClipboard(const String&) const; virtual String toIClipboard(const String&) const; protected: //! Convert from IClipboard format /*! Convert raw BGR pixel data to another image format. */ virtual String doBGRFromIClipboard(const UInt8* bgrData, UInt32 w, UInt32 h) const = 0; //! Convert from IClipboard format /*! Convert raw BGRA pixel data to another image format. */ virtual String doBGRAFromIClipboard(const UInt8* bgrData, UInt32 w, UInt32 h) const = 0; //! Convert to IClipboard format /*! Convert an image into raw BGR or BGRA image data and store the width, height, and image depth (24 or 32). */ virtual String doToIClipboard(const String&, UInt32& w, UInt32& h, UInt32& depth) const = 0; }; synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardBMPConverter.cpp000066400000000000000000000062101305627404700262250ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsClipboardBMPConverter.h" // BMP file header structure struct CBMPHeader { public: UInt16 type; UInt32 size; UInt16 reserved1; UInt16 reserved2; UInt32 offset; }; // BMP is little-endian static inline UInt32 fromLEU32(const UInt8* data) { return static_cast(data[0]) | (static_cast(data[1]) << 8) | (static_cast(data[2]) << 16) | (static_cast(data[3]) << 24); } static void toLE(UInt8*& dst, char src) { dst[0] = static_cast(src); dst += 1; } static void toLE(UInt8*& dst, UInt16 src) { dst[0] = static_cast(src & 0xffu); dst[1] = static_cast((src >> 8) & 0xffu); dst += 2; } static void toLE(UInt8*& dst, UInt32 src) { dst[0] = static_cast(src & 0xffu); dst[1] = static_cast((src >> 8) & 0xffu); dst[2] = static_cast((src >> 16) & 0xffu); dst[3] = static_cast((src >> 24) & 0xffu); dst += 4; } // // XWindowsClipboardBMPConverter // XWindowsClipboardBMPConverter::XWindowsClipboardBMPConverter( Display* display) : m_atom(XInternAtom(display, "image/bmp", False)) { // do nothing } XWindowsClipboardBMPConverter::~XWindowsClipboardBMPConverter() { // do nothing } IClipboard::EFormat XWindowsClipboardBMPConverter::getFormat() const { return IClipboard::kBitmap; } Atom XWindowsClipboardBMPConverter::getAtom() const { return m_atom; } int XWindowsClipboardBMPConverter::getDataSize() const { return 8; } String XWindowsClipboardBMPConverter::fromIClipboard(const String& bmp) const { // create BMP image UInt8 header[14]; UInt8* dst = header; toLE(dst, 'B'); toLE(dst, 'M'); toLE(dst, static_cast(14 + bmp.size())); toLE(dst, static_cast(0)); toLE(dst, static_cast(0)); toLE(dst, static_cast(14 + 40)); return String(reinterpret_cast(header), 14) + bmp; } String XWindowsClipboardBMPConverter::toIClipboard(const String& bmp) const { // make sure data is big enough for a BMP file if (bmp.size() <= 14 + 40) { return String(); } // check BMP file header const UInt8* rawBMPHeader = reinterpret_cast(bmp.data()); if (rawBMPHeader[0] != 'B' || rawBMPHeader[1] != 'M') { return String(); } // get offset to image data UInt32 offset = fromLEU32(rawBMPHeader + 10); // construct BMP if (offset == 14 + 40) { return bmp.substr(14); } else { return bmp.substr(14, 40) + bmp.substr(offset, bmp.size() - offset); } } synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardBMPConverter.h000066400000000000000000000024331305627404700256750ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/XWindowsClipboard.h" //! Convert to/from some text encoding class XWindowsClipboardBMPConverter : public IXWindowsClipboardConverter { public: XWindowsClipboardBMPConverter(Display* display); virtual ~XWindowsClipboardBMPConverter(); // IXWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual Atom getAtom() const; virtual int getDataSize() const; virtual String fromIClipboard(const String&) const; virtual String toIClipboard(const String&) const; private: Atom m_atom; }; synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardHTMLConverter.cpp000066400000000000000000000030741305627404700263600ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsClipboardHTMLConverter.h" #include "base/Unicode.h" // // XWindowsClipboardHTMLConverter // XWindowsClipboardHTMLConverter::XWindowsClipboardHTMLConverter( Display* display, const char* name) : m_atom(XInternAtom(display, name, False)) { // do nothing } XWindowsClipboardHTMLConverter::~XWindowsClipboardHTMLConverter() { // do nothing } IClipboard::EFormat XWindowsClipboardHTMLConverter::getFormat() const { return IClipboard::kHTML; } Atom XWindowsClipboardHTMLConverter::getAtom() const { return m_atom; } int XWindowsClipboardHTMLConverter::getDataSize() const { return 8; } String XWindowsClipboardHTMLConverter::fromIClipboard(const String& data) const { return Unicode::UTF8ToUTF16(data); } String XWindowsClipboardHTMLConverter::toIClipboard(const String& data) const { return Unicode::UTF16ToUTF8(data); } synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardHTMLConverter.h000066400000000000000000000025641305627404700260300ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/XWindowsClipboard.h" //! Convert to/from HTML encoding class XWindowsClipboardHTMLConverter : public IXWindowsClipboardConverter { public: /*! \c name is converted to an atom and that is reported by getAtom(). */ XWindowsClipboardHTMLConverter(Display* display, const char* name); virtual ~XWindowsClipboardHTMLConverter(); // IXWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual Atom getAtom() const; virtual int getDataSize() const; virtual String fromIClipboard(const String&) const; virtual String toIClipboard(const String&) const; private: Atom m_atom; }; synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardTextConverter.cpp000066400000000000000000000036301305627404700265360ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsClipboardTextConverter.h" #include "base/Unicode.h" // // XWindowsClipboardTextConverter // XWindowsClipboardTextConverter::XWindowsClipboardTextConverter( Display* display, const char* name) : m_atom(XInternAtom(display, name, False)) { // do nothing } XWindowsClipboardTextConverter::~XWindowsClipboardTextConverter() { // do nothing } IClipboard::EFormat XWindowsClipboardTextConverter::getFormat() const { return IClipboard::kText; } Atom XWindowsClipboardTextConverter::getAtom() const { return m_atom; } int XWindowsClipboardTextConverter::getDataSize() const { return 8; } String XWindowsClipboardTextConverter::fromIClipboard(const String& data) const { return Unicode::UTF8ToText(data); } String XWindowsClipboardTextConverter::toIClipboard(const String& data) const { // convert to UTF-8 bool errors; String utf8 = Unicode::textToUTF8(data, &errors); // if there were decoding errors then, to support old applications // that don't understand UTF-8 but can report the exact binary // UTF-8 representation, see if the data appears to be UTF-8. if // so then use it as is. if (errors && Unicode::isUTF8(data)) { return data; } return utf8; } synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardTextConverter.h000066400000000000000000000025731305627404700262100ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/XWindowsClipboard.h" //! Convert to/from locale text encoding class XWindowsClipboardTextConverter : public IXWindowsClipboardConverter { public: /*! \c name is converted to an atom and that is reported by getAtom(). */ XWindowsClipboardTextConverter(Display* display, const char* name); virtual ~XWindowsClipboardTextConverter(); // IXWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual Atom getAtom() const; virtual int getDataSize() const; virtual String fromIClipboard(const String&) const; virtual String toIClipboard(const String&) const; private: Atom m_atom; }; synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardUCS2Converter.cpp000066400000000000000000000030731305627404700263270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsClipboardUCS2Converter.h" #include "base/Unicode.h" // // XWindowsClipboardUCS2Converter // XWindowsClipboardUCS2Converter::XWindowsClipboardUCS2Converter( Display* display, const char* name) : m_atom(XInternAtom(display, name, False)) { // do nothing } XWindowsClipboardUCS2Converter::~XWindowsClipboardUCS2Converter() { // do nothing } IClipboard::EFormat XWindowsClipboardUCS2Converter::getFormat() const { return IClipboard::kText; } Atom XWindowsClipboardUCS2Converter::getAtom() const { return m_atom; } int XWindowsClipboardUCS2Converter::getDataSize() const { return 16; } String XWindowsClipboardUCS2Converter::fromIClipboard(const String& data) const { return Unicode::UTF8ToUCS2(data); } String XWindowsClipboardUCS2Converter::toIClipboard(const String& data) const { return Unicode::UCS2ToUTF8(data); } synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardUCS2Converter.h000066400000000000000000000025651305627404700260010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/XWindowsClipboard.h" //! Convert to/from UCS-2 encoding class XWindowsClipboardUCS2Converter : public IXWindowsClipboardConverter { public: /*! \c name is converted to an atom and that is reported by getAtom(). */ XWindowsClipboardUCS2Converter(Display* display, const char* name); virtual ~XWindowsClipboardUCS2Converter(); // IXWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual Atom getAtom() const; virtual int getDataSize() const; virtual String fromIClipboard(const String&) const; virtual String toIClipboard(const String&) const; private: Atom m_atom; }; synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardUTF8Converter.cpp000066400000000000000000000027651305627404700263500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsClipboardUTF8Converter.h" // // XWindowsClipboardUTF8Converter // XWindowsClipboardUTF8Converter::XWindowsClipboardUTF8Converter( Display* display, const char* name) : m_atom(XInternAtom(display, name, False)) { // do nothing } XWindowsClipboardUTF8Converter::~XWindowsClipboardUTF8Converter() { // do nothing } IClipboard::EFormat XWindowsClipboardUTF8Converter::getFormat() const { return IClipboard::kText; } Atom XWindowsClipboardUTF8Converter::getAtom() const { return m_atom; } int XWindowsClipboardUTF8Converter::getDataSize() const { return 8; } String XWindowsClipboardUTF8Converter::fromIClipboard(const String& data) const { return data; } String XWindowsClipboardUTF8Converter::toIClipboard(const String& data) const { return data; } synergy-1.8.8-stable/src/lib/platform/XWindowsClipboardUTF8Converter.h000066400000000000000000000025651305627404700260130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "platform/XWindowsClipboard.h" //! Convert to/from UTF-8 encoding class XWindowsClipboardUTF8Converter : public IXWindowsClipboardConverter { public: /*! \c name is converted to an atom and that is reported by getAtom(). */ XWindowsClipboardUTF8Converter(Display* display, const char* name); virtual ~XWindowsClipboardUTF8Converter(); // IXWindowsClipboardConverter overrides virtual IClipboard::EFormat getFormat() const; virtual Atom getAtom() const; virtual int getDataSize() const; virtual String fromIClipboard(const String&) const; virtual String toIClipboard(const String&) const; private: Atom m_atom; }; synergy-1.8.8-stable/src/lib/platform/XWindowsEventQueueBuffer.cpp000066400000000000000000000162361305627404700253300ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsEventQueueBuffer.h" #include "mt/Lock.h" #include "mt/Thread.h" #include "base/Event.h" #include "base/IEventQueue.h" #include #if HAVE_UNISTD_H # include #endif #if HAVE_POLL # include #else # if HAVE_SYS_SELECT_H # include # endif # if HAVE_SYS_TIME_H # include # endif # if HAVE_SYS_TYPES_H # include # endif #endif // // EventQueueTimer // class EventQueueTimer { }; // // XWindowsEventQueueBuffer // XWindowsEventQueueBuffer::XWindowsEventQueueBuffer( Display* display, Window window, IEventQueue* events) : m_events(events), m_display(display), m_window(window), m_waiting(false) { assert(m_display != NULL); assert(m_window != None); m_userEvent = XInternAtom(m_display, "SYNERGY_USER_EVENT", False); // set up for pipe hack int result = pipe(m_pipefd); assert(result == 0); int pipeflags; pipeflags = fcntl(m_pipefd[0], F_GETFL); fcntl(m_pipefd[0], F_SETFL, pipeflags | O_NONBLOCK); pipeflags = fcntl(m_pipefd[1], F_GETFL); fcntl(m_pipefd[1], F_SETFL, pipeflags | O_NONBLOCK); } XWindowsEventQueueBuffer::~XWindowsEventQueueBuffer() { // release pipe hack resources close(m_pipefd[0]); close(m_pipefd[1]); } void XWindowsEventQueueBuffer::waitForEvent(double dtimeout) { Thread::testCancel(); // clear out the pipe in preparation for waiting. char buf[16]; ssize_t read_response = read(m_pipefd[0], buf, 15); // with linux automake, warnings are treated as errors by default if (read_response < 0) { // todo: handle read response } { Lock lock(&m_mutex); // we're now waiting for events m_waiting = true; // push out pending events flush(); } // calling flush may have queued up a new event. if (!XWindowsEventQueueBuffer::isEmpty()) { Thread::testCancel(); return; } // use poll() to wait for a message from the X server or for timeout. // this is a good deal more efficient than polling and sleeping. #if HAVE_POLL struct pollfd pfds[2]; pfds[0].fd = ConnectionNumber(m_display); pfds[0].events = POLLIN; pfds[1].fd = m_pipefd[0]; pfds[1].events = POLLIN; int timeout = (dtimeout < 0.0) ? -1 : static_cast(1000.0 * dtimeout); int remaining = timeout; int retval = 0; #else struct timeval timeout; struct timeval* timeoutPtr; if (dtimeout < 0.0) { timeoutPtr = NULL; } else { timeout.tv_sec = static_cast(dtimeout); timeout.tv_usec = static_cast(1.0e+6 * (dtimeout - timeout.tv_sec)); timeoutPtr = &timeout; } // initialize file descriptor sets fd_set rfds; FD_ZERO(&rfds); FD_SET(ConnectionNumber(m_display), &rfds); FD_SET(m_pipefd[0], &rfds); int nfds; if (ConnectionNumber(m_display) > m_pipefd[0]) { nfds = ConnectionNumber(m_display) + 1; } else { nfds = m_pipefd[0] + 1; } #endif // It's possible that the X server has queued events locally // in xlib's event buffer and not pushed on to the fd. Hence we // can't simply monitor the fd as we may never be woken up. // ie addEvent calls flush, XFlush may not send via the fd hence // there is an event waiting to be sent but we must exit the poll // before it can. // Instead we poll for a brief period of time (so if events // queued locally in the xlib buffer can be processed) // and continue doing this until timeout is reached. // The human eye can notice 60hz (ansi) which is 16ms, however // we want to give the cpu a chance s owe up this to 25ms #define TIMEOUT_DELAY 25 while (((dtimeout < 0.0) || (remaining > 0)) && QLength(m_display)==0 && retval==0){ #if HAVE_POLL retval = poll(pfds, 2, TIMEOUT_DELAY); //16ms = 60hz, but we make it > to play nicely with the cpu if (pfds[1].revents & POLLIN) { ssize_t read_response = read(m_pipefd[0], buf, 15); // with linux automake, warnings are treated as errors by default if (read_response < 0) { // todo: handle read response } } #else retval = select(nfds, SELECT_TYPE_ARG234 &rfds, SELECT_TYPE_ARG234 NULL, SELECT_TYPE_ARG234 NULL, SELECT_TYPE_ARG5 TIMEOUT_DELAY); if (FD_SET(m_pipefd[0], &rfds)) { read(m_pipefd[0], buf, 15); } #endif remaining-=TIMEOUT_DELAY; } { // we're no longer waiting for events Lock lock(&m_mutex); m_waiting = false; } Thread::testCancel(); } IEventQueueBuffer::Type XWindowsEventQueueBuffer::getEvent(Event& event, UInt32& dataID) { Lock lock(&m_mutex); // push out pending events flush(); // get next event XNextEvent(m_display, &m_event); // process event if (m_event.xany.type == ClientMessage && m_event.xclient.message_type == m_userEvent) { dataID = static_cast(m_event.xclient.data.l[0]); return kUser; } else { event = Event(Event::kSystem, m_events->getSystemTarget(), &m_event); return kSystem; } } bool XWindowsEventQueueBuffer::addEvent(UInt32 dataID) { // prepare a message XEvent xevent; xevent.xclient.type = ClientMessage; xevent.xclient.window = m_window; xevent.xclient.message_type = m_userEvent; xevent.xclient.format = 32; xevent.xclient.data.l[0] = static_cast(dataID); // save the message Lock lock(&m_mutex); m_postedEvents.push_back(xevent); // if we're currently waiting for an event then send saved events to // the X server now. if we're not waiting then some other thread // might be using the display connection so we can't safely use it // too. if (m_waiting) { flush(); // Send a character through the round-trip pipe to wake a thread // that is waiting for a ConnectionNumber() socket to be readable. // The flush call can read incoming data from the socket and put // it in Xlib's input buffer. That sneaks it past the other thread. ssize_t write_response = write(m_pipefd[1], "!", 1); // with linux automake, warnings are treated as errors by default if (write_response < 0) { // todo: handle read response } } return true; } bool XWindowsEventQueueBuffer::isEmpty() const { Lock lock(&m_mutex); return (XPending(m_display) == 0 ); } EventQueueTimer* XWindowsEventQueueBuffer::newTimer(double, bool) const { return new EventQueueTimer; } void XWindowsEventQueueBuffer::deleteTimer(EventQueueTimer* timer) const { delete timer; } void XWindowsEventQueueBuffer::flush() { // note -- m_mutex must be locked on entry // flush the posted event list to the X server for (size_t i = 0; i < m_postedEvents.size(); ++i) { XSendEvent(m_display, m_window, False, 0, &m_postedEvents[i]); } XFlush(m_display); m_postedEvents.clear(); } synergy-1.8.8-stable/src/lib/platform/XWindowsEventQueueBuffer.h000066400000000000000000000034131305627404700247660ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "mt/Mutex.h" #include "base/IEventQueueBuffer.h" #include "common/stdvector.h" #if X_DISPLAY_MISSING # error X11 is required to build synergy #else # include #endif class IEventQueue; //! Event queue buffer for X11 class XWindowsEventQueueBuffer : public IEventQueueBuffer { public: XWindowsEventQueueBuffer(Display*, Window, IEventQueue* events); virtual ~XWindowsEventQueueBuffer(); // IEventQueueBuffer overrides virtual void init() { } virtual void waitForEvent(double timeout); virtual Type getEvent(Event& event, UInt32& dataID); virtual bool addEvent(UInt32 dataID); virtual bool isEmpty() const; virtual EventQueueTimer* newTimer(double duration, bool oneShot) const; virtual void deleteTimer(EventQueueTimer*) const; private: void flush(); private: typedef std::vector EventList; Mutex m_mutex; Display* m_display; Window m_window; Atom m_userEvent; XEvent m_event; EventList m_postedEvents; bool m_waiting; int m_pipefd[2]; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/platform/XWindowsKeyState.cpp000066400000000000000000000610471305627404700236410ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsKeyState.h" #include "platform/XWindowsUtil.h" #include "base/Log.h" #include "base/String.h" #include "common/stdmap.h" #include #include #if X_DISPLAY_MISSING # error X11 is required to build synergy #else # include # include # define XK_MISCELLANY # define XK_XKB_KEYS # include #if HAVE_XKB_EXTENSION # include #endif #endif static const size_t ModifiersFromXDefaultSize = 32; XWindowsKeyState::XWindowsKeyState( Display* display, bool useXKB, IEventQueue* events) : KeyState(events), m_display(display), m_modifierFromX(ModifiersFromXDefaultSize) { init(display, useXKB); } XWindowsKeyState::XWindowsKeyState( Display* display, bool useXKB, IEventQueue* events, synergy::KeyMap& keyMap) : KeyState(events, keyMap), m_display(display), m_modifierFromX(ModifiersFromXDefaultSize) { init(display, useXKB); } XWindowsKeyState::~XWindowsKeyState() { #if HAVE_XKB_EXTENSION if (m_xkb != NULL) { XkbFreeKeyboard(m_xkb, 0, True); } #endif } void XWindowsKeyState::init(Display* display, bool useXKB) { XGetKeyboardControl(m_display, &m_keyboardState); #if HAVE_XKB_EXTENSION if (useXKB) { m_xkb = XkbGetMap(m_display, XkbKeyActionsMask | XkbKeyBehaviorsMask | XkbAllClientInfoMask, XkbUseCoreKbd); } else { m_xkb = NULL; } #endif setActiveGroup(kGroupPollAndSet); } void XWindowsKeyState::setActiveGroup(SInt32 group) { if (group == kGroupPollAndSet) { // we need to set the group to -1 in order for pollActiveGroup() to // actually poll for the group m_group = -1; m_group = pollActiveGroup(); } else if (group == kGroupPoll) { m_group = -1; } else { assert(group >= 0); m_group = group; } } void XWindowsKeyState::setAutoRepeat(const XKeyboardState& state) { m_keyboardState = state; } KeyModifierMask XWindowsKeyState::mapModifiersFromX(unsigned int state) const { LOG((CLOG_DEBUG2 "mapping state: %i", state)); UInt32 offset = 8 * getGroupFromState(state); KeyModifierMask mask = 0; for (int i = 0; i < 8; ++i) { if ((state & (1u << i)) != 0) { LOG((CLOG_DEBUG2 "|= modifier: %i", offset + i)); if (offset + i >= m_modifierFromX.size()) { LOG((CLOG_ERR "m_modifierFromX is too small (%d) for the " "requested offset (%d)", m_modifierFromX.size(), offset+i)); } else { mask |= m_modifierFromX[offset + i]; } } } return mask; } bool XWindowsKeyState::mapModifiersToX(KeyModifierMask mask, unsigned int& modifiers) const { modifiers = 0; for (SInt32 i = 0; i < kKeyModifierNumBits; ++i) { KeyModifierMask bit = (1u << i); if ((mask & bit) != 0) { KeyModifierToXMask::const_iterator j = m_modifierToX.find(bit); if (j == m_modifierToX.end()) { return false; } else { modifiers |= j->second; } } } return true; } void XWindowsKeyState::mapKeyToKeycodes(KeyID key, KeycodeList& keycodes) const { keycodes.clear(); std::pair range = m_keyCodeFromKey.equal_range(key); for (KeyToKeyCodeMap::const_iterator i = range.first; i != range.second; ++i) { keycodes.push_back(i->second); } } bool XWindowsKeyState::fakeCtrlAltDel() { // pass keys through unchanged return false; } KeyModifierMask XWindowsKeyState::pollActiveModifiers() const { Window root = DefaultRootWindow(m_display), window; int xRoot, yRoot, xWindow, yWindow; unsigned int state = 0; if (XQueryPointer(m_display, root, &root, &window, &xRoot, &yRoot, &xWindow, &yWindow, &state) == False) { state = 0; } return mapModifiersFromX(state); } SInt32 XWindowsKeyState::pollActiveGroup() const { // fixed condition where any group < -1 would have undetermined behaviour if (m_group >= 0) { return m_group; } #if HAVE_XKB_EXTENSION if (m_xkb != NULL) { XkbStateRec state; if (XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) { return state.group; } } #endif return 0; } void XWindowsKeyState::pollPressedKeys(KeyButtonSet& pressedKeys) const { char keys[32]; XQueryKeymap(m_display, keys); for (UInt32 i = 0; i < 32; ++i) { for (UInt32 j = 0; j < 8; ++j) { if ((keys[i] & (1u << j)) != 0) { pressedKeys.insert(8 * i + j); } } } } void XWindowsKeyState::getKeyMap(synergy::KeyMap& keyMap) { // get autorepeat info. we must use the global_auto_repeat told to // us because it may have modified by synergy. int oldGlobalAutoRepeat = m_keyboardState.global_auto_repeat; XGetKeyboardControl(m_display, &m_keyboardState); m_keyboardState.global_auto_repeat = oldGlobalAutoRepeat; #if HAVE_XKB_EXTENSION if (m_xkb != NULL) { if (XkbGetUpdatedMap(m_display, XkbKeyActionsMask | XkbKeyBehaviorsMask | XkbAllClientInfoMask, m_xkb) == Success) { updateKeysymMapXKB(keyMap); return; } } #endif updateKeysymMap(keyMap); } void XWindowsKeyState::fakeKey(const Keystroke& keystroke) { switch (keystroke.m_type) { case Keystroke::kButton: LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up")); if (keystroke.m_data.m_button.m_repeat) { int c = keystroke.m_data.m_button.m_button; int i = (c >> 3); int b = 1 << (c & 7); if (m_keyboardState.global_auto_repeat == AutoRepeatModeOff || (c!=113 && c!=116 && (m_keyboardState.auto_repeats[i] & b) == 0)) { LOG((CLOG_DEBUG1 " discard autorepeat")); break; } } XTestFakeKeyEvent(m_display, keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_press ? True : False, CurrentTime); break; case Keystroke::kGroup: if (keystroke.m_data.m_group.m_absolute) { LOG((CLOG_DEBUG1 " group %d", keystroke.m_data.m_group.m_group)); #if HAVE_XKB_EXTENSION if (m_xkb != NULL) { if (XkbLockGroup(m_display, XkbUseCoreKbd, keystroke.m_data.m_group.m_group) == False) { LOG((CLOG_DEBUG1 "XkbLockGroup request not sent")); } } else #endif { LOG((CLOG_DEBUG1 " ignored")); } } else { LOG((CLOG_DEBUG1 " group %+d", keystroke.m_data.m_group.m_group)); #if HAVE_XKB_EXTENSION if (m_xkb != NULL) { if (XkbLockGroup(m_display, XkbUseCoreKbd, getEffectiveGroup(pollActiveGroup(), keystroke.m_data.m_group.m_group)) == False) { LOG((CLOG_DEBUG1 "XkbLockGroup request not sent")); } } else #endif { LOG((CLOG_DEBUG1 " ignored")); } } break; } XFlush(m_display); } void XWindowsKeyState::updateKeysymMap(synergy::KeyMap& keyMap) { // there are up to 4 keysyms per keycode static const int maxKeysyms = 4; LOG((CLOG_DEBUG1 "non-XKB mapping")); // prepare map from X modifier to KeyModifierMask. certain bits // are predefined. std::fill(m_modifierFromX.begin(), m_modifierFromX.end(), 0); m_modifierFromX[ShiftMapIndex] = KeyModifierShift; m_modifierFromX[LockMapIndex] = KeyModifierCapsLock; m_modifierFromX[ControlMapIndex] = KeyModifierControl; m_modifierToX.clear(); m_modifierToX[KeyModifierShift] = ShiftMask; m_modifierToX[KeyModifierCapsLock] = LockMask; m_modifierToX[KeyModifierControl] = ControlMask; // prepare map from KeyID to KeyCode m_keyCodeFromKey.clear(); // get the number of keycodes int minKeycode, maxKeycode; XDisplayKeycodes(m_display, &minKeycode, &maxKeycode); int numKeycodes = maxKeycode - minKeycode + 1; // get the keyboard mapping for all keys int keysymsPerKeycode; KeySym* allKeysyms = XGetKeyboardMapping(m_display, minKeycode, numKeycodes, &keysymsPerKeycode); // it's more convenient to always have maxKeysyms KeySyms per key { KeySym* tmpKeysyms = new KeySym[maxKeysyms * numKeycodes]; for (int i = 0; i < numKeycodes; ++i) { for (int j = 0; j < maxKeysyms; ++j) { if (j < keysymsPerKeycode) { tmpKeysyms[maxKeysyms * i + j] = allKeysyms[keysymsPerKeycode * i + j]; } else { tmpKeysyms[maxKeysyms * i + j] = NoSymbol; } } } XFree(allKeysyms); allKeysyms = tmpKeysyms; } // get the buttons assigned to modifiers. X11 does not predefine // the meaning of any modifiers except shift, caps lock, and the // control key. the meaning of a modifier bit (other than those) // depends entirely on the KeySyms mapped to that bit. unfortunately // you cannot map a bit back to the KeySym used to produce it. // for example, let's say button 1 maps to Alt_L without shift and // Meta_L with shift. now if mod1 is mapped to button 1 that could // mean the user used Alt or Meta to turn on that modifier and there's // no way to know which. it's also possible for one button to be // mapped to multiple bits so both mod1 and mod2 could be generated // by button 1. // // we're going to ignore any modifier for a button except the first. // with the above example, that means we'll ignore the mod2 modifier // bit unless it's also mapped to some other button. we're also // going to ignore all KeySyms except the first modifier KeySym, // which means button 1 above won't map to Meta, just Alt. std::map modifierButtons; XModifierKeymap* modifiers = XGetModifierMapping(m_display); for (unsigned int i = 0; i < 8; ++i) { const KeyCode* buttons = modifiers->modifiermap + i * modifiers->max_keypermod; for (int j = 0; j < modifiers->max_keypermod; ++j) { modifierButtons.insert(std::make_pair(buttons[j], i)); } } XFreeModifiermap(modifiers); modifierButtons.erase(0); // Hack to deal with VMware. When a VMware client grabs input the // player clears out the X modifier map for whatever reason. We're // notified of the change and arrive here to discover that there // are no modifiers at all. Since this prevents the modifiers from // working in the VMware client we'll use the last known good set // of modifiers when there are no modifiers. If there are modifiers // we update the last known good set. if (!modifierButtons.empty()) { m_lastGoodNonXKBModifiers = modifierButtons; } else { modifierButtons = m_lastGoodNonXKBModifiers; } // add entries for each keycode synergy::KeyMap::KeyItem item; for (int i = 0; i < numKeycodes; ++i) { KeySym* keysyms = allKeysyms + maxKeysyms * i; KeyCode keycode = static_cast(i + minKeycode); item.m_button = static_cast(keycode); item.m_client = 0; // determine modifier sensitivity item.m_sensitive = 0; // if the keysyms in levels 2 or 3 exist and differ from levels // 0 and 1 then the key is sensitive AltGr (Mode_switch) if ((keysyms[2] != NoSymbol && keysyms[2] != keysyms[0]) || (keysyms[3] != NoSymbol && keysyms[2] != keysyms[1])) { item.m_sensitive |= KeyModifierAltGr; } // check if the key is caps-lock sensitive. some systems only // provide one keysym for keys sensitive to caps-lock. if we // find that then fill in the missing keysym. if (keysyms[0] != NoSymbol && keysyms[1] == NoSymbol && keysyms[2] == NoSymbol && keysyms[3] == NoSymbol) { KeySym lKeysym, uKeysym; XConvertCase(keysyms[0], &lKeysym, &uKeysym); if (lKeysym != uKeysym) { keysyms[0] = lKeysym; keysyms[1] = uKeysym; item.m_sensitive |= KeyModifierCapsLock; } } else if (keysyms[0] != NoSymbol && keysyms[1] != NoSymbol) { KeySym lKeysym, uKeysym; XConvertCase(keysyms[0], &lKeysym, &uKeysym); if (lKeysym != uKeysym && lKeysym == keysyms[0] && uKeysym == keysyms[1]) { item.m_sensitive |= KeyModifierCapsLock; } else if (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol) { XConvertCase(keysyms[2], &lKeysym, &uKeysym); if (lKeysym != uKeysym && lKeysym == keysyms[2] && uKeysym == keysyms[3]) { item.m_sensitive |= KeyModifierCapsLock; } } } // key is sensitive to shift if keysyms in levels 0 and 1 or // levels 2 and 3 don't match. it's also sensitive to shift // if it's sensitive to caps-lock. if ((item.m_sensitive & KeyModifierCapsLock) != 0) { item.m_sensitive |= KeyModifierShift; } else if ((keysyms[0] != NoSymbol && keysyms[1] != NoSymbol && keysyms[0] != keysyms[1]) || (keysyms[2] != NoSymbol && keysyms[3] != NoSymbol && keysyms[2] != keysyms[3])) { item.m_sensitive |= KeyModifierShift; } // key is sensitive to numlock if any keysym on it is if (IsKeypadKey(keysyms[0]) || IsPrivateKeypadKey(keysyms[0]) || IsKeypadKey(keysyms[1]) || IsPrivateKeypadKey(keysyms[1]) || IsKeypadKey(keysyms[2]) || IsPrivateKeypadKey(keysyms[2]) || IsKeypadKey(keysyms[3]) || IsPrivateKeypadKey(keysyms[3])) { item.m_sensitive |= KeyModifierNumLock; } // do each keysym (shift level) for (int j = 0; j < maxKeysyms; ++j) { item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[j]); if (item.m_id == kKeyNone) { if (j != 0 && modifierButtons.count(keycode) > 0) { // pretend the modifier works in other shift levels // because it probably does. if (keysyms[1] == NoSymbol || j != 3) { item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[0]); } else { item.m_id = XWindowsUtil::mapKeySymToKeyID(keysyms[1]); } } if (item.m_id == kKeyNone) { continue; } } // group is 0 for levels 0 and 1 and 1 for levels 2 and 3 item.m_group = (j >= 2) ? 1 : 0; // compute required modifiers item.m_required = 0; if ((j & 1) != 0) { item.m_required |= KeyModifierShift; } if ((j & 2) != 0) { item.m_required |= KeyModifierAltGr; } item.m_generates = 0; item.m_lock = false; if (modifierButtons.count(keycode) > 0) { // get flags for modifier keys synergy::KeyMap::initModifierKey(item); // add mapping from X (unless we already have) if (item.m_generates != 0) { unsigned int bit = modifierButtons[keycode]; if (m_modifierFromX[bit] == 0) { m_modifierFromX[bit] = item.m_generates; m_modifierToX[item.m_generates] = (1u << bit); } } } // add key keyMap.addKeyEntry(item); m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode)); // add other ways to synthesize the key if ((j & 1) != 0) { // add capslock version of key is sensitive to capslock KeySym lKeysym, uKeysym; XConvertCase(keysyms[j], &lKeysym, &uKeysym); if (lKeysym != uKeysym && lKeysym == keysyms[j - 1] && uKeysym == keysyms[j]) { item.m_required &= ~KeyModifierShift; item.m_required |= KeyModifierCapsLock; keyMap.addKeyEntry(item); item.m_required |= KeyModifierShift; item.m_required &= ~KeyModifierCapsLock; } // add numlock version of key if sensitive to numlock if (IsKeypadKey(keysyms[j]) || IsPrivateKeypadKey(keysyms[j])) { item.m_required &= ~KeyModifierShift; item.m_required |= KeyModifierNumLock; keyMap.addKeyEntry(item); item.m_required |= KeyModifierShift; item.m_required &= ~KeyModifierNumLock; } } } } delete[] allKeysyms; } #if HAVE_XKB_EXTENSION void XWindowsKeyState::updateKeysymMapXKB(synergy::KeyMap& keyMap) { static const XkbKTMapEntryRec defMapEntry = { True, // active 0, // level { 0, // mods.mask 0, // mods.real_mods 0 // mods.vmods } }; LOG((CLOG_DEBUG1 "XKB mapping")); // find the number of groups int maxNumGroups = 0; for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) { int numGroups = XkbKeyNumGroups(m_xkb, static_cast(i)); if (numGroups > maxNumGroups) { maxNumGroups = numGroups; } } // prepare map from X modifier to KeyModifierMask std::vector modifierLevel(maxNumGroups * 8, 4); m_modifierFromX.clear(); m_modifierFromX.resize(maxNumGroups * 8); m_modifierToX.clear(); // prepare map from KeyID to KeyCode m_keyCodeFromKey.clear(); // Hack to deal with VMware. When a VMware client grabs input the // player clears out the X modifier map for whatever reason. We're // notified of the change and arrive here to discover that there // are no modifiers at all. Since this prevents the modifiers from // working in the VMware client we'll use the last known good set // of modifiers when there are no modifiers. If there are modifiers // we update the last known good set. bool useLastGoodModifiers = !hasModifiersXKB(); if (!useLastGoodModifiers) { m_lastGoodXKBModifiers.clear(); } // check every button. on this pass we save all modifiers as native // X modifier masks. synergy::KeyMap::KeyItem item; for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) { KeyCode keycode = static_cast(i); item.m_button = static_cast(keycode); item.m_client = 0; // skip keys with no groups (they generate no symbols) if (XkbKeyNumGroups(m_xkb, keycode) == 0) { continue; } // note half-duplex keys const XkbBehavior& b = m_xkb->server->behaviors[keycode]; if ((b.type & XkbKB_OpMask) == XkbKB_Lock) { keyMap.addHalfDuplexButton(item.m_button); } // iterate over all groups for (int group = 0; group < maxNumGroups; ++group) { item.m_group = group; int eGroup = getEffectiveGroup(keycode, group); // get key info XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, eGroup); // set modifiers the item is sensitive to item.m_sensitive = type->mods.mask; // iterate over all shift levels for the button (including none) for (int j = -1; j < type->map_count; ++j) { const XkbKTMapEntryRec* mapEntry = ((j == -1) ? &defMapEntry : type->map + j); if (!mapEntry->active) { continue; } int level = mapEntry->level; // set required modifiers for this item item.m_required = mapEntry->mods.mask; if ((item.m_required & LockMask) != 0 && j != -1 && type->preserve != NULL && (type->preserve[j].mask & LockMask) != 0) { // sensitive caps lock and we preserve caps-lock. // preserving caps-lock means we Xlib functions would // yield the capitialized KeySym so we'll adjust the // level accordingly. if ((level ^ 1) < type->num_levels) { level ^= 1; } } // get the keysym for this item KeySym keysym = XkbKeySymEntry(m_xkb, keycode, level, eGroup); // check for group change actions, locking modifiers, and // modifier masks. item.m_lock = false; bool isModifier = false; UInt32 modifierMask = m_xkb->map->modmap[keycode]; if (XkbKeyHasActions(m_xkb, keycode) == True) { XkbAction* action = XkbKeyActionEntry(m_xkb, keycode, level, eGroup); if (action->type == XkbSA_SetMods || action->type == XkbSA_LockMods) { isModifier = true; // note toggles item.m_lock = (action->type == XkbSA_LockMods); // maybe use action's mask if ((action->mods.flags & XkbSA_UseModMapMods) == 0) { modifierMask = action->mods.mask; } } else if (action->type == XkbSA_SetGroup || action->type == XkbSA_LatchGroup || action->type == XkbSA_LockGroup) { // ignore group change key continue; } } level = mapEntry->level; // VMware modifier hack if (useLastGoodModifiers) { XKBModifierMap::const_iterator k = m_lastGoodXKBModifiers.find(eGroup * 256 + keycode); if (k != m_lastGoodXKBModifiers.end()) { // Use last known good modifier isModifier = true; level = k->second.m_level; modifierMask = k->second.m_mask; item.m_lock = k->second.m_lock; } } else if (isModifier) { // Save known good modifier XKBModifierInfo& info = m_lastGoodXKBModifiers[eGroup * 256 + keycode]; info.m_level = level; info.m_mask = modifierMask; info.m_lock = item.m_lock; } // record the modifier mask for this key. don't bother // for keys that change the group. item.m_generates = 0; UInt32 modifierBit = XWindowsUtil::getModifierBitForKeySym(keysym); if (isModifier && modifierBit != kKeyModifierBitNone) { item.m_generates = (1u << modifierBit); for (SInt32 j = 0; j < 8; ++j) { // skip modifiers this key doesn't generate if ((modifierMask & (1u << j)) == 0) { continue; } // skip keys that map to a modifier that we've // already seen using fewer modifiers. that is // if this key must combine with other modifiers // and we know of a key that combines with fewer // modifiers (or no modifiers) then prefer the // other key. if (level >= modifierLevel[8 * group + j]) { continue; } modifierLevel[8 * group + j] = level; // save modifier m_modifierFromX[8 * group + j] |= (1u << modifierBit); m_modifierToX.insert(std::make_pair( 1u << modifierBit, 1u << j)); } } // handle special cases of just one keysym for the keycode if (type->num_levels == 1) { // if there are upper- and lowercase versions of the // keysym then add both. KeySym lKeysym, uKeysym; XConvertCase(keysym, &lKeysym, &uKeysym); if (lKeysym != uKeysym) { if (j != -1) { continue; } item.m_sensitive |= ShiftMask | LockMask; KeyID lKeyID = XWindowsUtil::mapKeySymToKeyID(lKeysym); KeyID uKeyID = XWindowsUtil::mapKeySymToKeyID(uKeysym); if (lKeyID == kKeyNone || uKeyID == kKeyNone) { continue; } item.m_id = lKeyID; item.m_required = 0; keyMap.addKeyEntry(item); item.m_id = uKeyID; item.m_required = ShiftMask; keyMap.addKeyEntry(item); item.m_required = LockMask; keyMap.addKeyEntry(item); if (group == 0) { m_keyCodeFromKey.insert( std::make_pair(lKeyID, keycode)); m_keyCodeFromKey.insert( std::make_pair(uKeyID, keycode)); } continue; } } // add entry item.m_id = XWindowsUtil::mapKeySymToKeyID(keysym); keyMap.addKeyEntry(item); if (group == 0) { m_keyCodeFromKey.insert(std::make_pair(item.m_id, keycode)); } } } } // change all modifier masks to synergy masks from X masks keyMap.foreachKey(&XWindowsKeyState::remapKeyModifiers, this); // allow composition across groups keyMap.allowGroupSwitchDuringCompose(); } #endif void XWindowsKeyState::remapKeyModifiers(KeyID id, SInt32 group, synergy::KeyMap::KeyItem& item, void* vself) { XWindowsKeyState* self = static_cast(vself); item.m_required = self->mapModifiersFromX(XkbBuildCoreState(item.m_required, group)); item.m_sensitive = self->mapModifiersFromX(XkbBuildCoreState(item.m_sensitive, group)); } bool XWindowsKeyState::hasModifiersXKB() const { #if HAVE_XKB_EXTENSION // iterate over all keycodes for (int i = m_xkb->min_key_code; i <= m_xkb->max_key_code; ++i) { KeyCode keycode = static_cast(i); if (XkbKeyHasActions(m_xkb, keycode) == True) { // iterate over all groups int numGroups = XkbKeyNumGroups(m_xkb, keycode); for (int group = 0; group < numGroups; ++group) { // iterate over all shift levels for the button (including none) XkbKeyTypePtr type = XkbKeyKeyType(m_xkb, keycode, group); for (int j = -1; j < type->map_count; ++j) { if (j != -1 && !type->map[j].active) { continue; } int level = ((j == -1) ? 0 : type->map[j].level); XkbAction* action = XkbKeyActionEntry(m_xkb, keycode, level, group); if (action->type == XkbSA_SetMods || action->type == XkbSA_LockMods) { return true; } } } } } #endif return false; } int XWindowsKeyState::getEffectiveGroup(KeyCode keycode, int group) const { (void)keycode; #if HAVE_XKB_EXTENSION // get effective group for key int numGroups = XkbKeyNumGroups(m_xkb, keycode); if (group >= numGroups) { unsigned char groupInfo = XkbKeyGroupInfo(m_xkb, keycode); switch (XkbOutOfRangeGroupAction(groupInfo)) { case XkbClampIntoRange: group = numGroups - 1; break; case XkbRedirectIntoRange: group = XkbOutOfRangeGroupNumber(groupInfo); if (group >= numGroups) { group = 0; } break; default: // wrap group %= numGroups; break; } } #endif return group; } UInt32 XWindowsKeyState::getGroupFromState(unsigned int state) const { #if HAVE_XKB_EXTENSION if (m_xkb != NULL) { return XkbGroupForCoreState(state); } #endif return 0; } synergy-1.8.8-stable/src/lib/platform/XWindowsKeyState.h000066400000000000000000000113141305627404700232760ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/KeyState.h" #include "common/stdmap.h" #include "common/stdvector.h" #if X_DISPLAY_MISSING # error X11 is required to build synergy #else # include # if HAVE_X11_EXTENSIONS_XTEST_H # include # else # error The XTest extension is required to build synergy # endif # if HAVE_XKB_EXTENSION # include # endif #endif class IEventQueue; //! X Windows key state /*! A key state for X Windows. */ class XWindowsKeyState : public KeyState { public: typedef std::vector KeycodeList; enum { kGroupPoll = -1, kGroupPollAndSet = -2 }; XWindowsKeyState(Display*, bool useXKB, IEventQueue* events); XWindowsKeyState(Display*, bool useXKB, IEventQueue* events, synergy::KeyMap& keyMap); ~XWindowsKeyState(); //! @name modifiers //@{ //! Set active group /*! Sets the active group to \p group. This is the group returned by \c pollActiveGroup(). If \p group is \c kGroupPoll then \c pollActiveGroup() will really poll, but that's a slow operation on X11. If \p group is \c kGroupPollAndSet then this will poll the active group now and use it for future calls to \c pollActiveGroup(). */ void setActiveGroup(SInt32 group); //! Set the auto-repeat state /*! Sets the auto-repeat state. */ void setAutoRepeat(const XKeyboardState&); //@} //! @name accessors //@{ //! Convert X modifier mask to synergy mask /*! Returns the synergy modifier mask corresponding to the X modifier mask in \p state. */ KeyModifierMask mapModifiersFromX(unsigned int state) const; //! Convert synergy modifier mask to X mask /*! Converts the synergy modifier mask to the corresponding X modifier mask. Returns \c true if successful and \c false if any modifier could not be converted. */ bool mapModifiersToX(KeyModifierMask, unsigned int&) const; //! Convert synergy key to all corresponding X keycodes /*! Converts the synergy key \p key to all of the keycodes that map to that key. */ void mapKeyToKeycodes(KeyID key, KeycodeList& keycodes) const; //@} // IKeyState overrides virtual bool fakeCtrlAltDel(); virtual KeyModifierMask pollActiveModifiers() const; virtual SInt32 pollActiveGroup() const; virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const; protected: // KeyState overrides virtual void getKeyMap(synergy::KeyMap& keyMap); virtual void fakeKey(const Keystroke& keystroke); private: void init(Display* display, bool useXKB); void updateKeysymMap(synergy::KeyMap&); void updateKeysymMapXKB(synergy::KeyMap&); bool hasModifiersXKB() const; int getEffectiveGroup(KeyCode, int group) const; UInt32 getGroupFromState(unsigned int state) const; static void remapKeyModifiers(KeyID, SInt32, synergy::KeyMap::KeyItem&, void*); private: struct XKBModifierInfo { public: unsigned char m_level; UInt32 m_mask; bool m_lock; }; #ifdef TEST_ENV public: // yuck #endif typedef std::vector KeyModifierMaskList; private: typedef std::map KeyModifierToXMask; typedef std::multimap KeyToKeyCodeMap; typedef std::map NonXKBModifierMap; typedef std::map XKBModifierMap; Display* m_display; #if HAVE_XKB_EXTENSION XkbDescPtr m_xkb; #endif SInt32 m_group; XKBModifierMap m_lastGoodXKBModifiers; NonXKBModifierMap m_lastGoodNonXKBModifiers; // X modifier (bit number) to synergy modifier (mask) mapping KeyModifierMaskList m_modifierFromX; // synergy modifier (mask) to X modifier (mask) KeyModifierToXMask m_modifierToX; // map KeyID to all keycodes that can synthesize that KeyID KeyToKeyCodeMap m_keyCodeFromKey; // autorepeat state XKeyboardState m_keyboardState; #ifdef TEST_ENV public: SInt32 group() const { return m_group; } void group(const SInt32& group) { m_group = group; } KeyModifierMaskList modifierFromX() const { return m_modifierFromX; } #endif }; synergy-1.8.8-stable/src/lib/platform/XWindowsScreen.cpp000066400000000000000000001557171305627404700233370ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsScreen.h" #include "platform/XWindowsClipboard.h" #include "platform/XWindowsEventQueueBuffer.h" #include "platform/XWindowsKeyState.h" #include "platform/XWindowsScreenSaver.h" #include "platform/XWindowsUtil.h" #include "synergy/Clipboard.h" #include "synergy/KeyMap.h" #include "synergy/XScreen.h" #include "arch/XArch.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/Stopwatch.h" #include "base/String.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include #include #include #if X_DISPLAY_MISSING # error X11 is required to build synergy #else # include # include # define XK_MISCELLANY # define XK_XKB_KEYS # include # if HAVE_X11_EXTENSIONS_DPMS_H extern "C" { # include } # endif # if HAVE_X11_EXTENSIONS_XTEST_H # include # else # error The XTest extension is required to build synergy # endif # if HAVE_X11_EXTENSIONS_XINERAMA_H // Xinerama.h may lack extern "C" for inclusion by C++ extern "C" { # include } # endif # if HAVE_X11_EXTENSIONS_XRANDR_H # include # endif # if HAVE_XKB_EXTENSION # include # endif # ifdef HAVE_XI2 # include # endif #endif static int xi_opcode; // // XWindowsScreen // // NOTE -- the X display is shared among several objects but is owned // by the XWindowsScreen. Xlib is not reentrant so we must ensure // that no two objects can simultaneously call Xlib with the display. // this is easy since we only make X11 calls from the main thread. // we must also ensure that these objects do not use the display in // their destructors or, if they do, we can tell them not to. This // is to handle unexpected disconnection of the X display, when any // call on the display is invalid. In that situation we discard the // display and the X11 event queue buffer, ignore any calls that try // to use the display, and wait to be destroyed. XWindowsScreen* XWindowsScreen::s_screen = NULL; XWindowsScreen::XWindowsScreen( const char* displayName, bool isPrimary, bool disableXInitThreads, int mouseScrollDelta, IEventQueue* events) : m_isPrimary(isPrimary), m_mouseScrollDelta(mouseScrollDelta), m_display(NULL), m_root(None), m_window(None), m_isOnScreen(m_isPrimary), m_x(0), m_y(0), m_w(0), m_h(0), m_xCenter(0), m_yCenter(0), m_xCursor(0), m_yCursor(0), m_keyState(NULL), m_lastFocus(None), m_lastFocusRevert(RevertToNone), m_im(NULL), m_ic(NULL), m_lastKeycode(0), m_sequenceNumber(0), m_screensaver(NULL), m_screensaverNotify(false), m_xtestIsXineramaUnaware(true), m_preserveFocus(false), m_xkb(false), m_xi2detected(false), m_xrandr(false), m_events(events), PlatformScreen(events) { assert(s_screen == NULL); if (mouseScrollDelta==0) m_mouseScrollDelta=120; s_screen = this; if (!disableXInitThreads) { // initializes Xlib support for concurrent threads. if (XInitThreads() == 0) throw XArch("XInitThreads() returned zero"); } else { LOG((CLOG_DEBUG "skipping XInitThreads()")); } // set the X I/O error handler so we catch the display disconnecting XSetIOErrorHandler(&XWindowsScreen::ioErrorHandler); try { m_display = openDisplay(displayName); m_root = DefaultRootWindow(m_display); saveShape(); m_window = openWindow(); m_screensaver = new XWindowsScreenSaver(m_display, m_window, getEventTarget(), events); m_keyState = new XWindowsKeyState(m_display, m_xkb, events, m_keyMap); LOG((CLOG_DEBUG "screen shape: %d,%d %dx%d %s", m_x, m_y, m_w, m_h, m_xinerama ? "(xinerama)" : "")); LOG((CLOG_DEBUG "window is 0x%08x", m_window)); } catch (...) { if (m_display != NULL) { XCloseDisplay(m_display); } throw; } // primary/secondary screen only initialization if (m_isPrimary) { #ifdef HAVE_XI2 m_xi2detected = detectXI2(); if (m_xi2detected) { selectXIRawMotion(); } else #endif { // start watching for events on other windows selectEvents(m_root); } // prepare to use input methods openIM(); } else { // become impervious to server grabs XTestGrabControl(m_display, True); } // initialize the clipboards for (ClipboardID id = 0; id < kClipboardEnd; ++id) { m_clipboard[id] = new XWindowsClipboard(m_display, m_window, id); } // install event handlers m_events->adoptHandler(Event::kSystem, m_events->getSystemTarget(), new TMethodEventJob(this, &XWindowsScreen::handleSystemEvent)); // install the platform event queue m_events->adoptBuffer(new XWindowsEventQueueBuffer( m_display, m_window, m_events)); } XWindowsScreen::~XWindowsScreen() { assert(s_screen != NULL); assert(m_display != NULL); m_events->adoptBuffer(NULL); m_events->removeHandler(Event::kSystem, m_events->getSystemTarget()); for (ClipboardID id = 0; id < kClipboardEnd; ++id) { delete m_clipboard[id]; } delete m_keyState; delete m_screensaver; m_keyState = NULL; m_screensaver = NULL; if (m_display != NULL) { // FIXME -- is it safe to clean up the IC and IM without a display? if (m_ic != NULL) { XDestroyIC(m_ic); } if (m_im != NULL) { XCloseIM(m_im); } XDestroyWindow(m_display, m_window); XCloseDisplay(m_display); } XSetIOErrorHandler(NULL); s_screen = NULL; } void XWindowsScreen::enable() { if (!m_isPrimary) { // get the keyboard control state XKeyboardState keyControl; XGetKeyboardControl(m_display, &keyControl); m_autoRepeat = (keyControl.global_auto_repeat == AutoRepeatModeOn); m_keyState->setAutoRepeat(keyControl); // move hider window under the cursor center XMoveWindow(m_display, m_window, m_xCenter, m_yCenter); // raise and show the window // FIXME -- take focus? XMapRaised(m_display, m_window); // warp the mouse to the cursor center fakeMouseMove(m_xCenter, m_yCenter); } } void XWindowsScreen::disable() { // release input context focus if (m_ic != NULL) { XUnsetICFocus(m_ic); } // unmap the hider/grab window. this also ungrabs the mouse and // keyboard if they're grabbed. XUnmapWindow(m_display, m_window); // restore auto-repeat state if (!m_isPrimary && m_autoRepeat) { //XAutoRepeatOn(m_display); } } void XWindowsScreen::enter() { screensaver(false); // release input context focus if (m_ic != NULL) { XUnsetICFocus(m_ic); } // set the input focus to what it had been when we took it if (m_lastFocus != None) { // the window may not exist anymore so ignore errors XWindowsUtil::ErrorLock lock(m_display); XSetInputFocus(m_display, m_lastFocus, m_lastFocusRevert, CurrentTime); } #if HAVE_X11_EXTENSIONS_DPMS_H // Force the DPMS to turn screen back on since we don't // actually cause physical hardware input to trigger it int dummy; CARD16 powerlevel; BOOL enabled; if (DPMSQueryExtension(m_display, &dummy, &dummy) && DPMSCapable(m_display) && DPMSInfo(m_display, &powerlevel, &enabled)) { if (enabled && powerlevel != DPMSModeOn) DPMSForceLevel(m_display, DPMSModeOn); } #endif // unmap the hider/grab window. this also ungrabs the mouse and // keyboard if they're grabbed. XUnmapWindow(m_display, m_window); /* maybe call this if entering for the screensaver // set keyboard focus to root window. the screensaver should then // pick up key events for when the user enters a password to unlock. XSetInputFocus(m_display, PointerRoot, PointerRoot, CurrentTime); */ if (!m_isPrimary) { // get the keyboard control state XKeyboardState keyControl; XGetKeyboardControl(m_display, &keyControl); m_autoRepeat = (keyControl.global_auto_repeat == AutoRepeatModeOn); m_keyState->setAutoRepeat(keyControl); // turn off auto-repeat. we do this so fake key press events don't // cause the local server to generate their own auto-repeats of // those keys. //XAutoRepeatOff(m_display); } // now on screen m_isOnScreen = true; } bool XWindowsScreen::leave() { if (!m_isPrimary) { // restore the previous keyboard auto-repeat state. if the user // changed the auto-repeat configuration while on the client then // that state is lost. that's because we can't get notified by // the X server when the auto-repeat configuration is changed so // we can't track the desired configuration. if (m_autoRepeat) { //XAutoRepeatOn(m_display); } // move hider window under the cursor center XMoveWindow(m_display, m_window, m_xCenter, m_yCenter); } // raise and show the window XMapRaised(m_display, m_window); // grab the mouse and keyboard, if primary and possible if (m_isPrimary && !grabMouseAndKeyboard()) { XUnmapWindow(m_display, m_window); return false; } // save current focus XGetInputFocus(m_display, &m_lastFocus, &m_lastFocusRevert); // take focus if (m_isPrimary || !m_preserveFocus) { XSetInputFocus(m_display, m_window, RevertToPointerRoot, CurrentTime); } // now warp the mouse. we warp after showing the window so we're // guaranteed to get the mouse leave event and to prevent the // keyboard focus from changing under point-to-focus policies. if (m_isPrimary) { warpCursor(m_xCenter, m_yCenter); } else { fakeMouseMove(m_xCenter, m_yCenter); } // set input context focus to our window if (m_ic != NULL) { XmbResetIC(m_ic); XSetICFocus(m_ic); m_filtered.clear(); } // now off screen m_isOnScreen = false; return true; } bool XWindowsScreen::setClipboard(ClipboardID id, const IClipboard* clipboard) { // fail if we don't have the requested clipboard if (m_clipboard[id] == NULL) { return false; } // get the actual time. ICCCM does not allow CurrentTime. Time timestamp = XWindowsUtil::getCurrentTime( m_display, m_clipboard[id]->getWindow()); if (clipboard != NULL) { // save clipboard data return Clipboard::copy(m_clipboard[id], clipboard, timestamp); } else { // assert clipboard ownership if (!m_clipboard[id]->open(timestamp)) { return false; } m_clipboard[id]->empty(); m_clipboard[id]->close(); return true; } } void XWindowsScreen::checkClipboards() { // do nothing, we're always up to date } void XWindowsScreen::openScreensaver(bool notify) { m_screensaverNotify = notify; if (!m_screensaverNotify) { m_screensaver->disable(); } } void XWindowsScreen::closeScreensaver() { if (!m_screensaverNotify) { m_screensaver->enable(); } } void XWindowsScreen::screensaver(bool activate) { if (activate) { m_screensaver->activate(); } else { m_screensaver->deactivate(); } } void XWindowsScreen::resetOptions() { m_xtestIsXineramaUnaware = true; m_preserveFocus = false; } void XWindowsScreen::setOptions(const OptionsList& options) { for (UInt32 i = 0, n = options.size(); i < n; i += 2) { if (options[i] == kOptionXTestXineramaUnaware) { m_xtestIsXineramaUnaware = (options[i + 1] != 0); LOG((CLOG_DEBUG1 "XTest is Xinerama unaware %s", m_xtestIsXineramaUnaware ? "true" : "false")); } else if (options[i] == kOptionScreenPreserveFocus) { m_preserveFocus = (options[i + 1] != 0); LOG((CLOG_DEBUG1 "Preserve Focus = %s", m_preserveFocus ? "true" : "false")); } } } void XWindowsScreen::setSequenceNumber(UInt32 seqNum) { m_sequenceNumber = seqNum; } bool XWindowsScreen::isPrimary() const { return m_isPrimary; } void* XWindowsScreen::getEventTarget() const { return const_cast(this); } bool XWindowsScreen::getClipboard(ClipboardID id, IClipboard* clipboard) const { assert(clipboard != NULL); // fail if we don't have the requested clipboard if (m_clipboard[id] == NULL) { return false; } // get the actual time. ICCCM does not allow CurrentTime. Time timestamp = XWindowsUtil::getCurrentTime( m_display, m_clipboard[id]->getWindow()); // copy the clipboard return Clipboard::copy(clipboard, m_clipboard[id], timestamp); } void XWindowsScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { x = m_x; y = m_y; w = m_w; h = m_h; } void XWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const { Window root, window; int mx, my, xWindow, yWindow; unsigned int mask; if (XQueryPointer(m_display, m_root, &root, &window, &mx, &my, &xWindow, &yWindow, &mask)) { x = mx; y = my; } else { x = m_xCenter; y = m_yCenter; } } void XWindowsScreen::reconfigure(UInt32) { // do nothing } void XWindowsScreen::warpCursor(SInt32 x, SInt32 y) { // warp mouse warpCursorNoFlush(x, y); // remove all input events before and including warp XEvent event; while (XCheckMaskEvent(m_display, PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | KeymapStateMask, &event)) { // do nothing } // save position as last position m_xCursor = x; m_yCursor = y; } UInt32 XWindowsScreen::registerHotKey(KeyID key, KeyModifierMask mask) { // only allow certain modifiers if ((mask & ~(KeyModifierShift | KeyModifierControl | KeyModifierAlt | KeyModifierSuper)) != 0) { LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); return 0; } // fail if no keys if (key == kKeyNone && mask == 0) { return 0; } // convert to X unsigned int modifiers; if (!m_keyState->mapModifiersToX(mask, modifiers)) { // can't map all modifiers LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); return 0; } XWindowsKeyState::KeycodeList keycodes; m_keyState->mapKeyToKeycodes(key, keycodes); if (key != kKeyNone && keycodes.empty()) { // can't map key LOG((CLOG_DEBUG "could not map hotkey id=%04x mask=%04x", key, mask)); return 0; } // choose hotkey id UInt32 id; if (!m_oldHotKeyIDs.empty()) { id = m_oldHotKeyIDs.back(); m_oldHotKeyIDs.pop_back(); } else { id = m_hotKeys.size() + 1; } HotKeyList& hotKeys = m_hotKeys[id]; // all modifier hotkey must be treated specially. for each modifier // we need to grab the modifier key in combination with all the other // requested modifiers. bool err = false; { XWindowsUtil::ErrorLock lock(m_display, &err); if (key == kKeyNone) { static const KeyModifierMask s_hotKeyModifiers[] = { KeyModifierShift, KeyModifierControl, KeyModifierAlt, KeyModifierMeta, KeyModifierSuper }; XModifierKeymap* modKeymap = XGetModifierMapping(m_display); for (size_t j = 0; j < sizeof(s_hotKeyModifiers) / sizeof(s_hotKeyModifiers[0]) && !err; ++j) { // skip modifier if not in mask if ((mask & s_hotKeyModifiers[j]) == 0) { continue; } // skip with error if we can't map remaining modifiers unsigned int modifiers2; KeyModifierMask mask2 = (mask & ~s_hotKeyModifiers[j]); if (!m_keyState->mapModifiersToX(mask2, modifiers2)) { err = true; continue; } // compute modifier index for modifier. there should be // exactly one X modifier missing int index; switch (modifiers ^ modifiers2) { case ShiftMask: index = ShiftMapIndex; break; case LockMask: index = LockMapIndex; break; case ControlMask: index = ControlMapIndex; break; case Mod1Mask: index = Mod1MapIndex; break; case Mod2Mask: index = Mod2MapIndex; break; case Mod3Mask: index = Mod3MapIndex; break; case Mod4Mask: index = Mod4MapIndex; break; case Mod5Mask: index = Mod5MapIndex; break; default: err = true; continue; } // grab each key for the modifier const KeyCode* modifiermap = modKeymap->modifiermap + index * modKeymap->max_keypermod; for (int k = 0; k < modKeymap->max_keypermod && !err; ++k) { KeyCode code = modifiermap[k]; if (modifiermap[k] != 0) { XGrabKey(m_display, code, modifiers2, m_root, False, GrabModeAsync, GrabModeAsync); if (!err) { hotKeys.push_back(std::make_pair(code, modifiers2)); m_hotKeyToIDMap[HotKeyItem(code, modifiers2)] = id; } } } } XFreeModifiermap(modKeymap); } // a non-modifier key must be insensitive to CapsLock, NumLock and // ScrollLock, so we have to grab the key with every combination of // those. else { // collect available toggle modifiers unsigned int modifier; unsigned int toggleModifiers[3]; size_t numToggleModifiers = 0; if (m_keyState->mapModifiersToX(KeyModifierCapsLock, modifier)) { toggleModifiers[numToggleModifiers++] = modifier; } if (m_keyState->mapModifiersToX(KeyModifierNumLock, modifier)) { toggleModifiers[numToggleModifiers++] = modifier; } if (m_keyState->mapModifiersToX(KeyModifierScrollLock, modifier)) { toggleModifiers[numToggleModifiers++] = modifier; } for (XWindowsKeyState::KeycodeList::iterator j = keycodes.begin(); j != keycodes.end() && !err; ++j) { for (size_t i = 0; i < (1u << numToggleModifiers); ++i) { // add toggle modifiers for index i unsigned int tmpModifiers = modifiers; if ((i & 1) != 0) { tmpModifiers |= toggleModifiers[0]; } if ((i & 2) != 0) { tmpModifiers |= toggleModifiers[1]; } if ((i & 4) != 0) { tmpModifiers |= toggleModifiers[2]; } // add grab XGrabKey(m_display, *j, tmpModifiers, m_root, False, GrabModeAsync, GrabModeAsync); if (!err) { hotKeys.push_back(std::make_pair(*j, tmpModifiers)); m_hotKeyToIDMap[HotKeyItem(*j, tmpModifiers)] = id; } } } } } if (err) { // if any failed then unregister any we did get for (HotKeyList::iterator j = hotKeys.begin(); j != hotKeys.end(); ++j) { XUngrabKey(m_display, j->first, j->second, m_root); m_hotKeyToIDMap.erase(HotKeyItem(j->first, j->second)); } m_oldHotKeyIDs.push_back(id); m_hotKeys.erase(id); LOG((CLOG_WARN "failed to register hotkey %s (id=%04x mask=%04x)", synergy::KeyMap::formatKey(key, mask).c_str(), key, mask)); return 0; } LOG((CLOG_DEBUG "registered hotkey %s (id=%04x mask=%04x) as id=%d", synergy::KeyMap::formatKey(key, mask).c_str(), key, mask, id)); return id; } void XWindowsScreen::unregisterHotKey(UInt32 id) { // look up hotkey HotKeyMap::iterator i = m_hotKeys.find(id); if (i == m_hotKeys.end()) { return; } // unregister with OS bool err = false; { XWindowsUtil::ErrorLock lock(m_display, &err); HotKeyList& hotKeys = i->second; for (HotKeyList::iterator j = hotKeys.begin(); j != hotKeys.end(); ++j) { XUngrabKey(m_display, j->first, j->second, m_root); m_hotKeyToIDMap.erase(HotKeyItem(j->first, j->second)); } } if (err) { LOG((CLOG_WARN "failed to unregister hotkey id=%d", id)); } else { LOG((CLOG_DEBUG "unregistered hotkey id=%d", id)); } // discard hot key from map and record old id for reuse m_hotKeys.erase(i); m_oldHotKeyIDs.push_back(id); } void XWindowsScreen::fakeInputBegin() { // FIXME -- not implemented } void XWindowsScreen::fakeInputEnd() { // FIXME -- not implemented } SInt32 XWindowsScreen::getJumpZoneSize() const { return 1; } bool XWindowsScreen::isAnyMouseButtonDown(UInt32& buttonID) const { // query the pointer to get the button state Window root, window; int xRoot, yRoot, xWindow, yWindow; unsigned int state; if (XQueryPointer(m_display, m_root, &root, &window, &xRoot, &yRoot, &xWindow, &yWindow, &state)) { return ((state & (Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask)) != 0); } return false; } void XWindowsScreen::getCursorCenter(SInt32& x, SInt32& y) const { x = m_xCenter; y = m_yCenter; } void XWindowsScreen::fakeMouseButton(ButtonID button, bool press) { const unsigned int xButton = mapButtonToX(button); if (xButton > 0 && xButton < 11) { XTestFakeButtonEvent(m_display, xButton, press ? True : False, CurrentTime); XFlush(m_display); } } void XWindowsScreen::fakeMouseMove(SInt32 x, SInt32 y) { if (m_xinerama && m_xtestIsXineramaUnaware) { XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y); } else { XTestFakeMotionEvent(m_display, DefaultScreen(m_display), x, y, CurrentTime); } XFlush(m_display); } void XWindowsScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const { // FIXME -- ignore xinerama for now if (false && m_xinerama && m_xtestIsXineramaUnaware) { // XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y); } else { XTestFakeRelativeMotionEvent(m_display, dx, dy, CurrentTime); } XFlush(m_display); } void XWindowsScreen::fakeMouseWheel(SInt32, SInt32 yDelta) const { // XXX -- support x-axis scrolling if (yDelta == 0) { return; } // choose button depending on rotation direction const unsigned int xButton = mapButtonToX(static_cast( (yDelta >= 0) ? -1 : -2)); if (xButton == 0) { // If we get here, then the XServer does not support the scroll // wheel buttons, so send PageUp/PageDown keystrokes instead. // Patch by Tom Chadwick. KeyCode keycode = 0; if (yDelta >= 0) { keycode = XKeysymToKeycode(m_display, XK_Page_Up); } else { keycode = XKeysymToKeycode(m_display, XK_Page_Down); } if (keycode != 0) { XTestFakeKeyEvent(m_display, keycode, True, CurrentTime); XTestFakeKeyEvent(m_display, keycode, False, CurrentTime); } return; } // now use absolute value of delta if (yDelta < 0) { yDelta = -yDelta; } if (yDelta < m_mouseScrollDelta) { LOG((CLOG_WARN "Wheel scroll delta (%d) smaller than threshold (%d)", yDelta, m_mouseScrollDelta)); } // send as many clicks as necessary for (; yDelta >= m_mouseScrollDelta; yDelta -= m_mouseScrollDelta) { XTestFakeButtonEvent(m_display, xButton, True, CurrentTime); XTestFakeButtonEvent(m_display, xButton, False, CurrentTime); } XFlush(m_display); } Display* XWindowsScreen::openDisplay(const char* displayName) { // get the DISPLAY if (displayName == NULL) { displayName = getenv("DISPLAY"); if (displayName == NULL) { displayName = ":0.0"; } } // open the display LOG((CLOG_DEBUG "XOpenDisplay(\"%s\")", displayName)); Display* display = XOpenDisplay(displayName); if (display == NULL) { throw XScreenUnavailable(60.0); } // verify the availability of the XTest extension if (!m_isPrimary) { int majorOpcode, firstEvent, firstError; if (!XQueryExtension(display, XTestExtensionName, &majorOpcode, &firstEvent, &firstError)) { LOG((CLOG_ERR "XTEST extension not available")); XCloseDisplay(display); throw XScreenOpenFailure(); } } #if HAVE_XKB_EXTENSION { m_xkb = false; int major = XkbMajorVersion, minor = XkbMinorVersion; if (XkbLibraryVersion(&major, &minor)) { int opcode, firstError; if (XkbQueryExtension(display, &opcode, &m_xkbEventBase, &firstError, &major, &minor)) { m_xkb = true; XkbSelectEvents(display, XkbUseCoreKbd, XkbMapNotifyMask, XkbMapNotifyMask); XkbSelectEventDetails(display, XkbUseCoreKbd, XkbStateNotifyMask, XkbGroupStateMask, XkbGroupStateMask); } } } #endif #if HAVE_X11_EXTENSIONS_XRANDR_H // query for XRandR extension int dummyError; m_xrandr = XRRQueryExtension(display, &m_xrandrEventBase, &dummyError); if (m_xrandr) { // enable XRRScreenChangeNotifyEvent XRRSelectInput(display, DefaultRootWindow(display), RRScreenChangeNotifyMask | RRCrtcChangeNotifyMask); } #endif return display; } void XWindowsScreen::saveShape() { // get shape of default screen m_x = 0; m_y = 0; m_w = WidthOfScreen(DefaultScreenOfDisplay(m_display)); m_h = HeightOfScreen(DefaultScreenOfDisplay(m_display)); // get center of default screen m_xCenter = m_x + (m_w >> 1); m_yCenter = m_y + (m_h >> 1); // check if xinerama is enabled and there is more than one screen. // get center of first Xinerama screen. Xinerama appears to have // a bug when XWarpPointer() is used in combination with // XGrabPointer(). in that case, the warp is successful but the // next pointer motion warps the pointer again, apparently to // constrain it to some unknown region, possibly the region from // 0,0 to Wm,Hm where Wm (Hm) is the minimum width (height) over // all physical screens. this warp only seems to happen if the // pointer wasn't in that region before the XWarpPointer(). the // second (unexpected) warp causes synergy to think the pointer // has been moved when it hasn't. to work around the problem, // we warp the pointer to the center of the first physical // screen instead of the logical screen. m_xinerama = false; #if HAVE_X11_EXTENSIONS_XINERAMA_H int eventBase, errorBase; if (XineramaQueryExtension(m_display, &eventBase, &errorBase) && XineramaIsActive(m_display)) { int numScreens; XineramaScreenInfo* screens; screens = XineramaQueryScreens(m_display, &numScreens); if (screens != NULL) { if (numScreens > 1) { m_xinerama = true; m_xCenter = screens[0].x_org + (screens[0].width >> 1); m_yCenter = screens[0].y_org + (screens[0].height >> 1); } XFree(screens); } } #endif } Window XWindowsScreen::openWindow() const { // default window attributes. we don't want the window manager // messing with our window and we don't want the cursor to be // visible inside the window. XSetWindowAttributes attr; attr.do_not_propagate_mask = 0; attr.override_redirect = True; attr.cursor = createBlankCursor(); // adjust attributes and get size and shape SInt32 x, y, w, h; if (m_isPrimary) { // grab window attributes. this window is used to capture user // input when the user is focused on another client. it covers // the whole screen. attr.event_mask = PointerMotionMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | KeymapStateMask | PropertyChangeMask; x = m_x; y = m_y; w = m_w; h = m_h; } else { // cursor hider window attributes. this window is used to hide the // cursor when it's not on the screen. the window is hidden as soon // as the cursor enters the screen or the display's real mouse is // moved. we'll reposition the window as necessary so its // position here doesn't matter. it only needs to be 1x1 because // it only needs to contain the cursor's hotspot. attr.event_mask = LeaveWindowMask; x = 0; y = 0; w = 1; h = 1; } // create and return the window Window window = XCreateWindow(m_display, m_root, x, y, w, h, 0, 0, InputOnly, CopyFromParent, CWDontPropagate | CWEventMask | CWOverrideRedirect | CWCursor, &attr); if (window == None) { throw XScreenOpenFailure(); } return window; } void XWindowsScreen::openIM() { // open the input methods XIM im = XOpenIM(m_display, NULL, NULL, NULL); if (im == NULL) { LOG((CLOG_INFO "no support for IM")); return; } // find the appropriate style. synergy supports XIMPreeditNothing // only at the moment. XIMStyles* styles; if (XGetIMValues(im, XNQueryInputStyle, &styles, NULL) != NULL || styles == NULL) { LOG((CLOG_WARN "cannot get IM styles")); XCloseIM(im); return; } XIMStyle style = 0; for (unsigned short i = 0; i < styles->count_styles; ++i) { style = styles->supported_styles[i]; if ((style & XIMPreeditNothing) != 0) { if ((style & (XIMStatusNothing | XIMStatusNone)) != 0) { break; } } } XFree(styles); if (style == 0) { LOG((CLOG_INFO "no supported IM styles")); XCloseIM(im); return; } // create an input context for the style and tell it about our window XIC ic = XCreateIC(im, XNInputStyle, style, XNClientWindow, m_window, NULL); if (ic == NULL) { LOG((CLOG_WARN "cannot create IC")); XCloseIM(im); return; } // find out the events we must select for and do so unsigned long mask; if (XGetICValues(ic, XNFilterEvents, &mask, NULL) != NULL) { LOG((CLOG_WARN "cannot get IC filter events")); XDestroyIC(ic); XCloseIM(im); return; } // we have IM m_im = im; m_ic = ic; m_lastKeycode = 0; // select events on our window that IM requires XWindowAttributes attr; XGetWindowAttributes(m_display, m_window, &attr); XSelectInput(m_display, m_window, attr.your_event_mask | mask); } void XWindowsScreen::sendEvent(Event::Type type, void* data) { m_events->addEvent(Event(type, getEventTarget(), data)); } void XWindowsScreen::sendClipboardEvent(Event::Type type, ClipboardID id) { ClipboardInfo* info = (ClipboardInfo*)malloc(sizeof(ClipboardInfo)); info->m_id = id; info->m_sequenceNumber = m_sequenceNumber; sendEvent(type, info); } IKeyState* XWindowsScreen::getKeyState() const { return m_keyState; } Bool XWindowsScreen::findKeyEvent(Display*, XEvent* xevent, XPointer arg) { KeyEventFilter* filter = reinterpret_cast(arg); return (xevent->type == filter->m_event && xevent->xkey.window == filter->m_window && xevent->xkey.time == filter->m_time && xevent->xkey.keycode == filter->m_keycode) ? True : False; } void XWindowsScreen::handleSystemEvent(const Event& event, void*) { XEvent* xevent = static_cast(event.getData()); assert(xevent != NULL); // update key state bool isRepeat = false; if (m_isPrimary) { if (xevent->type == KeyRelease) { // check if this is a key repeat by getting the next // KeyPress event that has the same key and time as // this release event, if any. first prepare the // filter info. KeyEventFilter filter; filter.m_event = KeyPress; filter.m_window = xevent->xkey.window; filter.m_time = xevent->xkey.time; filter.m_keycode = xevent->xkey.keycode; XEvent xevent2; isRepeat = (XCheckIfEvent(m_display, &xevent2, &XWindowsScreen::findKeyEvent, (XPointer)&filter) == True); } if (xevent->type == KeyPress || xevent->type == KeyRelease) { if (xevent->xkey.window == m_root) { // this is a hot key onHotKey(xevent->xkey, isRepeat); return; } else if (!m_isOnScreen) { // this might be a hot key if (onHotKey(xevent->xkey, isRepeat)) { return; } } bool down = (isRepeat || xevent->type == KeyPress); KeyModifierMask state = m_keyState->mapModifiersFromX(xevent->xkey.state); m_keyState->onKey(xevent->xkey.keycode, down, state); } } // let input methods try to handle event first if (m_ic != NULL) { // XFilterEvent() may eat the event and generate a new KeyPress // event with a keycode of 0 because there isn't an actual key // associated with the keysym. but the KeyRelease may pass // through XFilterEvent() and keep its keycode. this means // there's a mismatch between KeyPress and KeyRelease keycodes. // since we use the keycode on the client to detect when a key // is released this won't do. so we remember the keycode on // the most recent KeyPress (and clear it on a matching // KeyRelease) so we have a keycode for a synthesized KeyPress. if (xevent->type == KeyPress && xevent->xkey.keycode != 0) { m_lastKeycode = xevent->xkey.keycode; } else if (xevent->type == KeyRelease && xevent->xkey.keycode == m_lastKeycode) { m_lastKeycode = 0; } // now filter the event if (XFilterEvent(xevent, DefaultRootWindow(m_display))) { if (xevent->type == KeyPress) { // add filtered presses to the filtered list m_filtered.insert(m_lastKeycode); } return; } // discard matching key releases for key presses that were // filtered and remove them from our filtered list. else if (xevent->type == KeyRelease && m_filtered.count(xevent->xkey.keycode) > 0) { m_filtered.erase(xevent->xkey.keycode); return; } } // let screen saver have a go if (m_screensaver->handleXEvent(xevent)) { // screen saver handled it return; } #ifdef HAVE_XI2 if (m_xi2detected) { // Process RawMotion XGenericEventCookie *cookie = (XGenericEventCookie*)&xevent->xcookie; if (XGetEventData(m_display, cookie) && cookie->type == GenericEvent && cookie->extension == xi_opcode) { if (cookie->evtype == XI_RawMotion) { // Get current pointer's position Window root, child; XMotionEvent xmotion; xmotion.type = MotionNotify; xmotion.send_event = False; // Raw motion xmotion.display = m_display; xmotion.window = m_window; /* xmotion's time, state and is_hint are not used */ unsigned int msk; xmotion.same_screen = XQueryPointer( m_display, m_root, &xmotion.root, &xmotion.subwindow, &xmotion.x_root, &xmotion.y_root, &xmotion.x, &xmotion.y, &msk); onMouseMove(xmotion); XFreeEventData(m_display, cookie); return; } XFreeEventData(m_display, cookie); } } #endif // handle the event ourself switch (xevent->type) { case CreateNotify: if (m_isPrimary && !m_xi2detected) { // select events on new window selectEvents(xevent->xcreatewindow.window); } break; case MappingNotify: refreshKeyboard(xevent); break; case LeaveNotify: if (!m_isPrimary) { // mouse moved out of hider window somehow. hide the window. XUnmapWindow(m_display, m_window); } break; case SelectionClear: { // we just lost the selection. that means someone else // grabbed the selection so this screen is now the // selection owner. report that to the receiver. ClipboardID id = getClipboardID(xevent->xselectionclear.selection); if (id != kClipboardEnd) { m_clipboard[id]->lost(xevent->xselectionclear.time); sendClipboardEvent(m_events->forClipboard().clipboardGrabbed(), id); return; } } break; case SelectionNotify: // notification of selection transferred. we shouldn't // get this here because we handle them in the selection // retrieval methods. we'll just delete the property // with the data (satisfying the usual ICCCM protocol). if (xevent->xselection.property != None) { XDeleteProperty(m_display, xevent->xselection.requestor, xevent->xselection.property); } break; case SelectionRequest: { // somebody is asking for clipboard data ClipboardID id = getClipboardID( xevent->xselectionrequest.selection); if (id != kClipboardEnd) { m_clipboard[id]->addRequest( xevent->xselectionrequest.owner, xevent->xselectionrequest.requestor, xevent->xselectionrequest.target, xevent->xselectionrequest.time, xevent->xselectionrequest.property); return; } } break; case PropertyNotify: // property delete may be part of a selection conversion if (xevent->xproperty.state == PropertyDelete) { processClipboardRequest(xevent->xproperty.window, xevent->xproperty.time, xevent->xproperty.atom); } break; case DestroyNotify: // looks like one of the windows that requested a clipboard // transfer has gone bye-bye. destroyClipboardRequest(xevent->xdestroywindow.window); break; case KeyPress: if (m_isPrimary) { onKeyPress(xevent->xkey); } return; case KeyRelease: if (m_isPrimary) { onKeyRelease(xevent->xkey, isRepeat); } return; case ButtonPress: if (m_isPrimary) { onMousePress(xevent->xbutton); } return; case ButtonRelease: if (m_isPrimary) { onMouseRelease(xevent->xbutton); } return; case MotionNotify: if (m_isPrimary) { onMouseMove(xevent->xmotion); } return; default: #if HAVE_XKB_EXTENSION if (m_xkb && xevent->type == m_xkbEventBase) { XkbEvent* xkbEvent = reinterpret_cast(xevent); switch (xkbEvent->any.xkb_type) { case XkbMapNotify: refreshKeyboard(xevent); return; case XkbStateNotify: LOG((CLOG_INFO "group change: %d", xkbEvent->state.group)); m_keyState->setActiveGroup((SInt32)xkbEvent->state.group); return; } } #endif #if HAVE_X11_EXTENSIONS_XRANDR_H if (m_xrandr) { if (xevent->type == m_xrandrEventBase + RRScreenChangeNotify || xevent->type == m_xrandrEventBase + RRNotify && reinterpret_cast(xevent)->subtype == RRNotify_CrtcChange) { LOG((CLOG_INFO "XRRScreenChangeNotifyEvent or RRNotify_CrtcChange received")); // we're required to call back into XLib so XLib can update its internal state XRRUpdateConfiguration(xevent); // requery/recalculate the screen shape saveShape(); // we need to resize m_window, otherwise we'll get a weird problem where moving // off the server onto the client causes the pointer to warp to the // center of the server (so you can't move the pointer off the server) if (m_isPrimary) { XMoveWindow(m_display, m_window, m_x, m_y); XResizeWindow(m_display, m_window, m_w, m_h); } sendEvent(m_events->forIScreen().shapeChanged()); } } #endif break; } } void XWindowsScreen::onKeyPress(XKeyEvent& xkey) { LOG((CLOG_DEBUG1 "event: KeyPress code=%d, state=0x%04x", xkey.keycode, xkey.state)); const KeyModifierMask mask = m_keyState->mapModifiersFromX(xkey.state); KeyID key = mapKeyFromX(&xkey); if (key != kKeyNone) { // check for ctrl+alt+del emulation if ((key == kKeyPause || key == kKeyBreak) && (mask & (KeyModifierControl | KeyModifierAlt)) == (KeyModifierControl | KeyModifierAlt)) { // pretend it's ctrl+alt+del LOG((CLOG_DEBUG "emulate ctrl+alt+del")); key = kKeyDelete; } // get which button. see call to XFilterEvent() in onEvent() // for more info. bool isFake = false; KeyButton keycode = static_cast(xkey.keycode); if (keycode == 0) { isFake = true; keycode = static_cast(m_lastKeycode); if (keycode == 0) { // no keycode LOG((CLOG_DEBUG1 "event: KeyPress no keycode")); return; } } // handle key m_keyState->sendKeyEvent(getEventTarget(), true, false, key, mask, 1, keycode); // do fake release if this is a fake press if (isFake) { m_keyState->sendKeyEvent(getEventTarget(), false, false, key, mask, 1, keycode); } } else { LOG((CLOG_DEBUG1 "can't map keycode to key id")); } } void XWindowsScreen::onKeyRelease(XKeyEvent& xkey, bool isRepeat) { const KeyModifierMask mask = m_keyState->mapModifiersFromX(xkey.state); KeyID key = mapKeyFromX(&xkey); if (key != kKeyNone) { // check for ctrl+alt+del emulation if ((key == kKeyPause || key == kKeyBreak) && (mask & (KeyModifierControl | KeyModifierAlt)) == (KeyModifierControl | KeyModifierAlt)) { // pretend it's ctrl+alt+del and ignore autorepeat LOG((CLOG_DEBUG "emulate ctrl+alt+del")); key = kKeyDelete; isRepeat = false; } KeyButton keycode = static_cast(xkey.keycode); if (!isRepeat) { // no press event follows so it's a plain release LOG((CLOG_DEBUG1 "event: KeyRelease code=%d, state=0x%04x", keycode, xkey.state)); m_keyState->sendKeyEvent(getEventTarget(), false, false, key, mask, 1, keycode); } else { // found a press event following so it's a repeat. // we could attempt to count the already queued // repeats but we'll just send a repeat of 1. // note that we discard the press event. LOG((CLOG_DEBUG1 "event: repeat code=%d, state=0x%04x", keycode, xkey.state)); m_keyState->sendKeyEvent(getEventTarget(), false, true, key, mask, 1, keycode); } } } bool XWindowsScreen::onHotKey(XKeyEvent& xkey, bool isRepeat) { // find the hot key id HotKeyToIDMap::const_iterator i = m_hotKeyToIDMap.find(HotKeyItem(xkey.keycode, xkey.state)); if (i == m_hotKeyToIDMap.end()) { return false; } // find what kind of event Event::Type type; if (xkey.type == KeyPress) { type = m_events->forIPrimaryScreen().hotKeyDown(); } else if (xkey.type == KeyRelease) { type = m_events->forIPrimaryScreen().hotKeyUp(); } else { return false; } // generate event (ignore key repeats) if (!isRepeat) { m_events->addEvent(Event(type, getEventTarget(), HotKeyInfo::alloc(i->second))); } return true; } void XWindowsScreen::onMousePress(const XButtonEvent& xbutton) { LOG((CLOG_DEBUG1 "event: ButtonPress button=%d", xbutton.button)); ButtonID button = mapButtonFromX(&xbutton); KeyModifierMask mask = m_keyState->mapModifiersFromX(xbutton.state); if (button != kButtonNone) { sendEvent(m_events->forIPrimaryScreen().buttonDown(), ButtonInfo::alloc(button, mask)); } } void XWindowsScreen::onMouseRelease(const XButtonEvent& xbutton) { LOG((CLOG_DEBUG1 "event: ButtonRelease button=%d", xbutton.button)); ButtonID button = mapButtonFromX(&xbutton); KeyModifierMask mask = m_keyState->mapModifiersFromX(xbutton.state); if (button != kButtonNone) { sendEvent(m_events->forIPrimaryScreen().buttonUp(), ButtonInfo::alloc(button, mask)); } else if (xbutton.button == 4) { // wheel forward (away from user) sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, 120)); } else if (xbutton.button == 5) { // wheel backward (toward user) sendEvent(m_events->forIPrimaryScreen().wheel(), WheelInfo::alloc(0, -120)); } // XXX -- support x-axis scrolling } void XWindowsScreen::onMouseMove(const XMotionEvent& xmotion) { LOG((CLOG_DEBUG2 "event: MotionNotify %d,%d", xmotion.x_root, xmotion.y_root)); // compute motion delta (relative to the last known // mouse position) SInt32 x = xmotion.x_root - m_xCursor; SInt32 y = xmotion.y_root - m_yCursor; // save position to compute delta of next motion m_xCursor = xmotion.x_root; m_yCursor = xmotion.y_root; if (xmotion.send_event) { // we warped the mouse. discard events until we // find the matching sent event. see // warpCursorNoFlush() for where the events are // sent. we discard the matching sent event and // can be sure we've skipped the warp event. XEvent xevent; char cntr = 0; do { XMaskEvent(m_display, PointerMotionMask, &xevent); if (cntr++ > 10) { LOG((CLOG_WARN "too many discarded events! %d", cntr)); break; } } while (!xevent.xany.send_event); cntr = 0; } else if (m_isOnScreen) { // motion on primary screen sendEvent(m_events->forIPrimaryScreen().motionOnPrimary(), MotionInfo::alloc(m_xCursor, m_yCursor)); } else { // motion on secondary screen. warp mouse back to // center. // // my lombard (powerbook g3) running linux and // using the adbmouse driver has two problems: // first, the driver only sends motions of +/-2 // pixels and, second, it seems to discard some // physical input after a warp. the former isn't a // big deal (we're just limited to every other // pixel) but the latter is a PITA. to work around // it we only warp when the mouse has moved more // than s_size pixels from the center. static const SInt32 s_size = 32; if (xmotion.x_root - m_xCenter < -s_size || xmotion.x_root - m_xCenter > s_size || xmotion.y_root - m_yCenter < -s_size || xmotion.y_root - m_yCenter > s_size) { warpCursorNoFlush(m_xCenter, m_yCenter); } // send event if mouse moved. do this after warping // back to center in case the motion takes us onto // the primary screen. if we sent the event first // in that case then the warp would happen after // warping to the primary screen's enter position, // effectively overriding it. if (x != 0 || y != 0) { sendEvent(m_events->forIPrimaryScreen().motionOnSecondary(), MotionInfo::alloc(x, y)); } } } Cursor XWindowsScreen::createBlankCursor() const { // this seems just a bit more complicated than really necessary // get the closet cursor size to 1x1 unsigned int w = 0, h = 0; XQueryBestCursor(m_display, m_root, 1, 1, &w, &h); w = std::max(1u, w); h = std::max(1u, h); // make bitmap data for cursor of closet size. since the cursor // is blank we can use the same bitmap for shape and mask: all // zeros. const int size = ((w + 7) >> 3) * h; char* data = new char[size]; memset(data, 0, size); // make bitmap Pixmap bitmap = XCreateBitmapFromData(m_display, m_root, data, w, h); // need an arbitrary color for the cursor XColor color; color.pixel = 0; color.red = color.green = color.blue = 0; color.flags = DoRed | DoGreen | DoBlue; // make cursor from bitmap Cursor cursor = XCreatePixmapCursor(m_display, bitmap, bitmap, &color, &color, 0, 0); // don't need bitmap or the data anymore delete[] data; XFreePixmap(m_display, bitmap); return cursor; } ClipboardID XWindowsScreen::getClipboardID(Atom selection) const { for (ClipboardID id = 0; id < kClipboardEnd; ++id) { if (m_clipboard[id] != NULL && m_clipboard[id]->getSelection() == selection) { return id; } } return kClipboardEnd; } void XWindowsScreen::processClipboardRequest(Window requestor, Time time, Atom property) { // check every clipboard until one returns success for (ClipboardID id = 0; id < kClipboardEnd; ++id) { if (m_clipboard[id] != NULL && m_clipboard[id]->processRequest(requestor, time, property)) { break; } } } void XWindowsScreen::destroyClipboardRequest(Window requestor) { // check every clipboard until one returns success for (ClipboardID id = 0; id < kClipboardEnd; ++id) { if (m_clipboard[id] != NULL && m_clipboard[id]->destroyRequest(requestor)) { break; } } } void XWindowsScreen::onError() { // prevent further access to the X display m_events->adoptBuffer(NULL); m_screensaver->destroy(); m_screensaver = NULL; m_display = NULL; // notify of failure sendEvent(m_events->forIScreen().error(), NULL); // FIXME -- should ensure that we ignore operations that involve // m_display from now on. however, Xlib will simply exit the // application in response to the X I/O error so there's no // point in trying to really handle the error. if we did want // to handle the error, it'd probably be easiest to delegate to // one of two objects. one object would take the implementation // from this class. the other object would be stub methods that // don't use X11. on error, we'd switch to the latter. } int XWindowsScreen::ioErrorHandler(Display*) { // the display has disconnected, probably because X is shutting // down. X forces us to exit at this point which is annoying. // we'll pretend as if we won't exit so we try to make sure we // don't access the display anymore. LOG((CLOG_CRIT "X display has unexpectedly disconnected")); s_screen->onError(); return 0; } void XWindowsScreen::selectEvents(Window w) const { // ignore errors while we adjust event masks. windows could be // destroyed at any time after the XQueryTree() in doSelectEvents() // so we must ignore BadWindow errors. XWindowsUtil::ErrorLock lock(m_display); // adjust event masks doSelectEvents(w); } void XWindowsScreen::doSelectEvents(Window w) const { // we want to track the mouse everywhere on the display. to achieve // that we select PointerMotionMask on every window. we also select // SubstructureNotifyMask in order to get CreateNotify events so we // select events on new windows too. // we don't want to adjust our grab window if (w == m_window) { return; } // X11 has a design flaw. If *no* client selected PointerMotionMask for // a window, motion events will be delivered to that window's parent. // If *any* client, not necessarily the owner, selects PointerMotionMask // on such a window, X will stop propagating motion events to its // parent. This breaks applications that rely on event propagation // behavior. // // Avoid selecting PointerMotionMask unless some other client selected // it already. long mask = SubstructureNotifyMask; XWindowAttributes attr; XGetWindowAttributes(m_display, w, &attr); if ((attr.all_event_masks & PointerMotionMask) == PointerMotionMask) { mask |= PointerMotionMask; } // select events of interest. do this before querying the tree so // we'll get notifications of children created after the XQueryTree() // so we won't miss them. XSelectInput(m_display, w, mask); // recurse on child windows Window rw, pw, *cw; unsigned int nc; if (XQueryTree(m_display, w, &rw, &pw, &cw, &nc)) { for (unsigned int i = 0; i < nc; ++i) { doSelectEvents(cw[i]); } XFree(cw); } } KeyID XWindowsScreen::mapKeyFromX(XKeyEvent* event) const { // convert to a keysym KeySym keysym; if (event->type == KeyPress && m_ic != NULL) { // do multibyte lookup. can only call XmbLookupString with a // key press event and a valid XIC so we checked those above. char scratch[32]; int n = sizeof(scratch) / sizeof(scratch[0]); char* buffer = scratch; int status; n = XmbLookupString(m_ic, event, buffer, n, &keysym, &status); if (status == XBufferOverflow) { // not enough space. grow buffer and try again. buffer = new char[n]; n = XmbLookupString(m_ic, event, buffer, n, &keysym, &status); delete[] buffer; } // see what we got. since we don't care about the string // we'll just look for a keysym. switch (status) { default: case XLookupNone: case XLookupChars: keysym = 0; break; case XLookupKeySym: case XLookupBoth: break; } } else { // plain old lookup char dummy[1]; XLookupString(event, dummy, 0, &keysym, NULL); } LOG((CLOG_DEBUG2 "mapped code=%d to keysym=0x%04x", event->keycode, keysym)); // convert key KeyID result = XWindowsUtil::mapKeySymToKeyID(keysym); LOG((CLOG_DEBUG2 "mapped keysym=0x%04x to keyID=%d", keysym, result)); return result; } ButtonID XWindowsScreen::mapButtonFromX(const XButtonEvent* event) const { unsigned int button = event->button; // first three buttons map to 1, 2, 3 (kButtonLeft, Middle, Right) if (button >= 1 && button <= 3) { return static_cast(button); } // buttons 4 and 5 are ignored here. they're used for the wheel. // buttons 6, 7, etc and up map to 4, 5, etc. else if (button >= 6) { return static_cast(button - 2); } // unknown button else { return kButtonNone; } } unsigned int XWindowsScreen::mapButtonToX(ButtonID id) const { // map button -1 to button 4 (+wheel) if (id == static_cast(-1)) { id = 4; } // map button -2 to button 5 (-wheel) else if (id == static_cast(-2)) { id = 5; } // map buttons 4, 5, etc. to 6, 7, etc. to make room for buttons // 4 and 5 used to simulate the mouse wheel. else if (id >= 4) { id += 2; } // check button is in legal range if (id < 1 || id > m_buttons.size()) { // out of range return 0; } // map button return static_cast(id); } void XWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y) { assert(m_window != None); // send an event that we can recognize before the mouse warp XEvent eventBefore; eventBefore.type = MotionNotify; eventBefore.xmotion.display = m_display; eventBefore.xmotion.window = m_window; eventBefore.xmotion.root = m_root; eventBefore.xmotion.subwindow = m_window; eventBefore.xmotion.time = CurrentTime; eventBefore.xmotion.x = x; eventBefore.xmotion.y = y; eventBefore.xmotion.x_root = x; eventBefore.xmotion.y_root = y; eventBefore.xmotion.state = 0; eventBefore.xmotion.is_hint = NotifyNormal; eventBefore.xmotion.same_screen = True; XEvent eventAfter = eventBefore; XSendEvent(m_display, m_window, False, 0, &eventBefore); // warp mouse XWarpPointer(m_display, None, m_root, 0, 0, 0, 0, x, y); // send an event that we can recognize after the mouse warp XSendEvent(m_display, m_window, False, 0, &eventAfter); XSync(m_display, False); LOG((CLOG_DEBUG2 "warped to %d,%d", x, y)); } void XWindowsScreen::updateButtons() { // query the button mapping UInt32 numButtons = XGetPointerMapping(m_display, NULL, 0); unsigned char* tmpButtons = new unsigned char[numButtons]; XGetPointerMapping(m_display, tmpButtons, numButtons); // find the largest logical button id unsigned char maxButton = 0; for (UInt32 i = 0; i < numButtons; ++i) { if (tmpButtons[i] > maxButton) { maxButton = tmpButtons[i]; } } // allocate button array m_buttons.resize(maxButton); // fill in button array values. m_buttons[i] is the physical // button number for logical button i+1. for (UInt32 i = 0; i < numButtons; ++i) { m_buttons[i] = 0; } for (UInt32 i = 0; i < numButtons; ++i) { m_buttons[tmpButtons[i] - 1] = i + 1; } // clean up delete[] tmpButtons; } bool XWindowsScreen::grabMouseAndKeyboard() { unsigned int event_mask = ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask; // grab the mouse and keyboard. keep trying until we get them. // if we can't grab one after grabbing the other then ungrab // and wait before retrying. give up after s_timeout seconds. static const double s_timeout = 1.0; int result; Stopwatch timer; do { // keyboard first do { result = XGrabKeyboard(m_display, m_window, True, GrabModeAsync, GrabModeAsync, CurrentTime); assert(result != GrabNotViewable); if (result != GrabSuccess) { LOG((CLOG_DEBUG2 "waiting to grab keyboard")); ARCH->sleep(0.05); if (timer.getTime() >= s_timeout) { LOG((CLOG_DEBUG2 "grab keyboard timed out")); return false; } } } while (result != GrabSuccess); LOG((CLOG_DEBUG2 "grabbed keyboard")); // now the mouse --- use event_mask to get EnterNotify, LeaveNotify events result = XGrabPointer(m_display, m_window, False, event_mask, GrabModeAsync, GrabModeAsync, m_window, None, CurrentTime); assert(result != GrabNotViewable); if (result != GrabSuccess) { // back off to avoid grab deadlock XUngrabKeyboard(m_display, CurrentTime); LOG((CLOG_DEBUG2 "ungrabbed keyboard, waiting to grab pointer")); ARCH->sleep(0.05); if (timer.getTime() >= s_timeout) { LOG((CLOG_DEBUG2 "grab pointer timed out")); return false; } } } while (result != GrabSuccess); LOG((CLOG_DEBUG1 "grabbed pointer and keyboard")); return true; } void XWindowsScreen::refreshKeyboard(XEvent* event) { if (XPending(m_display) > 0) { XEvent tmpEvent; XPeekEvent(m_display, &tmpEvent); if (tmpEvent.type == MappingNotify) { // discard this event since another follows. // we tend to get a bunch of these in a row. return; } } // keyboard mapping changed #if HAVE_XKB_EXTENSION if (m_xkb && event->type == m_xkbEventBase) { XkbRefreshKeyboardMapping((XkbMapNotifyEvent*)event); } else #else { XRefreshKeyboardMapping(&event->xmapping); } #endif m_keyState->updateKeyMap(); m_keyState->updateKeyState(); } // // XWindowsScreen::HotKeyItem // XWindowsScreen::HotKeyItem::HotKeyItem(int keycode, unsigned int mask) : m_keycode(keycode), m_mask(mask) { // do nothing } bool XWindowsScreen::HotKeyItem::operator<(const HotKeyItem& x) const { return (m_keycode < x.m_keycode || (m_keycode == x.m_keycode && m_mask < x.m_mask)); } bool XWindowsScreen::detectXI2() { int event, error; return XQueryExtension(m_display, "XInputExtension", &xi_opcode, &event, &error); } #ifdef HAVE_XI2 void XWindowsScreen::selectXIRawMotion() { XIEventMask mask; mask.deviceid = XIAllDevices; mask.mask_len = XIMaskLen(XI_RawMotion); mask.mask = (unsigned char*)calloc(mask.mask_len, sizeof(char)); mask.deviceid = XIAllMasterDevices; memset(mask.mask, 0, 2); XISetMask(mask.mask, XI_RawKeyRelease); XISetMask(mask.mask, XI_RawMotion); XISelectEvents(m_display, DefaultRootWindow(m_display), &mask, 1); free(mask.mask); } #endif synergy-1.8.8-stable/src/lib/platform/XWindowsScreen.h000066400000000000000000000156171305627404700227760ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/PlatformScreen.h" #include "synergy/KeyMap.h" #include "common/stdset.h" #include "common/stdvector.h" #if X_DISPLAY_MISSING # error X11 is required to build synergy #else # include #endif class XWindowsClipboard; class XWindowsKeyState; class XWindowsScreenSaver; //! Implementation of IPlatformScreen for X11 class XWindowsScreen : public PlatformScreen { public: XWindowsScreen(const char* displayName, bool isPrimary, bool disableXInitThreads, int mouseScrollDelta, IEventQueue* events); virtual ~XWindowsScreen(); //! @name manipulators //@{ //@} // IScreen overrides virtual void* getEventTarget() const; virtual bool getClipboard(ClipboardID id, IClipboard*) const; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const; virtual void getCursorPos(SInt32& x, SInt32& y) const; // IPrimaryScreen overrides virtual void reconfigure(UInt32 activeSides); virtual void warpCursor(SInt32 x, SInt32 y); virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); virtual void unregisterHotKey(UInt32 id); virtual void fakeInputBegin(); virtual void fakeInputEnd(); virtual SInt32 getJumpZoneSize() const; virtual bool isAnyMouseButtonDown(UInt32& buttonID) const; virtual void getCursorCenter(SInt32& x, SInt32& y) const; // ISecondaryScreen overrides virtual void fakeMouseButton(ButtonID id, bool press); virtual void fakeMouseMove(SInt32 x, SInt32 y); virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const; // IPlatformScreen overrides virtual void enable(); virtual void disable(); virtual void enter(); virtual bool leave(); virtual bool setClipboard(ClipboardID, const IClipboard*); virtual void checkClipboards(); virtual void openScreensaver(bool notify); virtual void closeScreensaver(); virtual void screensaver(bool activate); virtual void resetOptions(); virtual void setOptions(const OptionsList& options); virtual void setSequenceNumber(UInt32); virtual bool isPrimary() const; protected: // IPlatformScreen overrides virtual void handleSystemEvent(const Event&, void*); virtual void updateButtons(); virtual IKeyState* getKeyState() const; private: // event sending void sendEvent(Event::Type, void* = NULL); void sendClipboardEvent(Event::Type, ClipboardID); // create the transparent cursor Cursor createBlankCursor() const; // determine the clipboard from the X selection. returns // kClipboardEnd if no such clipboard. ClipboardID getClipboardID(Atom selection) const; // continue processing a selection request void processClipboardRequest(Window window, Time time, Atom property); // terminate a selection request void destroyClipboardRequest(Window window); // X I/O error handler void onError(); static int ioErrorHandler(Display*); private: class KeyEventFilter { public: int m_event; Window m_window; Time m_time; KeyCode m_keycode; }; Display* openDisplay(const char* displayName); void saveShape(); Window openWindow() const; void openIM(); bool grabMouseAndKeyboard(); void onKeyPress(XKeyEvent&); void onKeyRelease(XKeyEvent&, bool isRepeat); bool onHotKey(XKeyEvent&, bool isRepeat); void onMousePress(const XButtonEvent&); void onMouseRelease(const XButtonEvent&); void onMouseMove(const XMotionEvent&); bool detectXI2(); #ifdef HAVE_XI2 void selectXIRawMotion(); #endif void selectEvents(Window) const; void doSelectEvents(Window) const; KeyID mapKeyFromX(XKeyEvent*) const; ButtonID mapButtonFromX(const XButtonEvent*) const; unsigned int mapButtonToX(ButtonID id) const; void warpCursorNoFlush(SInt32 x, SInt32 y); void refreshKeyboard(XEvent*); static Bool findKeyEvent(Display*, XEvent* xevent, XPointer arg); private: struct HotKeyItem { public: HotKeyItem(int, unsigned int); bool operator<(const HotKeyItem&) const; private: int m_keycode; unsigned int m_mask; }; typedef std::set FilteredKeycodes; typedef std::vector > HotKeyList; typedef std::map HotKeyMap; typedef std::vector HotKeyIDList; typedef std::map HotKeyToIDMap; // true if screen is being used as a primary screen, false otherwise bool m_isPrimary; int m_mouseScrollDelta; Display* m_display; Window m_root; Window m_window; // true if mouse has entered the screen bool m_isOnScreen; // screen shape stuff SInt32 m_x, m_y; SInt32 m_w, m_h; SInt32 m_xCenter, m_yCenter; // last mouse position SInt32 m_xCursor, m_yCursor; // keyboard stuff XWindowsKeyState* m_keyState; // hot key stuff HotKeyMap m_hotKeys; HotKeyIDList m_oldHotKeyIDs; HotKeyToIDMap m_hotKeyToIDMap; // input focus stuff Window m_lastFocus; int m_lastFocusRevert; // input method stuff XIM m_im; XIC m_ic; KeyCode m_lastKeycode; FilteredKeycodes m_filtered; // clipboards XWindowsClipboard* m_clipboard[kClipboardEnd]; UInt32 m_sequenceNumber; // screen saver stuff XWindowsScreenSaver* m_screensaver; bool m_screensaverNotify; // logical to physical button mapping. m_buttons[i] gives the // physical button for logical button i+1. std::vector m_buttons; // true if global auto-repeat was enabled before we turned it off bool m_autoRepeat; // stuff to workaround xtest being xinerama unaware. attempting // to fake a mouse motion under xinerama may behave strangely, // especially if screen 0 is not at 0,0 or if faking a motion on // a screen other than screen 0. bool m_xtestIsXineramaUnaware; bool m_xinerama; // stuff to work around lost focus issues on certain systems // (ie: a MythTV front-end). bool m_preserveFocus; // XKB extension stuff bool m_xkb; int m_xkbEventBase; bool m_xi2detected; // XRandR extension stuff bool m_xrandr; int m_xrandrEventBase; IEventQueue* m_events; synergy::KeyMap m_keyMap; // pointer to (singleton) screen. this is only needed by // ioErrorHandler(). static XWindowsScreen* s_screen; }; synergy-1.8.8-stable/src/lib/platform/XWindowsScreenSaver.cpp000066400000000000000000000347431305627404700243330ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsScreenSaver.h" #include "platform/XWindowsUtil.h" #include "synergy/IPlatformScreen.h" #include "base/Log.h" #include "base/Event.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include #if HAVE_X11_EXTENSIONS_XTEST_H # include #else # error The XTest extension is required to build synergy #endif #if HAVE_X11_EXTENSIONS_DPMS_H extern "C" { # include # include # if !HAVE_DPMS_PROTOTYPES # undef DPMSModeOn # undef DPMSModeStandby # undef DPMSModeSuspend # undef DPMSModeOff # define DPMSModeOn 0 # define DPMSModeStandby 1 # define DPMSModeSuspend 2 # define DPMSModeOff 3 extern Bool DPMSQueryExtension(Display *, int *, int *); extern Bool DPMSCapable(Display *); extern Status DPMSEnable(Display *); extern Status DPMSDisable(Display *); extern Status DPMSForceLevel(Display *, CARD16); extern Status DPMSInfo(Display *, CARD16 *, BOOL *); # endif } #endif // // XWindowsScreenSaver // XWindowsScreenSaver::XWindowsScreenSaver( Display* display, Window window, void* eventTarget, IEventQueue* events) : m_display(display), m_xscreensaverSink(window), m_eventTarget(eventTarget), m_xscreensaver(None), m_xscreensaverActive(false), m_dpms(false), m_disabled(false), m_suppressDisable(false), m_disableTimer(NULL), m_disablePos(0), m_events(events) { // get atoms m_atomScreenSaver = XInternAtom(m_display, "SCREENSAVER", False); m_atomScreenSaverVersion = XInternAtom(m_display, "_SCREENSAVER_VERSION", False); m_atomScreenSaverActivate = XInternAtom(m_display, "ACTIVATE", False); m_atomScreenSaverDeactivate = XInternAtom(m_display, "DEACTIVATE", False); // check for DPMS extension. this is an alternative screen saver // that powers down the display. #if HAVE_X11_EXTENSIONS_DPMS_H int eventBase, errorBase; if (DPMSQueryExtension(m_display, &eventBase, &errorBase)) { if (DPMSCapable(m_display)) { // we have DPMS m_dpms = true; } } #endif // watch top-level windows for changes bool error = false; { XWindowsUtil::ErrorLock lock(m_display, &error); Window root = DefaultRootWindow(m_display); XWindowAttributes attr; XGetWindowAttributes(m_display, root, &attr); m_rootEventMask = attr.your_event_mask; XSelectInput(m_display, root, m_rootEventMask | SubstructureNotifyMask); } if (error) { LOG((CLOG_DEBUG "didn't set root event mask")); m_rootEventMask = 0; } // get the built-in settings XGetScreenSaver(m_display, &m_timeout, &m_interval, &m_preferBlanking, &m_allowExposures); // get the DPMS settings m_dpmsEnabled = isDPMSEnabled(); // get the xscreensaver window, if any if (!findXScreenSaver()) { setXScreenSaver(None); } // install disable timer event handler m_events->adoptHandler(Event::kTimer, this, new TMethodEventJob(this, &XWindowsScreenSaver::handleDisableTimer)); } XWindowsScreenSaver::~XWindowsScreenSaver() { // done with disable job if (m_disableTimer != NULL) { m_events->deleteTimer(m_disableTimer); } m_events->removeHandler(Event::kTimer, this); if (m_display != NULL) { enableDPMS(m_dpmsEnabled); XSetScreenSaver(m_display, m_timeout, m_interval, m_preferBlanking, m_allowExposures); clearWatchForXScreenSaver(); XWindowsUtil::ErrorLock lock(m_display); XSelectInput(m_display, DefaultRootWindow(m_display), m_rootEventMask); } } void XWindowsScreenSaver::destroy() { m_display = NULL; delete this; } bool XWindowsScreenSaver::handleXEvent(const XEvent* xevent) { switch (xevent->type) { case CreateNotify: if (m_xscreensaver == None) { if (isXScreenSaver(xevent->xcreatewindow.window)) { // found the xscreensaver setXScreenSaver(xevent->xcreatewindow.window); } else { // another window to watch. to detect the xscreensaver // window we look for a property but that property may // not yet exist by the time we get this event so we // have to watch the window for property changes. // this would be so much easier if xscreensaver did the // smart thing and stored its window in a property on // the root window. addWatchXScreenSaver(xevent->xcreatewindow.window); } } break; case DestroyNotify: if (xevent->xdestroywindow.window == m_xscreensaver) { // xscreensaver is gone LOG((CLOG_DEBUG "xscreensaver died")); setXScreenSaver(None); return true; } break; case PropertyNotify: if (xevent->xproperty.state == PropertyNewValue) { if (isXScreenSaver(xevent->xproperty.window)) { // found the xscreensaver setXScreenSaver(xevent->xcreatewindow.window); } } break; case MapNotify: if (xevent->xmap.window == m_xscreensaver) { // xscreensaver has activated setXScreenSaverActive(true); return true; } break; case UnmapNotify: if (xevent->xunmap.window == m_xscreensaver) { // xscreensaver has deactivated setXScreenSaverActive(false); return true; } break; } return false; } void XWindowsScreenSaver::enable() { // for xscreensaver m_disabled = false; updateDisableTimer(); // for built-in X screen saver XSetScreenSaver(m_display, m_timeout, m_interval, m_preferBlanking, m_allowExposures); // for DPMS enableDPMS(m_dpmsEnabled); } void XWindowsScreenSaver::disable() { // for xscreensaver m_disabled = true; updateDisableTimer(); // use built-in X screen saver XGetScreenSaver(m_display, &m_timeout, &m_interval, &m_preferBlanking, &m_allowExposures); XSetScreenSaver(m_display, 0, m_interval, m_preferBlanking, m_allowExposures); // for DPMS m_dpmsEnabled = isDPMSEnabled(); enableDPMS(false); // FIXME -- now deactivate? } void XWindowsScreenSaver::activate() { // remove disable job timer m_suppressDisable = true; updateDisableTimer(); // enable DPMS if it was enabled enableDPMS(m_dpmsEnabled); // try xscreensaver findXScreenSaver(); if (m_xscreensaver != None) { sendXScreenSaverCommand(m_atomScreenSaverActivate); return; } // try built-in X screen saver if (m_timeout != 0) { XForceScreenSaver(m_display, ScreenSaverActive); } // try DPMS activateDPMS(true); } void XWindowsScreenSaver::deactivate() { // reinstall disable job timer m_suppressDisable = false; updateDisableTimer(); // try DPMS activateDPMS(false); // disable DPMS if screen saver is disabled if (m_disabled) { enableDPMS(false); } // try xscreensaver findXScreenSaver(); if (m_xscreensaver != None) { sendXScreenSaverCommand(m_atomScreenSaverDeactivate); return; } // use built-in X screen saver XForceScreenSaver(m_display, ScreenSaverReset); } bool XWindowsScreenSaver::isActive() const { // check xscreensaver if (m_xscreensaver != None) { return m_xscreensaverActive; } // check DPMS if (isDPMSActivated()) { return true; } // can't check built-in X screen saver activity return false; } bool XWindowsScreenSaver::findXScreenSaver() { // do nothing if we've already got the xscreensaver window if (m_xscreensaver == None) { // find top-level window xscreensaver window Window root = DefaultRootWindow(m_display); Window rw, pw, *cw; unsigned int nc; if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) { for (unsigned int i = 0; i < nc; ++i) { if (isXScreenSaver(cw[i])) { setXScreenSaver(cw[i]); break; } } XFree(cw); } } return (m_xscreensaver != None); } void XWindowsScreenSaver::setXScreenSaver(Window window) { LOG((CLOG_DEBUG "xscreensaver window: 0x%08x", window)); // save window m_xscreensaver = window; if (m_xscreensaver != None) { // clear old watch list clearWatchForXScreenSaver(); // see if xscreensaver is active bool error = false; XWindowAttributes attr; { XWindowsUtil::ErrorLock lock(m_display, &error); XGetWindowAttributes(m_display, m_xscreensaver, &attr); } setXScreenSaverActive(!error && attr.map_state != IsUnmapped); // save current DPMS state; xscreensaver may have changed it. m_dpmsEnabled = isDPMSEnabled(); } else { // screen saver can't be active if it doesn't exist setXScreenSaverActive(false); // start watching for xscreensaver watchForXScreenSaver(); } } bool XWindowsScreenSaver::isXScreenSaver(Window w) const { // check for m_atomScreenSaverVersion string property Atom type; return (XWindowsUtil::getWindowProperty(m_display, w, m_atomScreenSaverVersion, NULL, &type, NULL, False) && type == XA_STRING); } void XWindowsScreenSaver::setXScreenSaverActive(bool activated) { if (m_xscreensaverActive != activated) { LOG((CLOG_DEBUG "xscreensaver %s on window 0x%08x", activated ? "activated" : "deactivated", m_xscreensaver)); m_xscreensaverActive = activated; // if screen saver was activated forcefully (i.e. against // our will) then just accept it. don't try to keep it // from activating since that'll just pop up the password // dialog if locking is enabled. m_suppressDisable = activated; updateDisableTimer(); if (activated) { m_events->addEvent(Event( m_events->forIPrimaryScreen().screensaverActivated(), m_eventTarget)); } else { m_events->addEvent(Event( m_events->forIPrimaryScreen().screensaverDeactivated(), m_eventTarget)); } } } void XWindowsScreenSaver::sendXScreenSaverCommand(Atom cmd, long arg1, long arg2) { XEvent event; event.xclient.type = ClientMessage; event.xclient.display = m_display; event.xclient.window = m_xscreensaverSink; event.xclient.message_type = m_atomScreenSaver; event.xclient.format = 32; event.xclient.data.l[0] = static_cast(cmd); event.xclient.data.l[1] = arg1; event.xclient.data.l[2] = arg2; event.xclient.data.l[3] = 0; event.xclient.data.l[4] = 0; LOG((CLOG_DEBUG "send xscreensaver command: %d %d %d", (long)cmd, arg1, arg2)); bool error = false; { XWindowsUtil::ErrorLock lock(m_display, &error); XSendEvent(m_display, m_xscreensaver, False, 0, &event); } if (error) { findXScreenSaver(); } } void XWindowsScreenSaver::watchForXScreenSaver() { // clear old watch list clearWatchForXScreenSaver(); // add every child of the root to the list of windows to watch Window root = DefaultRootWindow(m_display); Window rw, pw, *cw; unsigned int nc; if (XQueryTree(m_display, root, &rw, &pw, &cw, &nc)) { for (unsigned int i = 0; i < nc; ++i) { addWatchXScreenSaver(cw[i]); } XFree(cw); } // now check for xscreensaver window in case it set the property // before we could request property change events. if (findXScreenSaver()) { // found it so clear out our watch list clearWatchForXScreenSaver(); } } void XWindowsScreenSaver::clearWatchForXScreenSaver() { // stop watching all windows XWindowsUtil::ErrorLock lock(m_display); for (WatchList::iterator index = m_watchWindows.begin(); index != m_watchWindows.end(); ++index) { XSelectInput(m_display, index->first, index->second); } m_watchWindows.clear(); } void XWindowsScreenSaver::addWatchXScreenSaver(Window window) { // get window attributes bool error = false; XWindowAttributes attr; { XWindowsUtil::ErrorLock lock(m_display, &error); XGetWindowAttributes(m_display, window, &attr); } // if successful and window uses override_redirect (like xscreensaver // does) then watch it for property changes. if (!error && attr.override_redirect == True) { error = false; { XWindowsUtil::ErrorLock lock(m_display, &error); XSelectInput(m_display, window, attr.your_event_mask | PropertyChangeMask); } if (!error) { // if successful then add the window to our list m_watchWindows.insert(std::make_pair(window, attr.your_event_mask)); } } } void XWindowsScreenSaver::updateDisableTimer() { if (m_disabled && !m_suppressDisable && m_disableTimer == NULL) { // 5 seconds should be plenty often to suppress the screen saver m_disableTimer = m_events->newTimer(5.0, this); } else if ((!m_disabled || m_suppressDisable) && m_disableTimer != NULL) { m_events->deleteTimer(m_disableTimer); m_disableTimer = NULL; } } void XWindowsScreenSaver::handleDisableTimer(const Event&, void*) { // send fake mouse motion directly to xscreensaver if (m_xscreensaver != None) { XEvent event; event.xmotion.type = MotionNotify; event.xmotion.display = m_display; event.xmotion.window = m_xscreensaver; event.xmotion.root = DefaultRootWindow(m_display); event.xmotion.subwindow = None; event.xmotion.time = CurrentTime; event.xmotion.x = m_disablePos; event.xmotion.y = 0; event.xmotion.x_root = m_disablePos; event.xmotion.y_root = 0; event.xmotion.state = 0; event.xmotion.is_hint = NotifyNormal; event.xmotion.same_screen = True; XWindowsUtil::ErrorLock lock(m_display); XSendEvent(m_display, m_xscreensaver, False, 0, &event); m_disablePos = 20 - m_disablePos; } } void XWindowsScreenSaver::activateDPMS(bool activate) { #if HAVE_X11_EXTENSIONS_DPMS_H if (m_dpms) { // DPMSForceLevel will generate a BadMatch if DPMS is disabled XWindowsUtil::ErrorLock lock(m_display); DPMSForceLevel(m_display, activate ? DPMSModeStandby : DPMSModeOn); } #endif } void XWindowsScreenSaver::enableDPMS(bool enable) { #if HAVE_X11_EXTENSIONS_DPMS_H if (m_dpms) { if (enable) { DPMSEnable(m_display); } else { DPMSDisable(m_display); } } #endif } bool XWindowsScreenSaver::isDPMSEnabled() const { #if HAVE_X11_EXTENSIONS_DPMS_H if (m_dpms) { CARD16 level; BOOL state; DPMSInfo(m_display, &level, &state); return (state != False); } else { return false; } #else return false; #endif } bool XWindowsScreenSaver::isDPMSActivated() const { #if HAVE_X11_EXTENSIONS_DPMS_H if (m_dpms) { CARD16 level; BOOL state; DPMSInfo(m_display, &level, &state); return (level != DPMSModeOn); } else { return false; } #else return false; #endif } synergy-1.8.8-stable/src/lib/platform/XWindowsScreenSaver.h000066400000000000000000000110071305627404700237640ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/IScreenSaver.h" #include "base/IEventQueue.h" #include "common/stdmap.h" #if X_DISPLAY_MISSING # error X11 is required to build synergy #else # include #endif class Event; class EventQueueTimer; //! X11 screen saver implementation class XWindowsScreenSaver : public IScreenSaver { public: XWindowsScreenSaver(Display*, Window, void* eventTarget, IEventQueue* events); virtual ~XWindowsScreenSaver(); //! @name manipulators //@{ //! Event filtering /*! Should be called for each system event before event translation and dispatch. Returns true to skip translation and dispatch. */ bool handleXEvent(const XEvent*); //! Destroy without the display /*! Tells this object to delete itself without using the X11 display. It may leak some resources as a result. */ void destroy(); //@} // IScreenSaver overrides virtual void enable(); virtual void disable(); virtual void activate(); virtual void deactivate(); virtual bool isActive() const; private: // find and set the running xscreensaver's window. returns true iff // found. bool findXScreenSaver(); // set the xscreensaver's window, updating the activation state flag void setXScreenSaver(Window); // returns true if the window appears to be the xscreensaver window bool isXScreenSaver(Window) const; // set xscreensaver's activation state flag. sends notification // if the state has changed. void setXScreenSaverActive(bool activated); // send a command to xscreensaver void sendXScreenSaverCommand(Atom, long = 0, long = 0); // watch all windows that could potentially be the xscreensaver for // the events that will confirm it. void watchForXScreenSaver(); // stop watching all watched windows void clearWatchForXScreenSaver(); // add window to the watch list void addWatchXScreenSaver(Window window); // install/uninstall the job used to suppress the screensaver void updateDisableTimer(); // called periodically to prevent the screen saver from starting void handleDisableTimer(const Event&, void*); // force DPMS to activate or deactivate void activateDPMS(bool activate); // enable/disable DPMS screen saver void enableDPMS(bool); // check if DPMS is enabled bool isDPMSEnabled() const; // check if DPMS is activate bool isDPMSActivated() const; private: typedef std::map WatchList; // the X display Display* m_display; // window to receive xscreensaver repsonses Window m_xscreensaverSink; // the target for the events we generate void* m_eventTarget; // xscreensaver's window Window m_xscreensaver; // xscreensaver activation state bool m_xscreensaverActive; // old event mask on root window long m_rootEventMask; // potential xscreensaver windows being watched WatchList m_watchWindows; // atoms used to communicate with xscreensaver's window Atom m_atomScreenSaver; Atom m_atomScreenSaverVersion; Atom m_atomScreenSaverActivate; Atom m_atomScreenSaverDeactivate; // built-in screen saver settings int m_timeout; int m_interval; int m_preferBlanking; int m_allowExposures; // DPMS screen saver settings bool m_dpms; bool m_dpmsEnabled; // true iff the client wants the screen saver suppressed bool m_disabled; // true iff we're ignoring m_disabled. this is true, for example, // when the client has called activate() and so presumably wants // to activate the screen saver even if disabled. bool m_suppressDisable; // the disable timer (NULL if not installed) EventQueueTimer* m_disableTimer; // fake mouse motion position for suppressing the screen saver. // xscreensaver since 2.21 requires the mouse to move more than 10 // pixels to be considered significant. SInt32 m_disablePos; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/platform/XWindowsUtil.cpp000066400000000000000000002421271305627404700230250ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/XWindowsUtil.h" #include "synergy/key_types.h" #include "mt/Thread.h" #include "base/Log.h" #include "base/String.h" #include #define XK_APL #define XK_ARABIC #define XK_ARMENIAN #define XK_CAUCASUS #define XK_CURRENCY #define XK_CYRILLIC #define XK_GEORGIAN #define XK_GREEK #define XK_HEBREW #define XK_KATAKANA #define XK_KOREAN #define XK_LATIN1 #define XK_LATIN2 #define XK_LATIN3 #define XK_LATIN4 #define XK_LATIN8 #define XK_LATIN9 #define XK_MISCELLANY #define XK_PUBLISHING #define XK_SPECIAL #define XK_TECHNICAL #define XK_THAI #define XK_VIETNAMESE #define XK_XKB_KEYS #include #if !defined(XK_OE) #define XK_OE 0x13bc #endif #if !defined(XK_oe) #define XK_oe 0x13bd #endif #if !defined(XK_Ydiaeresis) #define XK_Ydiaeresis 0x13be #endif /* * This table maps keysym values into the corresponding ISO 10646 * (UCS, Unicode) values. * * The array keysymtab[] contains pairs of X11 keysym values for graphical * characters and the corresponding Unicode value. * * Author: Markus G. Kuhn , * University of Cambridge, April 2001 * * Special thanks to Richard Verhoeven for preparing * an initial draft of the mapping table. * * This software is in the public domain. Share and enjoy! */ struct codepair { KeySym keysym; UInt32 ucs4; } s_keymap[] = { { XK_Aogonek, 0x0104 }, /* LATIN CAPITAL LETTER A WITH OGONEK */ { XK_breve, 0x02d8 }, /* BREVE */ { XK_Lstroke, 0x0141 }, /* LATIN CAPITAL LETTER L WITH STROKE */ { XK_Lcaron, 0x013d }, /* LATIN CAPITAL LETTER L WITH CARON */ { XK_Sacute, 0x015a }, /* LATIN CAPITAL LETTER S WITH ACUTE */ { XK_Scaron, 0x0160 }, /* LATIN CAPITAL LETTER S WITH CARON */ { XK_Scedilla, 0x015e }, /* LATIN CAPITAL LETTER S WITH CEDILLA */ { XK_Tcaron, 0x0164 }, /* LATIN CAPITAL LETTER T WITH CARON */ { XK_Zacute, 0x0179 }, /* LATIN CAPITAL LETTER Z WITH ACUTE */ { XK_Zcaron, 0x017d }, /* LATIN CAPITAL LETTER Z WITH CARON */ { XK_Zabovedot, 0x017b }, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */ { XK_aogonek, 0x0105 }, /* LATIN SMALL LETTER A WITH OGONEK */ { XK_ogonek, 0x02db }, /* OGONEK */ { XK_lstroke, 0x0142 }, /* LATIN SMALL LETTER L WITH STROKE */ { XK_lcaron, 0x013e }, /* LATIN SMALL LETTER L WITH CARON */ { XK_sacute, 0x015b }, /* LATIN SMALL LETTER S WITH ACUTE */ { XK_caron, 0x02c7 }, /* CARON */ { XK_scaron, 0x0161 }, /* LATIN SMALL LETTER S WITH CARON */ { XK_scedilla, 0x015f }, /* LATIN SMALL LETTER S WITH CEDILLA */ { XK_tcaron, 0x0165 }, /* LATIN SMALL LETTER T WITH CARON */ { XK_zacute, 0x017a }, /* LATIN SMALL LETTER Z WITH ACUTE */ { XK_doubleacute, 0x02dd }, /* DOUBLE ACUTE ACCENT */ { XK_zcaron, 0x017e }, /* LATIN SMALL LETTER Z WITH CARON */ { XK_zabovedot, 0x017c }, /* LATIN SMALL LETTER Z WITH DOT ABOVE */ { XK_Racute, 0x0154 }, /* LATIN CAPITAL LETTER R WITH ACUTE */ { XK_Abreve, 0x0102 }, /* LATIN CAPITAL LETTER A WITH BREVE */ { XK_Lacute, 0x0139 }, /* LATIN CAPITAL LETTER L WITH ACUTE */ { XK_Cacute, 0x0106 }, /* LATIN CAPITAL LETTER C WITH ACUTE */ { XK_Ccaron, 0x010c }, /* LATIN CAPITAL LETTER C WITH CARON */ { XK_Eogonek, 0x0118 }, /* LATIN CAPITAL LETTER E WITH OGONEK */ { XK_Ecaron, 0x011a }, /* LATIN CAPITAL LETTER E WITH CARON */ { XK_Dcaron, 0x010e }, /* LATIN CAPITAL LETTER D WITH CARON */ { XK_Dstroke, 0x0110 }, /* LATIN CAPITAL LETTER D WITH STROKE */ { XK_Nacute, 0x0143 }, /* LATIN CAPITAL LETTER N WITH ACUTE */ { XK_Ncaron, 0x0147 }, /* LATIN CAPITAL LETTER N WITH CARON */ { XK_Odoubleacute, 0x0150 }, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ { XK_Rcaron, 0x0158 }, /* LATIN CAPITAL LETTER R WITH CARON */ { XK_Uring, 0x016e }, /* LATIN CAPITAL LETTER U WITH RING ABOVE */ { XK_Udoubleacute, 0x0170 }, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ { XK_Tcedilla, 0x0162 }, /* LATIN CAPITAL LETTER T WITH CEDILLA */ { XK_racute, 0x0155 }, /* LATIN SMALL LETTER R WITH ACUTE */ { XK_abreve, 0x0103 }, /* LATIN SMALL LETTER A WITH BREVE */ { XK_lacute, 0x013a }, /* LATIN SMALL LETTER L WITH ACUTE */ { XK_cacute, 0x0107 }, /* LATIN SMALL LETTER C WITH ACUTE */ { XK_ccaron, 0x010d }, /* LATIN SMALL LETTER C WITH CARON */ { XK_eogonek, 0x0119 }, /* LATIN SMALL LETTER E WITH OGONEK */ { XK_ecaron, 0x011b }, /* LATIN SMALL LETTER E WITH CARON */ { XK_dcaron, 0x010f }, /* LATIN SMALL LETTER D WITH CARON */ { XK_dstroke, 0x0111 }, /* LATIN SMALL LETTER D WITH STROKE */ { XK_nacute, 0x0144 }, /* LATIN SMALL LETTER N WITH ACUTE */ { XK_ncaron, 0x0148 }, /* LATIN SMALL LETTER N WITH CARON */ { XK_odoubleacute, 0x0151 }, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */ { XK_rcaron, 0x0159 }, /* LATIN SMALL LETTER R WITH CARON */ { XK_uring, 0x016f }, /* LATIN SMALL LETTER U WITH RING ABOVE */ { XK_udoubleacute, 0x0171 }, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */ { XK_tcedilla, 0x0163 }, /* LATIN SMALL LETTER T WITH CEDILLA */ { XK_abovedot, 0x02d9 }, /* DOT ABOVE */ { XK_Hstroke, 0x0126 }, /* LATIN CAPITAL LETTER H WITH STROKE */ { XK_Hcircumflex, 0x0124 }, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ { XK_Iabovedot, 0x0130 }, /* LATIN CAPITAL LETTER I WITH DOT ABOVE */ { XK_Gbreve, 0x011e }, /* LATIN CAPITAL LETTER G WITH BREVE */ { XK_Jcircumflex, 0x0134 }, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ { XK_hstroke, 0x0127 }, /* LATIN SMALL LETTER H WITH STROKE */ { XK_hcircumflex, 0x0125 }, /* LATIN SMALL LETTER H WITH CIRCUMFLEX */ { XK_idotless, 0x0131 }, /* LATIN SMALL LETTER DOTLESS I */ { XK_gbreve, 0x011f }, /* LATIN SMALL LETTER G WITH BREVE */ { XK_jcircumflex, 0x0135 }, /* LATIN SMALL LETTER J WITH CIRCUMFLEX */ { XK_Cabovedot, 0x010a }, /* LATIN CAPITAL LETTER C WITH DOT ABOVE */ { XK_Ccircumflex, 0x0108 }, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ { XK_Gabovedot, 0x0120 }, /* LATIN CAPITAL LETTER G WITH DOT ABOVE */ { XK_Gcircumflex, 0x011c }, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ { XK_Ubreve, 0x016c }, /* LATIN CAPITAL LETTER U WITH BREVE */ { XK_Scircumflex, 0x015c }, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ { XK_cabovedot, 0x010b }, /* LATIN SMALL LETTER C WITH DOT ABOVE */ { XK_ccircumflex, 0x0109 }, /* LATIN SMALL LETTER C WITH CIRCUMFLEX */ { XK_gabovedot, 0x0121 }, /* LATIN SMALL LETTER G WITH DOT ABOVE */ { XK_gcircumflex, 0x011d }, /* LATIN SMALL LETTER G WITH CIRCUMFLEX */ { XK_ubreve, 0x016d }, /* LATIN SMALL LETTER U WITH BREVE */ { XK_scircumflex, 0x015d }, /* LATIN SMALL LETTER S WITH CIRCUMFLEX */ { XK_kra, 0x0138 }, /* LATIN SMALL LETTER KRA */ { XK_Rcedilla, 0x0156 }, /* LATIN CAPITAL LETTER R WITH CEDILLA */ { XK_Itilde, 0x0128 }, /* LATIN CAPITAL LETTER I WITH TILDE */ { XK_Lcedilla, 0x013b }, /* LATIN CAPITAL LETTER L WITH CEDILLA */ { XK_Emacron, 0x0112 }, /* LATIN CAPITAL LETTER E WITH MACRON */ { XK_Gcedilla, 0x0122 }, /* LATIN CAPITAL LETTER G WITH CEDILLA */ { XK_Tslash, 0x0166 }, /* LATIN CAPITAL LETTER T WITH STROKE */ { XK_rcedilla, 0x0157 }, /* LATIN SMALL LETTER R WITH CEDILLA */ { XK_itilde, 0x0129 }, /* LATIN SMALL LETTER I WITH TILDE */ { XK_lcedilla, 0x013c }, /* LATIN SMALL LETTER L WITH CEDILLA */ { XK_emacron, 0x0113 }, /* LATIN SMALL LETTER E WITH MACRON */ { XK_gcedilla, 0x0123 }, /* LATIN SMALL LETTER G WITH CEDILLA */ { XK_tslash, 0x0167 }, /* LATIN SMALL LETTER T WITH STROKE */ { XK_ENG, 0x014a }, /* LATIN CAPITAL LETTER ENG */ { XK_eng, 0x014b }, /* LATIN SMALL LETTER ENG */ { XK_Amacron, 0x0100 }, /* LATIN CAPITAL LETTER A WITH MACRON */ { XK_Iogonek, 0x012e }, /* LATIN CAPITAL LETTER I WITH OGONEK */ { XK_Eabovedot, 0x0116 }, /* LATIN CAPITAL LETTER E WITH DOT ABOVE */ { XK_Imacron, 0x012a }, /* LATIN CAPITAL LETTER I WITH MACRON */ { XK_Ncedilla, 0x0145 }, /* LATIN CAPITAL LETTER N WITH CEDILLA */ { XK_Omacron, 0x014c }, /* LATIN CAPITAL LETTER O WITH MACRON */ { XK_Kcedilla, 0x0136 }, /* LATIN CAPITAL LETTER K WITH CEDILLA */ { XK_Uogonek, 0x0172 }, /* LATIN CAPITAL LETTER U WITH OGONEK */ { XK_Utilde, 0x0168 }, /* LATIN CAPITAL LETTER U WITH TILDE */ { XK_Umacron, 0x016a }, /* LATIN CAPITAL LETTER U WITH MACRON */ { XK_amacron, 0x0101 }, /* LATIN SMALL LETTER A WITH MACRON */ { XK_iogonek, 0x012f }, /* LATIN SMALL LETTER I WITH OGONEK */ { XK_eabovedot, 0x0117 }, /* LATIN SMALL LETTER E WITH DOT ABOVE */ { XK_imacron, 0x012b }, /* LATIN SMALL LETTER I WITH MACRON */ { XK_ncedilla, 0x0146 }, /* LATIN SMALL LETTER N WITH CEDILLA */ { XK_omacron, 0x014d }, /* LATIN SMALL LETTER O WITH MACRON */ { XK_kcedilla, 0x0137 }, /* LATIN SMALL LETTER K WITH CEDILLA */ { XK_uogonek, 0x0173 }, /* LATIN SMALL LETTER U WITH OGONEK */ { XK_utilde, 0x0169 }, /* LATIN SMALL LETTER U WITH TILDE */ { XK_umacron, 0x016b }, /* LATIN SMALL LETTER U WITH MACRON */ #if defined(XK_Babovedot) { XK_Babovedot, 0x1e02 }, /* LATIN CAPITAL LETTER B WITH DOT ABOVE */ { XK_babovedot, 0x1e03 }, /* LATIN SMALL LETTER B WITH DOT ABOVE */ { XK_Dabovedot, 0x1e0a }, /* LATIN CAPITAL LETTER D WITH DOT ABOVE */ { XK_Wgrave, 0x1e80 }, /* LATIN CAPITAL LETTER W WITH GRAVE */ { XK_Wacute, 0x1e82 }, /* LATIN CAPITAL LETTER W WITH ACUTE */ { XK_dabovedot, 0x1e0b }, /* LATIN SMALL LETTER D WITH DOT ABOVE */ { XK_Ygrave, 0x1ef2 }, /* LATIN CAPITAL LETTER Y WITH GRAVE */ { XK_Fabovedot, 0x1e1e }, /* LATIN CAPITAL LETTER F WITH DOT ABOVE */ { XK_fabovedot, 0x1e1f }, /* LATIN SMALL LETTER F WITH DOT ABOVE */ { XK_Mabovedot, 0x1e40 }, /* LATIN CAPITAL LETTER M WITH DOT ABOVE */ { XK_mabovedot, 0x1e41 }, /* LATIN SMALL LETTER M WITH DOT ABOVE */ { XK_Pabovedot, 0x1e56 }, /* LATIN CAPITAL LETTER P WITH DOT ABOVE */ { XK_wgrave, 0x1e81 }, /* LATIN SMALL LETTER W WITH GRAVE */ { XK_pabovedot, 0x1e57 }, /* LATIN SMALL LETTER P WITH DOT ABOVE */ { XK_wacute, 0x1e83 }, /* LATIN SMALL LETTER W WITH ACUTE */ { XK_Sabovedot, 0x1e60 }, /* LATIN CAPITAL LETTER S WITH DOT ABOVE */ { XK_ygrave, 0x1ef3 }, /* LATIN SMALL LETTER Y WITH GRAVE */ { XK_Wdiaeresis, 0x1e84 }, /* LATIN CAPITAL LETTER W WITH DIAERESIS */ { XK_wdiaeresis, 0x1e85 }, /* LATIN SMALL LETTER W WITH DIAERESIS */ { XK_sabovedot, 0x1e61 }, /* LATIN SMALL LETTER S WITH DOT ABOVE */ { XK_Wcircumflex, 0x0174 }, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */ { XK_Tabovedot, 0x1e6a }, /* LATIN CAPITAL LETTER T WITH DOT ABOVE */ { XK_Ycircumflex, 0x0176 }, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */ { XK_wcircumflex, 0x0175 }, /* LATIN SMALL LETTER W WITH CIRCUMFLEX */ { XK_tabovedot, 0x1e6b }, /* LATIN SMALL LETTER T WITH DOT ABOVE */ { XK_ycircumflex, 0x0177 }, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX */ #endif // defined(XK_Babovedot) #if defined(XK_overline) { XK_overline, 0x203e }, /* OVERLINE */ { XK_kana_fullstop, 0x3002 }, /* IDEOGRAPHIC FULL STOP */ { XK_kana_openingbracket, 0x300c }, /* LEFT CORNER BRACKET */ { XK_kana_closingbracket, 0x300d }, /* RIGHT CORNER BRACKET */ { XK_kana_comma, 0x3001 }, /* IDEOGRAPHIC COMMA */ { XK_kana_conjunctive, 0x30fb }, /* KATAKANA MIDDLE DOT */ { XK_kana_WO, 0x30f2 }, /* KATAKANA LETTER WO */ { XK_kana_a, 0x30a1 }, /* KATAKANA LETTER SMALL A */ { XK_kana_i, 0x30a3 }, /* KATAKANA LETTER SMALL I */ { XK_kana_u, 0x30a5 }, /* KATAKANA LETTER SMALL U */ { XK_kana_e, 0x30a7 }, /* KATAKANA LETTER SMALL E */ { XK_kana_o, 0x30a9 }, /* KATAKANA LETTER SMALL O */ { XK_kana_ya, 0x30e3 }, /* KATAKANA LETTER SMALL YA */ { XK_kana_yu, 0x30e5 }, /* KATAKANA LETTER SMALL YU */ { XK_kana_yo, 0x30e7 }, /* KATAKANA LETTER SMALL YO */ { XK_kana_tsu, 0x30c3 }, /* KATAKANA LETTER SMALL TU */ { XK_prolongedsound, 0x30fc }, /* KATAKANA-HIRAGANA PROLONGED SOUND MARK */ { XK_kana_A, 0x30a2 }, /* KATAKANA LETTER A */ { XK_kana_I, 0x30a4 }, /* KATAKANA LETTER I */ { XK_kana_U, 0x30a6 }, /* KATAKANA LETTER U */ { XK_kana_E, 0x30a8 }, /* KATAKANA LETTER E */ { XK_kana_O, 0x30aa }, /* KATAKANA LETTER O */ { XK_kana_KA, 0x30ab }, /* KATAKANA LETTER KA */ { XK_kana_KI, 0x30ad }, /* KATAKANA LETTER KI */ { XK_kana_KU, 0x30af }, /* KATAKANA LETTER KU */ { XK_kana_KE, 0x30b1 }, /* KATAKANA LETTER KE */ { XK_kana_KO, 0x30b3 }, /* KATAKANA LETTER KO */ { XK_kana_SA, 0x30b5 }, /* KATAKANA LETTER SA */ { XK_kana_SHI, 0x30b7 }, /* KATAKANA LETTER SI */ { XK_kana_SU, 0x30b9 }, /* KATAKANA LETTER SU */ { XK_kana_SE, 0x30bb }, /* KATAKANA LETTER SE */ { XK_kana_SO, 0x30bd }, /* KATAKANA LETTER SO */ { XK_kana_TA, 0x30bf }, /* KATAKANA LETTER TA */ { XK_kana_CHI, 0x30c1 }, /* KATAKANA LETTER TI */ { XK_kana_TSU, 0x30c4 }, /* KATAKANA LETTER TU */ { XK_kana_TE, 0x30c6 }, /* KATAKANA LETTER TE */ { XK_kana_TO, 0x30c8 }, /* KATAKANA LETTER TO */ { XK_kana_NA, 0x30ca }, /* KATAKANA LETTER NA */ { XK_kana_NI, 0x30cb }, /* KATAKANA LETTER NI */ { XK_kana_NU, 0x30cc }, /* KATAKANA LETTER NU */ { XK_kana_NE, 0x30cd }, /* KATAKANA LETTER NE */ { XK_kana_NO, 0x30ce }, /* KATAKANA LETTER NO */ { XK_kana_HA, 0x30cf }, /* KATAKANA LETTER HA */ { XK_kana_HI, 0x30d2 }, /* KATAKANA LETTER HI */ { XK_kana_FU, 0x30d5 }, /* KATAKANA LETTER HU */ { XK_kana_HE, 0x30d8 }, /* KATAKANA LETTER HE */ { XK_kana_HO, 0x30db }, /* KATAKANA LETTER HO */ { XK_kana_MA, 0x30de }, /* KATAKANA LETTER MA */ { XK_kana_MI, 0x30df }, /* KATAKANA LETTER MI */ { XK_kana_MU, 0x30e0 }, /* KATAKANA LETTER MU */ { XK_kana_ME, 0x30e1 }, /* KATAKANA LETTER ME */ { XK_kana_MO, 0x30e2 }, /* KATAKANA LETTER MO */ { XK_kana_YA, 0x30e4 }, /* KATAKANA LETTER YA */ { XK_kana_YU, 0x30e6 }, /* KATAKANA LETTER YU */ { XK_kana_YO, 0x30e8 }, /* KATAKANA LETTER YO */ { XK_kana_RA, 0x30e9 }, /* KATAKANA LETTER RA */ { XK_kana_RI, 0x30ea }, /* KATAKANA LETTER RI */ { XK_kana_RU, 0x30eb }, /* KATAKANA LETTER RU */ { XK_kana_RE, 0x30ec }, /* KATAKANA LETTER RE */ { XK_kana_RO, 0x30ed }, /* KATAKANA LETTER RO */ { XK_kana_WA, 0x30ef }, /* KATAKANA LETTER WA */ { XK_kana_N, 0x30f3 }, /* KATAKANA LETTER N */ { XK_voicedsound, 0x309b }, /* KATAKANA-HIRAGANA VOICED SOUND MARK */ { XK_semivoicedsound, 0x309c }, /* KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK */ #endif // defined(XK_overline) #if defined(XK_Farsi_0) { XK_Farsi_0, 0x06f0 }, /* EXTENDED ARABIC-INDIC DIGIT 0 */ { XK_Farsi_1, 0x06f1 }, /* EXTENDED ARABIC-INDIC DIGIT 1 */ { XK_Farsi_2, 0x06f2 }, /* EXTENDED ARABIC-INDIC DIGIT 2 */ { XK_Farsi_3, 0x06f3 }, /* EXTENDED ARABIC-INDIC DIGIT 3 */ { XK_Farsi_4, 0x06f4 }, /* EXTENDED ARABIC-INDIC DIGIT 4 */ { XK_Farsi_5, 0x06f5 }, /* EXTENDED ARABIC-INDIC DIGIT 5 */ { XK_Farsi_6, 0x06f6 }, /* EXTENDED ARABIC-INDIC DIGIT 6 */ { XK_Farsi_7, 0x06f7 }, /* EXTENDED ARABIC-INDIC DIGIT 7 */ { XK_Farsi_8, 0x06f8 }, /* EXTENDED ARABIC-INDIC DIGIT 8 */ { XK_Farsi_9, 0x06f9 }, /* EXTENDED ARABIC-INDIC DIGIT 9 */ { XK_Arabic_percent, 0x066a }, /* ARABIC PERCENT */ { XK_Arabic_superscript_alef, 0x0670 }, /* ARABIC LETTER SUPERSCRIPT ALEF */ { XK_Arabic_tteh, 0x0679 }, /* ARABIC LETTER TTEH */ { XK_Arabic_peh, 0x067e }, /* ARABIC LETTER PEH */ { XK_Arabic_tcheh, 0x0686 }, /* ARABIC LETTER TCHEH */ { XK_Arabic_ddal, 0x0688 }, /* ARABIC LETTER DDAL */ { XK_Arabic_rreh, 0x0691 }, /* ARABIC LETTER RREH */ { XK_Arabic_comma, 0x060c }, /* ARABIC COMMA */ { XK_Arabic_fullstop, 0x06d4 }, /* ARABIC FULLSTOP */ { XK_Arabic_semicolon, 0x061b }, /* ARABIC SEMICOLON */ { XK_Arabic_0, 0x0660 }, /* ARABIC 0 */ { XK_Arabic_1, 0x0661 }, /* ARABIC 1 */ { XK_Arabic_2, 0x0662 }, /* ARABIC 2 */ { XK_Arabic_3, 0x0663 }, /* ARABIC 3 */ { XK_Arabic_4, 0x0664 }, /* ARABIC 4 */ { XK_Arabic_5, 0x0665 }, /* ARABIC 5 */ { XK_Arabic_6, 0x0666 }, /* ARABIC 6 */ { XK_Arabic_7, 0x0667 }, /* ARABIC 7 */ { XK_Arabic_8, 0x0668 }, /* ARABIC 8 */ { XK_Arabic_9, 0x0669 }, /* ARABIC 9 */ { XK_Arabic_question_mark, 0x061f }, /* ARABIC QUESTION MARK */ { XK_Arabic_hamza, 0x0621 }, /* ARABIC LETTER HAMZA */ { XK_Arabic_maddaonalef, 0x0622 }, /* ARABIC LETTER ALEF WITH MADDA ABOVE */ { XK_Arabic_hamzaonalef, 0x0623 }, /* ARABIC LETTER ALEF WITH HAMZA ABOVE */ { XK_Arabic_hamzaonwaw, 0x0624 }, /* ARABIC LETTER WAW WITH HAMZA ABOVE */ { XK_Arabic_hamzaunderalef, 0x0625 }, /* ARABIC LETTER ALEF WITH HAMZA BELOW */ { XK_Arabic_hamzaonyeh, 0x0626 }, /* ARABIC LETTER YEH WITH HAMZA ABOVE */ { XK_Arabic_alef, 0x0627 }, /* ARABIC LETTER ALEF */ { XK_Arabic_beh, 0x0628 }, /* ARABIC LETTER BEH */ { XK_Arabic_tehmarbuta, 0x0629 }, /* ARABIC LETTER TEH MARBUTA */ { XK_Arabic_teh, 0x062a }, /* ARABIC LETTER TEH */ { XK_Arabic_theh, 0x062b }, /* ARABIC LETTER THEH */ { XK_Arabic_jeem, 0x062c }, /* ARABIC LETTER JEEM */ { XK_Arabic_hah, 0x062d }, /* ARABIC LETTER HAH */ { XK_Arabic_khah, 0x062e }, /* ARABIC LETTER KHAH */ { XK_Arabic_dal, 0x062f }, /* ARABIC LETTER DAL */ { XK_Arabic_thal, 0x0630 }, /* ARABIC LETTER THAL */ { XK_Arabic_ra, 0x0631 }, /* ARABIC LETTER REH */ { XK_Arabic_zain, 0x0632 }, /* ARABIC LETTER ZAIN */ { XK_Arabic_seen, 0x0633 }, /* ARABIC LETTER SEEN */ { XK_Arabic_sheen, 0x0634 }, /* ARABIC LETTER SHEEN */ { XK_Arabic_sad, 0x0635 }, /* ARABIC LETTER SAD */ { XK_Arabic_dad, 0x0636 }, /* ARABIC LETTER DAD */ { XK_Arabic_tah, 0x0637 }, /* ARABIC LETTER TAH */ { XK_Arabic_zah, 0x0638 }, /* ARABIC LETTER ZAH */ { XK_Arabic_ain, 0x0639 }, /* ARABIC LETTER AIN */ { XK_Arabic_ghain, 0x063a }, /* ARABIC LETTER GHAIN */ { XK_Arabic_tatweel, 0x0640 }, /* ARABIC TATWEEL */ { XK_Arabic_feh, 0x0641 }, /* ARABIC LETTER FEH */ { XK_Arabic_qaf, 0x0642 }, /* ARABIC LETTER QAF */ { XK_Arabic_kaf, 0x0643 }, /* ARABIC LETTER KAF */ { XK_Arabic_lam, 0x0644 }, /* ARABIC LETTER LAM */ { XK_Arabic_meem, 0x0645 }, /* ARABIC LETTER MEEM */ { XK_Arabic_noon, 0x0646 }, /* ARABIC LETTER NOON */ { XK_Arabic_ha, 0x0647 }, /* ARABIC LETTER HEH */ { XK_Arabic_waw, 0x0648 }, /* ARABIC LETTER WAW */ { XK_Arabic_alefmaksura, 0x0649 }, /* ARABIC LETTER ALEF MAKSURA */ { XK_Arabic_yeh, 0x064a }, /* ARABIC LETTER YEH */ { XK_Arabic_fathatan, 0x064b }, /* ARABIC FATHATAN */ { XK_Arabic_dammatan, 0x064c }, /* ARABIC DAMMATAN */ { XK_Arabic_kasratan, 0x064d }, /* ARABIC KASRATAN */ { XK_Arabic_fatha, 0x064e }, /* ARABIC FATHA */ { XK_Arabic_damma, 0x064f }, /* ARABIC DAMMA */ { XK_Arabic_kasra, 0x0650 }, /* ARABIC KASRA */ { XK_Arabic_shadda, 0x0651 }, /* ARABIC SHADDA */ { XK_Arabic_sukun, 0x0652 }, /* ARABIC SUKUN */ { XK_Arabic_madda_above, 0x0653 }, /* ARABIC MADDA ABOVE */ { XK_Arabic_hamza_above, 0x0654 }, /* ARABIC HAMZA ABOVE */ { XK_Arabic_hamza_below, 0x0655 }, /* ARABIC HAMZA BELOW */ { XK_Arabic_jeh, 0x0698 }, /* ARABIC LETTER JEH */ { XK_Arabic_veh, 0x06a4 }, /* ARABIC LETTER VEH */ { XK_Arabic_keheh, 0x06a9 }, /* ARABIC LETTER KEHEH */ { XK_Arabic_gaf, 0x06af }, /* ARABIC LETTER GAF */ { XK_Arabic_noon_ghunna, 0x06ba }, /* ARABIC LETTER NOON GHUNNA */ { XK_Arabic_heh_doachashmee, 0x06be }, /* ARABIC LETTER HEH DOACHASHMEE */ { XK_Arabic_farsi_yeh, 0x06cc }, /* ARABIC LETTER FARSI YEH */ { XK_Arabic_yeh_baree, 0x06d2 }, /* ARABIC LETTER YEH BAREE */ { XK_Arabic_heh_goal, 0x06c1 }, /* ARABIC LETTER HEH GOAL */ #endif // defined(XK_Farsi_0) #if defined(XK_Serbian_dje) { XK_Serbian_dje, 0x0452 }, /* CYRILLIC SMALL LETTER DJE */ { XK_Macedonia_gje, 0x0453 }, /* CYRILLIC SMALL LETTER GJE */ { XK_Cyrillic_io, 0x0451 }, /* CYRILLIC SMALL LETTER IO */ { XK_Ukrainian_ie, 0x0454 }, /* CYRILLIC SMALL LETTER UKRAINIAN IE */ { XK_Macedonia_dse, 0x0455 }, /* CYRILLIC SMALL LETTER DZE */ { XK_Ukrainian_i, 0x0456 }, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ { XK_Ukrainian_yi, 0x0457 }, /* CYRILLIC SMALL LETTER YI */ { XK_Cyrillic_je, 0x0458 }, /* CYRILLIC SMALL LETTER JE */ { XK_Cyrillic_lje, 0x0459 }, /* CYRILLIC SMALL LETTER LJE */ { XK_Cyrillic_nje, 0x045a }, /* CYRILLIC SMALL LETTER NJE */ { XK_Serbian_tshe, 0x045b }, /* CYRILLIC SMALL LETTER TSHE */ { XK_Macedonia_kje, 0x045c }, /* CYRILLIC SMALL LETTER KJE */ #if defined(XK_Ukrainian_ghe_with_upturn) { XK_Ukrainian_ghe_with_upturn, 0x0491 }, /* CYRILLIC SMALL LETTER GHE WITH UPTURN */ #endif { XK_Byelorussian_shortu, 0x045e }, /* CYRILLIC SMALL LETTER SHORT U */ { XK_Cyrillic_dzhe, 0x045f }, /* CYRILLIC SMALL LETTER DZHE */ { XK_numerosign, 0x2116 }, /* NUMERO SIGN */ { XK_Serbian_DJE, 0x0402 }, /* CYRILLIC CAPITAL LETTER DJE */ { XK_Macedonia_GJE, 0x0403 }, /* CYRILLIC CAPITAL LETTER GJE */ { XK_Cyrillic_IO, 0x0401 }, /* CYRILLIC CAPITAL LETTER IO */ { XK_Ukrainian_IE, 0x0404 }, /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */ { XK_Macedonia_DSE, 0x0405 }, /* CYRILLIC CAPITAL LETTER DZE */ { XK_Ukrainian_I, 0x0406 }, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ { XK_Ukrainian_YI, 0x0407 }, /* CYRILLIC CAPITAL LETTER YI */ { XK_Cyrillic_JE, 0x0408 }, /* CYRILLIC CAPITAL LETTER JE */ { XK_Cyrillic_LJE, 0x0409 }, /* CYRILLIC CAPITAL LETTER LJE */ { XK_Cyrillic_NJE, 0x040a }, /* CYRILLIC CAPITAL LETTER NJE */ { XK_Serbian_TSHE, 0x040b }, /* CYRILLIC CAPITAL LETTER TSHE */ { XK_Macedonia_KJE, 0x040c }, /* CYRILLIC CAPITAL LETTER KJE */ #if defined(XK_Ukrainian_GHE_WITH_UPTURN) { XK_Ukrainian_GHE_WITH_UPTURN, 0x0490 }, /* CYRILLIC CAPITAL LETTER GHE WITH UPTURN */ #endif { XK_Byelorussian_SHORTU, 0x040e }, /* CYRILLIC CAPITAL LETTER SHORT U */ { XK_Cyrillic_DZHE, 0x040f }, /* CYRILLIC CAPITAL LETTER DZHE */ { XK_Cyrillic_yu, 0x044e }, /* CYRILLIC SMALL LETTER YU */ { XK_Cyrillic_a, 0x0430 }, /* CYRILLIC SMALL LETTER A */ { XK_Cyrillic_be, 0x0431 }, /* CYRILLIC SMALL LETTER BE */ { XK_Cyrillic_tse, 0x0446 }, /* CYRILLIC SMALL LETTER TSE */ { XK_Cyrillic_de, 0x0434 }, /* CYRILLIC SMALL LETTER DE */ { XK_Cyrillic_ie, 0x0435 }, /* CYRILLIC SMALL LETTER IE */ { XK_Cyrillic_ef, 0x0444 }, /* CYRILLIC SMALL LETTER EF */ { XK_Cyrillic_ghe, 0x0433 }, /* CYRILLIC SMALL LETTER GHE */ { XK_Cyrillic_ha, 0x0445 }, /* CYRILLIC SMALL LETTER HA */ { XK_Cyrillic_i, 0x0438 }, /* CYRILLIC SMALL LETTER I */ { XK_Cyrillic_shorti, 0x0439 }, /* CYRILLIC SMALL LETTER SHORT I */ { XK_Cyrillic_ka, 0x043a }, /* CYRILLIC SMALL LETTER KA */ { XK_Cyrillic_el, 0x043b }, /* CYRILLIC SMALL LETTER EL */ { XK_Cyrillic_em, 0x043c }, /* CYRILLIC SMALL LETTER EM */ { XK_Cyrillic_en, 0x043d }, /* CYRILLIC SMALL LETTER EN */ { XK_Cyrillic_o, 0x043e }, /* CYRILLIC SMALL LETTER O */ { XK_Cyrillic_pe, 0x043f }, /* CYRILLIC SMALL LETTER PE */ { XK_Cyrillic_ya, 0x044f }, /* CYRILLIC SMALL LETTER YA */ { XK_Cyrillic_er, 0x0440 }, /* CYRILLIC SMALL LETTER ER */ { XK_Cyrillic_es, 0x0441 }, /* CYRILLIC SMALL LETTER ES */ { XK_Cyrillic_te, 0x0442 }, /* CYRILLIC SMALL LETTER TE */ { XK_Cyrillic_u, 0x0443 }, /* CYRILLIC SMALL LETTER U */ { XK_Cyrillic_zhe, 0x0436 }, /* CYRILLIC SMALL LETTER ZHE */ { XK_Cyrillic_ve, 0x0432 }, /* CYRILLIC SMALL LETTER VE */ { XK_Cyrillic_softsign, 0x044c }, /* CYRILLIC SMALL LETTER SOFT SIGN */ { XK_Cyrillic_yeru, 0x044b }, /* CYRILLIC SMALL LETTER YERU */ { XK_Cyrillic_ze, 0x0437 }, /* CYRILLIC SMALL LETTER ZE */ { XK_Cyrillic_sha, 0x0448 }, /* CYRILLIC SMALL LETTER SHA */ { XK_Cyrillic_e, 0x044d }, /* CYRILLIC SMALL LETTER E */ { XK_Cyrillic_shcha, 0x0449 }, /* CYRILLIC SMALL LETTER SHCHA */ { XK_Cyrillic_che, 0x0447 }, /* CYRILLIC SMALL LETTER CHE */ { XK_Cyrillic_hardsign, 0x044a }, /* CYRILLIC SMALL LETTER HARD SIGN */ { XK_Cyrillic_YU, 0x042e }, /* CYRILLIC CAPITAL LETTER YU */ { XK_Cyrillic_A, 0x0410 }, /* CYRILLIC CAPITAL LETTER A */ { XK_Cyrillic_BE, 0x0411 }, /* CYRILLIC CAPITAL LETTER BE */ { XK_Cyrillic_TSE, 0x0426 }, /* CYRILLIC CAPITAL LETTER TSE */ { XK_Cyrillic_DE, 0x0414 }, /* CYRILLIC CAPITAL LETTER DE */ { XK_Cyrillic_IE, 0x0415 }, /* CYRILLIC CAPITAL LETTER IE */ { XK_Cyrillic_EF, 0x0424 }, /* CYRILLIC CAPITAL LETTER EF */ { XK_Cyrillic_GHE, 0x0413 }, /* CYRILLIC CAPITAL LETTER GHE */ { XK_Cyrillic_HA, 0x0425 }, /* CYRILLIC CAPITAL LETTER HA */ { XK_Cyrillic_I, 0x0418 }, /* CYRILLIC CAPITAL LETTER I */ { XK_Cyrillic_SHORTI, 0x0419 }, /* CYRILLIC CAPITAL LETTER SHORT I */ { XK_Cyrillic_KA, 0x041a }, /* CYRILLIC CAPITAL LETTER KA */ { XK_Cyrillic_EL, 0x041b }, /* CYRILLIC CAPITAL LETTER EL */ { XK_Cyrillic_EM, 0x041c }, /* CYRILLIC CAPITAL LETTER EM */ { XK_Cyrillic_EN, 0x041d }, /* CYRILLIC CAPITAL LETTER EN */ { XK_Cyrillic_O, 0x041e }, /* CYRILLIC CAPITAL LETTER O */ { XK_Cyrillic_PE, 0x041f }, /* CYRILLIC CAPITAL LETTER PE */ { XK_Cyrillic_YA, 0x042f }, /* CYRILLIC CAPITAL LETTER YA */ { XK_Cyrillic_ER, 0x0420 }, /* CYRILLIC CAPITAL LETTER ER */ { XK_Cyrillic_ES, 0x0421 }, /* CYRILLIC CAPITAL LETTER ES */ { XK_Cyrillic_TE, 0x0422 }, /* CYRILLIC CAPITAL LETTER TE */ { XK_Cyrillic_U, 0x0423 }, /* CYRILLIC CAPITAL LETTER U */ { XK_Cyrillic_ZHE, 0x0416 }, /* CYRILLIC CAPITAL LETTER ZHE */ { XK_Cyrillic_VE, 0x0412 }, /* CYRILLIC CAPITAL LETTER VE */ { XK_Cyrillic_SOFTSIGN, 0x042c }, /* CYRILLIC CAPITAL LETTER SOFT SIGN */ { XK_Cyrillic_YERU, 0x042b }, /* CYRILLIC CAPITAL LETTER YERU */ { XK_Cyrillic_ZE, 0x0417 }, /* CYRILLIC CAPITAL LETTER ZE */ { XK_Cyrillic_SHA, 0x0428 }, /* CYRILLIC CAPITAL LETTER SHA */ { XK_Cyrillic_E, 0x042d }, /* CYRILLIC CAPITAL LETTER E */ { XK_Cyrillic_SHCHA, 0x0429 }, /* CYRILLIC CAPITAL LETTER SHCHA */ { XK_Cyrillic_CHE, 0x0427 }, /* CYRILLIC CAPITAL LETTER CHE */ { XK_Cyrillic_HARDSIGN, 0x042a }, /* CYRILLIC CAPITAL LETTER HARD SIGN */ #endif // defined(XK_Serbian_dje) #if defined(XK_Greek_ALPHAaccent) { XK_Greek_ALPHAaccent, 0x0386 }, /* GREEK CAPITAL LETTER ALPHA WITH TONOS */ { XK_Greek_EPSILONaccent, 0x0388 }, /* GREEK CAPITAL LETTER EPSILON WITH TONOS */ { XK_Greek_ETAaccent, 0x0389 }, /* GREEK CAPITAL LETTER ETA WITH TONOS */ { XK_Greek_IOTAaccent, 0x038a }, /* GREEK CAPITAL LETTER IOTA WITH TONOS */ { XK_Greek_IOTAdiaeresis, 0x03aa }, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ { XK_Greek_OMICRONaccent, 0x038c }, /* GREEK CAPITAL LETTER OMICRON WITH TONOS */ { XK_Greek_UPSILONaccent, 0x038e }, /* GREEK CAPITAL LETTER UPSILON WITH TONOS */ { XK_Greek_UPSILONdieresis, 0x03ab }, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ { XK_Greek_OMEGAaccent, 0x038f }, /* GREEK CAPITAL LETTER OMEGA WITH TONOS */ { XK_Greek_accentdieresis, 0x0385 }, /* GREEK DIALYTIKA TONOS */ { XK_Greek_horizbar, 0x2015 }, /* HORIZONTAL BAR */ { XK_Greek_alphaaccent, 0x03ac }, /* GREEK SMALL LETTER ALPHA WITH TONOS */ { XK_Greek_epsilonaccent, 0x03ad }, /* GREEK SMALL LETTER EPSILON WITH TONOS */ { XK_Greek_etaaccent, 0x03ae }, /* GREEK SMALL LETTER ETA WITH TONOS */ { XK_Greek_iotaaccent, 0x03af }, /* GREEK SMALL LETTER IOTA WITH TONOS */ { XK_Greek_iotadieresis, 0x03ca }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA */ { XK_Greek_iotaaccentdieresis, 0x0390 }, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS */ { XK_Greek_omicronaccent, 0x03cc }, /* GREEK SMALL LETTER OMICRON WITH TONOS */ { XK_Greek_upsilonaccent, 0x03cd }, /* GREEK SMALL LETTER UPSILON WITH TONOS */ { XK_Greek_upsilondieresis, 0x03cb }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ { XK_Greek_upsilonaccentdieresis, 0x03b0 }, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS */ { XK_Greek_omegaaccent, 0x03ce }, /* GREEK SMALL LETTER OMEGA WITH TONOS */ { XK_Greek_ALPHA, 0x0391 }, /* GREEK CAPITAL LETTER ALPHA */ { XK_Greek_BETA, 0x0392 }, /* GREEK CAPITAL LETTER BETA */ { XK_Greek_GAMMA, 0x0393 }, /* GREEK CAPITAL LETTER GAMMA */ { XK_Greek_DELTA, 0x0394 }, /* GREEK CAPITAL LETTER DELTA */ { XK_Greek_EPSILON, 0x0395 }, /* GREEK CAPITAL LETTER EPSILON */ { XK_Greek_ZETA, 0x0396 }, /* GREEK CAPITAL LETTER ZETA */ { XK_Greek_ETA, 0x0397 }, /* GREEK CAPITAL LETTER ETA */ { XK_Greek_THETA, 0x0398 }, /* GREEK CAPITAL LETTER THETA */ { XK_Greek_IOTA, 0x0399 }, /* GREEK CAPITAL LETTER IOTA */ { XK_Greek_KAPPA, 0x039a }, /* GREEK CAPITAL LETTER KAPPA */ { XK_Greek_LAMBDA, 0x039b }, /* GREEK CAPITAL LETTER LAMDA */ { XK_Greek_MU, 0x039c }, /* GREEK CAPITAL LETTER MU */ { XK_Greek_NU, 0x039d }, /* GREEK CAPITAL LETTER NU */ { XK_Greek_XI, 0x039e }, /* GREEK CAPITAL LETTER XI */ { XK_Greek_OMICRON, 0x039f }, /* GREEK CAPITAL LETTER OMICRON */ { XK_Greek_PI, 0x03a0 }, /* GREEK CAPITAL LETTER PI */ { XK_Greek_RHO, 0x03a1 }, /* GREEK CAPITAL LETTER RHO */ { XK_Greek_SIGMA, 0x03a3 }, /* GREEK CAPITAL LETTER SIGMA */ { XK_Greek_TAU, 0x03a4 }, /* GREEK CAPITAL LETTER TAU */ { XK_Greek_UPSILON, 0x03a5 }, /* GREEK CAPITAL LETTER UPSILON */ { XK_Greek_PHI, 0x03a6 }, /* GREEK CAPITAL LETTER PHI */ { XK_Greek_CHI, 0x03a7 }, /* GREEK CAPITAL LETTER CHI */ { XK_Greek_PSI, 0x03a8 }, /* GREEK CAPITAL LETTER PSI */ { XK_Greek_OMEGA, 0x03a9 }, /* GREEK CAPITAL LETTER OMEGA */ { XK_Greek_alpha, 0x03b1 }, /* GREEK SMALL LETTER ALPHA */ { XK_Greek_beta, 0x03b2 }, /* GREEK SMALL LETTER BETA */ { XK_Greek_gamma, 0x03b3 }, /* GREEK SMALL LETTER GAMMA */ { XK_Greek_delta, 0x03b4 }, /* GREEK SMALL LETTER DELTA */ { XK_Greek_epsilon, 0x03b5 }, /* GREEK SMALL LETTER EPSILON */ { XK_Greek_zeta, 0x03b6 }, /* GREEK SMALL LETTER ZETA */ { XK_Greek_eta, 0x03b7 }, /* GREEK SMALL LETTER ETA */ { XK_Greek_theta, 0x03b8 }, /* GREEK SMALL LETTER THETA */ { XK_Greek_iota, 0x03b9 }, /* GREEK SMALL LETTER IOTA */ { XK_Greek_kappa, 0x03ba }, /* GREEK SMALL LETTER KAPPA */ { XK_Greek_lambda, 0x03bb }, /* GREEK SMALL LETTER LAMDA */ { XK_Greek_mu, 0x03bc }, /* GREEK SMALL LETTER MU */ { XK_Greek_nu, 0x03bd }, /* GREEK SMALL LETTER NU */ { XK_Greek_xi, 0x03be }, /* GREEK SMALL LETTER XI */ { XK_Greek_omicron, 0x03bf }, /* GREEK SMALL LETTER OMICRON */ { XK_Greek_pi, 0x03c0 }, /* GREEK SMALL LETTER PI */ { XK_Greek_rho, 0x03c1 }, /* GREEK SMALL LETTER RHO */ { XK_Greek_sigma, 0x03c3 }, /* GREEK SMALL LETTER SIGMA */ { XK_Greek_finalsmallsigma, 0x03c2 }, /* GREEK SMALL LETTER FINAL SIGMA */ { XK_Greek_tau, 0x03c4 }, /* GREEK SMALL LETTER TAU */ { XK_Greek_upsilon, 0x03c5 }, /* GREEK SMALL LETTER UPSILON */ { XK_Greek_phi, 0x03c6 }, /* GREEK SMALL LETTER PHI */ { XK_Greek_chi, 0x03c7 }, /* GREEK SMALL LETTER CHI */ { XK_Greek_psi, 0x03c8 }, /* GREEK SMALL LETTER PSI */ { XK_Greek_omega, 0x03c9 }, /* GREEK SMALL LETTER OMEGA */ #endif // defined(XK_Greek_ALPHAaccent) { XK_leftradical, 0x23b7 }, /* ??? */ { XK_topleftradical, 0x250c }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */ { XK_horizconnector, 0x2500 }, /* BOX DRAWINGS LIGHT HORIZONTAL */ { XK_topintegral, 0x2320 }, /* TOP HALF INTEGRAL */ { XK_botintegral, 0x2321 }, /* BOTTOM HALF INTEGRAL */ { XK_vertconnector, 0x2502 }, /* BOX DRAWINGS LIGHT VERTICAL */ { XK_topleftsqbracket, 0x23a1 }, /* ??? */ { XK_botleftsqbracket, 0x23a3 }, /* ??? */ { XK_toprightsqbracket, 0x23a4 }, /* ??? */ { XK_botrightsqbracket, 0x23a6 }, /* ??? */ { XK_topleftparens, 0x239b }, /* ??? */ { XK_botleftparens, 0x239d }, /* ??? */ { XK_toprightparens, 0x239e }, /* ??? */ { XK_botrightparens, 0x23a0 }, /* ??? */ { XK_leftmiddlecurlybrace, 0x23a8 }, /* ??? */ { XK_rightmiddlecurlybrace, 0x23ac }, /* ??? */ { XK_lessthanequal, 0x2264 }, /* LESS-THAN OR EQUAL TO */ { XK_notequal, 0x2260 }, /* NOT EQUAL TO */ { XK_greaterthanequal, 0x2265 }, /* GREATER-THAN OR EQUAL TO */ { XK_integral, 0x222b }, /* INTEGRAL */ { XK_therefore, 0x2234 }, /* THEREFORE */ { XK_variation, 0x221d }, /* PROPORTIONAL TO */ { XK_infinity, 0x221e }, /* INFINITY */ { XK_nabla, 0x2207 }, /* NABLA */ { XK_approximate, 0x223c }, /* TILDE OPERATOR */ { XK_similarequal, 0x2243 }, /* ASYMPTOTICALLY EQUAL TO */ { XK_ifonlyif, 0x21d4 }, /* LEFT RIGHT DOUBLE ARROW */ { XK_implies, 0x21d2 }, /* RIGHTWARDS DOUBLE ARROW */ { XK_identical, 0x2261 }, /* IDENTICAL TO */ { XK_radical, 0x221a }, /* SQUARE ROOT */ { XK_includedin, 0x2282 }, /* SUBSET OF */ { XK_includes, 0x2283 }, /* SUPERSET OF */ { XK_intersection, 0x2229 }, /* INTERSECTION */ { XK_union, 0x222a }, /* UNION */ { XK_logicaland, 0x2227 }, /* LOGICAL AND */ { XK_logicalor, 0x2228 }, /* LOGICAL OR */ { XK_partialderivative, 0x2202 }, /* PARTIAL DIFFERENTIAL */ { XK_function, 0x0192 }, /* LATIN SMALL LETTER F WITH HOOK */ { XK_leftarrow, 0x2190 }, /* LEFTWARDS ARROW */ { XK_uparrow, 0x2191 }, /* UPWARDS ARROW */ { XK_rightarrow, 0x2192 }, /* RIGHTWARDS ARROW */ { XK_downarrow, 0x2193 }, /* DOWNWARDS ARROW */ /*{ XK_blank, ??? }, */ { XK_soliddiamond, 0x25c6 }, /* BLACK DIAMOND */ { XK_checkerboard, 0x2592 }, /* MEDIUM SHADE */ { XK_ht, 0x2409 }, /* SYMBOL FOR HORIZONTAL TABULATION */ { XK_ff, 0x240c }, /* SYMBOL FOR FORM FEED */ { XK_cr, 0x240d }, /* SYMBOL FOR CARRIAGE RETURN */ { XK_lf, 0x240a }, /* SYMBOL FOR LINE FEED */ { XK_nl, 0x2424 }, /* SYMBOL FOR NEWLINE */ { XK_vt, 0x240b }, /* SYMBOL FOR VERTICAL TABULATION */ { XK_lowrightcorner, 0x2518 }, /* BOX DRAWINGS LIGHT UP AND LEFT */ { XK_uprightcorner, 0x2510 }, /* BOX DRAWINGS LIGHT DOWN AND LEFT */ { XK_upleftcorner, 0x250c }, /* BOX DRAWINGS LIGHT DOWN AND RIGHT */ { XK_lowleftcorner, 0x2514 }, /* BOX DRAWINGS LIGHT UP AND RIGHT */ { XK_crossinglines, 0x253c }, /* BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL */ { XK_horizlinescan1, 0x23ba }, /* HORIZONTAL SCAN LINE-1 (Unicode 3.2 draft) */ { XK_horizlinescan3, 0x23bb }, /* HORIZONTAL SCAN LINE-3 (Unicode 3.2 draft) */ { XK_horizlinescan5, 0x2500 }, /* BOX DRAWINGS LIGHT HORIZONTAL */ { XK_horizlinescan7, 0x23bc }, /* HORIZONTAL SCAN LINE-7 (Unicode 3.2 draft) */ { XK_horizlinescan9, 0x23bd }, /* HORIZONTAL SCAN LINE-9 (Unicode 3.2 draft) */ { XK_leftt, 0x251c }, /* BOX DRAWINGS LIGHT VERTICAL AND RIGHT */ { XK_rightt, 0x2524 }, /* BOX DRAWINGS LIGHT VERTICAL AND LEFT */ { XK_bott, 0x2534 }, /* BOX DRAWINGS LIGHT UP AND HORIZONTAL */ { XK_topt, 0x252c }, /* BOX DRAWINGS LIGHT DOWN AND HORIZONTAL */ { XK_vertbar, 0x2502 }, /* BOX DRAWINGS LIGHT VERTICAL */ { XK_emspace, 0x2003 }, /* EM SPACE */ { XK_enspace, 0x2002 }, /* EN SPACE */ { XK_em3space, 0x2004 }, /* THREE-PER-EM SPACE */ { XK_em4space, 0x2005 }, /* FOUR-PER-EM SPACE */ { XK_digitspace, 0x2007 }, /* FIGURE SPACE */ { XK_punctspace, 0x2008 }, /* PUNCTUATION SPACE */ { XK_thinspace, 0x2009 }, /* THIN SPACE */ { XK_hairspace, 0x200a }, /* HAIR SPACE */ { XK_emdash, 0x2014 }, /* EM DASH */ { XK_endash, 0x2013 }, /* EN DASH */ /*{ XK_signifblank, ??? }, */ { XK_ellipsis, 0x2026 }, /* HORIZONTAL ELLIPSIS */ { XK_doubbaselinedot, 0x2025 }, /* TWO DOT LEADER */ { XK_onethird, 0x2153 }, /* VULGAR FRACTION ONE THIRD */ { XK_twothirds, 0x2154 }, /* VULGAR FRACTION TWO THIRDS */ { XK_onefifth, 0x2155 }, /* VULGAR FRACTION ONE FIFTH */ { XK_twofifths, 0x2156 }, /* VULGAR FRACTION TWO FIFTHS */ { XK_threefifths, 0x2157 }, /* VULGAR FRACTION THREE FIFTHS */ { XK_fourfifths, 0x2158 }, /* VULGAR FRACTION FOUR FIFTHS */ { XK_onesixth, 0x2159 }, /* VULGAR FRACTION ONE SIXTH */ { XK_fivesixths, 0x215a }, /* VULGAR FRACTION FIVE SIXTHS */ { XK_careof, 0x2105 }, /* CARE OF */ { XK_figdash, 0x2012 }, /* FIGURE DASH */ { XK_leftanglebracket, 0x2329 }, /* LEFT-POINTING ANGLE BRACKET */ /*{ XK_decimalpoint, ??? }, */ { XK_rightanglebracket, 0x232a }, /* RIGHT-POINTING ANGLE BRACKET */ /*{ XK_marker, ??? }, */ { XK_oneeighth, 0x215b }, /* VULGAR FRACTION ONE EIGHTH */ { XK_threeeighths, 0x215c }, /* VULGAR FRACTION THREE EIGHTHS */ { XK_fiveeighths, 0x215d }, /* VULGAR FRACTION FIVE EIGHTHS */ { XK_seveneighths, 0x215e }, /* VULGAR FRACTION SEVEN EIGHTHS */ { XK_trademark, 0x2122 }, /* TRADE MARK SIGN */ { XK_signaturemark, 0x2613 }, /* SALTIRE */ /*{ XK_trademarkincircle, ??? }, */ { XK_leftopentriangle, 0x25c1 }, /* WHITE LEFT-POINTING TRIANGLE */ { XK_rightopentriangle, 0x25b7 }, /* WHITE RIGHT-POINTING TRIANGLE */ { XK_emopencircle, 0x25cb }, /* WHITE CIRCLE */ { XK_emopenrectangle, 0x25af }, /* WHITE VERTICAL RECTANGLE */ { XK_leftsinglequotemark, 0x2018 }, /* LEFT SINGLE QUOTATION MARK */ { XK_rightsinglequotemark, 0x2019 }, /* RIGHT SINGLE QUOTATION MARK */ { XK_leftdoublequotemark, 0x201c }, /* LEFT DOUBLE QUOTATION MARK */ { XK_rightdoublequotemark, 0x201d }, /* RIGHT DOUBLE QUOTATION MARK */ { XK_prescription, 0x211e }, /* PRESCRIPTION TAKE */ { XK_minutes, 0x2032 }, /* PRIME */ { XK_seconds, 0x2033 }, /* DOUBLE PRIME */ { XK_latincross, 0x271d }, /* LATIN CROSS */ /*{ XK_hexagram, ??? }, */ { XK_filledrectbullet, 0x25ac }, /* BLACK RECTANGLE */ { XK_filledlefttribullet, 0x25c0 }, /* BLACK LEFT-POINTING TRIANGLE */ { XK_filledrighttribullet, 0x25b6 }, /* BLACK RIGHT-POINTING TRIANGLE */ { XK_emfilledcircle, 0x25cf }, /* BLACK CIRCLE */ { XK_emfilledrect, 0x25ae }, /* BLACK VERTICAL RECTANGLE */ { XK_enopencircbullet, 0x25e6 }, /* WHITE BULLET */ { XK_enopensquarebullet, 0x25ab }, /* WHITE SMALL SQUARE */ { XK_openrectbullet, 0x25ad }, /* WHITE RECTANGLE */ { XK_opentribulletup, 0x25b3 }, /* WHITE UP-POINTING TRIANGLE */ { XK_opentribulletdown, 0x25bd }, /* WHITE DOWN-POINTING TRIANGLE */ { XK_openstar, 0x2606 }, /* WHITE STAR */ { XK_enfilledcircbullet, 0x2022 }, /* BULLET */ { XK_enfilledsqbullet, 0x25aa }, /* BLACK SMALL SQUARE */ { XK_filledtribulletup, 0x25b2 }, /* BLACK UP-POINTING TRIANGLE */ { XK_filledtribulletdown, 0x25bc }, /* BLACK DOWN-POINTING TRIANGLE */ { XK_leftpointer, 0x261c }, /* WHITE LEFT POINTING INDEX */ { XK_rightpointer, 0x261e }, /* WHITE RIGHT POINTING INDEX */ { XK_club, 0x2663 }, /* BLACK CLUB SUIT */ { XK_diamond, 0x2666 }, /* BLACK DIAMOND SUIT */ { XK_heart, 0x2665 }, /* BLACK HEART SUIT */ { XK_maltesecross, 0x2720 }, /* MALTESE CROSS */ { XK_dagger, 0x2020 }, /* DAGGER */ { XK_doubledagger, 0x2021 }, /* DOUBLE DAGGER */ { XK_checkmark, 0x2713 }, /* CHECK MARK */ { XK_ballotcross, 0x2717 }, /* BALLOT X */ { XK_musicalsharp, 0x266f }, /* MUSIC SHARP SIGN */ { XK_musicalflat, 0x266d }, /* MUSIC FLAT SIGN */ { XK_malesymbol, 0x2642 }, /* MALE SIGN */ { XK_femalesymbol, 0x2640 }, /* FEMALE SIGN */ { XK_telephone, 0x260e }, /* BLACK TELEPHONE */ { XK_telephonerecorder, 0x2315 }, /* TELEPHONE RECORDER */ { XK_phonographcopyright, 0x2117 }, /* SOUND RECORDING COPYRIGHT */ { XK_caret, 0x2038 }, /* CARET */ { XK_singlelowquotemark, 0x201a }, /* SINGLE LOW-9 QUOTATION MARK */ { XK_doublelowquotemark, 0x201e }, /* DOUBLE LOW-9 QUOTATION MARK */ /*{ XK_cursor, ??? }, */ { XK_leftcaret, 0x003c }, /* LESS-THAN SIGN */ { XK_rightcaret, 0x003e }, /* GREATER-THAN SIGN */ { XK_downcaret, 0x2228 }, /* LOGICAL OR */ { XK_upcaret, 0x2227 }, /* LOGICAL AND */ { XK_overbar, 0x00af }, /* MACRON */ { XK_downtack, 0x22a5 }, /* UP TACK */ { XK_upshoe, 0x2229 }, /* INTERSECTION */ { XK_downstile, 0x230a }, /* LEFT FLOOR */ { XK_underbar, 0x005f }, /* LOW LINE */ { XK_jot, 0x2218 }, /* RING OPERATOR */ { XK_quad, 0x2395 }, /* APL FUNCTIONAL SYMBOL QUAD */ { XK_uptack, 0x22a4 }, /* DOWN TACK */ { XK_circle, 0x25cb }, /* WHITE CIRCLE */ { XK_upstile, 0x2308 }, /* LEFT CEILING */ { XK_downshoe, 0x222a }, /* UNION */ { XK_rightshoe, 0x2283 }, /* SUPERSET OF */ { XK_leftshoe, 0x2282 }, /* SUBSET OF */ { XK_lefttack, 0x22a2 }, /* RIGHT TACK */ { XK_righttack, 0x22a3 }, /* LEFT TACK */ #if defined(XK_hebrew_doublelowline) { XK_hebrew_doublelowline, 0x2017 }, /* DOUBLE LOW LINE */ { XK_hebrew_aleph, 0x05d0 }, /* HEBREW LETTER ALEF */ { XK_hebrew_bet, 0x05d1 }, /* HEBREW LETTER BET */ { XK_hebrew_gimel, 0x05d2 }, /* HEBREW LETTER GIMEL */ { XK_hebrew_dalet, 0x05d3 }, /* HEBREW LETTER DALET */ { XK_hebrew_he, 0x05d4 }, /* HEBREW LETTER HE */ { XK_hebrew_waw, 0x05d5 }, /* HEBREW LETTER VAV */ { XK_hebrew_zain, 0x05d6 }, /* HEBREW LETTER ZAYIN */ { XK_hebrew_chet, 0x05d7 }, /* HEBREW LETTER HET */ { XK_hebrew_tet, 0x05d8 }, /* HEBREW LETTER TET */ { XK_hebrew_yod, 0x05d9 }, /* HEBREW LETTER YOD */ { XK_hebrew_finalkaph, 0x05da }, /* HEBREW LETTER FINAL KAF */ { XK_hebrew_kaph, 0x05db }, /* HEBREW LETTER KAF */ { XK_hebrew_lamed, 0x05dc }, /* HEBREW LETTER LAMED */ { XK_hebrew_finalmem, 0x05dd }, /* HEBREW LETTER FINAL MEM */ { XK_hebrew_mem, 0x05de }, /* HEBREW LETTER MEM */ { XK_hebrew_finalnun, 0x05df }, /* HEBREW LETTER FINAL NUN */ { XK_hebrew_nun, 0x05e0 }, /* HEBREW LETTER NUN */ { XK_hebrew_samech, 0x05e1 }, /* HEBREW LETTER SAMEKH */ { XK_hebrew_ayin, 0x05e2 }, /* HEBREW LETTER AYIN */ { XK_hebrew_finalpe, 0x05e3 }, /* HEBREW LETTER FINAL PE */ { XK_hebrew_pe, 0x05e4 }, /* HEBREW LETTER PE */ { XK_hebrew_finalzade, 0x05e5 }, /* HEBREW LETTER FINAL TSADI */ { XK_hebrew_zade, 0x05e6 }, /* HEBREW LETTER TSADI */ { XK_hebrew_qoph, 0x05e7 }, /* HEBREW LETTER QOF */ { XK_hebrew_resh, 0x05e8 }, /* HEBREW LETTER RESH */ { XK_hebrew_shin, 0x05e9 }, /* HEBREW LETTER SHIN */ { XK_hebrew_taw, 0x05ea }, /* HEBREW LETTER TAV */ #endif // defined(XK_hebrew_doublelowline) #if defined(XK_Thai_kokai) { XK_Thai_kokai, 0x0e01 }, /* THAI CHARACTER KO KAI */ { XK_Thai_khokhai, 0x0e02 }, /* THAI CHARACTER KHO KHAI */ { XK_Thai_khokhuat, 0x0e03 }, /* THAI CHARACTER KHO KHUAT */ { XK_Thai_khokhwai, 0x0e04 }, /* THAI CHARACTER KHO KHWAI */ { XK_Thai_khokhon, 0x0e05 }, /* THAI CHARACTER KHO KHON */ { XK_Thai_khorakhang, 0x0e06 }, /* THAI CHARACTER KHO RAKHANG */ { XK_Thai_ngongu, 0x0e07 }, /* THAI CHARACTER NGO NGU */ { XK_Thai_chochan, 0x0e08 }, /* THAI CHARACTER CHO CHAN */ { XK_Thai_choching, 0x0e09 }, /* THAI CHARACTER CHO CHING */ { XK_Thai_chochang, 0x0e0a }, /* THAI CHARACTER CHO CHANG */ { XK_Thai_soso, 0x0e0b }, /* THAI CHARACTER SO SO */ { XK_Thai_chochoe, 0x0e0c }, /* THAI CHARACTER CHO CHOE */ { XK_Thai_yoying, 0x0e0d }, /* THAI CHARACTER YO YING */ { XK_Thai_dochada, 0x0e0e }, /* THAI CHARACTER DO CHADA */ { XK_Thai_topatak, 0x0e0f }, /* THAI CHARACTER TO PATAK */ { XK_Thai_thothan, 0x0e10 }, /* THAI CHARACTER THO THAN */ { XK_Thai_thonangmontho, 0x0e11 }, /* THAI CHARACTER THO NANGMONTHO */ { XK_Thai_thophuthao, 0x0e12 }, /* THAI CHARACTER THO PHUTHAO */ { XK_Thai_nonen, 0x0e13 }, /* THAI CHARACTER NO NEN */ { XK_Thai_dodek, 0x0e14 }, /* THAI CHARACTER DO DEK */ { XK_Thai_totao, 0x0e15 }, /* THAI CHARACTER TO TAO */ { XK_Thai_thothung, 0x0e16 }, /* THAI CHARACTER THO THUNG */ { XK_Thai_thothahan, 0x0e17 }, /* THAI CHARACTER THO THAHAN */ { XK_Thai_thothong, 0x0e18 }, /* THAI CHARACTER THO THONG */ { XK_Thai_nonu, 0x0e19 }, /* THAI CHARACTER NO NU */ { XK_Thai_bobaimai, 0x0e1a }, /* THAI CHARACTER BO BAIMAI */ { XK_Thai_popla, 0x0e1b }, /* THAI CHARACTER PO PLA */ { XK_Thai_phophung, 0x0e1c }, /* THAI CHARACTER PHO PHUNG */ { XK_Thai_fofa, 0x0e1d }, /* THAI CHARACTER FO FA */ { XK_Thai_phophan, 0x0e1e }, /* THAI CHARACTER PHO PHAN */ { XK_Thai_fofan, 0x0e1f }, /* THAI CHARACTER FO FAN */ { XK_Thai_phosamphao, 0x0e20 }, /* THAI CHARACTER PHO SAMPHAO */ { XK_Thai_moma, 0x0e21 }, /* THAI CHARACTER MO MA */ { XK_Thai_yoyak, 0x0e22 }, /* THAI CHARACTER YO YAK */ { XK_Thai_rorua, 0x0e23 }, /* THAI CHARACTER RO RUA */ { XK_Thai_ru, 0x0e24 }, /* THAI CHARACTER RU */ { XK_Thai_loling, 0x0e25 }, /* THAI CHARACTER LO LING */ { XK_Thai_lu, 0x0e26 }, /* THAI CHARACTER LU */ { XK_Thai_wowaen, 0x0e27 }, /* THAI CHARACTER WO WAEN */ { XK_Thai_sosala, 0x0e28 }, /* THAI CHARACTER SO SALA */ { XK_Thai_sorusi, 0x0e29 }, /* THAI CHARACTER SO RUSI */ { XK_Thai_sosua, 0x0e2a }, /* THAI CHARACTER SO SUA */ { XK_Thai_hohip, 0x0e2b }, /* THAI CHARACTER HO HIP */ { XK_Thai_lochula, 0x0e2c }, /* THAI CHARACTER LO CHULA */ { XK_Thai_oang, 0x0e2d }, /* THAI CHARACTER O ANG */ { XK_Thai_honokhuk, 0x0e2e }, /* THAI CHARACTER HO NOKHUK */ { XK_Thai_paiyannoi, 0x0e2f }, /* THAI CHARACTER PAIYANNOI */ { XK_Thai_saraa, 0x0e30 }, /* THAI CHARACTER SARA A */ { XK_Thai_maihanakat, 0x0e31 }, /* THAI CHARACTER MAI HAN-AKAT */ { XK_Thai_saraaa, 0x0e32 }, /* THAI CHARACTER SARA AA */ { XK_Thai_saraam, 0x0e33 }, /* THAI CHARACTER SARA AM */ { XK_Thai_sarai, 0x0e34 }, /* THAI CHARACTER SARA I */ { XK_Thai_saraii, 0x0e35 }, /* THAI CHARACTER SARA II */ { XK_Thai_saraue, 0x0e36 }, /* THAI CHARACTER SARA UE */ { XK_Thai_sarauee, 0x0e37 }, /* THAI CHARACTER SARA UEE */ { XK_Thai_sarau, 0x0e38 }, /* THAI CHARACTER SARA U */ { XK_Thai_sarauu, 0x0e39 }, /* THAI CHARACTER SARA UU */ { XK_Thai_phinthu, 0x0e3a }, /* THAI CHARACTER PHINTHU */ /*{ XK_Thai_maihanakat_maitho, ??? }, */ { XK_Thai_baht, 0x0e3f }, /* THAI CURRENCY SYMBOL BAHT */ { XK_Thai_sarae, 0x0e40 }, /* THAI CHARACTER SARA E */ { XK_Thai_saraae, 0x0e41 }, /* THAI CHARACTER SARA AE */ { XK_Thai_sarao, 0x0e42 }, /* THAI CHARACTER SARA O */ { XK_Thai_saraaimaimuan, 0x0e43 }, /* THAI CHARACTER SARA AI MAIMUAN */ { XK_Thai_saraaimaimalai, 0x0e44 }, /* THAI CHARACTER SARA AI MAIMALAI */ { XK_Thai_lakkhangyao, 0x0e45 }, /* THAI CHARACTER LAKKHANGYAO */ { XK_Thai_maiyamok, 0x0e46 }, /* THAI CHARACTER MAIYAMOK */ { XK_Thai_maitaikhu, 0x0e47 }, /* THAI CHARACTER MAITAIKHU */ { XK_Thai_maiek, 0x0e48 }, /* THAI CHARACTER MAI EK */ { XK_Thai_maitho, 0x0e49 }, /* THAI CHARACTER MAI THO */ { XK_Thai_maitri, 0x0e4a }, /* THAI CHARACTER MAI TRI */ { XK_Thai_maichattawa, 0x0e4b }, /* THAI CHARACTER MAI CHATTAWA */ { XK_Thai_thanthakhat, 0x0e4c }, /* THAI CHARACTER THANTHAKHAT */ { XK_Thai_nikhahit, 0x0e4d }, /* THAI CHARACTER NIKHAHIT */ { XK_Thai_leksun, 0x0e50 }, /* THAI DIGIT ZERO */ { XK_Thai_leknung, 0x0e51 }, /* THAI DIGIT ONE */ { XK_Thai_leksong, 0x0e52 }, /* THAI DIGIT TWO */ { XK_Thai_leksam, 0x0e53 }, /* THAI DIGIT THREE */ { XK_Thai_leksi, 0x0e54 }, /* THAI DIGIT FOUR */ { XK_Thai_lekha, 0x0e55 }, /* THAI DIGIT FIVE */ { XK_Thai_lekhok, 0x0e56 }, /* THAI DIGIT SIX */ { XK_Thai_lekchet, 0x0e57 }, /* THAI DIGIT SEVEN */ { XK_Thai_lekpaet, 0x0e58 }, /* THAI DIGIT EIGHT */ { XK_Thai_lekkao, 0x0e59 }, /* THAI DIGIT NINE */ #endif // defined(XK_Thai_kokai) #if defined(XK_Hangul_Kiyeog) { XK_Hangul_Kiyeog, 0x3131 }, /* HANGUL LETTER KIYEOK */ { XK_Hangul_SsangKiyeog, 0x3132 }, /* HANGUL LETTER SSANGKIYEOK */ { XK_Hangul_KiyeogSios, 0x3133 }, /* HANGUL LETTER KIYEOK-SIOS */ { XK_Hangul_Nieun, 0x3134 }, /* HANGUL LETTER NIEUN */ { XK_Hangul_NieunJieuj, 0x3135 }, /* HANGUL LETTER NIEUN-CIEUC */ { XK_Hangul_NieunHieuh, 0x3136 }, /* HANGUL LETTER NIEUN-HIEUH */ { XK_Hangul_Dikeud, 0x3137 }, /* HANGUL LETTER TIKEUT */ { XK_Hangul_SsangDikeud, 0x3138 }, /* HANGUL LETTER SSANGTIKEUT */ { XK_Hangul_Rieul, 0x3139 }, /* HANGUL LETTER RIEUL */ { XK_Hangul_RieulKiyeog, 0x313a }, /* HANGUL LETTER RIEUL-KIYEOK */ { XK_Hangul_RieulMieum, 0x313b }, /* HANGUL LETTER RIEUL-MIEUM */ { XK_Hangul_RieulPieub, 0x313c }, /* HANGUL LETTER RIEUL-PIEUP */ { XK_Hangul_RieulSios, 0x313d }, /* HANGUL LETTER RIEUL-SIOS */ { XK_Hangul_RieulTieut, 0x313e }, /* HANGUL LETTER RIEUL-THIEUTH */ { XK_Hangul_RieulPhieuf, 0x313f }, /* HANGUL LETTER RIEUL-PHIEUPH */ { XK_Hangul_RieulHieuh, 0x3140 }, /* HANGUL LETTER RIEUL-HIEUH */ { XK_Hangul_Mieum, 0x3141 }, /* HANGUL LETTER MIEUM */ { XK_Hangul_Pieub, 0x3142 }, /* HANGUL LETTER PIEUP */ { XK_Hangul_SsangPieub, 0x3143 }, /* HANGUL LETTER SSANGPIEUP */ { XK_Hangul_PieubSios, 0x3144 }, /* HANGUL LETTER PIEUP-SIOS */ { XK_Hangul_Sios, 0x3145 }, /* HANGUL LETTER SIOS */ { XK_Hangul_SsangSios, 0x3146 }, /* HANGUL LETTER SSANGSIOS */ { XK_Hangul_Ieung, 0x3147 }, /* HANGUL LETTER IEUNG */ { XK_Hangul_Jieuj, 0x3148 }, /* HANGUL LETTER CIEUC */ { XK_Hangul_SsangJieuj, 0x3149 }, /* HANGUL LETTER SSANGCIEUC */ { XK_Hangul_Cieuc, 0x314a }, /* HANGUL LETTER CHIEUCH */ { XK_Hangul_Khieuq, 0x314b }, /* HANGUL LETTER KHIEUKH */ { XK_Hangul_Tieut, 0x314c }, /* HANGUL LETTER THIEUTH */ { XK_Hangul_Phieuf, 0x314d }, /* HANGUL LETTER PHIEUPH */ { XK_Hangul_Hieuh, 0x314e }, /* HANGUL LETTER HIEUH */ { XK_Hangul_A, 0x314f }, /* HANGUL LETTER A */ { XK_Hangul_AE, 0x3150 }, /* HANGUL LETTER AE */ { XK_Hangul_YA, 0x3151 }, /* HANGUL LETTER YA */ { XK_Hangul_YAE, 0x3152 }, /* HANGUL LETTER YAE */ { XK_Hangul_EO, 0x3153 }, /* HANGUL LETTER EO */ { XK_Hangul_E, 0x3154 }, /* HANGUL LETTER E */ { XK_Hangul_YEO, 0x3155 }, /* HANGUL LETTER YEO */ { XK_Hangul_YE, 0x3156 }, /* HANGUL LETTER YE */ { XK_Hangul_O, 0x3157 }, /* HANGUL LETTER O */ { XK_Hangul_WA, 0x3158 }, /* HANGUL LETTER WA */ { XK_Hangul_WAE, 0x3159 }, /* HANGUL LETTER WAE */ { XK_Hangul_OE, 0x315a }, /* HANGUL LETTER OE */ { XK_Hangul_YO, 0x315b }, /* HANGUL LETTER YO */ { XK_Hangul_U, 0x315c }, /* HANGUL LETTER U */ { XK_Hangul_WEO, 0x315d }, /* HANGUL LETTER WEO */ { XK_Hangul_WE, 0x315e }, /* HANGUL LETTER WE */ { XK_Hangul_WI, 0x315f }, /* HANGUL LETTER WI */ { XK_Hangul_YU, 0x3160 }, /* HANGUL LETTER YU */ { XK_Hangul_EU, 0x3161 }, /* HANGUL LETTER EU */ { XK_Hangul_YI, 0x3162 }, /* HANGUL LETTER YI */ { XK_Hangul_I, 0x3163 }, /* HANGUL LETTER I */ { XK_Hangul_J_Kiyeog, 0x11a8 }, /* HANGUL JONGSEONG KIYEOK */ { XK_Hangul_J_SsangKiyeog, 0x11a9 }, /* HANGUL JONGSEONG SSANGKIYEOK */ { XK_Hangul_J_KiyeogSios, 0x11aa }, /* HANGUL JONGSEONG KIYEOK-SIOS */ { XK_Hangul_J_Nieun, 0x11ab }, /* HANGUL JONGSEONG NIEUN */ { XK_Hangul_J_NieunJieuj, 0x11ac }, /* HANGUL JONGSEONG NIEUN-CIEUC */ { XK_Hangul_J_NieunHieuh, 0x11ad }, /* HANGUL JONGSEONG NIEUN-HIEUH */ { XK_Hangul_J_Dikeud, 0x11ae }, /* HANGUL JONGSEONG TIKEUT */ { XK_Hangul_J_Rieul, 0x11af }, /* HANGUL JONGSEONG RIEUL */ { XK_Hangul_J_RieulKiyeog, 0x11b0 }, /* HANGUL JONGSEONG RIEUL-KIYEOK */ { XK_Hangul_J_RieulMieum, 0x11b1 }, /* HANGUL JONGSEONG RIEUL-MIEUM */ { XK_Hangul_J_RieulPieub, 0x11b2 }, /* HANGUL JONGSEONG RIEUL-PIEUP */ { XK_Hangul_J_RieulSios, 0x11b3 }, /* HANGUL JONGSEONG RIEUL-SIOS */ { XK_Hangul_J_RieulTieut, 0x11b4 }, /* HANGUL JONGSEONG RIEUL-THIEUTH */ { XK_Hangul_J_RieulPhieuf, 0x11b5 }, /* HANGUL JONGSEONG RIEUL-PHIEUPH */ { XK_Hangul_J_RieulHieuh, 0x11b6 }, /* HANGUL JONGSEONG RIEUL-HIEUH */ { XK_Hangul_J_Mieum, 0x11b7 }, /* HANGUL JONGSEONG MIEUM */ { XK_Hangul_J_Pieub, 0x11b8 }, /* HANGUL JONGSEONG PIEUP */ { XK_Hangul_J_PieubSios, 0x11b9 }, /* HANGUL JONGSEONG PIEUP-SIOS */ { XK_Hangul_J_Sios, 0x11ba }, /* HANGUL JONGSEONG SIOS */ { XK_Hangul_J_SsangSios, 0x11bb }, /* HANGUL JONGSEONG SSANGSIOS */ { XK_Hangul_J_Ieung, 0x11bc }, /* HANGUL JONGSEONG IEUNG */ { XK_Hangul_J_Jieuj, 0x11bd }, /* HANGUL JONGSEONG CIEUC */ { XK_Hangul_J_Cieuc, 0x11be }, /* HANGUL JONGSEONG CHIEUCH */ { XK_Hangul_J_Khieuq, 0x11bf }, /* HANGUL JONGSEONG KHIEUKH */ { XK_Hangul_J_Tieut, 0x11c0 }, /* HANGUL JONGSEONG THIEUTH */ { XK_Hangul_J_Phieuf, 0x11c1 }, /* HANGUL JONGSEONG PHIEUPH */ { XK_Hangul_J_Hieuh, 0x11c2 }, /* HANGUL JONGSEONG HIEUH */ { XK_Hangul_RieulYeorinHieuh, 0x316d }, /* HANGUL LETTER RIEUL-YEORINHIEUH */ { XK_Hangul_SunkyeongeumMieum, 0x3171 }, /* HANGUL LETTER KAPYEOUNMIEUM */ { XK_Hangul_SunkyeongeumPieub, 0x3178 }, /* HANGUL LETTER KAPYEOUNPIEUP */ { XK_Hangul_PanSios, 0x317f }, /* HANGUL LETTER PANSIOS */ { XK_Hangul_KkogjiDalrinIeung, 0x3181 }, /* HANGUL LETTER YESIEUNG */ { XK_Hangul_SunkyeongeumPhieuf, 0x3184 }, /* HANGUL LETTER KAPYEOUNPHIEUPH */ { XK_Hangul_YeorinHieuh, 0x3186 }, /* HANGUL LETTER YEORINHIEUH */ { XK_Hangul_AraeA, 0x318d }, /* HANGUL LETTER ARAEA */ { XK_Hangul_AraeAE, 0x318e }, /* HANGUL LETTER ARAEAE */ { XK_Hangul_J_PanSios, 0x11eb }, /* HANGUL JONGSEONG PANSIOS */ { XK_Hangul_J_KkogjiDalrinIeung, 0x11f0 }, /* HANGUL JONGSEONG YESIEUNG */ { XK_Hangul_J_YeorinHieuh, 0x11f9 }, /* HANGUL JONGSEONG YEORINHIEUH */ { XK_Korean_Won, 0x20a9 }, /* WON SIGN */ #endif // defined(XK_Hangul_Kiyeog) { XK_OE, 0x0152 }, /* LATIN CAPITAL LIGATURE OE */ { XK_oe, 0x0153 }, /* LATIN SMALL LIGATURE OE */ { XK_Ydiaeresis, 0x0178 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ { XK_EuroSign, 0x20ac }, /* EURO SIGN */ /* combining dead keys */ { XK_dead_abovedot, 0x0307 }, /* COMBINING DOT ABOVE */ { XK_dead_abovering, 0x030a }, /* COMBINING RING ABOVE */ { XK_dead_acute, 0x0301 }, /* COMBINING ACUTE ACCENT */ { XK_dead_breve, 0x0306 }, /* COMBINING BREVE */ { XK_dead_caron, 0x030c }, /* COMBINING CARON */ { XK_dead_cedilla, 0x0327 }, /* COMBINING CEDILLA */ { XK_dead_circumflex, 0x0302 }, /* COMBINING CIRCUMFLEX ACCENT */ { XK_dead_diaeresis, 0x0308 }, /* COMBINING DIAERESIS */ { XK_dead_doubleacute, 0x030b }, /* COMBINING DOUBLE ACUTE ACCENT */ { XK_dead_grave, 0x0300 }, /* COMBINING GRAVE ACCENT */ { XK_dead_macron, 0x0304 }, /* COMBINING MACRON */ { XK_dead_ogonek, 0x0328 }, /* COMBINING OGONEK */ { XK_dead_tilde, 0x0303 } /* COMBINING TILDE */ }; /* XXX -- map these too XK_Cyrillic_GHE_bar XK_Cyrillic_ZHE_descender XK_Cyrillic_KA_descender XK_Cyrillic_KA_vertstroke XK_Cyrillic_EN_descender XK_Cyrillic_U_straight XK_Cyrillic_U_straight_bar XK_Cyrillic_HA_descender XK_Cyrillic_CHE_descender XK_Cyrillic_CHE_vertstroke XK_Cyrillic_SHHA XK_Cyrillic_SCHWA XK_Cyrillic_I_macron XK_Cyrillic_O_bar XK_Cyrillic_U_macron XK_Cyrillic_ghe_bar XK_Cyrillic_zhe_descender XK_Cyrillic_ka_descender XK_Cyrillic_ka_vertstroke XK_Cyrillic_en_descender XK_Cyrillic_u_straight XK_Cyrillic_u_straight_bar XK_Cyrillic_ha_descender XK_Cyrillic_che_descender XK_Cyrillic_che_vertstroke XK_Cyrillic_shha XK_Cyrillic_schwa XK_Cyrillic_i_macron XK_Cyrillic_o_bar XK_Cyrillic_u_macron XK_Armenian_eternity XK_Armenian_ligature_ew XK_Armenian_full_stop XK_Armenian_verjaket XK_Armenian_parenright XK_Armenian_parenleft XK_Armenian_guillemotright XK_Armenian_guillemotleft XK_Armenian_em_dash XK_Armenian_dot XK_Armenian_mijaket XK_Armenian_but XK_Armenian_separation_mark XK_Armenian_comma XK_Armenian_en_dash XK_Armenian_hyphen XK_Armenian_yentamna XK_Armenian_ellipsis XK_Armenian_amanak XK_Armenian_exclam XK_Armenian_accent XK_Armenian_shesht XK_Armenian_paruyk XK_Armenian_question XK_Armenian_AYB XK_Armenian_ayb XK_Armenian_BEN XK_Armenian_ben XK_Armenian_GIM XK_Armenian_gim XK_Armenian_DA XK_Armenian_da XK_Armenian_YECH XK_Armenian_yech XK_Armenian_ZA XK_Armenian_za XK_Armenian_E XK_Armenian_e XK_Armenian_AT XK_Armenian_at XK_Armenian_TO XK_Armenian_to XK_Armenian_ZHE XK_Armenian_zhe XK_Armenian_INI XK_Armenian_ini XK_Armenian_LYUN XK_Armenian_lyun XK_Armenian_KHE XK_Armenian_khe XK_Armenian_TSA XK_Armenian_tsa XK_Armenian_KEN XK_Armenian_ken XK_Armenian_HO XK_Armenian_ho XK_Armenian_DZA XK_Armenian_dza XK_Armenian_GHAT XK_Armenian_ghat XK_Armenian_TCHE XK_Armenian_tche XK_Armenian_MEN XK_Armenian_men XK_Armenian_HI XK_Armenian_hi XK_Armenian_NU XK_Armenian_nu XK_Armenian_SHA XK_Armenian_sha XK_Armenian_VO XK_Armenian_vo XK_Armenian_CHA XK_Armenian_cha XK_Armenian_PE XK_Armenian_pe XK_Armenian_JE XK_Armenian_je XK_Armenian_RA XK_Armenian_ra XK_Armenian_SE XK_Armenian_se XK_Armenian_VEV XK_Armenian_vev XK_Armenian_TYUN XK_Armenian_tyun XK_Armenian_RE XK_Armenian_re XK_Armenian_TSO XK_Armenian_tso XK_Armenian_VYUN XK_Armenian_vyun XK_Armenian_PYUR XK_Armenian_pyur XK_Armenian_KE XK_Armenian_ke XK_Armenian_O XK_Armenian_o XK_Armenian_FE XK_Armenian_fe XK_Armenian_apostrophe XK_Armenian_section_sign XK_Georgian_an XK_Georgian_ban XK_Georgian_gan XK_Georgian_don XK_Georgian_en XK_Georgian_vin XK_Georgian_zen XK_Georgian_tan XK_Georgian_in XK_Georgian_kan XK_Georgian_las XK_Georgian_man XK_Georgian_nar XK_Georgian_on XK_Georgian_par XK_Georgian_zhar XK_Georgian_rae XK_Georgian_san XK_Georgian_tar XK_Georgian_un XK_Georgian_phar XK_Georgian_khar XK_Georgian_ghan XK_Georgian_qar XK_Georgian_shin XK_Georgian_chin XK_Georgian_can XK_Georgian_jil XK_Georgian_cil XK_Georgian_char XK_Georgian_xan XK_Georgian_jhan XK_Georgian_hae XK_Georgian_he XK_Georgian_hie XK_Georgian_we XK_Georgian_har XK_Georgian_hoe XK_Georgian_fi XK_Ccedillaabovedot XK_Xabovedot XK_Qabovedot XK_Ibreve XK_IE XK_UO XK_Zstroke XK_Gcaron XK_Obarred XK_ccedillaabovedot XK_xabovedot XK_Ocaron XK_qabovedot XK_ibreve XK_ie XK_uo XK_zstroke XK_gcaron XK_ocaron XK_obarred XK_SCHWA XK_Lbelowdot XK_Lstrokebelowdot XK_Gtilde XK_lbelowdot XK_lstrokebelowdot XK_gtilde XK_schwa XK_Abelowdot XK_abelowdot XK_Ahook XK_ahook XK_Acircumflexacute XK_acircumflexacute XK_Acircumflexgrave XK_acircumflexgrave XK_Acircumflexhook XK_acircumflexhook XK_Acircumflextilde XK_acircumflextilde XK_Acircumflexbelowdot XK_acircumflexbelowdot XK_Abreveacute XK_abreveacute XK_Abrevegrave XK_abrevegrave XK_Abrevehook XK_abrevehook XK_Abrevetilde XK_abrevetilde XK_Abrevebelowdot XK_abrevebelowdot XK_Ebelowdot XK_ebelowdot XK_Ehook XK_ehook XK_Etilde XK_etilde XK_Ecircumflexacute XK_ecircumflexacute XK_Ecircumflexgrave XK_ecircumflexgrave XK_Ecircumflexhook XK_ecircumflexhook XK_Ecircumflextilde XK_ecircumflextilde XK_Ecircumflexbelowdot XK_ecircumflexbelowdot XK_Ihook XK_ihook XK_Ibelowdot XK_ibelowdot XK_Obelowdot XK_obelowdot XK_Ohook XK_ohook XK_Ocircumflexacute XK_ocircumflexacute XK_Ocircumflexgrave XK_ocircumflexgrave XK_Ocircumflexhook XK_ocircumflexhook XK_Ocircumflextilde XK_ocircumflextilde XK_Ocircumflexbelowdot XK_ocircumflexbelowdot XK_Ohornacute XK_ohornacute XK_Ohorngrave XK_ohorngrave XK_Ohornhook XK_ohornhook XK_Ohorntilde XK_ohorntilde XK_Ohornbelowdot XK_ohornbelowdot XK_Ubelowdot XK_ubelowdot XK_Uhook XK_uhook XK_Uhornacute XK_uhornacute XK_Uhorngrave XK_uhorngrave XK_Uhornhook XK_uhornhook XK_Uhorntilde XK_uhorntilde XK_Uhornbelowdot XK_uhornbelowdot XK_Ybelowdot XK_ybelowdot XK_Yhook XK_yhook XK_Ytilde XK_ytilde XK_Ohorn XK_ohorn XK_Uhorn XK_uhorn */ // map "Internet" keys to KeyIDs static const KeySym s_map1008FF[] = { /* 0x00 */ 0, 0, kKeyBrightnessUp, kKeyBrightnessDown, 0, 0, 0, 0, /* 0x08 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10 */ 0, kKeyAudioDown, kKeyAudioMute, kKeyAudioUp, /* 0x14 */ kKeyAudioPlay, kKeyAudioStop, kKeyAudioPrev, kKeyAudioNext, /* 0x18 */ kKeyWWWHome, kKeyAppMail, 0, kKeyWWWSearch, 0, 0, 0, 0, /* 0x20 */ 0, 0, 0, 0, 0, 0, kKeyWWWBack, kKeyWWWForward, /* 0x28 */ kKeyWWWStop, kKeyWWWRefresh, 0, 0, kKeyEject, 0, 0, 0, /* 0x30 */ kKeyWWWFavorites, 0, kKeyAppMedia, 0, 0, 0, 0, 0, /* 0x38 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 */ kKeyAppUser1, kKeyAppUser2, 0, 0, 0, 0, 0, 0, /* 0x48 */ 0, 0, kKeyMissionControl, kKeyLaunchpad, 0, 0, 0, 0, /* 0x50 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x78 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x88 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x98 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xa8 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xb8 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc0 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xc8 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd0 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xd8 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe0 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xe8 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf0 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xf8 */ 0, 0, 0, 0, 0, 0, 0, 0 }; // // XWindowsUtil // XWindowsUtil::KeySymMap XWindowsUtil::s_keySymToUCS4; bool XWindowsUtil::getWindowProperty(Display* display, Window window, Atom property, String* data, Atom* type, SInt32* format, bool deleteProperty) { assert(display != NULL); Atom actualType; int actualDatumSize; // ignore errors. XGetWindowProperty() will report failure. XWindowsUtil::ErrorLock lock(display); // read the property bool okay = true; const long length = XMaxRequestSize(display); long offset = 0; unsigned long bytesLeft = 1; while (bytesLeft != 0) { // get more data unsigned long numItems; unsigned char* rawData; if (XGetWindowProperty(display, window, property, offset, length, False, AnyPropertyType, &actualType, &actualDatumSize, &numItems, &bytesLeft, &rawData) != Success || actualType == None || actualDatumSize == 0) { // failed okay = false; break; } // compute bytes read and advance offset unsigned long numBytes; switch (actualDatumSize) { case 8: default: numBytes = numItems; offset += numItems / 4; break; case 16: numBytes = 2 * numItems; offset += numItems / 2; break; case 32: numBytes = 4 * numItems; offset += numItems; break; } // append data if (data != NULL) { data->append((char*)rawData, numBytes); } else { // data is not required so don't try to get any more bytesLeft = 0; } // done with returned data XFree(rawData); } // delete the property if requested if (deleteProperty) { XDeleteProperty(display, window, property); } // save property info if (type != NULL) { *type = actualType; } if (format != NULL) { *format = static_cast(actualDatumSize); } if (okay) { LOG((CLOG_DEBUG2 "read property %d on window 0x%08x: bytes=%d", property, window, (data == NULL) ? 0 : data->size())); return true; } else { LOG((CLOG_DEBUG2 "can't read property %d on window 0x%08x", property, window)); return false; } } bool XWindowsUtil::setWindowProperty(Display* display, Window window, Atom property, const void* vdata, UInt32 size, Atom type, SInt32 format) { const UInt32 length = 4 * XMaxRequestSize(display); const unsigned char* data = static_cast(vdata); UInt32 datumSize = static_cast(format / 8); // format 32 on 64bit systems is 8 bytes not 4. if (format == 32) { datumSize = sizeof(Atom); } // save errors bool error = false; XWindowsUtil::ErrorLock lock(display, &error); // how much data to send in first chunk? UInt32 chunkSize = size; if (chunkSize > length) { chunkSize = length; } // send first chunk XChangeProperty(display, window, property, type, format, PropModeReplace, data, chunkSize / datumSize); // append remaining chunks data += chunkSize; size -= chunkSize; while (!error && size > 0) { chunkSize = size; if (chunkSize > length) { chunkSize = length; } XChangeProperty(display, window, property, type, format, PropModeAppend, data, chunkSize / datumSize); data += chunkSize; size -= chunkSize; } return !error; } Time XWindowsUtil::getCurrentTime(Display* display, Window window) { XLockDisplay(display); // select property events on window XWindowAttributes attr; XGetWindowAttributes(display, window, &attr); XSelectInput(display, window, attr.your_event_mask | PropertyChangeMask); // make a property name to receive dummy change Atom atom = XInternAtom(display, "TIMESTAMP", False); // do a zero-length append to get the current time unsigned char dummy; XChangeProperty(display, window, atom, XA_INTEGER, 8, PropModeAppend, &dummy, 0); // look for property notify events with the following PropertyNotifyPredicateInfo filter; filter.m_window = window; filter.m_property = atom; // wait for reply XEvent xevent; XIfEvent(display, &xevent, &XWindowsUtil::propertyNotifyPredicate, (XPointer)&filter); assert(xevent.type == PropertyNotify); assert(xevent.xproperty.window == window); assert(xevent.xproperty.atom == atom); // restore event mask XSelectInput(display, window, attr.your_event_mask); XUnlockDisplay(display); return xevent.xproperty.time; } KeyID XWindowsUtil::mapKeySymToKeyID(KeySym k) { initKeyMaps(); switch (k & 0xffffff00) { case 0x0000: // Latin-1 return static_cast(k); case 0xfe00: // ISO 9995 Function and Modifier Keys switch (k) { case XK_ISO_Left_Tab: return kKeyLeftTab; case XK_ISO_Level3_Shift: return kKeyAltGr; #ifdef XK_ISO_Level5_Shift case XK_ISO_Level5_Shift: return XK_ISO_Level5_Shift; //FIXME: there is no "usual" key for this... #endif case XK_ISO_Next_Group: return kKeyNextGroup; case XK_ISO_Prev_Group: return kKeyPrevGroup; case XK_dead_grave: return kKeyDeadGrave; case XK_dead_acute: return kKeyDeadAcute; case XK_dead_circumflex: return kKeyDeadCircumflex; case XK_dead_tilde: return kKeyDeadTilde; case XK_dead_macron: return kKeyDeadMacron; case XK_dead_breve: return kKeyDeadBreve; case XK_dead_abovedot: return kKeyDeadAbovedot; case XK_dead_diaeresis: return kKeyDeadDiaeresis; case XK_dead_abovering: return kKeyDeadAbovering; case XK_dead_doubleacute: return kKeyDeadDoubleacute; case XK_dead_caron: return kKeyDeadCaron; case XK_dead_cedilla: return kKeyDeadCedilla; case XK_dead_ogonek: return kKeyDeadOgonek; default: return kKeyNone; } case 0xff00: // MISCELLANY return static_cast(k - 0xff00 + 0xef00); case 0x1008ff00: // "Internet" keys return s_map1008FF[k & 0xff]; default: { // lookup character in table KeySymMap::const_iterator index = s_keySymToUCS4.find(k); if (index != s_keySymToUCS4.end()) { return static_cast(index->second); } // unknown character return kKeyNone; } } } UInt32 XWindowsUtil::getModifierBitForKeySym(KeySym keysym) { switch (keysym) { case XK_Shift_L: case XK_Shift_R: return kKeyModifierBitShift; case XK_Control_L: case XK_Control_R: return kKeyModifierBitControl; case XK_Alt_L: case XK_Alt_R: return kKeyModifierBitAlt; case XK_Meta_L: case XK_Meta_R: return kKeyModifierBitMeta; case XK_Super_L: case XK_Super_R: case XK_Hyper_L: case XK_Hyper_R: return kKeyModifierBitSuper; case XK_Mode_switch: case XK_ISO_Level3_Shift: return kKeyModifierBitAltGr; #ifdef XK_ISO_Level5_Shift case XK_ISO_Level5_Shift: return kKeyModifierBitLevel5Lock; #endif case XK_Caps_Lock: return kKeyModifierBitCapsLock; case XK_Num_Lock: return kKeyModifierBitNumLock; case XK_Scroll_Lock: return kKeyModifierBitScrollLock; default: return kKeyModifierBitNone; } } String XWindowsUtil::atomToString(Display* display, Atom atom) { if (atom == 0) { return "None"; } bool error = false; XWindowsUtil::ErrorLock lock(display, &error); char* name = XGetAtomName(display, atom); if (error) { return synergy::string::sprintf(" (%d)", (int)atom); } else { String msg = synergy::string::sprintf("%s (%d)", name, (int)atom); XFree(name); return msg; } } String XWindowsUtil::atomsToString(Display* display, const Atom* atom, UInt32 num) { char** names = new char*[num]; bool error = false; XWindowsUtil::ErrorLock lock(display, &error); XGetAtomNames(display, const_cast(atom), (int)num, names); String msg; if (error) { for (UInt32 i = 0; i < num; ++i) { msg += synergy::string::sprintf(" (%d), ", (int)atom[i]); } } else { for (UInt32 i = 0; i < num; ++i) { msg += synergy::string::sprintf("%s (%d), ", names[i], (int)atom[i]); XFree(names[i]); } } delete[] names; if (msg.size() > 2) { msg.erase(msg.size() - 2); } return msg; } void XWindowsUtil::convertAtomProperty(String& data) { // as best i can tell, 64-bit systems don't pack Atoms into properties // as 32-bit numbers but rather as the 64-bit numbers they are. that // seems wrong but we have to cope. sometimes we'll get a list of // atoms that's 8*n+4 bytes long, missing the trailing 4 bytes which // should all be 0. since we're going to reference the Atoms as // 64-bit numbers we have to ensure the last number is a full 64 bits. if (sizeof(Atom) != 4 && ((data.size() / 4) & 1) != 0) { UInt32 zero = 0; data.append(reinterpret_cast(&zero), sizeof(zero)); } } void XWindowsUtil::appendAtomData(String& data, Atom atom) { data.append(reinterpret_cast(&atom), sizeof(Atom)); } void XWindowsUtil::replaceAtomData(String& data, UInt32 index, Atom atom) { data.replace(index * sizeof(Atom), sizeof(Atom), reinterpret_cast(&atom), sizeof(Atom)); } void XWindowsUtil::appendTimeData(String& data, Time time) { data.append(reinterpret_cast(&time), sizeof(Time)); } Bool XWindowsUtil::propertyNotifyPredicate(Display*, XEvent* xevent, XPointer arg) { PropertyNotifyPredicateInfo* filter = reinterpret_cast(arg); return (xevent->type == PropertyNotify && xevent->xproperty.window == filter->m_window && xevent->xproperty.atom == filter->m_property && xevent->xproperty.state == PropertyNewValue) ? True : False; } void XWindowsUtil::initKeyMaps() { if (s_keySymToUCS4.empty()) { for (size_t i =0; i < sizeof(s_keymap) / sizeof(s_keymap[0]); ++i) { s_keySymToUCS4[s_keymap[i].keysym] = s_keymap[i].ucs4; } } } // // XWindowsUtil::ErrorLock // XWindowsUtil::ErrorLock* XWindowsUtil::ErrorLock::s_top = NULL; XWindowsUtil::ErrorLock::ErrorLock(Display* display) : m_display(display) { install(&XWindowsUtil::ErrorLock::ignoreHandler, NULL); } XWindowsUtil::ErrorLock::ErrorLock(Display* display, bool* flag) : m_display(display) { install(&XWindowsUtil::ErrorLock::saveHandler, flag); } XWindowsUtil::ErrorLock::ErrorLock(Display* display, ErrorHandler handler, void* data) : m_display(display) { install(handler, data); } XWindowsUtil::ErrorLock::~ErrorLock() { // make sure everything finishes before uninstalling handler if (m_display != NULL) { XSync(m_display, False); } // restore old handler XSetErrorHandler(m_oldXHandler); s_top = m_next; } void XWindowsUtil::ErrorLock::install(ErrorHandler handler, void* data) { // make sure everything finishes before installing handler if (m_display != NULL) { XSync(m_display, False); } // install handler m_handler = handler; m_userData = data; m_oldXHandler = XSetErrorHandler( &XWindowsUtil::ErrorLock::internalHandler); m_next = s_top; s_top = this; } int XWindowsUtil::ErrorLock::internalHandler(Display* display, XErrorEvent* event) { if (s_top != NULL && s_top->m_handler != NULL) { s_top->m_handler(display, event, s_top->m_userData); } return 0; } void XWindowsUtil::ErrorLock::ignoreHandler(Display*, XErrorEvent* e, void*) { LOG((CLOG_DEBUG1 "ignoring X error: %d", e->error_code)); } void XWindowsUtil::ErrorLock::saveHandler(Display*, XErrorEvent* e, void* flag) { LOG((CLOG_DEBUG1 "flagging X error: %d", e->error_code)); *static_cast(flag) = true; } synergy-1.8.8-stable/src/lib/platform/XWindowsUtil.h000066400000000000000000000115041305627404700224630ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" #include "base/EventTypes.h" #include "common/stdmap.h" #include "common/stdvector.h" #if X_DISPLAY_MISSING # error X11 is required to build synergy #else # include #endif //! X11 utility functions class XWindowsUtil { public: typedef std::vector KeySyms; //! Get property /*! Gets property \c property on \c window. \b Appends the data to \c *data if \c data is not NULL, saves the property type in \c *type if \c type is not NULL, and saves the property format in \c *format if \c format is not NULL. If \c deleteProperty is true then the property is deleted after being read. */ static bool getWindowProperty(Display*, Window window, Atom property, String* data, Atom* type, SInt32* format, bool deleteProperty); //! Set property /*! Sets property \c property on \c window to \c size bytes of data from \c data. */ static bool setWindowProperty(Display*, Window window, Atom property, const void* data, UInt32 size, Atom type, SInt32 format); //! Get X server time /*! Returns the current X server time. */ static Time getCurrentTime(Display*, Window); //! Convert KeySym to KeyID /*! Converts a KeySym to the equivalent KeyID. Returns kKeyNone if the KeySym cannot be mapped. */ static UInt32 mapKeySymToKeyID(KeySym); //! Convert KeySym to corresponding KeyModifierMask /*! Converts a KeySym to the corresponding KeyModifierMask, or 0 if the KeySym is not a modifier. */ static UInt32 getModifierBitForKeySym(KeySym keysym); //! Convert Atom to its string /*! Converts \p atom to its string representation. */ static String atomToString(Display*, Atom atom); //! Convert several Atoms to a string /*! Converts each atom in \p atoms to its string representation and concatenates the results. */ static String atomsToString(Display* display, const Atom* atom, UInt32 num); //! Prepare a property of atoms for use /*! 64-bit systems may need to modify a property's data if it's a list of Atoms before using it. */ static void convertAtomProperty(String& data); //! Append an Atom to property data /*! Converts \p atom to a 32-bit on-the-wire format and appends it to \p data. */ static void appendAtomData(String& data, Atom atom); //! Replace an Atom in property data /*! Converts \p atom to a 32-bit on-the-wire format and replaces the atom at index \p index in \p data. */ static void replaceAtomData(String& data, UInt32 index, Atom atom); //! Append an Time to property data /*! Converts \p time to a 32-bit on-the-wire format and appends it to \p data. */ static void appendTimeData(String& data, Time time); //! X11 error handler /*! This class sets an X error handler in the c'tor and restores the previous error handler in the d'tor. A lock should only be installed while the display is locked by the thread. ErrorLock() ignores errors ErrorLock(bool* flag) sets *flag to true if any error occurs */ class ErrorLock { public: //! Error handler type typedef void (*ErrorHandler)(Display*, XErrorEvent*, void* userData); /*! Ignore X11 errors. */ ErrorLock(Display*); /*! Set \c *errorFlag if any error occurs. */ ErrorLock(Display*, bool* errorFlag); /*! Call \c handler on each error. */ ErrorLock(Display*, ErrorHandler handler, void* userData); ~ErrorLock(); private: void install(ErrorHandler, void*); static int internalHandler(Display*, XErrorEvent*); static void ignoreHandler(Display*, XErrorEvent*, void*); static void saveHandler(Display*, XErrorEvent*, void*); private: typedef int (*XErrorHandler)(Display*, XErrorEvent*); Display* m_display; ErrorHandler m_handler; void* m_userData; XErrorHandler m_oldXHandler; ErrorLock* m_next; static ErrorLock* s_top; }; private: class PropertyNotifyPredicateInfo { public: Window m_window; Atom m_property; }; static Bool propertyNotifyPredicate(Display*, XEvent* xevent, XPointer arg); static void initKeyMaps(); private: typedef std::map KeySymMap; static KeySymMap s_keySymToUCS4; }; synergy-1.8.8-stable/src/lib/server/000077500000000000000000000000001305627404700173535ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/server/BaseClientProxy.cpp000066400000000000000000000022521305627404700231330ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2006 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/BaseClientProxy.h" // // BaseClientProxy // BaseClientProxy::BaseClientProxy(const String& name) : m_name(name), m_x(0), m_y(0) { // do nothing } BaseClientProxy::~BaseClientProxy() { // do nothing } void BaseClientProxy::setJumpCursorPos(SInt32 x, SInt32 y) { m_x = x; m_y = y; } void BaseClientProxy::getJumpCursorPos(SInt32& x, SInt32& y) const { x = m_x; y = m_y; } String BaseClientProxy::getName() const { return m_name; } synergy-1.8.8-stable/src/lib/server/BaseClientProxy.h000066400000000000000000000060061305627404700226010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/IClient.h" #include "base/String.h" namespace synergy { class IStream; } //! Generic proxy for client or primary class BaseClientProxy : public IClient { public: /*! \c name is the name of the client. */ BaseClientProxy(const String& name); ~BaseClientProxy(); //! @name manipulators //@{ //! Save cursor position /*! Save the position of the cursor when jumping from client. */ void setJumpCursorPos(SInt32 x, SInt32 y); //@} //! @name accessors //@{ //! Get cursor position /*! Get the position of the cursor when last jumping from client. */ void getJumpCursorPos(SInt32& x, SInt32& y) const; //! Get cursor position /*! Return if this proxy is for client or primary. */ virtual bool isPrimary() const { return false; } //@} // IScreen virtual void* getEventTarget() const = 0; virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const = 0; virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; // IClient overrides virtual void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, bool forScreensaver) = 0; virtual bool leave() = 0; virtual void setClipboard(ClipboardID, const IClipboard*) = 0; virtual void grabClipboard(ClipboardID) = 0; virtual void setClipboardDirty(ClipboardID, bool) = 0; virtual void keyDown(KeyID, KeyModifierMask, KeyButton) = 0; virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton) = 0; virtual void keyUp(KeyID, KeyModifierMask, KeyButton) = 0; virtual void mouseDown(ButtonID) = 0; virtual void mouseUp(ButtonID) = 0; virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel) = 0; virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta) = 0; virtual void screensaver(bool activate) = 0; virtual void resetOptions() = 0; virtual void setOptions(const OptionsList& options) = 0; virtual void sendDragInfo(UInt32 fileCount, const char* info, size_t size) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0; virtual String getName() const; virtual synergy::IStream* getStream() const = 0; private: String m_name; SInt32 m_x, m_y; }; synergy-1.8.8-stable/src/lib/server/CMakeLists.txt000066400000000000000000000021031305627404700221070ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ../../../ext ../../../ext/gtest-1.6.0/include ) if (UNIX) include_directories( ../../.. ) endif() add_library(server STATIC ${sources}) target_link_libraries(server shared) if (UNIX) target_link_libraries(server synergy) endif() synergy-1.8.8-stable/src/lib/server/ClientListener.cpp000066400000000000000000000147421305627404700230130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/ClientListener.h" #include "server/ClientProxy.h" #include "server/ClientProxyUnknown.h" #include "synergy/PacketStreamFilter.h" #include "net/IDataSocket.h" #include "net/IListenSocket.h" #include "net/ISocketFactory.h" #include "net/XSocket.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" // // ClientListener // ClientListener::ClientListener(const NetworkAddress& address, ISocketFactory* socketFactory, IEventQueue* events, bool enableCrypto) : m_socketFactory(socketFactory), m_server(NULL), m_events(events), m_useSecureNetwork(enableCrypto) { assert(m_socketFactory != NULL); try { m_listen = m_socketFactory->createListen(m_useSecureNetwork); // setup event handler m_events->adoptHandler(m_events->forIListenSocket().connecting(), m_listen, new TMethodEventJob(this, &ClientListener::handleClientConnecting)); // bind listen address LOG((CLOG_DEBUG1 "binding listen socket")); m_listen->bind(address); } catch (XSocketAddressInUse&) { cleanupListenSocket(); delete m_socketFactory; throw; } catch (XBase&) { cleanupListenSocket(); delete m_socketFactory; throw; } LOG((CLOG_DEBUG1 "listening for clients")); } ClientListener::~ClientListener() { LOG((CLOG_DEBUG1 "stop listening for clients")); // discard already connected clients for (NewClients::iterator index = m_newClients.begin(); index != m_newClients.end(); ++index) { ClientProxyUnknown* client = *index; m_events->removeHandler( m_events->forClientProxyUnknown().success(), client); m_events->removeHandler( m_events->forClientProxyUnknown().failure(), client); m_events->removeHandler( m_events->forClientProxy().disconnected(), client); delete client; } // discard waiting clients ClientProxy* client = getNextClient(); while (client != NULL) { delete client; client = getNextClient(); } m_events->removeHandler(m_events->forIListenSocket().connecting(), m_listen); cleanupListenSocket(); delete m_socketFactory; } void ClientListener::setServer(Server* server) { assert(server != NULL); m_server = server; } ClientProxy* ClientListener::getNextClient() { ClientProxy* client = NULL; if (!m_waitingClients.empty()) { client = m_waitingClients.front(); m_waitingClients.pop_front(); m_events->removeHandler(m_events->forClientProxy().disconnected(), client); } return client; } void ClientListener::handleClientConnecting(const Event&, void*) { // accept client connection IDataSocket* socket = m_listen->accept(); if (socket == NULL) { return; } m_events->adoptHandler(m_events->forClientListener().accepted(), socket->getEventTarget(), new TMethodEventJob(this, &ClientListener::handleClientAccepted, socket)); // When using non SSL, server accepts clients immediately, while SSL // has to call secure accept which may require retry if (!m_useSecureNetwork) { m_events->addEvent(Event(m_events->forClientListener().accepted(), socket->getEventTarget())); } } void ClientListener::handleClientAccepted(const Event&, void* vsocket) { LOG((CLOG_NOTE "accepted client connection")); IDataSocket* socket = static_cast(vsocket); // filter socket messages, including a packetizing filter synergy::IStream* stream = new PacketStreamFilter(m_events, socket, true); assert(m_server != NULL); // create proxy for unknown client ClientProxyUnknown* client = new ClientProxyUnknown(stream, 30.0, m_server, m_events); m_newClients.insert(client); // watch for events from unknown client m_events->adoptHandler(m_events->forClientProxyUnknown().success(), client, new TMethodEventJob(this, &ClientListener::handleUnknownClient, client)); m_events->adoptHandler(m_events->forClientProxyUnknown().failure(), client, new TMethodEventJob(this, &ClientListener::handleUnknownClient, client)); } void ClientListener::handleUnknownClient(const Event&, void* vclient) { ClientProxyUnknown* unknownClient = static_cast(vclient); // we should have the client in our new client list assert(m_newClients.count(unknownClient) == 1); // get the real client proxy and install it ClientProxy* client = unknownClient->orphanClientProxy(); bool handshakeOk = true; if (client != NULL) { // handshake was successful m_waitingClients.push_back(client); m_events->addEvent(Event(m_events->forClientListener().connected(), this)); // watch for client to disconnect while it's in our queue m_events->adoptHandler(m_events->forClientProxy().disconnected(), client, new TMethodEventJob(this, &ClientListener::handleClientDisconnected, client)); } else { handshakeOk = false; } // now finished with unknown client m_events->removeHandler(m_events->forClientProxyUnknown().success(), client); m_events->removeHandler(m_events->forClientProxyUnknown().failure(), client); m_newClients.erase(unknownClient); PacketStreamFilter* streamFileter = dynamic_cast(unknownClient->getStream()); IDataSocket* socket = NULL; if (streamFileter != NULL) { socket = dynamic_cast(streamFileter->getStream()); } delete unknownClient; } void ClientListener::handleClientDisconnected(const Event&, void* vclient) { ClientProxy* client = static_cast(vclient); // find client in waiting clients queue for (WaitingClients::iterator i = m_waitingClients.begin(), n = m_waitingClients.end(); i != n; ++i) { if (*i == client) { m_waitingClients.erase(i); m_events->removeHandler(m_events->forClientProxy().disconnected(), client); delete client; break; } } } void ClientListener::cleanupListenSocket() { delete m_listen; } synergy-1.8.8-stable/src/lib/server/ClientListener.h000066400000000000000000000043551305627404700224570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/Config.h" #include "base/EventTypes.h" #include "base/Event.h" #include "common/stddeque.h" #include "common/stdset.h" class ClientProxy; class ClientProxyUnknown; class NetworkAddress; class IListenSocket; class ISocketFactory; class Server; class IEventQueue; class ClientListener { public: // The factories are adopted. ClientListener(const NetworkAddress&, ISocketFactory*, IEventQueue* events, bool enableCrypto); ~ClientListener(); //! @name manipulators //@{ void setServer(Server* server); //@} //! @name accessors //@{ //! Get next connected client /*! Returns the next connected client and removes it from the internal list. The client is responsible for deleting the returned client. Returns NULL if no clients are available. */ ClientProxy* getNextClient(); //! Get server which owns this listener Server* getServer() { return m_server; } //@} private: // client connection event handlers void handleClientConnecting(const Event&, void*); void handleClientAccepted(const Event&, void*); void handleUnknownClient(const Event&, void*); void handleClientDisconnected(const Event&, void*); void cleanupListenSocket(); private: typedef std::set NewClients; typedef std::deque WaitingClients; IListenSocket* m_listen; ISocketFactory* m_socketFactory; NewClients m_newClients; WaitingClients m_waitingClients; Server* m_server; IEventQueue* m_events; bool m_useSecureNetwork; }; synergy-1.8.8-stable/src/lib/server/ClientProxy.cpp000066400000000000000000000027131305627404700223420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/ClientProxy.h" #include "synergy/ProtocolUtil.h" #include "io/IStream.h" #include "base/Log.h" #include "base/EventQueue.h" // // ClientProxy // ClientProxy::ClientProxy(const String& name, synergy::IStream* stream) : BaseClientProxy(name), m_stream(stream) { } ClientProxy::~ClientProxy() { delete m_stream; } void ClientProxy::close(const char* msg) { LOG((CLOG_DEBUG1 "send close \"%s\" to \"%s\"", msg, getName().c_str())); ProtocolUtil::writef(getStream(), msg); // force the close to be sent before we return getStream()->flush(); } synergy::IStream* ClientProxy::getStream() const { return m_stream; } void* ClientProxy::getEventTarget() const { return static_cast(const_cast(this)); } synergy-1.8.8-stable/src/lib/server/ClientProxy.h000066400000000000000000000054461305627404700220150ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/BaseClientProxy.h" #include "base/Event.h" #include "base/String.h" #include "base/EventTypes.h" namespace synergy { class IStream; } //! Generic proxy for client class ClientProxy : public BaseClientProxy { public: /*! \c name is the name of the client. */ ClientProxy(const String& name, synergy::IStream* adoptedStream); ~ClientProxy(); //! @name manipulators //@{ //! Disconnect /*! Ask the client to disconnect, using \p msg as the reason. */ void close(const char* msg); //@} //! @name accessors //@{ //! Get stream /*! Returns the original stream passed to the c'tor. */ synergy::IStream* getStream() const; //@} // IScreen virtual void* getEventTarget() const; virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const = 0; virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; // IClient overrides virtual void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, bool forScreensaver) = 0; virtual bool leave() = 0; virtual void setClipboard(ClipboardID, const IClipboard*) = 0; virtual void grabClipboard(ClipboardID) = 0; virtual void setClipboardDirty(ClipboardID, bool) = 0; virtual void keyDown(KeyID, KeyModifierMask, KeyButton) = 0; virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton) = 0; virtual void keyUp(KeyID, KeyModifierMask, KeyButton) = 0; virtual void mouseDown(ButtonID) = 0; virtual void mouseUp(ButtonID) = 0; virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel) = 0; virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta) = 0; virtual void screensaver(bool activate) = 0; virtual void resetOptions() = 0; virtual void setOptions(const OptionsList& options) = 0; virtual void sendDragInfo(UInt32 fileCount, const char* info, size_t size) = 0; virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize) = 0; private: synergy::IStream* m_stream; }; synergy-1.8.8-stable/src/lib/server/ClientProxy1_0.cpp000066400000000000000000000300671305627404700226450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/ClientProxy1_0.h" #include "synergy/ProtocolUtil.h" #include "synergy/XSynergy.h" #include "io/IStream.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include // // ClientProxy1_0 // ClientProxy1_0::ClientProxy1_0(const String& name, synergy::IStream* stream, IEventQueue* events) : ClientProxy(name, stream), m_heartbeatTimer(NULL), m_parser(&ClientProxy1_0::parseHandshakeMessage), m_events(events) { // install event handlers m_events->adoptHandler(m_events->forIStream().inputReady(), stream->getEventTarget(), new TMethodEventJob(this, &ClientProxy1_0::handleData, NULL)); m_events->adoptHandler(m_events->forIStream().outputError(), stream->getEventTarget(), new TMethodEventJob(this, &ClientProxy1_0::handleWriteError, NULL)); m_events->adoptHandler(m_events->forIStream().inputShutdown(), stream->getEventTarget(), new TMethodEventJob(this, &ClientProxy1_0::handleDisconnect, NULL)); m_events->adoptHandler(m_events->forIStream().outputShutdown(), stream->getEventTarget(), new TMethodEventJob(this, &ClientProxy1_0::handleWriteError, NULL)); m_events->adoptHandler(Event::kTimer, this, new TMethodEventJob(this, &ClientProxy1_0::handleFlatline, NULL)); setHeartbeatRate(kHeartRate, kHeartRate * kHeartBeatsUntilDeath); LOG((CLOG_DEBUG1 "querying client \"%s\" info", getName().c_str())); ProtocolUtil::writef(getStream(), kMsgQInfo); } ClientProxy1_0::~ClientProxy1_0() { removeHandlers(); } void ClientProxy1_0::disconnect() { removeHandlers(); getStream()->close(); m_events->addEvent(Event(m_events->forClientProxy().disconnected(), getEventTarget())); } void ClientProxy1_0::removeHandlers() { // uninstall event handlers m_events->removeHandler(m_events->forIStream().inputReady(), getStream()->getEventTarget()); m_events->removeHandler(m_events->forIStream().outputError(), getStream()->getEventTarget()); m_events->removeHandler(m_events->forIStream().inputShutdown(), getStream()->getEventTarget()); m_events->removeHandler(m_events->forIStream().outputShutdown(), getStream()->getEventTarget()); m_events->removeHandler(Event::kTimer, this); // remove timer removeHeartbeatTimer(); } void ClientProxy1_0::addHeartbeatTimer() { if (m_heartbeatAlarm > 0.0) { m_heartbeatTimer = m_events->newOneShotTimer(m_heartbeatAlarm, this); } } void ClientProxy1_0::removeHeartbeatTimer() { if (m_heartbeatTimer != NULL) { m_events->deleteTimer(m_heartbeatTimer); m_heartbeatTimer = NULL; } } void ClientProxy1_0::resetHeartbeatTimer() { // reset the alarm removeHeartbeatTimer(); addHeartbeatTimer(); } void ClientProxy1_0::resetHeartbeatRate() { setHeartbeatRate(kHeartRate, kHeartRate * kHeartBeatsUntilDeath); } void ClientProxy1_0::setHeartbeatRate(double, double alarm) { m_heartbeatAlarm = alarm; } void ClientProxy1_0::handleData(const Event&, void*) { // handle messages until there are no more. first read message code. UInt8 code[4]; UInt32 n = getStream()->read(code, 4); while (n != 0) { // verify we got an entire code if (n != 4) { LOG((CLOG_ERR "incomplete message from \"%s\": %d bytes", getName().c_str(), n)); disconnect(); return; } // parse message LOG((CLOG_DEBUG2 "msg from \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3])); if (!(this->*m_parser)(code)) { LOG((CLOG_ERR "invalid message from client \"%s\": %c%c%c%c", getName().c_str(), code[0], code[1], code[2], code[3])); disconnect(); return; } // next message n = getStream()->read(code, 4); } // restart heartbeat timer resetHeartbeatTimer(); } bool ClientProxy1_0::parseHandshakeMessage(const UInt8* code) { if (memcmp(code, kMsgCNoop, 4) == 0) { // discard no-ops LOG((CLOG_DEBUG2 "no-op from", getName().c_str())); return true; } else if (memcmp(code, kMsgDInfo, 4) == 0) { // future messages get parsed by parseMessage m_parser = &ClientProxy1_0::parseMessage; if (recvInfo()) { m_events->addEvent(Event(m_events->forClientProxy().ready(), getEventTarget())); addHeartbeatTimer(); return true; } } return false; } bool ClientProxy1_0::parseMessage(const UInt8* code) { if (memcmp(code, kMsgDInfo, 4) == 0) { if (recvInfo()) { m_events->addEvent( Event(m_events->forIScreen().shapeChanged(), getEventTarget())); return true; } return false; } else if (memcmp(code, kMsgCNoop, 4) == 0) { // discard no-ops LOG((CLOG_DEBUG2 "no-op from", getName().c_str())); return true; } else if (memcmp(code, kMsgCClipboard, 4) == 0) { return recvGrabClipboard(); } else if (memcmp(code, kMsgDClipboard, 4) == 0) { return recvClipboard(); } return false; } void ClientProxy1_0::handleDisconnect(const Event&, void*) { LOG((CLOG_NOTE "client \"%s\" has disconnected", getName().c_str())); disconnect(); } void ClientProxy1_0::handleWriteError(const Event&, void*) { LOG((CLOG_WARN "error writing to client \"%s\"", getName().c_str())); disconnect(); } void ClientProxy1_0::handleFlatline(const Event&, void*) { // didn't get a heartbeat fast enough. assume client is dead. LOG((CLOG_NOTE "client \"%s\" is dead", getName().c_str())); disconnect(); } bool ClientProxy1_0::getClipboard(ClipboardID id, IClipboard* clipboard) const { Clipboard::copy(clipboard, &m_clipboard[id].m_clipboard); return true; } void ClientProxy1_0::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { x = m_info.m_x; y = m_info.m_y; w = m_info.m_w; h = m_info.m_h; } void ClientProxy1_0::getCursorPos(SInt32& x, SInt32& y) const { // note -- this returns the cursor pos from when we last got client info x = m_info.m_mx; y = m_info.m_my; } void ClientProxy1_0::enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, bool) { LOG((CLOG_DEBUG1 "send enter to \"%s\", %d,%d %d %04x", getName().c_str(), xAbs, yAbs, seqNum, mask)); ProtocolUtil::writef(getStream(), kMsgCEnter, xAbs, yAbs, seqNum, mask); } bool ClientProxy1_0::leave() { LOG((CLOG_DEBUG1 "send leave to \"%s\"", getName().c_str())); ProtocolUtil::writef(getStream(), kMsgCLeave); // we can never prevent the user from leaving return true; } void ClientProxy1_0::setClipboard(ClipboardID id, const IClipboard* clipboard) { // ignore -- deprecated in protocol 1.0 } void ClientProxy1_0::grabClipboard(ClipboardID id) { LOG((CLOG_DEBUG "send grab clipboard %d to \"%s\"", id, getName().c_str())); ProtocolUtil::writef(getStream(), kMsgCClipboard, id, 0); // this clipboard is now dirty m_clipboard[id].m_dirty = true; } void ClientProxy1_0::setClipboardDirty(ClipboardID id, bool dirty) { m_clipboard[id].m_dirty = dirty; } void ClientProxy1_0::keyDown(KeyID key, KeyModifierMask mask, KeyButton) { LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask)); ProtocolUtil::writef(getStream(), kMsgDKeyDown1_0, key, mask); } void ClientProxy1_0::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, KeyButton) { LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d", getName().c_str(), key, mask, count)); ProtocolUtil::writef(getStream(), kMsgDKeyRepeat1_0, key, mask, count); } void ClientProxy1_0::keyUp(KeyID key, KeyModifierMask mask, KeyButton) { LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x", getName().c_str(), key, mask)); ProtocolUtil::writef(getStream(), kMsgDKeyUp1_0, key, mask); } void ClientProxy1_0::mouseDown(ButtonID button) { LOG((CLOG_DEBUG1 "send mouse down to \"%s\" id=%d", getName().c_str(), button)); ProtocolUtil::writef(getStream(), kMsgDMouseDown, button); } void ClientProxy1_0::mouseUp(ButtonID button) { LOG((CLOG_DEBUG1 "send mouse up to \"%s\" id=%d", getName().c_str(), button)); ProtocolUtil::writef(getStream(), kMsgDMouseUp, button); } void ClientProxy1_0::mouseMove(SInt32 xAbs, SInt32 yAbs) { LOG((CLOG_DEBUG2 "send mouse move to \"%s\" %d,%d", getName().c_str(), xAbs, yAbs)); ProtocolUtil::writef(getStream(), kMsgDMouseMove, xAbs, yAbs); } void ClientProxy1_0::mouseRelativeMove(SInt32, SInt32) { // ignore -- not supported in protocol 1.0 } void ClientProxy1_0::mouseWheel(SInt32, SInt32 yDelta) { // clients prior to 1.3 only support the y axis LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d", getName().c_str(), yDelta)); ProtocolUtil::writef(getStream(), kMsgDMouseWheel1_0, yDelta); } void ClientProxy1_0::sendDragInfo(UInt32 fileCount, const char* info, size_t size) { // ignore -- not supported in protocol 1.0 LOG((CLOG_DEBUG "draggingInfoSending not supported")); } void ClientProxy1_0::fileChunkSending(UInt8 mark, char* data, size_t dataSize) { // ignore -- not supported in protocol 1.0 LOG((CLOG_DEBUG "fileChunkSending not supported")); } void ClientProxy1_0::screensaver(bool on) { LOG((CLOG_DEBUG1 "send screen saver to \"%s\" on=%d", getName().c_str(), on ? 1 : 0)); ProtocolUtil::writef(getStream(), kMsgCScreenSaver, on ? 1 : 0); } void ClientProxy1_0::resetOptions() { LOG((CLOG_DEBUG1 "send reset options to \"%s\"", getName().c_str())); ProtocolUtil::writef(getStream(), kMsgCResetOptions); // reset heart rate and death resetHeartbeatRate(); removeHeartbeatTimer(); addHeartbeatTimer(); } void ClientProxy1_0::setOptions(const OptionsList& options) { LOG((CLOG_DEBUG1 "send set options to \"%s\" size=%d", getName().c_str(), options.size())); ProtocolUtil::writef(getStream(), kMsgDSetOptions, &options); // check options for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { if (options[i] == kOptionHeartbeat) { double rate = 1.0e-3 * static_cast(options[i + 1]); if (rate <= 0.0) { rate = -1.0; } setHeartbeatRate(rate, rate * kHeartBeatsUntilDeath); removeHeartbeatTimer(); addHeartbeatTimer(); } } } bool ClientProxy1_0::recvInfo() { // parse the message SInt16 x, y, w, h, dummy1, mx, my; if (!ProtocolUtil::readf(getStream(), kMsgDInfo + 4, &x, &y, &w, &h, &dummy1, &mx, &my)) { return false; } LOG((CLOG_DEBUG "received client \"%s\" info shape=%d,%d %dx%d at %d,%d", getName().c_str(), x, y, w, h, mx, my)); // validate if (w <= 0 || h <= 0) { return false; } if (mx < x || mx >= x + w || my < y || my >= y + h) { mx = x + w / 2; my = y + h / 2; } // save m_info.m_x = x; m_info.m_y = y; m_info.m_w = w; m_info.m_h = h; m_info.m_mx = mx; m_info.m_my = my; // acknowledge receipt LOG((CLOG_DEBUG1 "send info ack to \"%s\"", getName().c_str())); ProtocolUtil::writef(getStream(), kMsgCInfoAck); return true; } bool ClientProxy1_0::recvClipboard() { // deprecated in protocol 1.0 return false; } bool ClientProxy1_0::recvGrabClipboard() { // parse message ClipboardID id; UInt32 seqNum; if (!ProtocolUtil::readf(getStream(), kMsgCClipboard + 4, &id, &seqNum)) { return false; } LOG((CLOG_DEBUG "received client \"%s\" grabbed clipboard %d seqnum=%d", getName().c_str(), id, seqNum)); // validate if (id >= kClipboardEnd) { return false; } // notify ClipboardInfo* info = new ClipboardInfo; info->m_id = id; info->m_sequenceNumber = seqNum; m_events->addEvent(Event(m_events->forClipboard().clipboardGrabbed(), getEventTarget(), info)); return true; } // // ClientProxy1_0::ClientClipboard // ClientProxy1_0::ClientClipboard::ClientClipboard() : m_clipboard(), m_sequenceNumber(0), m_dirty(true) { // do nothing } synergy-1.8.8-stable/src/lib/server/ClientProxy1_0.h000066400000000000000000000066021305627404700223100ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/ClientProxy.h" #include "synergy/Clipboard.h" #include "synergy/protocol_types.h" class Event; class EventQueueTimer; class IEventQueue; //! Proxy for client implementing protocol version 1.0 class ClientProxy1_0 : public ClientProxy { public: ClientProxy1_0(const String& name, synergy::IStream* adoptedStream, IEventQueue* events); ~ClientProxy1_0(); // IScreen virtual bool getClipboard(ClipboardID id, IClipboard*) const; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const; virtual void getCursorPos(SInt32& x, SInt32& y) const; // IClient overrides virtual void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, bool forScreensaver); virtual bool leave(); virtual void setClipboard(ClipboardID, const IClipboard*); virtual void grabClipboard(ClipboardID); virtual void setClipboardDirty(ClipboardID, bool); virtual void keyDown(KeyID, KeyModifierMask, KeyButton); virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton); virtual void keyUp(KeyID, KeyModifierMask, KeyButton); virtual void mouseDown(ButtonID); virtual void mouseUp(ButtonID); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta); virtual void screensaver(bool activate); virtual void resetOptions(); virtual void setOptions(const OptionsList& options); virtual void sendDragInfo(UInt32 fileCount, const char* info, size_t size); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); protected: virtual bool parseHandshakeMessage(const UInt8* code); virtual bool parseMessage(const UInt8* code); virtual void resetHeartbeatRate(); virtual void setHeartbeatRate(double rate, double alarm); virtual void resetHeartbeatTimer(); virtual void addHeartbeatTimer(); virtual void removeHeartbeatTimer(); virtual bool recvClipboard(); private: void disconnect(); void removeHandlers(); void handleData(const Event&, void*); void handleDisconnect(const Event&, void*); void handleWriteError(const Event&, void*); void handleFlatline(const Event&, void*); bool recvInfo(); bool recvGrabClipboard(); protected: struct ClientClipboard { public: ClientClipboard(); public: Clipboard m_clipboard; UInt32 m_sequenceNumber; bool m_dirty; }; ClientClipboard m_clipboard[kClipboardEnd]; private: typedef bool (ClientProxy1_0::*MessageParser)(const UInt8*); ClientInfo m_info; double m_heartbeatAlarm; EventQueueTimer* m_heartbeatTimer; MessageParser m_parser; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/server/ClientProxy1_1.cpp000066400000000000000000000036261305627404700226470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/ClientProxy1_1.h" #include "synergy/ProtocolUtil.h" #include "base/Log.h" #include // // ClientProxy1_1 // ClientProxy1_1::ClientProxy1_1(const String& name, synergy::IStream* stream, IEventQueue* events) : ClientProxy1_0(name, stream, events) { // do nothing } ClientProxy1_1::~ClientProxy1_1() { // do nothing } void ClientProxy1_1::keyDown(KeyID key, KeyModifierMask mask, KeyButton button) { LOG((CLOG_DEBUG1 "send key down to \"%s\" id=%d, mask=0x%04x, button=0x%04x", getName().c_str(), key, mask, button)); ProtocolUtil::writef(getStream(), kMsgDKeyDown, key, mask, button); } void ClientProxy1_1::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button) { LOG((CLOG_DEBUG1 "send key repeat to \"%s\" id=%d, mask=0x%04x, count=%d, button=0x%04x", getName().c_str(), key, mask, count, button)); ProtocolUtil::writef(getStream(), kMsgDKeyRepeat, key, mask, count, button); } void ClientProxy1_1::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) { LOG((CLOG_DEBUG1 "send key up to \"%s\" id=%d, mask=0x%04x, button=0x%04x", getName().c_str(), key, mask, button)); ProtocolUtil::writef(getStream(), kMsgDKeyUp, key, mask, button); } synergy-1.8.8-stable/src/lib/server/ClientProxy1_1.h000066400000000000000000000023131305627404700223040ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/ClientProxy1_0.h" //! Proxy for client implementing protocol version 1.1 class ClientProxy1_1 : public ClientProxy1_0 { public: ClientProxy1_1(const String& name, synergy::IStream* adoptedStream, IEventQueue* events); ~ClientProxy1_1(); // IClient overrides virtual void keyDown(KeyID, KeyModifierMask, KeyButton); virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton); virtual void keyUp(KeyID, KeyModifierMask, KeyButton); }; synergy-1.8.8-stable/src/lib/server/ClientProxy1_2.cpp000066400000000000000000000024151305627404700226430ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/ClientProxy1_2.h" #include "synergy/ProtocolUtil.h" #include "base/Log.h" // // ClientProxy1_1 // ClientProxy1_2::ClientProxy1_2(const String& name, synergy::IStream* stream, IEventQueue* events) : ClientProxy1_1(name, stream, events) { // do nothing } ClientProxy1_2::~ClientProxy1_2() { // do nothing } void ClientProxy1_2::mouseRelativeMove(SInt32 xRel, SInt32 yRel) { LOG((CLOG_DEBUG2 "send mouse relative move to \"%s\" %d,%d", getName().c_str(), xRel, yRel)); ProtocolUtil::writef(getStream(), kMsgDMouseRelMove, xRel, yRel); } synergy-1.8.8-stable/src/lib/server/ClientProxy1_2.h000066400000000000000000000021251305627404700223060ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/ClientProxy1_1.h" class IEventQueue; //! Proxy for client implementing protocol version 1.2 class ClientProxy1_2 : public ClientProxy1_1 { public: ClientProxy1_2(const String& name, synergy::IStream* adoptedStream, IEventQueue* events); ~ClientProxy1_2(); // IClient overrides virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); }; synergy-1.8.8-stable/src/lib/server/ClientProxy1_3.cpp000066400000000000000000000062621305627404700226500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2006 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/ClientProxy1_3.h" #include "synergy/ProtocolUtil.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include #include // // ClientProxy1_3 // ClientProxy1_3::ClientProxy1_3(const String& name, synergy::IStream* stream, IEventQueue* events) : ClientProxy1_2(name, stream, events), m_keepAliveRate(kKeepAliveRate), m_keepAliveTimer(NULL), m_events(events) { setHeartbeatRate(kKeepAliveRate, kKeepAliveRate * kKeepAlivesUntilDeath); } ClientProxy1_3::~ClientProxy1_3() { // cannot do this in superclass or our override wouldn't get called removeHeartbeatTimer(); } void ClientProxy1_3::mouseWheel(SInt32 xDelta, SInt32 yDelta) { LOG((CLOG_DEBUG2 "send mouse wheel to \"%s\" %+d,%+d", getName().c_str(), xDelta, yDelta)); ProtocolUtil::writef(getStream(), kMsgDMouseWheel, xDelta, yDelta); } bool ClientProxy1_3::parseMessage(const UInt8* code) { // process message if (memcmp(code, kMsgCKeepAlive, 4) == 0) { // reset alarm resetHeartbeatTimer(); return true; } else { return ClientProxy1_2::parseMessage(code); } } void ClientProxy1_3::resetHeartbeatRate() { setHeartbeatRate(kKeepAliveRate, kKeepAliveRate * kKeepAlivesUntilDeath); } void ClientProxy1_3::setHeartbeatRate(double rate, double) { m_keepAliveRate = rate; ClientProxy1_2::setHeartbeatRate(rate, rate * kKeepAlivesUntilDeath); } void ClientProxy1_3::resetHeartbeatTimer() { // reset the alarm but not the keep alive timer ClientProxy1_2::removeHeartbeatTimer(); ClientProxy1_2::addHeartbeatTimer(); } void ClientProxy1_3::addHeartbeatTimer() { // create and install a timer to periodically send keep alives if (m_keepAliveRate > 0.0) { m_keepAliveTimer = m_events->newTimer(m_keepAliveRate, NULL); m_events->adoptHandler(Event::kTimer, m_keepAliveTimer, new TMethodEventJob(this, &ClientProxy1_3::handleKeepAlive, NULL)); } // superclass does the alarm ClientProxy1_2::addHeartbeatTimer(); } void ClientProxy1_3::removeHeartbeatTimer() { // remove the timer that sends keep alives periodically if (m_keepAliveTimer != NULL) { m_events->removeHandler(Event::kTimer, m_keepAliveTimer); m_events->deleteTimer(m_keepAliveTimer); m_keepAliveTimer = NULL; } // superclass does the alarm ClientProxy1_2::removeHeartbeatTimer(); } void ClientProxy1_3::handleKeepAlive(const Event&, void*) { keepAlive(); } void ClientProxy1_3::keepAlive() { ProtocolUtil::writef(getStream(), kMsgCKeepAlive); } synergy-1.8.8-stable/src/lib/server/ClientProxy1_3.h000066400000000000000000000030251305627404700223070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2006 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/ClientProxy1_2.h" //! Proxy for client implementing protocol version 1.3 class ClientProxy1_3 : public ClientProxy1_2 { public: ClientProxy1_3(const String& name, synergy::IStream* adoptedStream, IEventQueue* events); ~ClientProxy1_3(); // IClient overrides virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta); void handleKeepAlive(const Event&, void*); protected: // ClientProxy overrides virtual bool parseMessage(const UInt8* code); virtual void resetHeartbeatRate(); virtual void setHeartbeatRate(double rate, double alarm); virtual void resetHeartbeatTimer(); virtual void addHeartbeatTimer(); virtual void removeHeartbeatTimer(); virtual void keepAlive(); private: double m_keepAliveRate; EventQueueTimer* m_keepAliveTimer; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/server/ClientProxy1_4.cpp000066400000000000000000000032441305627404700226460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/ClientProxy1_4.h" #include "server/Server.h" #include "synergy/ProtocolUtil.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include #include // // ClientProxy1_4 // ClientProxy1_4::ClientProxy1_4(const String& name, synergy::IStream* stream, Server* server, IEventQueue* events) : ClientProxy1_3(name, stream, events), m_server(server) { assert(m_server != NULL); } ClientProxy1_4::~ClientProxy1_4() { } void ClientProxy1_4::keyDown(KeyID key, KeyModifierMask mask, KeyButton button) { ClientProxy1_3::keyDown(key, mask, button); } void ClientProxy1_4::keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button) { ClientProxy1_3::keyRepeat(key, mask, count, button); } void ClientProxy1_4::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) { ClientProxy1_3::keyUp(key, mask, button); } void ClientProxy1_4::keepAlive() { ClientProxy1_3::keepAlive(); } synergy-1.8.8-stable/src/lib/server/ClientProxy1_4.h000066400000000000000000000026551305627404700223200ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/ClientProxy1_3.h" class Server; //! Proxy for client implementing protocol version 1.4 class ClientProxy1_4 : public ClientProxy1_3 { public: ClientProxy1_4(const String& name, synergy::IStream* adoptedStream, Server* server, IEventQueue* events); ~ClientProxy1_4(); //! @name accessors //@{ //! get server pointer Server* getServer() { return m_server; } //@} // IClient overrides virtual void keyDown(KeyID key, KeyModifierMask mask, KeyButton button); virtual void keyRepeat(KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button); virtual void keyUp(KeyID key, KeyModifierMask mask, KeyButton button); virtual void keepAlive(); Server* m_server; }; synergy-1.8.8-stable/src/lib/server/ClientProxy1_5.cpp000066400000000000000000000053471305627404700226550ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/ClientProxy1_5.h" #include "server/Server.h" #include "synergy/FileChunk.h" #include "synergy/StreamChunker.h" #include "synergy/ProtocolUtil.h" #include "io/IStream.h" #include "base/TMethodEventJob.h" #include "base/Log.h" #include // // ClientProxy1_5 // ClientProxy1_5::ClientProxy1_5(const String& name, synergy::IStream* stream, Server* server, IEventQueue* events) : ClientProxy1_4(name, stream, server, events), m_events(events) { m_events->adoptHandler(m_events->forFile().keepAlive(), this, new TMethodEventJob(this, &ClientProxy1_3::handleKeepAlive, NULL)); } ClientProxy1_5::~ClientProxy1_5() { m_events->removeHandler(m_events->forFile().keepAlive(), this); } void ClientProxy1_5::sendDragInfo(UInt32 fileCount, const char* info, size_t size) { String data(info, size); ProtocolUtil::writef(getStream(), kMsgDDragInfo, fileCount, &data); } void ClientProxy1_5::fileChunkSending(UInt8 mark, char* data, size_t dataSize) { FileChunk::send(getStream(), mark, data, dataSize); } bool ClientProxy1_5::parseMessage(const UInt8* code) { if (memcmp(code, kMsgDFileTransfer, 4) == 0) { fileChunkReceived(); } else if (memcmp(code, kMsgDDragInfo, 4) == 0) { dragInfoReceived(); } else { return ClientProxy1_4::parseMessage(code); } return true; } void ClientProxy1_5::fileChunkReceived() { Server* server = getServer(); int result = FileChunk::assemble( getStream(), server->getReceivedFileData(), server->getExpectedFileSize()); if (result == kFinish) { m_events->addEvent(Event(m_events->forFile().fileRecieveCompleted(), server)); } else if (result == kStart) { if (server->getFakeDragFileList().size() > 0) { String filename = server->getFakeDragFileList().at(0).getFilename(); LOG((CLOG_DEBUG "start receiving %s", filename.c_str())); } } } void ClientProxy1_5::dragInfoReceived() { // parse UInt32 fileNum = 0; String content; ProtocolUtil::readf(getStream(), kMsgDDragInfo + 4, &fileNum, &content); m_server->dragInfoReceived(fileNum, content); } synergy-1.8.8-stable/src/lib/server/ClientProxy1_5.h000066400000000000000000000025321305627404700223130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/ClientProxy1_4.h" #include "base/Stopwatch.h" #include "common/stdvector.h" class Server; class IEventQueue; //! Proxy for client implementing protocol version 1.5 class ClientProxy1_5 : public ClientProxy1_4 { public: ClientProxy1_5(const String& name, synergy::IStream* adoptedStream, Server* server, IEventQueue* events); ~ClientProxy1_5(); virtual void sendDragInfo(UInt32 fileCount, const char* info, size_t size); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); virtual bool parseMessage(const UInt8* code); void fileChunkReceived(); void dragInfoReceived(); private: IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/server/ClientProxy1_6.cpp000066400000000000000000000054721305627404700226550ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/ClientProxy1_6.h" #include "server/Server.h" #include "synergy/ProtocolUtil.h" #include "synergy/StreamChunker.h" #include "synergy/ClipboardChunk.h" #include "io/IStream.h" #include "base/TMethodEventJob.h" #include "base/Log.h" // // ClientProxy1_6 // ClientProxy1_6::ClientProxy1_6(const String& name, synergy::IStream* stream, Server* server, IEventQueue* events) : ClientProxy1_5(name, stream, server, events), m_events(events) { m_events->adoptHandler(m_events->forClipboard().clipboardSending(), this, new TMethodEventJob(this, &ClientProxy1_6::handleClipboardSendingEvent)); } ClientProxy1_6::~ClientProxy1_6() { } void ClientProxy1_6::setClipboard(ClipboardID id, const IClipboard* clipboard) { // ignore if this clipboard is already clean if (m_clipboard[id].m_dirty) { // this clipboard is now clean m_clipboard[id].m_dirty = false; Clipboard::copy(&m_clipboard[id].m_clipboard, clipboard); String data = m_clipboard[id].m_clipboard.marshall(); size_t size = data.size(); LOG((CLOG_DEBUG "sending clipboard %d to \"%s\"", id, getName().c_str())); StreamChunker::sendClipboard(data, size, id, 0, m_events, this); } } void ClientProxy1_6::handleClipboardSendingEvent(const Event& event, void*) { ClipboardChunk::send(getStream(), event.getData()); } bool ClientProxy1_6::recvClipboard() { // parse message static String dataCached; ClipboardID id; UInt32 seq; int r = ClipboardChunk::assemble(getStream(), dataCached, id, seq); if (r == kStart) { size_t size = ClipboardChunk::getExpectedSize(); LOG((CLOG_DEBUG "receiving clipboard %d size=%d", id, size)); } else if (r == kFinish) { LOG((CLOG_DEBUG "received client \"%s\" clipboard %d seqnum=%d, size=%d", getName().c_str(), id, seq, dataCached.size())); // save clipboard m_clipboard[id].m_clipboard.unmarshall(dataCached, 0); m_clipboard[id].m_sequenceNumber = seq; // notify ClipboardInfo* info = new ClipboardInfo; info->m_id = id; info->m_sequenceNumber = seq; m_events->addEvent(Event(m_events->forClipboard().clipboardChanged(), getEventTarget(), info)); } return true; } synergy-1.8.8-stable/src/lib/server/ClientProxy1_6.h000066400000000000000000000023141305627404700223120ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/ClientProxy1_5.h" class Server; class IEventQueue; //! Proxy for client implementing protocol version 1.6 class ClientProxy1_6 : public ClientProxy1_5 { public: ClientProxy1_6(const String& name, synergy::IStream* adoptedStream, Server* server, IEventQueue* events); ~ClientProxy1_6(); virtual void setClipboard(ClipboardID id, const IClipboard* clipboard); virtual bool recvClipboard(); private: void handleClipboardSendingEvent(const Event&, void*); private: IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/server/ClientProxyUnknown.cpp000066400000000000000000000171171305627404700237260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/ClientProxyUnknown.h" #include "server/Server.h" #include "server/ClientProxy1_0.h" #include "server/ClientProxy1_1.h" #include "server/ClientProxy1_2.h" #include "server/ClientProxy1_3.h" #include "server/ClientProxy1_4.h" #include "server/ClientProxy1_5.h" #include "server/ClientProxy1_6.h" #include "synergy/protocol_types.h" #include "synergy/ProtocolUtil.h" #include "synergy/XSynergy.h" #include "io/IStream.h" #include "io/XIO.h" #include "base/Log.h" #include "base/String.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" // // ClientProxyUnknown // ClientProxyUnknown::ClientProxyUnknown(synergy::IStream* stream, double timeout, Server* server, IEventQueue* events) : m_stream(stream), m_proxy(NULL), m_ready(false), m_server(server), m_events(events) { assert(m_server != NULL); m_events->adoptHandler(Event::kTimer, this, new TMethodEventJob(this, &ClientProxyUnknown::handleTimeout, NULL)); m_timer = m_events->newOneShotTimer(timeout, this); addStreamHandlers(); LOG((CLOG_DEBUG1 "saying hello")); ProtocolUtil::writef(m_stream, kMsgHello, kProtocolMajorVersion, kProtocolMinorVersion); } ClientProxyUnknown::~ClientProxyUnknown() { removeHandlers(); removeTimer(); delete m_stream; delete m_proxy; } ClientProxy* ClientProxyUnknown::orphanClientProxy() { if (m_ready) { removeHandlers(); ClientProxy* proxy = m_proxy; m_proxy = NULL; return proxy; } else { return NULL; } } void ClientProxyUnknown::sendSuccess() { m_ready = true; removeTimer(); m_events->addEvent(Event(m_events->forClientProxyUnknown().success(), this)); } void ClientProxyUnknown::sendFailure() { delete m_proxy; m_proxy = NULL; m_ready = false; removeHandlers(); removeTimer(); m_events->addEvent(Event(m_events->forClientProxyUnknown().failure(), this)); } void ClientProxyUnknown::addStreamHandlers() { assert(m_stream != NULL); m_events->adoptHandler(m_events->forIStream().inputReady(), m_stream->getEventTarget(), new TMethodEventJob(this, &ClientProxyUnknown::handleData)); m_events->adoptHandler(m_events->forIStream().outputError(), m_stream->getEventTarget(), new TMethodEventJob(this, &ClientProxyUnknown::handleWriteError)); m_events->adoptHandler(m_events->forIStream().inputShutdown(), m_stream->getEventTarget(), new TMethodEventJob(this, &ClientProxyUnknown::handleDisconnect)); m_events->adoptHandler(m_events->forIStream().outputShutdown(), m_stream->getEventTarget(), new TMethodEventJob(this, &ClientProxyUnknown::handleWriteError)); } void ClientProxyUnknown::addProxyHandlers() { assert(m_proxy != NULL); m_events->adoptHandler(m_events->forClientProxy().ready(), m_proxy, new TMethodEventJob(this, &ClientProxyUnknown::handleReady)); m_events->adoptHandler(m_events->forClientProxy().disconnected(), m_proxy, new TMethodEventJob(this, &ClientProxyUnknown::handleDisconnect)); } void ClientProxyUnknown::removeHandlers() { if (m_stream != NULL) { m_events->removeHandler(m_events->forIStream().inputReady(), m_stream->getEventTarget()); m_events->removeHandler(m_events->forIStream().outputError(), m_stream->getEventTarget()); m_events->removeHandler(m_events->forIStream().inputShutdown(), m_stream->getEventTarget()); m_events->removeHandler(m_events->forIStream().outputShutdown(), m_stream->getEventTarget()); } if (m_proxy != NULL) { m_events->removeHandler(m_events->forClientProxy().ready(), m_proxy); m_events->removeHandler(m_events->forClientProxy().disconnected(), m_proxy); } } void ClientProxyUnknown::removeTimer() { if (m_timer != NULL) { m_events->deleteTimer(m_timer); m_events->removeHandler(Event::kTimer, this); m_timer = NULL; } } void ClientProxyUnknown::handleData(const Event&, void*) { LOG((CLOG_DEBUG1 "parsing hello reply")); String name(""); try { // limit the maximum length of the hello UInt32 n = m_stream->getSize(); if (n > kMaxHelloLength) { LOG((CLOG_DEBUG1 "hello reply too long")); throw XBadClient(); } // parse the reply to hello SInt16 major, minor; if (!ProtocolUtil::readf(m_stream, kMsgHelloBack, &major, &minor, &name)) { throw XBadClient(); } // disallow invalid version numbers if (major <= 0 || minor < 0) { throw XIncompatibleClient(major, minor); } // remove stream event handlers. the proxy we're about to create // may install its own handlers and we don't want to accidentally // remove those later. removeHandlers(); // create client proxy for highest version supported by the client if (major == 1) { switch (minor) { case 0: m_proxy = new ClientProxy1_0(name, m_stream, m_events); break; case 1: m_proxy = new ClientProxy1_1(name, m_stream, m_events); break; case 2: m_proxy = new ClientProxy1_2(name, m_stream, m_events); break; case 3: m_proxy = new ClientProxy1_3(name, m_stream, m_events); break; case 4: m_proxy = new ClientProxy1_4(name, m_stream, m_server, m_events); break; case 5: m_proxy = new ClientProxy1_5(name, m_stream, m_server, m_events); break; case 6: m_proxy = new ClientProxy1_6(name, m_stream, m_server, m_events); break; } } // hangup (with error) if version isn't supported if (m_proxy == NULL) { throw XIncompatibleClient(major, minor); } // the proxy is created and now proxy now owns the stream LOG((CLOG_DEBUG1 "created proxy for client \"%s\" version %d.%d", name.c_str(), major, minor)); m_stream = NULL; // wait until the proxy signals that it's ready or has disconnected addProxyHandlers(); return; } catch (XIncompatibleClient& e) { // client is incompatible LOG((CLOG_WARN "client \"%s\" has incompatible version %d.%d)", name.c_str(), e.getMajor(), e.getMinor())); ProtocolUtil::writef(m_stream, kMsgEIncompatible, kProtocolMajorVersion, kProtocolMinorVersion); } catch (XBadClient&) { // client not behaving LOG((CLOG_WARN "protocol error from client \"%s\"", name.c_str())); ProtocolUtil::writef(m_stream, kMsgEBad); } catch (XBase& e) { // misc error LOG((CLOG_WARN "error communicating with client \"%s\": %s", name.c_str(), e.what())); } sendFailure(); } void ClientProxyUnknown::handleWriteError(const Event&, void*) { LOG((CLOG_NOTE "error communicating with new client")); sendFailure(); } void ClientProxyUnknown::handleTimeout(const Event&, void*) { LOG((CLOG_NOTE "new client is unresponsive")); sendFailure(); } void ClientProxyUnknown::handleDisconnect(const Event&, void*) { LOG((CLOG_NOTE "new client disconnected")); sendFailure(); } void ClientProxyUnknown::handleReady(const Event&, void*) { sendSuccess(); } synergy-1.8.8-stable/src/lib/server/ClientProxyUnknown.h000066400000000000000000000036751305627404700233770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/Event.h" #include "base/EventTypes.h" class ClientProxy; class EventQueueTimer; namespace synergy { class IStream; } class Server; class IEventQueue; class ClientProxyUnknown { public: ClientProxyUnknown(synergy::IStream* stream, double timeout, Server* server, IEventQueue* events); ~ClientProxyUnknown(); //! @name manipulators //@{ //! Get the client proxy /*! Returns the client proxy created after a successful handshake (i.e. when this object sends a success event). Returns NULL if the handshake is unsuccessful or incomplete. */ ClientProxy* orphanClientProxy(); //! Get the stream synergy::IStream* getStream() { return m_stream; } //@} private: void sendSuccess(); void sendFailure(); void addStreamHandlers(); void addProxyHandlers(); void removeHandlers(); void removeTimer(); void handleData(const Event&, void*); void handleWriteError(const Event&, void*); void handleTimeout(const Event&, void*); void handleDisconnect(const Event&, void*); void handleReady(const Event&, void*); private: synergy::IStream* m_stream; EventQueueTimer* m_timer; ClientProxy* m_proxy; bool m_ready; Server* m_server; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/server/Config.cpp000066400000000000000000001512351305627404700212730ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/Config.h" #include "server/Server.h" #include "synergy/KeyMap.h" #include "synergy/key_types.h" #include "net/XSocket.h" #include "base/IEventQueue.h" #include "common/stdistream.h" #include "common/stdostream.h" #include using namespace synergy::string; // // Config // Config::Config(IEventQueue* events) : m_inputFilter(events), m_hasLockToScreenAction(false), m_events(events) { // do nothing } Config::~Config() { // do nothing } bool Config::addScreen(const String& name) { // alias name must not exist if (m_nameToCanonicalName.find(name) != m_nameToCanonicalName.end()) { return false; } // add cell m_map.insert(std::make_pair(name, Cell())); // add name m_nameToCanonicalName.insert(std::make_pair(name, name)); return true; } bool Config::renameScreen(const String& oldName, const String& newName) { // get canonical name and find cell String oldCanonical = getCanonicalName(oldName); CellMap::iterator index = m_map.find(oldCanonical); if (index == m_map.end()) { return false; } // accept if names are equal but replace with new name to maintain // case. otherwise, the new name must not exist. if (!CaselessCmp::equal(oldName, newName) && m_nameToCanonicalName.find(newName) != m_nameToCanonicalName.end()) { return false; } // update cell Cell tmpCell = index->second; m_map.erase(index); m_map.insert(std::make_pair(newName, tmpCell)); // update name m_nameToCanonicalName.erase(oldCanonical); m_nameToCanonicalName.insert(std::make_pair(newName, newName)); // update connections Name oldNameObj(this, oldName); for (index = m_map.begin(); index != m_map.end(); ++index) { index->second.rename(oldNameObj, newName); } // update alias targets if (CaselessCmp::equal(oldName, oldCanonical)) { for (NameMap::iterator iter = m_nameToCanonicalName.begin(); iter != m_nameToCanonicalName.end(); ++iter) { if (CaselessCmp::equal( iter->second, oldCanonical)) { iter->second = newName; } } } return true; } void Config::removeScreen(const String& name) { // get canonical name and find cell String canonical = getCanonicalName(name); CellMap::iterator index = m_map.find(canonical); if (index == m_map.end()) { return; } // remove from map m_map.erase(index); // disconnect Name nameObj(this, name); for (index = m_map.begin(); index != m_map.end(); ++index) { index->second.remove(nameObj); } // remove aliases (and canonical name) for (NameMap::iterator iter = m_nameToCanonicalName.begin(); iter != m_nameToCanonicalName.end(); ) { if (iter->second == canonical) { m_nameToCanonicalName.erase(iter++); } else { ++index; } } } void Config::removeAllScreens() { m_map.clear(); m_nameToCanonicalName.clear(); } bool Config::addAlias(const String& canonical, const String& alias) { // alias name must not exist if (m_nameToCanonicalName.find(alias) != m_nameToCanonicalName.end()) { return false; } // canonical name must be known if (m_map.find(canonical) == m_map.end()) { return false; } // insert alias m_nameToCanonicalName.insert(std::make_pair(alias, canonical)); return true; } bool Config::removeAlias(const String& alias) { // must not be a canonical name if (m_map.find(alias) != m_map.end()) { return false; } // find alias NameMap::iterator index = m_nameToCanonicalName.find(alias); if (index == m_nameToCanonicalName.end()) { return false; } // remove alias m_nameToCanonicalName.erase(index); return true; } bool Config::removeAliases(const String& canonical) { // must be a canonical name if (m_map.find(canonical) == m_map.end()) { return false; } // find and removing matching aliases for (NameMap::iterator index = m_nameToCanonicalName.begin(); index != m_nameToCanonicalName.end(); ) { if (index->second == canonical && index->first != canonical) { m_nameToCanonicalName.erase(index++); } else { ++index; } } return true; } void Config::removeAllAliases() { // remove all names m_nameToCanonicalName.clear(); // put the canonical names back in for (CellMap::iterator index = m_map.begin(); index != m_map.end(); ++index) { m_nameToCanonicalName.insert( std::make_pair(index->first, index->first)); } } bool Config::connect(const String& srcName, EDirection srcSide, float srcStart, float srcEnd, const String& dstName, float dstStart, float dstEnd) { assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); // find source cell CellMap::iterator index = m_map.find(getCanonicalName(srcName)); if (index == m_map.end()) { return false; } // add link CellEdge srcEdge(srcSide, Interval(srcStart, srcEnd)); CellEdge dstEdge(dstName, srcSide, Interval(dstStart, dstEnd)); return index->second.add(srcEdge, dstEdge); } bool Config::disconnect(const String& srcName, EDirection srcSide) { assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); // find source cell CellMap::iterator index = m_map.find(srcName); if (index == m_map.end()) { return false; } // disconnect side index->second.remove(srcSide); return true; } bool Config::disconnect(const String& srcName, EDirection srcSide, float position) { assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); // find source cell CellMap::iterator index = m_map.find(srcName); if (index == m_map.end()) { return false; } // disconnect side index->second.remove(srcSide, position); return true; } void Config::setSynergyAddress(const NetworkAddress& addr) { m_synergyAddress = addr; } bool Config::addOption(const String& name, OptionID option, OptionValue value) { // find options ScreenOptions* options = NULL; if (name.empty()) { options = &m_globalOptions; } else { CellMap::iterator index = m_map.find(name); if (index != m_map.end()) { options = &index->second.m_options; } } if (options == NULL) { return false; } // add option options->insert(std::make_pair(option, value)); return true; } bool Config::removeOption(const String& name, OptionID option) { // find options ScreenOptions* options = NULL; if (name.empty()) { options = &m_globalOptions; } else { CellMap::iterator index = m_map.find(name); if (index != m_map.end()) { options = &index->second.m_options; } } if (options == NULL) { return false; } // remove option options->erase(option); return true; } bool Config::removeOptions(const String& name) { // find options ScreenOptions* options = NULL; if (name.empty()) { options = &m_globalOptions; } else { CellMap::iterator index = m_map.find(name); if (index != m_map.end()) { options = &index->second.m_options; } } if (options == NULL) { return false; } // remove options options->clear(); return true; } bool Config::isValidScreenName(const String& name) const { // name is valid if matches validname // name ::= [_A-Za-z0-9] | [_A-Za-z0-9][-_A-Za-z0-9]*[_A-Za-z0-9] // domain ::= . name // validname ::= name domain* // we also accept names ending in . because many OS X users have // so misconfigured their systems. // empty name is invalid if (name.empty()) { return false; } // check each dot separated part String::size_type b = 0; for (;;) { // accept trailing . if (b == name.size()) { break; } // find end of part String::size_type e = name.find('.', b); if (e == String::npos) { e = name.size(); } // part may not be empty if (e - b < 1) { return false; } // check first and last characters if (!(isalnum(name[b]) || name[b] == '_') || !(isalnum(name[e - 1]) || name[e - 1] == '_')) { return false; } // check interior characters for (String::size_type i = b; i < e; ++i) { if (!isalnum(name[i]) && name[i] != '_' && name[i] != '-') { return false; } } // next part if (e == name.size()) { // no more parts break; } b = e + 1; } return true; } Config::const_iterator Config::begin() const { return const_iterator(m_map.begin()); } Config::const_iterator Config::end() const { return const_iterator(m_map.end()); } Config::all_const_iterator Config::beginAll() const { return m_nameToCanonicalName.begin(); } Config::all_const_iterator Config::endAll() const { return m_nameToCanonicalName.end(); } bool Config::isScreen(const String& name) const { return (m_nameToCanonicalName.count(name) > 0); } bool Config::isCanonicalName(const String& name) const { return (!name.empty() && CaselessCmp::equal(getCanonicalName(name), name)); } String Config::getCanonicalName(const String& name) const { NameMap::const_iterator index = m_nameToCanonicalName.find(name); if (index == m_nameToCanonicalName.end()) { return String(); } else { return index->second; } } String Config::getNeighbor(const String& srcName, EDirection srcSide, float position, float* positionOut) const { assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); // find source cell CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); if (index == m_map.end()) { return String(); } // find edge const CellEdge* srcEdge, *dstEdge; if (!index->second.getLink(srcSide, position, srcEdge, dstEdge)) { // no neighbor return ""; } else { // compute position on neighbor if (positionOut != NULL) { *positionOut = dstEdge->inverseTransform(srcEdge->transform(position)); } // return neighbor's name return getCanonicalName(dstEdge->getName()); } } bool Config::hasNeighbor(const String& srcName, EDirection srcSide) const { return hasNeighbor(srcName, srcSide, 0.0f, 1.0f); } bool Config::hasNeighbor(const String& srcName, EDirection srcSide, float start, float end) const { assert(srcSide >= kFirstDirection && srcSide <= kLastDirection); // find source cell CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); if (index == m_map.end()) { return false; } return index->second.overlaps(CellEdge(srcSide, Interval(start, end))); } Config::link_const_iterator Config::beginNeighbor(const String& srcName) const { CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); assert(index != m_map.end()); return index->second.begin(); } Config::link_const_iterator Config::endNeighbor(const String& srcName) const { CellMap::const_iterator index = m_map.find(getCanonicalName(srcName)); assert(index != m_map.end()); return index->second.end(); } const NetworkAddress& Config::getSynergyAddress() const { return m_synergyAddress; } const Config::ScreenOptions* Config::getOptions(const String& name) const { // find options const ScreenOptions* options = NULL; if (name.empty()) { options = &m_globalOptions; } else { CellMap::const_iterator index = m_map.find(name); if (index != m_map.end()) { options = &index->second.m_options; } } // return options return options; } bool Config::hasLockToScreenAction() const { return m_hasLockToScreenAction; } bool Config::operator==(const Config& x) const { if (m_synergyAddress != x.m_synergyAddress) { return false; } if (m_map.size() != x.m_map.size()) { return false; } if (m_nameToCanonicalName.size() != x.m_nameToCanonicalName.size()) { return false; } // compare global options if (m_globalOptions != x.m_globalOptions) { return false; } for (CellMap::const_iterator index1 = m_map.begin(), index2 = x.m_map.begin(); index1 != m_map.end(); ++index1, ++index2) { // compare names if (!CaselessCmp::equal(index1->first, index2->first)) { return false; } // compare cells if (index1->second != index2->second) { return false; } } for (NameMap::const_iterator index1 = m_nameToCanonicalName.begin(), index2 = x.m_nameToCanonicalName.begin(); index1 != m_nameToCanonicalName.end(); ++index1, ++index2) { if (!CaselessCmp::equal(index1->first, index2->first) || !CaselessCmp::equal(index1->second, index2->second)) { return false; } } // compare input filters if (m_inputFilter != x.m_inputFilter) { return false; } return true; } bool Config::operator!=(const Config& x) const { return !operator==(x); } void Config::read(ConfigReadContext& context) { Config tmp(m_events); while (context.getStream()) { tmp.readSection(context); } *this = tmp; } const char* Config::dirName(EDirection dir) { static const char* s_name[] = { "left", "right", "up", "down" }; assert(dir >= kFirstDirection && dir <= kLastDirection); return s_name[dir - kFirstDirection]; } InputFilter* Config::getInputFilter() { return &m_inputFilter; } String Config::formatInterval(const Interval& x) { if (x.first == 0.0f && x.second == 1.0f) { return ""; } return synergy::string::sprintf("(%d,%d)", (int)(x.first * 100.0f + 0.5f), (int)(x.second * 100.0f + 0.5f)); } void Config::readSection(ConfigReadContext& s) { static const char s_section[] = "section:"; static const char s_options[] = "options"; static const char s_screens[] = "screens"; static const char s_links[] = "links"; static const char s_aliases[] = "aliases"; String line; if (!s.readLine(line)) { // no more sections return; } // should be a section header if (line.find(s_section) != 0) { throw XConfigRead(s, "found data outside section"); } // get section name String::size_type i = line.find_first_not_of(" \t", sizeof(s_section) - 1); if (i == String::npos) { throw XConfigRead(s, "section name is missing"); } String name = line.substr(i); i = name.find_first_of(" \t"); if (i != String::npos) { throw XConfigRead(s, "unexpected data after section name"); } // read section if (name == s_options) { readSectionOptions(s); } else if (name == s_screens) { readSectionScreens(s); } else if (name == s_links) { readSectionLinks(s); } else if (name == s_aliases) { readSectionAliases(s); } else { throw XConfigRead(s, "unknown section name \"%{1}\"", name); } } void Config::readSectionOptions(ConfigReadContext& s) { String line; while (s.readLine(line)) { // check for end of section if (line == "end") { return; } // parse argument: `nameAndArgs = [values][;[values]]' // nameAndArgs := [(arg[,...])] // values := valueAndArgs[,valueAndArgs]... // valueAndArgs := [(arg[,...])] String::size_type i = 0; String name, value; ConfigReadContext::ArgList nameArgs, valueArgs; s.parseNameWithArgs("name", line, "=", i, name, nameArgs); ++i; s.parseNameWithArgs("value", line, ",;\n", i, value, valueArgs); bool handled = true; if (name == "address") { try { m_synergyAddress = NetworkAddress(value, kDefaultPort); m_synergyAddress.resolve(); } catch (XSocketAddress& e) { throw XConfigRead(s, String("invalid address argument ") + e.what()); } } else if (name == "heartbeat") { addOption("", kOptionHeartbeat, s.parseInt(value)); } else if (name == "switchCorners") { addOption("", kOptionScreenSwitchCorners, s.parseCorners(value)); } else if (name == "switchCornerSize") { addOption("", kOptionScreenSwitchCornerSize, s.parseInt(value)); } else if (name == "switchDelay") { addOption("", kOptionScreenSwitchDelay, s.parseInt(value)); } else if (name == "switchDoubleTap") { addOption("", kOptionScreenSwitchTwoTap, s.parseInt(value)); } else if (name == "switchNeedsShift") { addOption("", kOptionScreenSwitchNeedsShift, s.parseBoolean(value)); } else if (name == "switchNeedsControl") { addOption("", kOptionScreenSwitchNeedsControl, s.parseBoolean(value)); } else if (name == "switchNeedsAlt") { addOption("", kOptionScreenSwitchNeedsAlt, s.parseBoolean(value)); } else if (name == "screenSaverSync") { addOption("", kOptionScreenSaverSync, s.parseBoolean(value)); } else if (name == "relativeMouseMoves") { addOption("", kOptionRelativeMouseMoves, s.parseBoolean(value)); } else if (name == "win32KeepForeground") { addOption("", kOptionWin32KeepForeground, s.parseBoolean(value)); } else if (name == "clipboardSharing") { addOption("", kOptionClipboardSharing, s.parseBoolean(value)); } else { handled = false; } if (handled) { // make sure handled options aren't followed by more values if (i < line.size() && (line[i] == ',' || line[i] == ';')) { throw XConfigRead(s, "to many arguments to %s", name.c_str()); } } else { // make filter rule InputFilter::Rule rule(parseCondition(s, name, nameArgs)); // save first action (if any) if (!value.empty() || line[i] != ';') { parseAction(s, value, valueArgs, rule, true); } // get remaining activate actions while (i < line.length() && line[i] != ';') { ++i; s.parseNameWithArgs("value", line, ",;\n", i, value, valueArgs); parseAction(s, value, valueArgs, rule, true); } // get deactivate actions if (i < line.length() && line[i] == ';') { // allow trailing ';' i = line.find_first_not_of(" \t", i + 1); if (i == String::npos) { i = line.length(); } else { --i; } // get actions while (i < line.length()) { ++i; s.parseNameWithArgs("value", line, ",\n", i, value, valueArgs); parseAction(s, value, valueArgs, rule, false); } } // add rule m_inputFilter.addFilterRule(rule); } } throw XConfigRead(s, "unexpected end of options section"); } void Config::readSectionScreens(ConfigReadContext& s) { String line; String screen; while (s.readLine(line)) { // check for end of section if (line == "end") { return; } // see if it's the next screen if (line[line.size() - 1] == ':') { // strip : screen = line.substr(0, line.size() - 1); // verify validity of screen name if (!isValidScreenName(screen)) { throw XConfigRead(s, "invalid screen name \"%{1}\"", screen); } // add the screen to the configuration if (!addScreen(screen)) { throw XConfigRead(s, "duplicate screen name \"%{1}\"", screen); } } else if (screen.empty()) { throw XConfigRead(s, "argument before first screen"); } else { // parse argument: `=' String::size_type i = line.find_first_of(" \t="); if (i == 0) { throw XConfigRead(s, "missing argument name"); } if (i == String::npos) { throw XConfigRead(s, "missing ="); } String name = line.substr(0, i); i = line.find_first_not_of(" \t", i); if (i == String::npos || line[i] != '=') { throw XConfigRead(s, "missing ="); } i = line.find_first_not_of(" \t", i + 1); String value; if (i != String::npos) { value = line.substr(i); } // handle argument if (name == "halfDuplexCapsLock") { addOption(screen, kOptionHalfDuplexCapsLock, s.parseBoolean(value)); } else if (name == "halfDuplexNumLock") { addOption(screen, kOptionHalfDuplexNumLock, s.parseBoolean(value)); } else if (name == "halfDuplexScrollLock") { addOption(screen, kOptionHalfDuplexScrollLock, s.parseBoolean(value)); } else if (name == "shift") { addOption(screen, kOptionModifierMapForShift, s.parseModifierKey(value)); } else if (name == "ctrl") { addOption(screen, kOptionModifierMapForControl, s.parseModifierKey(value)); } else if (name == "alt") { addOption(screen, kOptionModifierMapForAlt, s.parseModifierKey(value)); } else if (name == "altgr") { addOption(screen, kOptionModifierMapForAltGr, s.parseModifierKey(value)); } else if (name == "meta") { addOption(screen, kOptionModifierMapForMeta, s.parseModifierKey(value)); } else if (name == "super") { addOption(screen, kOptionModifierMapForSuper, s.parseModifierKey(value)); } else if (name == "xtestIsXineramaUnaware") { addOption(screen, kOptionXTestXineramaUnaware, s.parseBoolean(value)); } else if (name == "switchCorners") { addOption(screen, kOptionScreenSwitchCorners, s.parseCorners(value)); } else if (name == "switchCornerSize") { addOption(screen, kOptionScreenSwitchCornerSize, s.parseInt(value)); } else if (name == "preserveFocus") { addOption(screen, kOptionScreenPreserveFocus, s.parseBoolean(value)); } else { // unknown argument throw XConfigRead(s, "unknown argument \"%{1}\"", name); } } } throw XConfigRead(s, "unexpected end of screens section"); } void Config::readSectionLinks(ConfigReadContext& s) { String line; String screen; while (s.readLine(line)) { // check for end of section if (line == "end") { return; } // see if it's the next screen if (line[line.size() - 1] == ':') { // strip : screen = line.substr(0, line.size() - 1); // verify we know about the screen if (!isScreen(screen)) { throw XConfigRead(s, "unknown screen name \"%{1}\"", screen); } if (!isCanonicalName(screen)) { throw XConfigRead(s, "cannot use screen name alias here"); } } else if (screen.empty()) { throw XConfigRead(s, "argument before first screen"); } else { // parse argument: `[(,)]=[(,)]' // the stuff in brackets is optional. interval values must be // in the range [0,100] and start < end. if not given the // interval is taken to be (0,100). String::size_type i = 0; String side, dstScreen, srcArgString, dstArgString; ConfigReadContext::ArgList srcArgs, dstArgs; s.parseNameWithArgs("link", line, "=", i, side, srcArgs); ++i; s.parseNameWithArgs("screen", line, "", i, dstScreen, dstArgs); Interval srcInterval(s.parseInterval(srcArgs)); Interval dstInterval(s.parseInterval(dstArgs)); // handle argument EDirection dir; if (side == "left") { dir = kLeft; } else if (side == "right") { dir = kRight; } else if (side == "up") { dir = kTop; } else if (side == "down") { dir = kBottom; } else { // unknown argument throw XConfigRead(s, "unknown side \"%{1}\" in link", side); } if (!isScreen(dstScreen)) { throw XConfigRead(s, "unknown screen name \"%{1}\"", dstScreen); } if (!connect(screen, dir, srcInterval.first, srcInterval.second, dstScreen, dstInterval.first, dstInterval.second)) { throw XConfigRead(s, "overlapping range"); } } } throw XConfigRead(s, "unexpected end of links section"); } void Config::readSectionAliases(ConfigReadContext& s) { String line; String screen; while (s.readLine(line)) { // check for end of section if (line == "end") { return; } // see if it's the next screen if (line[line.size() - 1] == ':') { // strip : screen = line.substr(0, line.size() - 1); // verify we know about the screen if (!isScreen(screen)) { throw XConfigRead(s, "unknown screen name \"%{1}\"", screen); } if (!isCanonicalName(screen)) { throw XConfigRead(s, "cannot use screen name alias here"); } } else if (screen.empty()) { throw XConfigRead(s, "argument before first screen"); } else { // verify validity of screen name if (!isValidScreenName(line)) { throw XConfigRead(s, "invalid screen alias \"%{1}\"", line); } // add alias if (!addAlias(screen, line)) { throw XConfigRead(s, "alias \"%{1}\" is already used", line); } } } throw XConfigRead(s, "unexpected end of aliases section"); } InputFilter::Condition* Config::parseCondition(ConfigReadContext& s, const String& name, const std::vector& args) { if (name == "keystroke") { if (args.size() != 1) { throw XConfigRead(s, "syntax for condition: keystroke(modifiers+key)"); } IPlatformScreen::KeyInfo* keyInfo = s.parseKeystroke(args[0]); return new InputFilter::KeystrokeCondition(m_events, keyInfo); } if (name == "mousebutton") { if (args.size() != 1) { throw XConfigRead(s, "syntax for condition: mousebutton(modifiers+button)"); } IPlatformScreen::ButtonInfo* mouseInfo = s.parseMouse(args[0]); return new InputFilter::MouseButtonCondition(m_events, mouseInfo); } if (name == "connect") { if (args.size() != 1) { throw XConfigRead(s, "syntax for condition: connect([screen])"); } String screen = args[0]; if (isScreen(screen)) { screen = getCanonicalName(screen); } else if (!screen.empty()) { throw XConfigRead(s, "unknown screen name \"%{1}\" in connect", screen); } return new InputFilter::ScreenConnectedCondition(m_events, screen); } throw XConfigRead(s, "unknown argument \"%{1}\"", name); } void Config::parseAction(ConfigReadContext& s, const String& name, const std::vector& args, InputFilter::Rule& rule, bool activate) { InputFilter::Action* action; if (name == "keystroke" || name == "keyDown" || name == "keyUp") { if (args.size() < 1 || args.size() > 2) { throw XConfigRead(s, "syntax for action: keystroke(modifiers+key[,screens])"); } IPlatformScreen::KeyInfo* keyInfo; if (args.size() == 1) { keyInfo = s.parseKeystroke(args[0]); } else { std::set screens; parseScreens(s, args[1], screens); keyInfo = s.parseKeystroke(args[0], screens); } if (name == "keystroke") { IPlatformScreen::KeyInfo* keyInfo2 = IKeyState::KeyInfo::alloc(*keyInfo); action = new InputFilter::KeystrokeAction(m_events, keyInfo2, true); rule.adoptAction(action, true); action = new InputFilter::KeystrokeAction(m_events, keyInfo, false); activate = false; } else if (name == "keyDown") { action = new InputFilter::KeystrokeAction(m_events, keyInfo, true); } else { action = new InputFilter::KeystrokeAction(m_events, keyInfo, false); } } else if (name == "mousebutton" || name == "mouseDown" || name == "mouseUp") { if (args.size() != 1) { throw XConfigRead(s, "syntax for action: mousebutton(modifiers+button)"); } IPlatformScreen::ButtonInfo* mouseInfo = s.parseMouse(args[0]); if (name == "mousebutton") { IPlatformScreen::ButtonInfo* mouseInfo2 = IPlatformScreen::ButtonInfo::alloc(*mouseInfo); action = new InputFilter::MouseButtonAction(m_events, mouseInfo2, true); rule.adoptAction(action, true); action = new InputFilter::MouseButtonAction(m_events, mouseInfo, false); activate = false; } else if (name == "mouseDown") { action = new InputFilter::MouseButtonAction(m_events, mouseInfo, true); } else { action = new InputFilter::MouseButtonAction(m_events, mouseInfo, false); } } /* XXX -- not supported else if (name == "modifier") { if (args.size() != 1) { throw XConfigRead(s, "syntax for action: modifier(modifiers)"); } KeyModifierMask mask = s.parseModifier(args[0]); action = new InputFilter::ModifierAction(mask, ~mask); } */ else if (name == "switchToScreen") { if (args.size() != 1) { throw XConfigRead(s, "syntax for action: switchToScreen(name)"); } String screen = args[0]; if (isScreen(screen)) { screen = getCanonicalName(screen); } else if (!screen.empty()) { throw XConfigRead(s, "unknown screen name in switchToScreen"); } action = new InputFilter::SwitchToScreenAction(m_events, screen); } else if (name == "switchInDirection") { if (args.size() != 1) { throw XConfigRead(s, "syntax for action: switchInDirection()"); } EDirection direction; if (args[0] == "left") { direction = kLeft; } else if (args[0] == "right") { direction = kRight; } else if (args[0] == "up") { direction = kTop; } else if (args[0] == "down") { direction = kBottom; } else { throw XConfigRead(s, "unknown direction \"%{1}\" in switchToScreen", args[0]); } action = new InputFilter::SwitchInDirectionAction(m_events, direction); } else if (name == "lockCursorToScreen") { if (args.size() > 1) { throw XConfigRead(s, "syntax for action: lockCursorToScreen([{off|on|toggle}])"); } InputFilter::LockCursorToScreenAction::Mode mode = InputFilter::LockCursorToScreenAction::kToggle; if (args.size() == 1) { if (args[0] == "off") { mode = InputFilter::LockCursorToScreenAction::kOff; } else if (args[0] == "on") { mode = InputFilter::LockCursorToScreenAction::kOn; } else if (args[0] == "toggle") { mode = InputFilter::LockCursorToScreenAction::kToggle; } else { throw XConfigRead(s, "syntax for action: lockCursorToScreen([{off|on|toggle}])"); } } if (mode != InputFilter::LockCursorToScreenAction::kOff) { m_hasLockToScreenAction = true; } action = new InputFilter::LockCursorToScreenAction(m_events, mode); } else if (name == "keyboardBroadcast") { if (args.size() > 2) { throw XConfigRead(s, "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])"); } InputFilter::KeyboardBroadcastAction::Mode mode = InputFilter::KeyboardBroadcastAction::kToggle; if (args.size() >= 1) { if (args[0] == "off") { mode = InputFilter::KeyboardBroadcastAction::kOff; } else if (args[0] == "on") { mode = InputFilter::KeyboardBroadcastAction::kOn; } else if (args[0] == "toggle") { mode = InputFilter::KeyboardBroadcastAction::kToggle; } else { throw XConfigRead(s, "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])"); } } std::set screens; if (args.size() >= 2) { parseScreens(s, args[1], screens); } action = new InputFilter::KeyboardBroadcastAction(m_events, mode, screens); } else { throw XConfigRead(s, "unknown action argument \"%{1}\"", name); } rule.adoptAction(action, activate); } void Config::parseScreens(ConfigReadContext& c, const String& s, std::set& screens) const { screens.clear(); String::size_type i = 0; while (i < s.size()) { // find end of next screen name String::size_type j = s.find(':', i); if (j == String::npos) { j = s.size(); } // extract name String rawName; i = s.find_first_not_of(" \t", i); if (i < j) { rawName = s.substr(i, s.find_last_not_of(" \t", j - 1) - i + 1); } // add name if (rawName == "*") { screens.insert("*"); } else if (!rawName.empty()) { String name = getCanonicalName(rawName); if (name.empty()) { throw XConfigRead(c, "unknown screen name \"%{1}\"", rawName); } screens.insert(name); } // next i = j + 1; } } const char* Config::getOptionName(OptionID id) { if (id == kOptionHalfDuplexCapsLock) { return "halfDuplexCapsLock"; } if (id == kOptionHalfDuplexNumLock) { return "halfDuplexNumLock"; } if (id == kOptionHalfDuplexScrollLock) { return "halfDuplexScrollLock"; } if (id == kOptionModifierMapForShift) { return "shift"; } if (id == kOptionModifierMapForControl) { return "ctrl"; } if (id == kOptionModifierMapForAlt) { return "alt"; } if (id == kOptionModifierMapForAltGr) { return "altgr"; } if (id == kOptionModifierMapForMeta) { return "meta"; } if (id == kOptionModifierMapForSuper) { return "super"; } if (id == kOptionHeartbeat) { return "heartbeat"; } if (id == kOptionScreenSwitchCorners) { return "switchCorners"; } if (id == kOptionScreenSwitchCornerSize) { return "switchCornerSize"; } if (id == kOptionScreenSwitchDelay) { return "switchDelay"; } if (id == kOptionScreenSwitchTwoTap) { return "switchDoubleTap"; } if (id == kOptionScreenSwitchNeedsShift) { return "switchNeedsShift"; } if (id == kOptionScreenSwitchNeedsControl) { return "switchNeedsControl"; } if (id == kOptionScreenSwitchNeedsAlt) { return "switchNeedsAlt"; } if (id == kOptionScreenSaverSync) { return "screenSaverSync"; } if (id == kOptionXTestXineramaUnaware) { return "xtestIsXineramaUnaware"; } if (id == kOptionRelativeMouseMoves) { return "relativeMouseMoves"; } if (id == kOptionWin32KeepForeground) { return "win32KeepForeground"; } if (id == kOptionScreenPreserveFocus) { return "preserveFocus"; } if (id == kOptionClipboardSharing) { return "clipboardSharing"; } return NULL; } String Config::getOptionValue(OptionID id, OptionValue value) { if (id == kOptionHalfDuplexCapsLock || id == kOptionHalfDuplexNumLock || id == kOptionHalfDuplexScrollLock || id == kOptionScreenSwitchNeedsShift || id == kOptionScreenSwitchNeedsControl || id == kOptionScreenSwitchNeedsAlt || id == kOptionScreenSaverSync || id == kOptionXTestXineramaUnaware || id == kOptionRelativeMouseMoves || id == kOptionWin32KeepForeground || id == kOptionScreenPreserveFocus || id == kOptionClipboardSharing) { return (value != 0) ? "true" : "false"; } if (id == kOptionModifierMapForShift || id == kOptionModifierMapForControl || id == kOptionModifierMapForAlt || id == kOptionModifierMapForAltGr || id == kOptionModifierMapForMeta || id == kOptionModifierMapForSuper) { switch (value) { case kKeyModifierIDShift: return "shift"; case kKeyModifierIDControl: return "ctrl"; case kKeyModifierIDAlt: return "alt"; case kKeyModifierIDAltGr: return "altgr"; case kKeyModifierIDMeta: return "meta"; case kKeyModifierIDSuper: return "super"; default: return "none"; } } if (id == kOptionHeartbeat || id == kOptionScreenSwitchCornerSize || id == kOptionScreenSwitchDelay || id == kOptionScreenSwitchTwoTap) { return synergy::string::sprintf("%d", value); } if (id == kOptionScreenSwitchCorners) { std::string result("none"); if ((value & kTopLeftMask) != 0) { result += " +top-left"; } if ((value & kTopRightMask) != 0) { result += " +top-right"; } if ((value & kBottomLeftMask) != 0) { result += " +bottom-left"; } if ((value & kBottomRightMask) != 0) { result += " +bottom-right"; } return result; } return ""; } // // Config::Name // Config::Name::Name(Config* config, const String& name) : m_config(config), m_name(config->getCanonicalName(name)) { // do nothing } bool Config::Name::operator==(const String& name) const { String canonical = m_config->getCanonicalName(name); return CaselessCmp::equal(canonical, m_name); } // // Config::CellEdge // Config::CellEdge::CellEdge(EDirection side, float position) { init("", side, Interval(position, position)); } Config::CellEdge::CellEdge(EDirection side, const Interval& interval) { assert(interval.first >= 0.0f); assert(interval.second <= 1.0f); assert(interval.first < interval.second); init("", side, interval); } Config::CellEdge::CellEdge(const String& name, EDirection side, const Interval& interval) { assert(interval.first >= 0.0f); assert(interval.second <= 1.0f); assert(interval.first < interval.second); init(name, side, interval); } Config::CellEdge::~CellEdge() { // do nothing } void Config::CellEdge::init(const String& name, EDirection side, const Interval& interval) { assert(side != kNoDirection); m_name = name; m_side = side; m_interval = interval; } Config::Interval Config::CellEdge::getInterval() const { return m_interval; } void Config::CellEdge::setName(const String& newName) { m_name = newName; } String Config::CellEdge::getName() const { return m_name; } EDirection Config::CellEdge::getSide() const { return m_side; } bool Config::CellEdge::overlaps(const CellEdge& edge) const { const Interval& x = m_interval; const Interval& y = edge.m_interval; if (m_side != edge.m_side) { return false; } return (x.first >= y.first && x.first < y.second) || (x.second > y.first && x.second <= y.second) || (y.first >= x.first && y.first < x.second) || (y.second > x.first && y.second <= x.second); } bool Config::CellEdge::isInside(float x) const { return (x >= m_interval.first && x < m_interval.second); } float Config::CellEdge::transform(float x) const { return (x - m_interval.first) / (m_interval.second - m_interval.first); } float Config::CellEdge::inverseTransform(float x) const { return x * (m_interval.second - m_interval.first) + m_interval.first; } bool Config::CellEdge::operator<(const CellEdge& o) const { if (static_cast(m_side) < static_cast(o.m_side)) { return true; } else if (static_cast(m_side) > static_cast(o.m_side)) { return false; } return (m_interval.first < o.m_interval.first); } bool Config::CellEdge::operator==(const CellEdge& x) const { return (m_side == x.m_side && m_interval == x.m_interval); } bool Config::CellEdge::operator!=(const CellEdge& x) const { return !operator==(x); } // // Config::Cell // bool Config::Cell::add(const CellEdge& src, const CellEdge& dst) { // cannot add an edge that overlaps other existing edges but we // can exactly replace an edge. if (!hasEdge(src) && overlaps(src)) { return false; } m_neighbors.erase(src); m_neighbors.insert(std::make_pair(src, dst)); return true; } void Config::Cell::remove(EDirection side) { for (EdgeLinks::iterator j = m_neighbors.begin(); j != m_neighbors.end(); ) { if (j->first.getSide() == side) { m_neighbors.erase(j++); } else { ++j; } } } void Config::Cell::remove(EDirection side, float position) { for (EdgeLinks::iterator j = m_neighbors.begin(); j != m_neighbors.end(); ++j) { if (j->first.getSide() == side && j->first.isInside(position)) { m_neighbors.erase(j); break; } } } void Config::Cell::remove(const Name& name) { for (EdgeLinks::iterator j = m_neighbors.begin(); j != m_neighbors.end(); ) { if (name == j->second.getName()) { m_neighbors.erase(j++); } else { ++j; } } } void Config::Cell::rename(const Name& oldName, const String& newName) { for (EdgeLinks::iterator j = m_neighbors.begin(); j != m_neighbors.end(); ++j) { if (oldName == j->second.getName()) { j->second.setName(newName); } } } bool Config::Cell::hasEdge(const CellEdge& edge) const { EdgeLinks::const_iterator i = m_neighbors.find(edge); return (i != m_neighbors.end() && i->first == edge); } bool Config::Cell::overlaps(const CellEdge& edge) const { EdgeLinks::const_iterator i = m_neighbors.upper_bound(edge); if (i != m_neighbors.end() && i->first.overlaps(edge)) { return true; } if (i != m_neighbors.begin() && (--i)->first.overlaps(edge)) { return true; } return false; } bool Config::Cell::getLink(EDirection side, float position, const CellEdge*& src, const CellEdge*& dst) const { CellEdge edge(side, position); EdgeLinks::const_iterator i = m_neighbors.upper_bound(edge); if (i == m_neighbors.begin()) { return false; } --i; if (i->first.getSide() == side && i->first.isInside(position)) { src = &i->first; dst = &i->second; return true; } return false; } bool Config::Cell::operator==(const Cell& x) const { // compare options if (m_options != x.m_options) { return false; } // compare links if (m_neighbors.size() != x.m_neighbors.size()) { return false; } for (EdgeLinks::const_iterator index1 = m_neighbors.begin(), index2 = x.m_neighbors.begin(); index1 != m_neighbors.end(); ++index1, ++index2) { if (index1->first != index2->first) { return false; } if (index1->second != index2->second) { return false; } // operator== doesn't compare names. only compare destination // names. if (!CaselessCmp::equal(index1->second.getName(), index2->second.getName())) { return false; } } return true; } bool Config::Cell::operator!=(const Cell& x) const { return !operator==(x); } Config::Cell::const_iterator Config::Cell::begin() const { return m_neighbors.begin(); } Config::Cell::const_iterator Config::Cell::end() const { return m_neighbors.end(); } // // Config I/O // std::istream& operator>>(std::istream& s, Config& config) { ConfigReadContext context(s); config.read(context); return s; } std::ostream& operator<<(std::ostream& s, const Config& config) { // screens section s << "section: screens" << std::endl; for (Config::const_iterator screen = config.begin(); screen != config.end(); ++screen) { s << "\t" << screen->c_str() << ":" << std::endl; const Config::ScreenOptions* options = config.getOptions(*screen); if (options != NULL && options->size() > 0) { for (Config::ScreenOptions::const_iterator option = options->begin(); option != options->end(); ++option) { const char* name = Config::getOptionName(option->first); String value = Config::getOptionValue(option->first, option->second); if (name != NULL && !value.empty()) { s << "\t\t" << name << " = " << value << std::endl; } } } } s << "end" << std::endl; // links section String neighbor; s << "section: links" << std::endl; for (Config::const_iterator screen = config.begin(); screen != config.end(); ++screen) { s << "\t" << screen->c_str() << ":" << std::endl; for (Config::link_const_iterator link = config.beginNeighbor(*screen), nend = config.endNeighbor(*screen); link != nend; ++link) { s << "\t\t" << Config::dirName(link->first.getSide()) << Config::formatInterval(link->first.getInterval()) << " = " << link->second.getName().c_str() << Config::formatInterval(link->second.getInterval()) << std::endl; } } s << "end" << std::endl; // aliases section (if there are any) if (config.m_map.size() != config.m_nameToCanonicalName.size()) { // map canonical to alias typedef std::multimap CMNameMap; CMNameMap aliases; for (Config::NameMap::const_iterator index = config.m_nameToCanonicalName.begin(); index != config.m_nameToCanonicalName.end(); ++index) { if (index->first != index->second) { aliases.insert(std::make_pair(index->second, index->first)); } } // dump it String screen; s << "section: aliases" << std::endl; for (CMNameMap::const_iterator index = aliases.begin(); index != aliases.end(); ++index) { if (index->first != screen) { screen = index->first; s << "\t" << screen.c_str() << ":" << std::endl; } s << "\t\t" << index->second.c_str() << std::endl; } s << "end" << std::endl; } // options section s << "section: options" << std::endl; const Config::ScreenOptions* options = config.getOptions(""); if (options != NULL && options->size() > 0) { for (Config::ScreenOptions::const_iterator option = options->begin(); option != options->end(); ++option) { const char* name = Config::getOptionName(option->first); String value = Config::getOptionValue(option->first, option->second); if (name != NULL && !value.empty()) { s << "\t" << name << " = " << value << std::endl; } } } if (config.m_synergyAddress.isValid()) { s << "\taddress = " << config.m_synergyAddress.getHostname().c_str() << std::endl; } s << config.m_inputFilter.format("\t"); s << "end" << std::endl; return s; } // // ConfigReadContext // ConfigReadContext::ConfigReadContext(std::istream& s, SInt32 firstLine) : m_stream(s), m_line(firstLine - 1) { // do nothing } ConfigReadContext::~ConfigReadContext() { // do nothing } bool ConfigReadContext::readLine(String& line) { ++m_line; while (std::getline(m_stream, line)) { // strip leading whitespace String::size_type i = line.find_first_not_of(" \t"); if (i != String::npos) { line.erase(0, i); } // strip comments and then trailing whitespace i = line.find('#'); if (i != String::npos) { line.erase(i); } i = line.find_last_not_of(" \r\t"); if (i != String::npos) { line.erase(i + 1); } // return non empty line if (!line.empty()) { // make sure there are no invalid characters for (i = 0; i < line.length(); ++i) { if (!isgraph(line[i]) && line[i] != ' ' && line[i] != '\t') { throw XConfigRead(*this, "invalid character %{1}", synergy::string::sprintf("%#2x", line[i])); } } return true; } // next line ++m_line; } return false; } UInt32 ConfigReadContext::getLineNumber() const { return m_line; } bool ConfigReadContext::operator!() const { return !m_stream; } OptionValue ConfigReadContext::parseBoolean(const String& arg) const { if (CaselessCmp::equal(arg, "true")) { return static_cast(true); } if (CaselessCmp::equal(arg, "false")) { return static_cast(false); } throw XConfigRead(*this, "invalid boolean argument \"%{1}\"", arg); } OptionValue ConfigReadContext::parseInt(const String& arg) const { const char* s = arg.c_str(); char* end; long tmp = strtol(s, &end, 10); if (*end != '\0') { // invalid characters throw XConfigRead(*this, "invalid integer argument \"%{1}\"", arg); } OptionValue value = static_cast(tmp); if (value != tmp) { // out of range throw XConfigRead(*this, "integer argument \"%{1}\" out of range", arg); } return value; } OptionValue ConfigReadContext::parseModifierKey(const String& arg) const { if (CaselessCmp::equal(arg, "shift")) { return static_cast(kKeyModifierIDShift); } if (CaselessCmp::equal(arg, "ctrl")) { return static_cast(kKeyModifierIDControl); } if (CaselessCmp::equal(arg, "alt")) { return static_cast(kKeyModifierIDAlt); } if (CaselessCmp::equal(arg, "altgr")) { return static_cast(kKeyModifierIDAltGr); } if (CaselessCmp::equal(arg, "meta")) { return static_cast(kKeyModifierIDMeta); } if (CaselessCmp::equal(arg, "super")) { return static_cast(kKeyModifierIDSuper); } if (CaselessCmp::equal(arg, "none")) { return static_cast(kKeyModifierIDNull); } throw XConfigRead(*this, "invalid argument \"%{1}\"", arg); } OptionValue ConfigReadContext::parseCorner(const String& arg) const { if (CaselessCmp::equal(arg, "left")) { return kTopLeftMask | kBottomLeftMask; } else if (CaselessCmp::equal(arg, "right")) { return kTopRightMask | kBottomRightMask; } else if (CaselessCmp::equal(arg, "top")) { return kTopLeftMask | kTopRightMask; } else if (CaselessCmp::equal(arg, "bottom")) { return kBottomLeftMask | kBottomRightMask; } else if (CaselessCmp::equal(arg, "top-left")) { return kTopLeftMask; } else if (CaselessCmp::equal(arg, "top-right")) { return kTopRightMask; } else if (CaselessCmp::equal(arg, "bottom-left")) { return kBottomLeftMask; } else if (CaselessCmp::equal(arg, "bottom-right")) { return kBottomRightMask; } else if (CaselessCmp::equal(arg, "none")) { return kNoCornerMask; } else if (CaselessCmp::equal(arg, "all")) { return kAllCornersMask; } throw XConfigRead(*this, "invalid argument \"%{1}\"", arg); } OptionValue ConfigReadContext::parseCorners(const String& args) const { // find first token String::size_type i = args.find_first_not_of(" \t", 0); if (i == String::npos) { throw XConfigRead(*this, "missing corner argument"); } String::size_type j = args.find_first_of(" \t", i); // parse first corner token OptionValue corners = parseCorner(args.substr(i, j - i)); // get +/- i = args.find_first_not_of(" \t", j); while (i != String::npos) { // parse +/- bool add; if (args[i] == '-') { add = false; } else if (args[i] == '+') { add = true; } else { throw XConfigRead(*this, "invalid corner operator \"%{1}\"", String(args.c_str() + i, 1)); } // get next corner token i = args.find_first_not_of(" \t", i + 1); j = args.find_first_of(" \t", i); if (i == String::npos) { throw XConfigRead(*this, "missing corner argument"); } // parse next corner token if (add) { corners |= parseCorner(args.substr(i, j - i)); } else { corners &= ~parseCorner(args.substr(i, j - i)); } i = args.find_first_not_of(" \t", j); } return corners; } Config::Interval ConfigReadContext::parseInterval(const ArgList& args) const { if (args.size() == 0) { return Config::Interval(0.0f, 1.0f); } if (args.size() != 2 || args[0].empty() || args[1].empty()) { throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); } char* end; double startValue = strtod(args[0].c_str(), &end); if (end[0] != '\0') { throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); } double endValue = strtod(args[1].c_str(), &end); if (end[0] != '\0') { throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); } if (startValue < 0 || startValue > 100 || endValue < 0 || endValue > 100 || startValue >= endValue) { throw XConfigRead(*this, "invalid interval \"%{1}\"", concatArgs(args)); } return Config::Interval(startValue / 100.0f, endValue / 100.0f); } void ConfigReadContext::parseNameWithArgs( const String& type, const String& line, const String& delim, String::size_type& index, String& name, ArgList& args) const { // skip leading whitespace String::size_type i = line.find_first_not_of(" \t", index); if (i == String::npos) { throw XConfigRead(*this, String("missing ") + type); } // find end of name String::size_type j = line.find_first_of(" \t(" + delim, i); if (j == String::npos) { j = line.length(); } // save name name = line.substr(i, j - i); args.clear(); // is it okay to not find a delimiter? bool needDelim = (!delim.empty() && delim.find('\n') == String::npos); // skip whitespace i = line.find_first_not_of(" \t", j); if (i == String::npos && needDelim) { // expected delimiter but didn't find it throw XConfigRead(*this, String("missing ") + delim[0]); } if (i == String::npos) { // no arguments index = line.length(); return; } if (line[i] != '(') { // no arguments index = i; return; } // eat '(' ++i; // parse arguments j = line.find_first_of(",)", i); while (j != String::npos) { // extract arg String arg(line.substr(i, j - i)); i = j; // trim whitespace j = arg.find_first_not_of(" \t"); if (j != String::npos) { arg.erase(0, j); } j = arg.find_last_not_of(" \t"); if (j != String::npos) { arg.erase(j + 1); } // save arg args.push_back(arg); // exit loop at end of arguments if (line[i] == ')') { break; } // eat ',' ++i; // next j = line.find_first_of(",)", i); } // verify ')' if (j == String::npos) { // expected ) throw XConfigRead(*this, "missing )"); } // eat ')' ++i; // skip whitespace j = line.find_first_not_of(" \t", i); if (j == String::npos && needDelim) { // expected delimiter but didn't find it throw XConfigRead(*this, String("missing ") + delim[0]); } // verify delimiter if (needDelim && delim.find(line[j]) == String::npos) { throw XConfigRead(*this, String("expected ") + delim[0]); } if (j == String::npos) { j = line.length(); } index = j; return; } IPlatformScreen::KeyInfo* ConfigReadContext::parseKeystroke(const String& keystroke) const { return parseKeystroke(keystroke, std::set()); } IPlatformScreen::KeyInfo* ConfigReadContext::parseKeystroke(const String& keystroke, const std::set& screens) const { String s = keystroke; KeyModifierMask mask; if (!synergy::KeyMap::parseModifiers(s, mask)) { throw XConfigRead(*this, "unable to parse key modifiers"); } KeyID key; if (!synergy::KeyMap::parseKey(s, key)) { throw XConfigRead(*this, "unable to parse key"); } if (key == kKeyNone && mask == 0) { throw XConfigRead(*this, "missing key and/or modifiers in keystroke"); } return IPlatformScreen::KeyInfo::alloc(key, mask, 0, 0, screens); } IPlatformScreen::ButtonInfo* ConfigReadContext::parseMouse(const String& mouse) const { String s = mouse; KeyModifierMask mask; if (!synergy::KeyMap::parseModifiers(s, mask)) { throw XConfigRead(*this, "unable to parse button modifiers"); } char* end; ButtonID button = (ButtonID)strtol(s.c_str(), &end, 10); if (*end != '\0') { throw XConfigRead(*this, "unable to parse button"); } if (s.empty() || button <= 0) { throw XConfigRead(*this, "invalid button"); } return IPlatformScreen::ButtonInfo::alloc(button, mask); } KeyModifierMask ConfigReadContext::parseModifier(const String& modifiers) const { String s = modifiers; KeyModifierMask mask; if (!synergy::KeyMap::parseModifiers(s, mask)) { throw XConfigRead(*this, "unable to parse modifiers"); } if (mask == 0) { throw XConfigRead(*this, "no modifiers specified"); } return mask; } String ConfigReadContext::concatArgs(const ArgList& args) { String s("("); for (size_t i = 0; i < args.size(); ++i) { if (i != 0) { s += ","; } s += args[i]; } s += ")"; return s; } // // Config I/O exceptions // XConfigRead::XConfigRead(const ConfigReadContext& context, const String& error) : m_error(synergy::string::sprintf("line %d: %s", context.getLineNumber(), error.c_str())) { // do nothing } XConfigRead::XConfigRead(const ConfigReadContext& context, const char* errorFmt, const String& arg) : m_error(synergy::string::sprintf("line %d: ", context.getLineNumber()) + synergy::string::format(errorFmt, arg.c_str())) { // do nothing } XConfigRead::~XConfigRead() _NOEXCEPT { // do nothing } String XConfigRead::getWhat() const throw() { return format("XConfigRead", "read error: %{1}", m_error.c_str()); } synergy-1.8.8-stable/src/lib/server/Config.h000066400000000000000000000360551305627404700207420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/InputFilter.h" #include "synergy/option_types.h" #include "synergy/protocol_types.h" #include "synergy/IPlatformScreen.h" #include "net/NetworkAddress.h" #include "base/String.h" #include "base/XBase.h" #include "common/stdmap.h" #include "common/stdset.h" #include class Config; class ConfigReadContext; class IEventQueue; namespace std { template <> struct iterator_traits { typedef String value_type; typedef ptrdiff_t difference_type; typedef bidirectional_iterator_tag iterator_category; typedef String* pointer; typedef String& reference; }; }; //! Server configuration /*! This class holds server configuration information. That includes the names of screens and their aliases, the links between them, and network addresses. Note that case is preserved in screen names but is ignored when comparing names. Screen names and their aliases share a namespace and must be unique. */ class Config { public: typedef std::map ScreenOptions; typedef std::pair Interval; class CellEdge { public: CellEdge(EDirection side, float position); CellEdge(EDirection side, const Interval&); CellEdge(const String& name, EDirection side, const Interval&); ~CellEdge(); Interval getInterval() const; void setName(const String& newName); String getName() const; EDirection getSide() const; bool overlaps(const CellEdge&) const; bool isInside(float x) const; // transform position to [0,1] float transform(float x) const; // transform [0,1] to position float inverseTransform(float x) const; // compares side and start of interval bool operator<(const CellEdge&) const; // compares side and interval bool operator==(const CellEdge&) const; bool operator!=(const CellEdge&) const; private: void init(const String& name, EDirection side, const Interval&); private: String m_name; EDirection m_side; Interval m_interval; }; private: class Name { public: Name(Config*, const String& name); bool operator==(const String& name) const; private: Config* m_config; String m_name; }; class Cell { private: typedef std::map EdgeLinks; public: typedef EdgeLinks::const_iterator const_iterator; bool add(const CellEdge& src, const CellEdge& dst); void remove(EDirection side); void remove(EDirection side, float position); void remove(const Name& destinationName); void rename(const Name& oldName, const String& newName); bool hasEdge(const CellEdge&) const; bool overlaps(const CellEdge&) const; bool getLink(EDirection side, float position, const CellEdge*& src, const CellEdge*& dst) const; bool operator==(const Cell&) const; bool operator!=(const Cell&) const; const_iterator begin() const; const_iterator end() const; private: EdgeLinks m_neighbors; public: ScreenOptions m_options; }; typedef std::map CellMap; typedef std::map NameMap; public: typedef Cell::const_iterator link_const_iterator; typedef CellMap::const_iterator internal_const_iterator; typedef NameMap::const_iterator all_const_iterator; class const_iterator : std::iterator_traits { public: explicit const_iterator() : m_i() { } explicit const_iterator(const internal_const_iterator& i) : m_i(i) { } const_iterator& operator=(const const_iterator& i) { m_i = i.m_i; return *this; } String operator*() { return m_i->first; } const String* operator->() { return &(m_i->first); } const_iterator& operator++() { ++m_i; return *this; } const_iterator operator++(int) { return const_iterator(m_i++); } const_iterator& operator--() { --m_i; return *this; } const_iterator operator--(int) { return const_iterator(m_i--); } bool operator==(const const_iterator& i) const { return (m_i == i.m_i); } bool operator!=(const const_iterator& i) const { return (m_i != i.m_i); } private: internal_const_iterator m_i; }; Config(IEventQueue* events); virtual ~Config(); #ifdef TEST_ENV Config() : m_inputFilter(NULL) { } #endif //! @name manipulators //@{ //! Add screen /*! Adds a screen, returning true iff successful. If a screen or alias with the given name exists then it fails. */ bool addScreen(const String& name); //! Rename screen /*! Renames a screen. All references to the name are updated. Returns true iff successful. */ bool renameScreen(const String& oldName, const String& newName); //! Remove screen /*! Removes a screen. This also removes aliases for the screen and disconnects any connections to the screen. \c name may be an alias. */ void removeScreen(const String& name); //! Remove all screens /*! Removes all screens, aliases, and connections. */ void removeAllScreens(); //! Add alias /*! Adds an alias for a screen name. An alias can be used any place the canonical screen name can (except addScreen()). Returns false if the alias name already exists or the canonical name is unknown, otherwise returns true. */ bool addAlias(const String& canonical, const String& alias); //! Remove alias /*! Removes an alias for a screen name. It returns false if the alias is unknown or a canonical name, otherwise returns true. */ bool removeAlias(const String& alias); //! Remove aliases /*! Removes all aliases for a canonical screen name. It returns false if the canonical name is unknown, otherwise returns true. */ bool removeAliases(const String& canonical); //! Remove all aliases /*! This removes all aliases but not the screens. */ void removeAllAliases(); //! Connect screens /*! Establishes a one-way connection between portions of opposite edges of two screens. Each portion is described by an interval defined by two numbers, the start and end of the interval half-open on the end. The numbers range from 0 to 1, inclusive, for the left/top to the right/bottom. The user will be able to jump from the \c srcStart to \c srcSend interval of \c srcSide of screen \c srcName to the opposite side of screen \c dstName in the interval \c dstStart and \c dstEnd when both screens are connected to the server and the user isn't locked to a screen. Returns false if \c srcName is unknown. \c srcStart must be less than or equal to \c srcEnd and \c dstStart must be less then or equal to \c dstEnd and all of \c srcStart, \c srcEnd, \c dstStart, or \c dstEnd must be inside the range [0,1]. */ bool connect(const String& srcName, EDirection srcSide, float srcStart, float srcEnd, const String& dstName, float dstStart, float dstEnd); //! Disconnect screens /*! Removes all connections created by connect() on side \c srcSide. Returns false if \c srcName is unknown. */ bool disconnect(const String& srcName, EDirection srcSide); //! Disconnect screens /*! Removes the connections created by connect() on side \c srcSide covering position \c position. Returns false if \c srcName is unknown. */ bool disconnect(const String& srcName, EDirection srcSide, float position); //! Set server address /*! Set the synergy listen addresses. There is no default address so this must be called to run a server using this configuration. */ void setSynergyAddress(const NetworkAddress&); //! Add a screen option /*! Adds an option and its value to the named screen. Replaces the existing option's value if there is one. Returns true iff \c name is a known screen. */ bool addOption(const String& name, OptionID option, OptionValue value); //! Remove a screen option /*! Removes an option and its value from the named screen. Does nothing if the option doesn't exist on the screen. Returns true iff \c name is a known screen. */ bool removeOption(const String& name, OptionID option); //! Remove a screen options /*! Removes all options and values from the named screen. Returns true iff \c name is a known screen. */ bool removeOptions(const String& name); //! Get the hot key input filter /*! Returns the hot key input filter. Clients can modify hotkeys using that object. */ virtual InputFilter* getInputFilter(); //@} //! @name accessors //@{ //! Test screen name validity /*! Returns true iff \c name is a valid screen name. */ bool isValidScreenName(const String& name) const; //! Get beginning (canonical) screen name iterator const_iterator begin() const; //! Get ending (canonical) screen name iterator const_iterator end() const; //! Get beginning screen name iterator all_const_iterator beginAll() const; //! Get ending screen name iterator all_const_iterator endAll() const; //! Test for screen name /*! Returns true iff \c name names a screen. */ virtual bool isScreen(const String& name) const; //! Test for canonical screen name /*! Returns true iff \c name is the canonical name of a screen. */ bool isCanonicalName(const String& name) const; //! Get canonical name /*! Returns the canonical name of a screen or the empty string if the name is unknown. Returns the canonical name if one is given. */ String getCanonicalName(const String& name) const; //! Get neighbor /*! Returns the canonical screen name of the neighbor in the given direction (set through connect()) at position \c position. Returns the empty string if there is no neighbor in that direction, otherwise saves the position on the neighbor in \c positionOut if it's not \c NULL. */ String getNeighbor(const String&, EDirection, float position, float* positionOut) const; //! Check for neighbor /*! Returns \c true if the screen has a neighbor anywhere along the edge given by the direction. */ bool hasNeighbor(const String&, EDirection) const; //! Check for neighbor /*! Returns \c true if the screen has a neighbor in the given range along the edge given by the direction. */ bool hasNeighbor(const String&, EDirection, float start, float end) const; //! Get beginning neighbor iterator link_const_iterator beginNeighbor(const String&) const; //! Get ending neighbor iterator link_const_iterator endNeighbor(const String&) const; //! Get the server address const NetworkAddress& getSynergyAddress() const; //! Get the screen options /*! Returns all the added options for the named screen. Returns NULL if the screen is unknown and an empty collection if there are no options. */ const ScreenOptions* getOptions(const String& name) const; //! Check for lock to screen action /*! Returns \c true if this configuration has a lock to screen action. This is for backwards compatible support of ScrollLock locking. */ bool hasLockToScreenAction() const; //! Compare configurations bool operator==(const Config&) const; //! Compare configurations bool operator!=(const Config&) const; //! Read configuration /*! Reads a configuration from a context. Throws XConfigRead on error and context is unchanged. */ void read(ConfigReadContext& context); //! Read configuration /*! Reads a configuration from a stream. Throws XConfigRead on error. */ friend std::istream& operator>>(std::istream&, Config&); //! Write configuration /*! Writes a configuration to a stream. */ friend std::ostream& operator<<(std::ostream&, const Config&); //! Get direction name /*! Returns the name of a direction (for debugging). */ static const char* dirName(EDirection); //! Get interval as string /*! Returns an interval as a parseable string. */ static String formatInterval(const Interval&); //@} private: void readSection(ConfigReadContext&); void readSectionOptions(ConfigReadContext&); void readSectionScreens(ConfigReadContext&); void readSectionLinks(ConfigReadContext&); void readSectionAliases(ConfigReadContext&); InputFilter::Condition* parseCondition(ConfigReadContext&, const String& condition, const std::vector& args); void parseAction(ConfigReadContext&, const String& action, const std::vector& args, InputFilter::Rule&, bool activate); void parseScreens(ConfigReadContext&, const String&, std::set& screens) const; static const char* getOptionName(OptionID); static String getOptionValue(OptionID, OptionValue); private: CellMap m_map; NameMap m_nameToCanonicalName; NetworkAddress m_synergyAddress; ScreenOptions m_globalOptions; InputFilter m_inputFilter; bool m_hasLockToScreenAction; IEventQueue* m_events; }; //! Configuration read context /*! Maintains a context when reading a configuration from a stream. */ class ConfigReadContext { public: typedef std::vector ArgList; ConfigReadContext(std::istream&, SInt32 firstLine = 1); ~ConfigReadContext(); bool readLine(String&); UInt32 getLineNumber() const; bool operator!() const; OptionValue parseBoolean(const String&) const; OptionValue parseInt(const String&) const; OptionValue parseModifierKey(const String&) const; OptionValue parseCorner(const String&) const; OptionValue parseCorners(const String&) const; Config::Interval parseInterval(const ArgList& args) const; void parseNameWithArgs( const String& type, const String& line, const String& delim, String::size_type& index, String& name, ArgList& args) const; IPlatformScreen::KeyInfo* parseKeystroke(const String& keystroke) const; IPlatformScreen::KeyInfo* parseKeystroke(const String& keystroke, const std::set& screens) const; IPlatformScreen::ButtonInfo* parseMouse(const String& mouse) const; KeyModifierMask parseModifier(const String& modifiers) const; std::istream& getStream() const { return m_stream; }; private: // not implemented ConfigReadContext& operator=(const ConfigReadContext&); static String concatArgs(const ArgList& args); private: std::istream& m_stream; SInt32 m_line; }; //! Configuration stream read exception /*! Thrown when a configuration stream cannot be parsed. */ class XConfigRead : public XBase { public: XConfigRead(const ConfigReadContext& context, const String&); XConfigRead(const ConfigReadContext& context, const char* errorFmt, const String& arg); virtual ~XConfigRead() _NOEXCEPT; protected: // XBase overrides virtual String getWhat() const throw(); private: String m_error; }; synergy-1.8.8-stable/src/lib/server/InputFilter.cpp000066400000000000000000000615531305627404700223360ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2005 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/InputFilter.h" #include "server/Server.h" #include "server/PrimaryClient.h" #include "synergy/KeyMap.h" #include "base/EventQueue.h" #include "base/Log.h" #include "base/TMethodEventJob.h" #include #include // ----------------------------------------------------------------------------- // Input Filter Condition Classes // ----------------------------------------------------------------------------- InputFilter::Condition::Condition() { // do nothing } InputFilter::Condition::~Condition() { // do nothing } void InputFilter::Condition::enablePrimary(PrimaryClient*) { // do nothing } void InputFilter::Condition::disablePrimary(PrimaryClient*) { // do nothing } InputFilter::KeystrokeCondition::KeystrokeCondition( IEventQueue* events, IPlatformScreen::KeyInfo* info) : m_id(0), m_key(info->m_key), m_mask(info->m_mask), m_events(events) { free(info); } InputFilter::KeystrokeCondition::KeystrokeCondition( IEventQueue* events, KeyID key, KeyModifierMask mask) : m_id(0), m_key(key), m_mask(mask), m_events(events) { // do nothing } InputFilter::KeystrokeCondition::~KeystrokeCondition() { // do nothing } KeyID InputFilter::KeystrokeCondition::getKey() const { return m_key; } KeyModifierMask InputFilter::KeystrokeCondition::getMask() const { return m_mask; } InputFilter::Condition* InputFilter::KeystrokeCondition::clone() const { return new KeystrokeCondition(m_events, m_key, m_mask); } String InputFilter::KeystrokeCondition::format() const { return synergy::string::sprintf("keystroke(%s)", synergy::KeyMap::formatKey(m_key, m_mask).c_str()); } InputFilter::EFilterStatus InputFilter::KeystrokeCondition::match(const Event& event) { EFilterStatus status; // check for hotkey events Event::Type type = event.getType(); if (type == m_events->forIPrimaryScreen().hotKeyDown()) { status = kActivate; } else if (type == m_events->forIPrimaryScreen().hotKeyUp()) { status = kDeactivate; } else { return kNoMatch; } // check if it's our hotkey IPrimaryScreen::HotKeyInfo* kinfo = static_cast(event.getData()); if (kinfo->m_id != m_id) { return kNoMatch; } return status; } void InputFilter::KeystrokeCondition::enablePrimary(PrimaryClient* primary) { m_id = primary->registerHotKey(m_key, m_mask); } void InputFilter::KeystrokeCondition::disablePrimary(PrimaryClient* primary) { primary->unregisterHotKey(m_id); m_id = 0; } InputFilter::MouseButtonCondition::MouseButtonCondition( IEventQueue* events, IPlatformScreen::ButtonInfo* info) : m_button(info->m_button), m_mask(info->m_mask), m_events(events) { free(info); } InputFilter::MouseButtonCondition::MouseButtonCondition( IEventQueue* events, ButtonID button, KeyModifierMask mask) : m_button(button), m_mask(mask), m_events(events) { // do nothing } InputFilter::MouseButtonCondition::~MouseButtonCondition() { // do nothing } ButtonID InputFilter::MouseButtonCondition::getButton() const { return m_button; } KeyModifierMask InputFilter::MouseButtonCondition::getMask() const { return m_mask; } InputFilter::Condition* InputFilter::MouseButtonCondition::clone() const { return new MouseButtonCondition(m_events, m_button, m_mask); } String InputFilter::MouseButtonCondition::format() const { String key = synergy::KeyMap::formatKey(kKeyNone, m_mask); if (!key.empty()) { key += "+"; } return synergy::string::sprintf("mousebutton(%s%d)", key.c_str(), m_button); } InputFilter::EFilterStatus InputFilter::MouseButtonCondition::match(const Event& event) { static const KeyModifierMask s_ignoreMask = KeyModifierAltGr | KeyModifierCapsLock | KeyModifierNumLock | KeyModifierScrollLock; EFilterStatus status; // check for hotkey events Event::Type type = event.getType(); if (type == m_events->forIPrimaryScreen().buttonDown()) { status = kActivate; } else if (type == m_events->forIPrimaryScreen().buttonUp()) { status = kDeactivate; } else { return kNoMatch; } // check if it's the right button and modifiers. ignore modifiers // that cannot be combined with a mouse button. IPlatformScreen::ButtonInfo* minfo = static_cast(event.getData()); if (minfo->m_button != m_button || (minfo->m_mask & ~s_ignoreMask) != m_mask) { return kNoMatch; } return status; } InputFilter::ScreenConnectedCondition::ScreenConnectedCondition( IEventQueue* events, const String& screen) : m_screen(screen), m_events(events) { // do nothing } InputFilter::ScreenConnectedCondition::~ScreenConnectedCondition() { // do nothing } InputFilter::Condition* InputFilter::ScreenConnectedCondition::clone() const { return new ScreenConnectedCondition(m_events, m_screen); } String InputFilter::ScreenConnectedCondition::format() const { return synergy::string::sprintf("connect(%s)", m_screen.c_str()); } InputFilter::EFilterStatus InputFilter::ScreenConnectedCondition::match(const Event& event) { if (event.getType() == m_events->forServer().connected()) { Server::ScreenConnectedInfo* info = static_cast(event.getData()); if (m_screen == info->m_screen || m_screen.empty()) { return kActivate; } } return kNoMatch; } // ----------------------------------------------------------------------------- // Input Filter Action Classes // ----------------------------------------------------------------------------- InputFilter::Action::Action() { // do nothing } InputFilter::Action::~Action() { // do nothing } InputFilter::LockCursorToScreenAction::LockCursorToScreenAction( IEventQueue* events, Mode mode) : m_mode(mode), m_events(events) { // do nothing } InputFilter::LockCursorToScreenAction::Mode InputFilter::LockCursorToScreenAction::getMode() const { return m_mode; } InputFilter::Action* InputFilter::LockCursorToScreenAction::clone() const { return new LockCursorToScreenAction(*this); } String InputFilter::LockCursorToScreenAction::format() const { static const char* s_mode[] = { "off", "on", "toggle" }; return synergy::string::sprintf("lockCursorToScreen(%s)", s_mode[m_mode]); } void InputFilter::LockCursorToScreenAction::perform(const Event& event) { static const Server::LockCursorToScreenInfo::State s_state[] = { Server::LockCursorToScreenInfo::kOff, Server::LockCursorToScreenInfo::kOn, Server::LockCursorToScreenInfo::kToggle }; // send event Server::LockCursorToScreenInfo* info = Server::LockCursorToScreenInfo::alloc(s_state[m_mode]); m_events->addEvent(Event(m_events->forServer().lockCursorToScreen(), event.getTarget(), info, Event::kDeliverImmediately)); } InputFilter::SwitchToScreenAction::SwitchToScreenAction( IEventQueue* events, const String& screen) : m_screen(screen), m_events(events) { // do nothing } String InputFilter::SwitchToScreenAction::getScreen() const { return m_screen; } InputFilter::Action* InputFilter::SwitchToScreenAction::clone() const { return new SwitchToScreenAction(*this); } String InputFilter::SwitchToScreenAction::format() const { return synergy::string::sprintf("switchToScreen(%s)", m_screen.c_str()); } void InputFilter::SwitchToScreenAction::perform(const Event& event) { // pick screen name. if m_screen is empty then use the screen from // event if it has one. String screen = m_screen; if (screen.empty() && event.getType() == m_events->forServer().connected()) { Server::ScreenConnectedInfo* info = static_cast(event.getData()); screen = info->m_screen; } // send event Server::SwitchToScreenInfo* info = Server::SwitchToScreenInfo::alloc(screen); m_events->addEvent(Event(m_events->forServer().switchToScreen(), event.getTarget(), info, Event::kDeliverImmediately)); } InputFilter::SwitchInDirectionAction::SwitchInDirectionAction( IEventQueue* events, EDirection direction) : m_direction(direction), m_events(events) { // do nothing } EDirection InputFilter::SwitchInDirectionAction::getDirection() const { return m_direction; } InputFilter::Action* InputFilter::SwitchInDirectionAction::clone() const { return new SwitchInDirectionAction(*this); } String InputFilter::SwitchInDirectionAction::format() const { static const char* s_names[] = { "", "left", "right", "up", "down" }; return synergy::string::sprintf("switchInDirection(%s)", s_names[m_direction]); } void InputFilter::SwitchInDirectionAction::perform(const Event& event) { Server::SwitchInDirectionInfo* info = Server::SwitchInDirectionInfo::alloc(m_direction); m_events->addEvent(Event(m_events->forServer().switchInDirection(), event.getTarget(), info, Event::kDeliverImmediately)); } InputFilter::KeyboardBroadcastAction::KeyboardBroadcastAction( IEventQueue* events, Mode mode) : m_mode(mode), m_events(events) { // do nothing } InputFilter::KeyboardBroadcastAction::KeyboardBroadcastAction( IEventQueue* events, Mode mode, const std::set& screens) : m_mode(mode), m_screens(IKeyState::KeyInfo::join(screens)), m_events(events) { // do nothing } InputFilter::KeyboardBroadcastAction::Mode InputFilter::KeyboardBroadcastAction::getMode() const { return m_mode; } std::set InputFilter::KeyboardBroadcastAction::getScreens() const { std::set screens; IKeyState::KeyInfo::split(m_screens.c_str(), screens); return screens; } InputFilter::Action* InputFilter::KeyboardBroadcastAction::clone() const { return new KeyboardBroadcastAction(*this); } String InputFilter::KeyboardBroadcastAction::format() const { static const char* s_mode[] = { "off", "on", "toggle" }; static const char* s_name = "keyboardBroadcast"; if (m_screens.empty() || m_screens[0] == '*') { return synergy::string::sprintf("%s(%s)", s_name, s_mode[m_mode]); } else { return synergy::string::sprintf("%s(%s,%.*s)", s_name, s_mode[m_mode], m_screens.size() - 2, m_screens.c_str() + 1); } } void InputFilter::KeyboardBroadcastAction::perform(const Event& event) { static const Server::KeyboardBroadcastInfo::State s_state[] = { Server::KeyboardBroadcastInfo::kOff, Server::KeyboardBroadcastInfo::kOn, Server::KeyboardBroadcastInfo::kToggle }; // send event Server::KeyboardBroadcastInfo* info = Server::KeyboardBroadcastInfo::alloc(s_state[m_mode], m_screens); m_events->addEvent(Event(m_events->forServer().keyboardBroadcast(), event.getTarget(), info, Event::kDeliverImmediately)); } InputFilter::KeystrokeAction::KeystrokeAction( IEventQueue* events, IPlatformScreen::KeyInfo* info, bool press) : m_keyInfo(info), m_press(press), m_events(events) { // do nothing } InputFilter::KeystrokeAction::~KeystrokeAction() { free(m_keyInfo); } void InputFilter::KeystrokeAction::adoptInfo(IPlatformScreen::KeyInfo* info) { free(m_keyInfo); m_keyInfo = info; } const IPlatformScreen::KeyInfo* InputFilter::KeystrokeAction::getInfo() const { return m_keyInfo; } bool InputFilter::KeystrokeAction::isOnPress() const { return m_press; } InputFilter::Action* InputFilter::KeystrokeAction::clone() const { IKeyState::KeyInfo* info = IKeyState::KeyInfo::alloc(*m_keyInfo); return new KeystrokeAction(m_events, info, m_press); } String InputFilter::KeystrokeAction::format() const { const char* type = formatName(); if (m_keyInfo->m_screens[0] == '\0') { return synergy::string::sprintf("%s(%s)", type, synergy::KeyMap::formatKey(m_keyInfo->m_key, m_keyInfo->m_mask).c_str()); } else if (m_keyInfo->m_screens[0] == '*') { return synergy::string::sprintf("%s(%s,*)", type, synergy::KeyMap::formatKey(m_keyInfo->m_key, m_keyInfo->m_mask).c_str()); } else { return synergy::string::sprintf("%s(%s,%.*s)", type, synergy::KeyMap::formatKey(m_keyInfo->m_key, m_keyInfo->m_mask).c_str(), strlen(m_keyInfo->m_screens + 1) - 1, m_keyInfo->m_screens + 1); } } void InputFilter::KeystrokeAction::perform(const Event& event) { Event::Type type = m_press ? m_events->forIKeyState().keyDown() : m_events->forIKeyState().keyUp(); m_events->addEvent(Event(m_events->forIPrimaryScreen().fakeInputBegin(), event.getTarget(), NULL, Event::kDeliverImmediately)); m_events->addEvent(Event(type, event.getTarget(), m_keyInfo, Event::kDeliverImmediately | Event::kDontFreeData)); m_events->addEvent(Event(m_events->forIPrimaryScreen().fakeInputEnd(), event.getTarget(), NULL, Event::kDeliverImmediately)); } const char* InputFilter::KeystrokeAction::formatName() const { return (m_press ? "keyDown" : "keyUp"); } InputFilter::MouseButtonAction::MouseButtonAction( IEventQueue* events, IPlatformScreen::ButtonInfo* info, bool press) : m_buttonInfo(info), m_press(press), m_events(events) { // do nothing } InputFilter::MouseButtonAction::~MouseButtonAction() { free(m_buttonInfo); } const IPlatformScreen::ButtonInfo* InputFilter::MouseButtonAction::getInfo() const { return m_buttonInfo; } bool InputFilter::MouseButtonAction::isOnPress() const { return m_press; } InputFilter::Action* InputFilter::MouseButtonAction::clone() const { IPlatformScreen::ButtonInfo* info = IPrimaryScreen::ButtonInfo::alloc(*m_buttonInfo); return new MouseButtonAction(m_events, info, m_press); } String InputFilter::MouseButtonAction::format() const { const char* type = formatName(); String key = synergy::KeyMap::formatKey(kKeyNone, m_buttonInfo->m_mask); return synergy::string::sprintf("%s(%s%s%d)", type, key.c_str(), key.empty() ? "" : "+", m_buttonInfo->m_button); } void InputFilter::MouseButtonAction::perform(const Event& event) { // send modifiers IPlatformScreen::KeyInfo* modifierInfo = NULL; if (m_buttonInfo->m_mask != 0) { KeyID key = m_press ? kKeySetModifiers : kKeyClearModifiers; modifierInfo = IKeyState::KeyInfo::alloc(key, m_buttonInfo->m_mask, 0, 1); m_events->addEvent(Event(m_events->forIKeyState().keyDown(), event.getTarget(), modifierInfo, Event::kDeliverImmediately)); } // send button Event::Type type = m_press ? m_events->forIPrimaryScreen().buttonDown() : m_events->forIPrimaryScreen().buttonUp(); m_events->addEvent(Event(type, event.getTarget(), m_buttonInfo, Event::kDeliverImmediately | Event::kDontFreeData)); } const char* InputFilter::MouseButtonAction::formatName() const { return (m_press ? "mouseDown" : "mouseUp"); } // // InputFilter::Rule // InputFilter::Rule::Rule() : m_condition(NULL) { // do nothing } InputFilter::Rule::Rule(Condition* adoptedCondition) : m_condition(adoptedCondition) { // do nothing } InputFilter::Rule::Rule(const Rule& rule) : m_condition(NULL) { copy(rule); } InputFilter::Rule::~Rule() { clear(); } InputFilter::Rule& InputFilter::Rule::operator=(const Rule& rule) { if (&rule != this) { copy(rule); } return *this; } void InputFilter::Rule::clear() { delete m_condition; for (ActionList::iterator i = m_activateActions.begin(); i != m_activateActions.end(); ++i) { delete *i; } for (ActionList::iterator i = m_deactivateActions.begin(); i != m_deactivateActions.end(); ++i) { delete *i; } m_condition = NULL; m_activateActions.clear(); m_deactivateActions.clear(); } void InputFilter::Rule::copy(const Rule& rule) { clear(); if (rule.m_condition != NULL) { m_condition = rule.m_condition->clone(); } for (ActionList::const_iterator i = rule.m_activateActions.begin(); i != rule.m_activateActions.end(); ++i) { m_activateActions.push_back((*i)->clone()); } for (ActionList::const_iterator i = rule.m_deactivateActions.begin(); i != rule.m_deactivateActions.end(); ++i) { m_deactivateActions.push_back((*i)->clone()); } } void InputFilter::Rule::setCondition(Condition* adopted) { delete m_condition; m_condition = adopted; } void InputFilter::Rule::adoptAction(Action* action, bool onActivation) { if (action != NULL) { if (onActivation) { m_activateActions.push_back(action); } else { m_deactivateActions.push_back(action); } } } void InputFilter::Rule::removeAction(bool onActivation, UInt32 index) { if (onActivation) { delete m_activateActions[index]; m_activateActions.erase(m_activateActions.begin() + index); } else { delete m_deactivateActions[index]; m_deactivateActions.erase(m_deactivateActions.begin() + index); } } void InputFilter::Rule::replaceAction(Action* adopted, bool onActivation, UInt32 index) { if (adopted == NULL) { removeAction(onActivation, index); } else if (onActivation) { delete m_activateActions[index]; m_activateActions[index] = adopted; } else { delete m_deactivateActions[index]; m_deactivateActions[index] = adopted; } } void InputFilter::Rule::enable(PrimaryClient* primaryClient) { if (m_condition != NULL) { m_condition->enablePrimary(primaryClient); } } void InputFilter::Rule::disable(PrimaryClient* primaryClient) { if (m_condition != NULL) { m_condition->disablePrimary(primaryClient); } } bool InputFilter::Rule::handleEvent(const Event& event) { // NULL condition never matches if (m_condition == NULL) { return false; } // match const ActionList* actions; switch (m_condition->match(event)) { default: // not handled return false; case kActivate: actions = &m_activateActions; LOG((CLOG_DEBUG1 "activate actions")); break; case kDeactivate: actions = &m_deactivateActions; LOG((CLOG_DEBUG1 "deactivate actions")); break; } // perform actions for (ActionList::const_iterator i = actions->begin(); i != actions->end(); ++i) { LOG((CLOG_DEBUG1 "hotkey: %s", (*i)->format().c_str())); (*i)->perform(event); } return true; } String InputFilter::Rule::format() const { String s; if (m_condition != NULL) { // condition s += m_condition->format(); s += " = "; // activate actions ActionList::const_iterator i = m_activateActions.begin(); if (i != m_activateActions.end()) { s += (*i)->format(); while (++i != m_activateActions.end()) { s += ", "; s += (*i)->format(); } } // deactivate actions if (!m_deactivateActions.empty()) { s += "; "; i = m_deactivateActions.begin(); if (i != m_deactivateActions.end()) { s += (*i)->format(); while (++i != m_deactivateActions.end()) { s += ", "; s += (*i)->format(); } } } } return s; } const InputFilter::Condition* InputFilter::Rule::getCondition() const { return m_condition; } UInt32 InputFilter::Rule::getNumActions(bool onActivation) const { if (onActivation) { return static_cast(m_activateActions.size()); } else { return static_cast(m_deactivateActions.size()); } } const InputFilter::Action& InputFilter::Rule::getAction(bool onActivation, UInt32 index) const { if (onActivation) { return *m_activateActions[index]; } else { return *m_deactivateActions[index]; } } // ----------------------------------------------------------------------------- // Input Filter Class // ----------------------------------------------------------------------------- InputFilter::InputFilter(IEventQueue* events) : m_primaryClient(NULL), m_events(events) { // do nothing } InputFilter::InputFilter(const InputFilter& x) : m_ruleList(x.m_ruleList), m_primaryClient(NULL), m_events(x.m_events) { setPrimaryClient(x.m_primaryClient); } InputFilter::~InputFilter() { setPrimaryClient(NULL); } InputFilter& InputFilter::operator=(const InputFilter& x) { if (&x != this) { PrimaryClient* oldClient = m_primaryClient; setPrimaryClient(NULL); m_ruleList = x.m_ruleList; setPrimaryClient(oldClient); } return *this; } void InputFilter::addFilterRule(const Rule& rule) { m_ruleList.push_back(rule); if (m_primaryClient != NULL) { m_ruleList.back().enable(m_primaryClient); } } void InputFilter::removeFilterRule(UInt32 index) { if (m_primaryClient != NULL) { m_ruleList[index].disable(m_primaryClient); } m_ruleList.erase(m_ruleList.begin() + index); } InputFilter::Rule& InputFilter::getRule(UInt32 index) { return m_ruleList[index]; } void InputFilter::setPrimaryClient(PrimaryClient* client) { if (m_primaryClient == client) { return; } if (m_primaryClient != NULL) { for (RuleList::iterator rule = m_ruleList.begin(); rule != m_ruleList.end(); ++rule) { rule->disable(m_primaryClient); } m_events->removeHandler(m_events->forIKeyState().keyDown(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIKeyState().keyUp(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIKeyState().keyRepeat(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIPrimaryScreen().buttonDown(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIPrimaryScreen().buttonUp(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIPrimaryScreen().hotKeyDown(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIPrimaryScreen().hotKeyUp(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forServer().connected(), m_primaryClient->getEventTarget()); } m_primaryClient = client; if (m_primaryClient != NULL) { m_events->adoptHandler(m_events->forIKeyState().keyDown(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &InputFilter::handleEvent)); m_events->adoptHandler(m_events->forIKeyState().keyUp(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &InputFilter::handleEvent)); m_events->adoptHandler(m_events->forIKeyState().keyRepeat(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &InputFilter::handleEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().buttonDown(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &InputFilter::handleEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().buttonUp(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &InputFilter::handleEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().hotKeyDown(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &InputFilter::handleEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().hotKeyUp(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &InputFilter::handleEvent)); m_events->adoptHandler(m_events->forServer().connected(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &InputFilter::handleEvent)); for (RuleList::iterator rule = m_ruleList.begin(); rule != m_ruleList.end(); ++rule) { rule->enable(m_primaryClient); } } } String InputFilter::format(const String& linePrefix) const { String s; for (RuleList::const_iterator i = m_ruleList.begin(); i != m_ruleList.end(); ++i) { s += linePrefix; s += i->format(); s += "\n"; } return s; } UInt32 InputFilter::getNumRules() const { return static_cast(m_ruleList.size()); } bool InputFilter::operator==(const InputFilter& x) const { // if there are different numbers of rules then we can't be equal if (m_ruleList.size() != x.m_ruleList.size()) { return false; } // compare rule lists. the easiest way to do that is to format each // rule into a string, sort the strings, then compare the results. std::vector aList, bList; for (RuleList::const_iterator i = m_ruleList.begin(); i != m_ruleList.end(); ++i) { aList.push_back(i->format()); } for (RuleList::const_iterator i = x.m_ruleList.begin(); i != x.m_ruleList.end(); ++i) { bList.push_back(i->format()); } std::partial_sort(aList.begin(), aList.end(), aList.end()); std::partial_sort(bList.begin(), bList.end(), bList.end()); return (aList == bList); } bool InputFilter::operator!=(const InputFilter& x) const { return !operator==(x); } void InputFilter::handleEvent(const Event& event, void*) { // copy event and adjust target Event myEvent(event.getType(), this, event.getData(), event.getFlags() | Event::kDontFreeData | Event::kDeliverImmediately); // let each rule try to match the event until one does for (RuleList::iterator rule = m_ruleList.begin(); rule != m_ruleList.end(); ++rule) { if (rule->handleEvent(myEvent)) { // handled return; } } // not handled so pass through m_events->addEvent(myEvent); } synergy-1.8.8-stable/src/lib/server/InputFilter.h000066400000000000000000000215171305627404700217770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2005 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/key_types.h" #include "synergy/mouse_types.h" #include "synergy/protocol_types.h" #include "synergy/IPlatformScreen.h" #include "base/String.h" #include "common/stdmap.h" #include "common/stdset.h" class PrimaryClient; class Event; class IEventQueue; class InputFilter { public: // ------------------------------------------------------------------------- // Input Filter Condition Classes // ------------------------------------------------------------------------- enum EFilterStatus { kNoMatch, kActivate, kDeactivate }; class Condition { public: Condition(); virtual ~Condition(); virtual Condition* clone() const = 0; virtual String format() const = 0; virtual EFilterStatus match(const Event&) = 0; virtual void enablePrimary(PrimaryClient*); virtual void disablePrimary(PrimaryClient*); }; // KeystrokeCondition class KeystrokeCondition : public Condition { public: KeystrokeCondition(IEventQueue* events, IPlatformScreen::KeyInfo*); KeystrokeCondition(IEventQueue* events, KeyID key, KeyModifierMask mask); virtual ~KeystrokeCondition(); KeyID getKey() const; KeyModifierMask getMask() const; // Condition overrides virtual Condition* clone() const; virtual String format() const; virtual EFilterStatus match(const Event&); virtual void enablePrimary(PrimaryClient*); virtual void disablePrimary(PrimaryClient*); private: UInt32 m_id; KeyID m_key; KeyModifierMask m_mask; IEventQueue* m_events; }; // MouseButtonCondition class MouseButtonCondition : public Condition { public: MouseButtonCondition(IEventQueue* events, IPlatformScreen::ButtonInfo*); MouseButtonCondition(IEventQueue* events, ButtonID, KeyModifierMask mask); virtual ~MouseButtonCondition(); ButtonID getButton() const; KeyModifierMask getMask() const; // Condition overrides virtual Condition* clone() const; virtual String format() const; virtual EFilterStatus match(const Event&); private: ButtonID m_button; KeyModifierMask m_mask; IEventQueue* m_events; }; // ScreenConnectedCondition class ScreenConnectedCondition : public Condition { public: ScreenConnectedCondition(IEventQueue* events, const String& screen); virtual ~ScreenConnectedCondition(); // Condition overrides virtual Condition* clone() const; virtual String format() const; virtual EFilterStatus match(const Event&); private: String m_screen; IEventQueue* m_events; }; // ------------------------------------------------------------------------- // Input Filter Action Classes // ------------------------------------------------------------------------- class Action { public: Action(); virtual ~Action(); virtual Action* clone() const = 0; virtual String format() const = 0; virtual void perform(const Event&) = 0; }; // LockCursorToScreenAction class LockCursorToScreenAction : public Action { public: enum Mode { kOff, kOn, kToggle }; LockCursorToScreenAction(IEventQueue* events, Mode = kToggle); Mode getMode() const; // Action overrides virtual Action* clone() const; virtual String format() const; virtual void perform(const Event&); private: Mode m_mode; IEventQueue* m_events; }; // SwitchToScreenAction class SwitchToScreenAction : public Action { public: SwitchToScreenAction(IEventQueue* events, const String& screen); String getScreen() const; // Action overrides virtual Action* clone() const; virtual String format() const; virtual void perform(const Event&); private: String m_screen; IEventQueue* m_events; }; // SwitchInDirectionAction class SwitchInDirectionAction : public Action { public: SwitchInDirectionAction(IEventQueue* events, EDirection); EDirection getDirection() const; // Action overrides virtual Action* clone() const; virtual String format() const; virtual void perform(const Event&); private: EDirection m_direction; IEventQueue* m_events; }; // KeyboardBroadcastAction class KeyboardBroadcastAction : public Action { public: enum Mode { kOff, kOn, kToggle }; KeyboardBroadcastAction(IEventQueue* events, Mode = kToggle); KeyboardBroadcastAction(IEventQueue* events, Mode, const std::set& screens); Mode getMode() const; std::set getScreens() const; // Action overrides virtual Action* clone() const; virtual String format() const; virtual void perform(const Event&); private: Mode m_mode; String m_screens; IEventQueue* m_events; }; // KeystrokeAction class KeystrokeAction : public Action { public: KeystrokeAction(IEventQueue* events, IPlatformScreen::KeyInfo* adoptedInfo, bool press); ~KeystrokeAction(); void adoptInfo(IPlatformScreen::KeyInfo*); const IPlatformScreen::KeyInfo* getInfo() const; bool isOnPress() const; // Action overrides virtual Action* clone() const; virtual String format() const; virtual void perform(const Event&); protected: virtual const char* formatName() const; private: IPlatformScreen::KeyInfo* m_keyInfo; bool m_press; IEventQueue* m_events; }; // MouseButtonAction -- modifier combinations not implemented yet class MouseButtonAction : public Action { public: MouseButtonAction(IEventQueue* events, IPlatformScreen::ButtonInfo* adoptedInfo, bool press); ~MouseButtonAction(); const IPlatformScreen::ButtonInfo* getInfo() const; bool isOnPress() const; // Action overrides virtual Action* clone() const; virtual String format() const; virtual void perform(const Event&); protected: virtual const char* formatName() const; private: IPlatformScreen::ButtonInfo* m_buttonInfo; bool m_press; IEventQueue* m_events; }; class Rule { public: Rule(); Rule(Condition* adopted); Rule(const Rule&); ~Rule(); Rule& operator=(const Rule&); // replace the condition void setCondition(Condition* adopted); // add an action to the rule void adoptAction(Action*, bool onActivation); // remove an action from the rule void removeAction(bool onActivation, UInt32 index); // replace an action in the rule void replaceAction(Action* adopted, bool onActivation, UInt32 index); // enable/disable void enable(PrimaryClient*); void disable(PrimaryClient*); // event handling bool handleEvent(const Event&); // convert rule to a string String format() const; // get the rule's condition const Condition* getCondition() const; // get number of actions UInt32 getNumActions(bool onActivation) const; // get action by index const Action& getAction(bool onActivation, UInt32 index) const; private: void clear(); void copy(const Rule&); private: typedef std::vector ActionList; Condition* m_condition; ActionList m_activateActions; ActionList m_deactivateActions; }; // ------------------------------------------------------------------------- // Input Filter Class // ------------------------------------------------------------------------- typedef std::vector RuleList; InputFilter(IEventQueue* events); InputFilter(const InputFilter&); virtual ~InputFilter(); #ifdef TEST_ENV InputFilter() : m_primaryClient(NULL) { } #endif InputFilter& operator=(const InputFilter&); // add rule, adopting the condition and the actions void addFilterRule(const Rule& rule); // remove a rule void removeFilterRule(UInt32 index); // get rule by index Rule& getRule(UInt32 index); // enable event filtering using the given primary client. disable // if client is NULL. virtual void setPrimaryClient(PrimaryClient* client); // convert rules to a string String format(const String& linePrefix) const; // get number of rules UInt32 getNumRules() const; //! Compare filters bool operator==(const InputFilter&) const; //! Compare filters bool operator!=(const InputFilter&) const; private: // event handling void handleEvent(const Event&, void*); private: RuleList m_ruleList; PrimaryClient* m_primaryClient; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/server/PrimaryClient.cpp000066400000000000000000000113661305627404700226500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/PrimaryClient.h" #include "synergy/Screen.h" #include "synergy/Clipboard.h" #include "base/Log.h" // // PrimaryClient // PrimaryClient::PrimaryClient(const String& name, synergy::Screen* screen) : BaseClientProxy(name), m_screen(screen), m_fakeInputCount(0) { // all clipboards are clean for (UInt32 i = 0; i < kClipboardEnd; ++i) { m_clipboardDirty[i] = false; } } PrimaryClient::~PrimaryClient() { // do nothing } void PrimaryClient::reconfigure(UInt32 activeSides) { m_screen->reconfigure(activeSides); } UInt32 PrimaryClient::registerHotKey(KeyID key, KeyModifierMask mask) { return m_screen->registerHotKey(key, mask); } void PrimaryClient::unregisterHotKey(UInt32 id) { m_screen->unregisterHotKey(id); } void PrimaryClient::fakeInputBegin() { if (++m_fakeInputCount == 1) { m_screen->fakeInputBegin(); } } void PrimaryClient::fakeInputEnd() { if (--m_fakeInputCount == 0) { m_screen->fakeInputEnd(); } } SInt32 PrimaryClient::getJumpZoneSize() const { return m_screen->getJumpZoneSize(); } void PrimaryClient::getCursorCenter(SInt32& x, SInt32& y) const { m_screen->getCursorCenter(x, y); } KeyModifierMask PrimaryClient::getToggleMask() const { return m_screen->pollActiveModifiers(); } bool PrimaryClient::isLockedToScreen() const { return m_screen->isLockedToScreen(); } void* PrimaryClient::getEventTarget() const { return m_screen->getEventTarget(); } bool PrimaryClient::getClipboard(ClipboardID id, IClipboard* clipboard) const { return m_screen->getClipboard(id, clipboard); } void PrimaryClient::getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const { m_screen->getShape(x, y, width, height); } void PrimaryClient::getCursorPos(SInt32& x, SInt32& y) const { m_screen->getCursorPos(x, y); } void PrimaryClient::enable() { m_screen->enable(); } void PrimaryClient::disable() { m_screen->disable(); } void PrimaryClient::enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, bool screensaver) { m_screen->setSequenceNumber(seqNum); if (!screensaver) { m_screen->warpCursor(xAbs, yAbs); } m_screen->enter(mask); } bool PrimaryClient::leave() { return m_screen->leave(); } void PrimaryClient::setClipboard(ClipboardID id, const IClipboard* clipboard) { // ignore if this clipboard is already clean if (m_clipboardDirty[id]) { // this clipboard is now clean m_clipboardDirty[id] = false; // set clipboard m_screen->setClipboard(id, clipboard); } } void PrimaryClient::grabClipboard(ClipboardID id) { // grab clipboard m_screen->grabClipboard(id); // clipboard is dirty (because someone else owns it now) m_clipboardDirty[id] = true; } void PrimaryClient::setClipboardDirty(ClipboardID id, bool dirty) { m_clipboardDirty[id] = dirty; } void PrimaryClient::keyDown(KeyID key, KeyModifierMask mask, KeyButton button) { if (m_fakeInputCount > 0) { // XXX -- don't forward keystrokes to primary screen for now (void)key; (void)mask; (void)button; // m_screen->keyDown(key, mask, button); } } void PrimaryClient::keyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton) { // ignore } void PrimaryClient::keyUp(KeyID key, KeyModifierMask mask, KeyButton button) { if (m_fakeInputCount > 0) { // XXX -- don't forward keystrokes to primary screen for now (void)key; (void)mask; (void)button; // m_screen->keyUp(key, mask, button); } } void PrimaryClient::mouseDown(ButtonID) { // ignore } void PrimaryClient::mouseUp(ButtonID) { // ignore } void PrimaryClient::mouseMove(SInt32 x, SInt32 y) { m_screen->warpCursor(x, y); } void PrimaryClient::mouseRelativeMove(SInt32, SInt32) { // ignore } void PrimaryClient::mouseWheel(SInt32, SInt32) { // ignore } void PrimaryClient::screensaver(bool) { // ignore } void PrimaryClient::sendDragInfo(UInt32 fileCount, const char* info, size_t size) { // ignore } void PrimaryClient::fileChunkSending(UInt8 mark, char* data, size_t dataSize) { // ignore } void PrimaryClient::resetOptions() { m_screen->resetOptions(); } void PrimaryClient::setOptions(const OptionsList& options) { m_screen->setOptions(options); } synergy-1.8.8-stable/src/lib/server/PrimaryClient.h000066400000000000000000000112341305627404700223070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/BaseClientProxy.h" #include "synergy/protocol_types.h" namespace synergy { class Screen; } //! Primary screen as pseudo-client /*! The primary screen does not have a client associated with it. This class provides a pseudo-client to allow the primary screen to be treated as if it was a client. */ class PrimaryClient : public BaseClientProxy { public: /*! \c name is the name of the server and \p screen is primary screen. */ PrimaryClient(const String& name, synergy::Screen* screen); ~PrimaryClient(); #ifdef TEST_ENV PrimaryClient() : BaseClientProxy("") { } #endif //! @name manipulators //@{ //! Update configuration /*! Handles reconfiguration of jump zones. */ virtual void reconfigure(UInt32 activeSides); //! Register a system hotkey /*! Registers a system-wide hotkey for key \p key with modifiers \p mask. Returns an id used to unregister the hotkey. */ virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask); //! Unregister a system hotkey /*! Unregisters a previously registered hot key. */ virtual void unregisterHotKey(UInt32 id); //! Prepare to synthesize input on primary screen /*! Prepares the primary screen to receive synthesized input. We do not want to receive this synthesized input as user input so this method ensures that we ignore it. Calls to \c fakeInputBegin() and \c fakeInputEnd() may be nested; only the outermost have an effect. */ void fakeInputBegin(); //! Done synthesizing input on primary screen /*! Undoes whatever \c fakeInputBegin() did. */ void fakeInputEnd(); //@} //! @name accessors //@{ //! Get jump zone size /*! Return the jump zone size, the size of the regions on the edges of the screen that cause the cursor to jump to another screen. */ SInt32 getJumpZoneSize() const; //! Get cursor center position /*! Return the cursor center position which is where we park the cursor to compute cursor motion deltas and should be far from the edges of the screen, typically the center. */ void getCursorCenter(SInt32& x, SInt32& y) const; //! Get toggle key state /*! Returns the primary screen's current toggle modifier key state. */ virtual KeyModifierMask getToggleMask() const; //! Get screen lock state /*! Returns true if the user is locked to the screen. */ bool isLockedToScreen() const; //@} // FIXME -- these probably belong on IScreen virtual void enable(); virtual void disable(); // IScreen overrides virtual void* getEventTarget() const; virtual bool getClipboard(ClipboardID id, IClipboard*) const; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const; virtual void getCursorPos(SInt32& x, SInt32& y) const; // IClient overrides virtual void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, bool forScreensaver); virtual bool leave(); virtual void setClipboard(ClipboardID, const IClipboard*); virtual void grabClipboard(ClipboardID); virtual void setClipboardDirty(ClipboardID, bool); virtual void keyDown(KeyID, KeyModifierMask, KeyButton); virtual void keyRepeat(KeyID, KeyModifierMask, SInt32 count, KeyButton); virtual void keyUp(KeyID, KeyModifierMask, KeyButton); virtual void mouseDown(ButtonID); virtual void mouseUp(ButtonID); virtual void mouseMove(SInt32 xAbs, SInt32 yAbs); virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel); virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta); virtual void screensaver(bool activate); virtual void resetOptions(); virtual void setOptions(const OptionsList& options); virtual void sendDragInfo(UInt32 fileCount, const char* info, size_t size); virtual void fileChunkSending(UInt8 mark, char* data, size_t dataSize); virtual synergy::IStream* getStream() const { return NULL; } bool isPrimary() const { return true; } private: synergy::Screen* m_screen; bool m_clipboardDirty[kClipboardEnd]; SInt32 m_fakeInputCount; }; synergy-1.8.8-stable/src/lib/server/Server.cpp000066400000000000000000001724271305627404700213420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "server/Server.h" #include "server/ClientProxy.h" #include "server/ClientProxyUnknown.h" #include "server/PrimaryClient.h" #include "server/ClientListener.h" #include "synergy/FileChunk.h" #include "synergy/IPlatformScreen.h" #include "synergy/DropHelper.h" #include "synergy/option_types.h" #include "synergy/protocol_types.h" #include "synergy/XScreen.h" #include "synergy/XSynergy.h" #include "synergy/StreamChunker.h" #include "synergy/KeyState.h" #include "synergy/Screen.h" #include "synergy/PacketStreamFilter.h" #include "net/TCPSocket.h" #include "net/IDataSocket.h" #include "net/IListenSocket.h" #include "net/XSocket.h" #include "mt/Thread.h" #include "arch/Arch.h" #include "base/TMethodJob.h" #include "base/IEventQueue.h" #include "base/Log.h" #include "base/TMethodEventJob.h" #include "common/stdexcept.h" #include "shared/SerialKey.h" #include #include #include #include #include // // Server // Server::Server( Config& config, PrimaryClient* primaryClient, synergy::Screen* screen, IEventQueue* events, ServerArgs const& args) : m_mock(false), m_primaryClient(primaryClient), m_active(primaryClient), m_seqNum(0), m_xDelta(0), m_yDelta(0), m_xDelta2(0), m_yDelta2(0), m_config(&config), m_inputFilter(config.getInputFilter()), m_activeSaver(NULL), m_switchDir(kNoDirection), m_switchScreen(NULL), m_switchWaitDelay(0.0), m_switchWaitTimer(NULL), m_switchTwoTapDelay(0.0), m_switchTwoTapEngaged(false), m_switchTwoTapArmed(false), m_switchTwoTapZone(3), m_switchNeedsShift(false), m_switchNeedsControl(false), m_switchNeedsAlt(false), m_relativeMoves(false), m_keyboardBroadcasting(false), m_lockedToScreen(false), m_screen(screen), m_events(events), m_sendFileThread(NULL), m_writeToDropDirThread(NULL), m_ignoreFileTransfer(false), m_enableClipboard(true), m_sendDragInfoThread(NULL), m_waitDragInfoThread(true), m_args(args) { // must have a primary client and it must have a canonical name assert(m_primaryClient != NULL); assert(config.isScreen(primaryClient->getName())); assert(m_screen != NULL); String primaryName = getName(primaryClient); // clear clipboards for (ClipboardID id = 0; id < kClipboardEnd; ++id) { ClipboardInfo& clipboard = m_clipboards[id]; clipboard.m_clipboardOwner = primaryName; clipboard.m_clipboardSeqNum = m_seqNum; if (clipboard.m_clipboard.open(0)) { clipboard.m_clipboard.empty(); clipboard.m_clipboard.close(); } clipboard.m_clipboardData = clipboard.m_clipboard.marshall(); } // install event handlers m_events->adoptHandler(Event::kTimer, this, new TMethodEventJob(this, &Server::handleSwitchWaitTimeout)); m_events->adoptHandler(m_events->forIKeyState().keyDown(), m_inputFilter, new TMethodEventJob(this, &Server::handleKeyDownEvent)); m_events->adoptHandler(m_events->forIKeyState().keyUp(), m_inputFilter, new TMethodEventJob(this, &Server::handleKeyUpEvent)); m_events->adoptHandler(m_events->forIKeyState().keyRepeat(), m_inputFilter, new TMethodEventJob(this, &Server::handleKeyRepeatEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().buttonDown(), m_inputFilter, new TMethodEventJob(this, &Server::handleButtonDownEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().buttonUp(), m_inputFilter, new TMethodEventJob(this, &Server::handleButtonUpEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().motionOnPrimary(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &Server::handleMotionPrimaryEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().motionOnSecondary(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &Server::handleMotionSecondaryEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().wheel(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &Server::handleWheelEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().screensaverActivated(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &Server::handleScreensaverActivatedEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().screensaverDeactivated(), m_primaryClient->getEventTarget(), new TMethodEventJob(this, &Server::handleScreensaverDeactivatedEvent)); m_events->adoptHandler(m_events->forServer().switchToScreen(), m_inputFilter, new TMethodEventJob(this, &Server::handleSwitchToScreenEvent)); m_events->adoptHandler(m_events->forServer().switchInDirection(), m_inputFilter, new TMethodEventJob(this, &Server::handleSwitchInDirectionEvent)); m_events->adoptHandler(m_events->forServer().keyboardBroadcast(), m_inputFilter, new TMethodEventJob(this, &Server::handleKeyboardBroadcastEvent)); m_events->adoptHandler(m_events->forServer().lockCursorToScreen(), m_inputFilter, new TMethodEventJob(this, &Server::handleLockCursorToScreenEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().fakeInputBegin(), m_inputFilter, new TMethodEventJob(this, &Server::handleFakeInputBeginEvent)); m_events->adoptHandler(m_events->forIPrimaryScreen().fakeInputEnd(), m_inputFilter, new TMethodEventJob(this, &Server::handleFakeInputEndEvent)); if (m_args.m_enableDragDrop) { m_events->adoptHandler(m_events->forFile().fileChunkSending(), this, new TMethodEventJob(this, &Server::handleFileChunkSendingEvent)); m_events->adoptHandler(m_events->forFile().fileRecieveCompleted(), this, new TMethodEventJob(this, &Server::handleFileRecieveCompletedEvent)); } // add connection addClient(m_primaryClient); // set initial configuration setConfig(config); // enable primary client m_primaryClient->enable(); m_inputFilter->setPrimaryClient(m_primaryClient); // Determine if scroll lock is already set. If so, lock the cursor to the primary screen if (m_primaryClient->getToggleMask() & KeyModifierScrollLock) { LOG((CLOG_NOTE "Scroll Lock is on, locking cursor to screen")); m_lockedToScreen = true; } } Server::~Server() { if (m_mock) { return; } // remove event handlers and timers m_events->removeHandler(m_events->forIKeyState().keyDown(), m_inputFilter); m_events->removeHandler(m_events->forIKeyState().keyUp(), m_inputFilter); m_events->removeHandler(m_events->forIKeyState().keyRepeat(), m_inputFilter); m_events->removeHandler(m_events->forIPrimaryScreen().buttonDown(), m_inputFilter); m_events->removeHandler(m_events->forIPrimaryScreen().buttonUp(), m_inputFilter); m_events->removeHandler(m_events->forIPrimaryScreen().motionOnPrimary(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIPrimaryScreen().motionOnSecondary(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIPrimaryScreen().wheel(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIPrimaryScreen().screensaverActivated(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIPrimaryScreen().screensaverDeactivated(), m_primaryClient->getEventTarget()); m_events->removeHandler(m_events->forIPrimaryScreen().fakeInputBegin(), m_inputFilter); m_events->removeHandler(m_events->forIPrimaryScreen().fakeInputEnd(), m_inputFilter); m_events->removeHandler(Event::kTimer, this); stopSwitch(); // force immediate disconnection of secondary clients disconnect(); for (OldClients::iterator index = m_oldClients.begin(); index != m_oldClients.begin(); ++index) { BaseClientProxy* client = index->first; m_events->deleteTimer(index->second); m_events->removeHandler(Event::kTimer, client); m_events->removeHandler(m_events->forClientProxy().disconnected(), client); delete client; } // remove input filter m_inputFilter->setPrimaryClient(NULL); // disable and disconnect primary client m_primaryClient->disable(); removeClient(m_primaryClient); } bool Server::setConfig(const Config& config) { // refuse configuration if it doesn't include the primary screen if (!config.isScreen(m_primaryClient->getName())) { return false; } // close clients that are connected but being dropped from the // configuration. closeClients(config); // cut over processOptions(); // add ScrollLock as a hotkey to lock to the screen. this was a // built-in feature in earlier releases and is now supported via // the user configurable hotkey mechanism. if the user has already // registered ScrollLock for something else then that will win but // we will unfortunately generate a warning. if the user has // configured a LockCursorToScreenAction then we don't add // ScrollLock as a hotkey. if (!m_config->hasLockToScreenAction()) { IPlatformScreen::KeyInfo* key = IPlatformScreen::KeyInfo::alloc(kKeyScrollLock, 0, 0, 0); InputFilter::Rule rule(new InputFilter::KeystrokeCondition(m_events, key)); rule.adoptAction(new InputFilter::LockCursorToScreenAction(m_events), true); m_inputFilter->addFilterRule(rule); } // tell primary screen about reconfiguration m_primaryClient->reconfigure(getActivePrimarySides()); // tell all (connected) clients about current options for (ClientList::const_iterator index = m_clients.begin(); index != m_clients.end(); ++index) { BaseClientProxy* client = index->second; sendOptions(client); } return true; } void Server::adoptClient(BaseClientProxy* client) { assert(client != NULL); // watch for client disconnection m_events->adoptHandler(m_events->forClientProxy().disconnected(), client, new TMethodEventJob(this, &Server::handleClientDisconnected, client)); // name must be in our configuration if (!m_config->isScreen(client->getName())) { LOG((CLOG_WARN "unrecognised client name \"%s\", check server config", client->getName().c_str())); closeClient(client, kMsgEUnknown); return; } // add client to client list if (!addClient(client)) { // can only have one screen with a given name at any given time LOG((CLOG_WARN "a client with name \"%s\" is already connected", getName(client).c_str())); closeClient(client, kMsgEBusy); return; } LOG((CLOG_NOTE "client \"%s\" has connected", getName(client).c_str())); // send configuration options to client sendOptions(client); // activate screen saver on new client if active on the primary screen if (m_activeSaver != NULL) { client->screensaver(true); } // send notification Server::ScreenConnectedInfo* info = new Server::ScreenConnectedInfo(getName(client)); m_events->addEvent(Event(m_events->forServer().connected(), m_primaryClient->getEventTarget(), info)); } void Server::disconnect() { // close all secondary clients if (m_clients.size() > 1 || !m_oldClients.empty()) { Config emptyConfig(m_events); closeClients(emptyConfig); } else { m_events->addEvent(Event(m_events->forServer().disconnected(), this)); } } UInt32 Server::getNumClients() const { return (SInt32)m_clients.size(); } void Server::getClients(std::vector& list) const { list.clear(); for (ClientList::const_iterator index = m_clients.begin(); index != m_clients.end(); ++index) { list.push_back(index->first); } } String Server::getName(const BaseClientProxy* client) const { String name = m_config->getCanonicalName(client->getName()); if (name.empty()) { name = client->getName(); } return name; } UInt32 Server::getActivePrimarySides() const { UInt32 sides = 0; if (!isLockedToScreenServer()) { if (hasAnyNeighbor(m_primaryClient, kLeft)) { sides |= kLeftMask; } if (hasAnyNeighbor(m_primaryClient, kRight)) { sides |= kRightMask; } if (hasAnyNeighbor(m_primaryClient, kTop)) { sides |= kTopMask; } if (hasAnyNeighbor(m_primaryClient, kBottom)) { sides |= kBottomMask; } } return sides; } bool Server::isLockedToScreenServer() const { // locked if scroll-lock is toggled on return m_lockedToScreen; } bool Server::isLockedToScreen() const { // locked if we say we're locked if (isLockedToScreenServer()) { LOG((CLOG_NOTE "Cursor is locked to screen, check Scroll Lock key")); return true; } // locked if primary says we're locked if (m_primaryClient->isLockedToScreen()) { return true; } // not locked return false; } SInt32 Server::getJumpZoneSize(BaseClientProxy* client) const { if (client == m_primaryClient) { return m_primaryClient->getJumpZoneSize(); } else { return 0; } } void Server::switchScreen(BaseClientProxy* dst, SInt32 x, SInt32 y, bool forScreensaver) { assert(dst != NULL); // if trial is expired, exit the process if (m_args.m_serial.isExpired(std::time(0))) { LOG((CLOG_ERR "trial has expired, aborting server")); exit(kExitSuccess); } #ifndef NDEBUG { SInt32 dx, dy, dw, dh; dst->getShape(dx, dy, dw, dh); assert(x >= dx && y >= dy && x < dx + dw && y < dy + dh); } #endif assert(m_active != NULL); LOG((CLOG_INFO "switch from \"%s\" to \"%s\" at %d,%d", getName(m_active).c_str(), getName(dst).c_str(), x, y)); // stop waiting to switch stopSwitch(); // record new position m_x = x; m_y = y; m_xDelta = 0; m_yDelta = 0; m_xDelta2 = 0; m_yDelta2 = 0; // wrapping means leaving the active screen and entering it again. // since that's a waste of time we skip that and just warp the // mouse. if (m_active != dst) { // leave active screen if (!m_active->leave()) { // cannot leave screen LOG((CLOG_WARN "can't leave screen")); return; } // update the primary client's clipboards if we're leaving the // primary screen. if (m_active == m_primaryClient && m_enableClipboard) { for (ClipboardID id = 0; id < kClipboardEnd; ++id) { ClipboardInfo& clipboard = m_clipboards[id]; if (clipboard.m_clipboardOwner == getName(m_primaryClient)) { onClipboardChanged(m_primaryClient, id, clipboard.m_clipboardSeqNum); } } } // cut over m_active = dst; // increment enter sequence number ++m_seqNum; // enter new screen m_active->enter(x, y, m_seqNum, m_primaryClient->getToggleMask(), forScreensaver); if (m_enableClipboard) { // send the clipboard data to new active screen for (ClipboardID id = 0; id < kClipboardEnd; ++id) { m_active->setClipboard(id, &m_clipboards[id].m_clipboard); } } Server::SwitchToScreenInfo* info = Server::SwitchToScreenInfo::alloc(m_active->getName()); m_events->addEvent(Event(m_events->forServer().screenSwitched(), this, info)); } else { m_active->mouseMove(x, y); } } void Server::jumpToScreen(BaseClientProxy* newScreen) { assert(newScreen != NULL); // record the current cursor position on the active screen m_active->setJumpCursorPos(m_x, m_y); // get the last cursor position on the target screen SInt32 x, y; newScreen->getJumpCursorPos(x, y); switchScreen(newScreen, x, y, false); } float Server::mapToFraction(BaseClientProxy* client, EDirection dir, SInt32 x, SInt32 y) const { SInt32 sx, sy, sw, sh; client->getShape(sx, sy, sw, sh); switch (dir) { case kLeft: case kRight: return static_cast(y - sy + 0.5f) / static_cast(sh); case kTop: case kBottom: return static_cast(x - sx + 0.5f) / static_cast(sw); case kNoDirection: assert(0 && "bad direction"); break; } return 0.0f; } void Server::mapToPixel(BaseClientProxy* client, EDirection dir, float f, SInt32& x, SInt32& y) const { SInt32 sx, sy, sw, sh; client->getShape(sx, sy, sw, sh); switch (dir) { case kLeft: case kRight: y = static_cast(f * sh) + sy; break; case kTop: case kBottom: x = static_cast(f * sw) + sx; break; case kNoDirection: assert(0 && "bad direction"); break; } } bool Server::hasAnyNeighbor(BaseClientProxy* client, EDirection dir) const { assert(client != NULL); return m_config->hasNeighbor(getName(client), dir); } BaseClientProxy* Server::getNeighbor(BaseClientProxy* src, EDirection dir, SInt32& x, SInt32& y) const { // note -- must be locked on entry assert(src != NULL); // get source screen name String srcName = getName(src); assert(!srcName.empty()); LOG((CLOG_DEBUG2 "find neighbor on %s of \"%s\"", Config::dirName(dir), srcName.c_str())); // convert position to fraction float t = mapToFraction(src, dir, x, y); // search for the closest neighbor that exists in direction dir float tTmp; for (;;) { String dstName(m_config->getNeighbor(srcName, dir, t, &tTmp)); // if nothing in that direction then return NULL. if the // destination is the source then we can make no more // progress in this direction. since we haven't found a // connected neighbor we return NULL. if (dstName.empty()) { LOG((CLOG_DEBUG2 "no neighbor on %s of \"%s\"", Config::dirName(dir), srcName.c_str())); return NULL; } // look up neighbor cell. if the screen is connected and // ready then we can stop. ClientList::const_iterator index = m_clients.find(dstName); if (index != m_clients.end()) { LOG((CLOG_DEBUG2 "\"%s\" is on %s of \"%s\" at %f", dstName.c_str(), Config::dirName(dir), srcName.c_str(), t)); mapToPixel(index->second, dir, tTmp, x, y); return index->second; } // skip over unconnected screen LOG((CLOG_DEBUG2 "ignored \"%s\" on %s of \"%s\"", dstName.c_str(), Config::dirName(dir), srcName.c_str())); srcName = dstName; // use position on skipped screen t = tTmp; } } BaseClientProxy* Server::mapToNeighbor(BaseClientProxy* src, EDirection srcSide, SInt32& x, SInt32& y) const { // note -- must be locked on entry assert(src != NULL); // get the first neighbor BaseClientProxy* dst = getNeighbor(src, srcSide, x, y); if (dst == NULL) { return NULL; } // get the source screen's size SInt32 dx, dy, dw, dh; BaseClientProxy* lastGoodScreen = src; lastGoodScreen->getShape(dx, dy, dw, dh); // find destination screen, adjusting x or y (but not both). the // searches are done in a sort of canonical screen space where // the upper-left corner is 0,0 for each screen. we adjust from // actual to canonical position on entry to and from canonical to // actual on exit from the search. switch (srcSide) { case kLeft: x -= dx; while (dst != NULL) { lastGoodScreen = dst; lastGoodScreen->getShape(dx, dy, dw, dh); x += dw; if (x >= 0) { break; } LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); dst = getNeighbor(lastGoodScreen, srcSide, x, y); } assert(lastGoodScreen != NULL); x += dx; break; case kRight: x -= dx; while (dst != NULL) { x -= dw; lastGoodScreen = dst; lastGoodScreen->getShape(dx, dy, dw, dh); if (x < dw) { break; } LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); dst = getNeighbor(lastGoodScreen, srcSide, x, y); } assert(lastGoodScreen != NULL); x += dx; break; case kTop: y -= dy; while (dst != NULL) { lastGoodScreen = dst; lastGoodScreen->getShape(dx, dy, dw, dh); y += dh; if (y >= 0) { break; } LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); dst = getNeighbor(lastGoodScreen, srcSide, x, y); } assert(lastGoodScreen != NULL); y += dy; break; case kBottom: y -= dy; while (dst != NULL) { y -= dh; lastGoodScreen = dst; lastGoodScreen->getShape(dx, dy, dw, dh); if (y < dh) { break; } LOG((CLOG_DEBUG2 "skipping over screen %s", getName(dst).c_str())); dst = getNeighbor(lastGoodScreen, srcSide, x, y); } assert(lastGoodScreen != NULL); y += dy; break; case kNoDirection: assert(0 && "bad direction"); return NULL; } // save destination screen assert(lastGoodScreen != NULL); dst = lastGoodScreen; // if entering primary screen then be sure to move in far enough // to avoid the jump zone. if entering a side that doesn't have // a neighbor (i.e. an asymmetrical side) then we don't need to // move inwards because that side can't provoke a jump. avoidJumpZone(dst, srcSide, x, y); return dst; } void Server::avoidJumpZone(BaseClientProxy* dst, EDirection dir, SInt32& x, SInt32& y) const { // we only need to avoid jump zones on the primary screen if (dst != m_primaryClient) { return; } const String dstName(getName(dst)); SInt32 dx, dy, dw, dh; dst->getShape(dx, dy, dw, dh); float t = mapToFraction(dst, dir, x, y); SInt32 z = getJumpZoneSize(dst); // move in far enough to avoid the jump zone. if entering a side // that doesn't have a neighbor (i.e. an asymmetrical side) then we // don't need to move inwards because that side can't provoke a jump. switch (dir) { case kLeft: if (!m_config->getNeighbor(dstName, kRight, t, NULL).empty() && x > dx + dw - 1 - z) x = dx + dw - 1 - z; break; case kRight: if (!m_config->getNeighbor(dstName, kLeft, t, NULL).empty() && x < dx + z) x = dx + z; break; case kTop: if (!m_config->getNeighbor(dstName, kBottom, t, NULL).empty() && y > dy + dh - 1 - z) y = dy + dh - 1 - z; break; case kBottom: if (!m_config->getNeighbor(dstName, kTop, t, NULL).empty() && y < dy + z) y = dy + z; break; case kNoDirection: assert(0 && "bad direction"); } } bool Server::isSwitchOkay(BaseClientProxy* newScreen, EDirection dir, SInt32 x, SInt32 y, SInt32 xActive, SInt32 yActive) { LOG((CLOG_DEBUG1 "try to leave \"%s\" on %s", getName(m_active).c_str(), Config::dirName(dir))); // is there a neighbor? if (newScreen == NULL) { // there's no neighbor. we don't want to switch and we don't // want to try to switch later. LOG((CLOG_DEBUG1 "no neighbor %s", Config::dirName(dir))); stopSwitch(); return false; } // should we switch or not? bool preventSwitch = false; bool allowSwitch = false; // note if the switch direction has changed. save the new // direction and screen if so. bool isNewDirection = (dir != m_switchDir); if (isNewDirection || m_switchScreen == NULL) { m_switchDir = dir; m_switchScreen = newScreen; } // is this a double tap and do we care? if (!allowSwitch && m_switchTwoTapDelay > 0.0) { if (isNewDirection || !isSwitchTwoTapStarted() || !shouldSwitchTwoTap()) { // tapping a different or new edge or second tap not // fast enough. prepare for second tap. preventSwitch = true; startSwitchTwoTap(); } else { // got second tap allowSwitch = true; } } // if waiting before a switch then prepare to switch later if (!allowSwitch && m_switchWaitDelay > 0.0) { if (isNewDirection || !isSwitchWaitStarted()) { startSwitchWait(x, y); } preventSwitch = true; } // are we in a locked corner? first check if screen has the option set // and, if not, check the global options. const Config::ScreenOptions* options = m_config->getOptions(getName(m_active)); if (options == NULL || options->count(kOptionScreenSwitchCorners) == 0) { options = m_config->getOptions(""); } if (options != NULL && options->count(kOptionScreenSwitchCorners) > 0) { // get corner mask and size Config::ScreenOptions::const_iterator i = options->find(kOptionScreenSwitchCorners); UInt32 corners = static_cast(i->second); i = options->find(kOptionScreenSwitchCornerSize); SInt32 size = 0; if (i != options->end()) { size = i->second; } // see if we're in a locked corner if ((getCorner(m_active, xActive, yActive, size) & corners) != 0) { // yep, no switching LOG((CLOG_DEBUG1 "locked in corner")); preventSwitch = true; stopSwitch(); } } // ignore if mouse is locked to screen and don't try to switch later if (!preventSwitch && isLockedToScreen()) { LOG((CLOG_DEBUG1 "locked to screen")); preventSwitch = true; stopSwitch(); } // check for optional needed modifiers KeyModifierMask mods = this->m_primaryClient->getToggleMask(); if (!preventSwitch && ( (this->m_switchNeedsShift && ((mods & KeyModifierShift) != KeyModifierShift)) || (this->m_switchNeedsControl && ((mods & KeyModifierControl) != KeyModifierControl)) || (this->m_switchNeedsAlt && ((mods & KeyModifierAlt) != KeyModifierAlt)) )) { LOG((CLOG_DEBUG1 "need modifiers to switch")); preventSwitch = true; stopSwitch(); } return !preventSwitch; } void Server::noSwitch(SInt32 x, SInt32 y) { armSwitchTwoTap(x, y); stopSwitchWait(); } void Server::stopSwitch() { if (m_switchScreen != NULL) { m_switchScreen = NULL; m_switchDir = kNoDirection; stopSwitchTwoTap(); stopSwitchWait(); } } void Server::startSwitchTwoTap() { m_switchTwoTapEngaged = true; m_switchTwoTapArmed = false; m_switchTwoTapTimer.reset(); LOG((CLOG_DEBUG1 "waiting for second tap")); } void Server::armSwitchTwoTap(SInt32 x, SInt32 y) { if (m_switchTwoTapEngaged) { if (m_switchTwoTapTimer.getTime() > m_switchTwoTapDelay) { // second tap took too long. disengage. stopSwitchTwoTap(); } else if (!m_switchTwoTapArmed) { // still time for a double tap. see if we left the tap // zone and, if so, arm the two tap. SInt32 ax, ay, aw, ah; m_active->getShape(ax, ay, aw, ah); SInt32 tapZone = m_primaryClient->getJumpZoneSize(); if (tapZone < m_switchTwoTapZone) { tapZone = m_switchTwoTapZone; } if (x >= ax + tapZone && x < ax + aw - tapZone && y >= ay + tapZone && y < ay + ah - tapZone) { // win32 can generate bogus mouse events that appear to // move in the opposite direction that the mouse actually // moved. try to ignore that crap here. switch (m_switchDir) { case kLeft: m_switchTwoTapArmed = (m_xDelta > 0 && m_xDelta2 > 0); break; case kRight: m_switchTwoTapArmed = (m_xDelta < 0 && m_xDelta2 < 0); break; case kTop: m_switchTwoTapArmed = (m_yDelta > 0 && m_yDelta2 > 0); break; case kBottom: m_switchTwoTapArmed = (m_yDelta < 0 && m_yDelta2 < 0); break; default: break; } } } } } void Server::stopSwitchTwoTap() { m_switchTwoTapEngaged = false; m_switchTwoTapArmed = false; } bool Server::isSwitchTwoTapStarted() const { return m_switchTwoTapEngaged; } bool Server::shouldSwitchTwoTap() const { // this is the second tap if two-tap is armed and this tap // came fast enough return (m_switchTwoTapArmed && m_switchTwoTapTimer.getTime() <= m_switchTwoTapDelay); } void Server::startSwitchWait(SInt32 x, SInt32 y) { stopSwitchWait(); m_switchWaitX = x; m_switchWaitY = y; m_switchWaitTimer = m_events->newOneShotTimer(m_switchWaitDelay, this); LOG((CLOG_DEBUG1 "waiting to switch")); } void Server::stopSwitchWait() { if (m_switchWaitTimer != NULL) { m_events->deleteTimer(m_switchWaitTimer); m_switchWaitTimer = NULL; } } bool Server::isSwitchWaitStarted() const { return (m_switchWaitTimer != NULL); } UInt32 Server::getCorner(BaseClientProxy* client, SInt32 x, SInt32 y, SInt32 size) const { assert(client != NULL); // get client screen shape SInt32 ax, ay, aw, ah; client->getShape(ax, ay, aw, ah); // check for x,y on the left or right SInt32 xSide; if (x <= ax) { xSide = -1; } else if (x >= ax + aw - 1) { xSide = 1; } else { xSide = 0; } // check for x,y on the top or bottom SInt32 ySide; if (y <= ay) { ySide = -1; } else if (y >= ay + ah - 1) { ySide = 1; } else { ySide = 0; } // if against the left or right then check if y is within size if (xSide != 0) { if (y < ay + size) { return (xSide < 0) ? kTopLeftMask : kTopRightMask; } else if (y >= ay + ah - size) { return (xSide < 0) ? kBottomLeftMask : kBottomRightMask; } } // if against the left or right then check if y is within size if (ySide != 0) { if (x < ax + size) { return (ySide < 0) ? kTopLeftMask : kBottomLeftMask; } else if (x >= ax + aw - size) { return (ySide < 0) ? kTopRightMask : kBottomRightMask; } } return kNoCornerMask; } void Server::stopRelativeMoves() { if (m_relativeMoves && m_active != m_primaryClient) { // warp to the center of the active client so we know where we are SInt32 ax, ay, aw, ah; m_active->getShape(ax, ay, aw, ah); m_x = ax + (aw >> 1); m_y = ay + (ah >> 1); m_xDelta = 0; m_yDelta = 0; m_xDelta2 = 0; m_yDelta2 = 0; LOG((CLOG_DEBUG2 "synchronize move on %s by %d,%d", getName(m_active).c_str(), m_x, m_y)); m_active->mouseMove(m_x, m_y); } } void Server::sendOptions(BaseClientProxy* client) const { OptionsList optionsList; // look up options for client const Config::ScreenOptions* options = m_config->getOptions(getName(client)); if (options != NULL) { // convert options to a more convenient form for sending optionsList.reserve(2 * options->size()); for (Config::ScreenOptions::const_iterator index = options->begin(); index != options->end(); ++index) { optionsList.push_back(index->first); optionsList.push_back(static_cast(index->second)); } } // look up global options options = m_config->getOptions(""); if (options != NULL) { // convert options to a more convenient form for sending optionsList.reserve(optionsList.size() + 2 * options->size()); for (Config::ScreenOptions::const_iterator index = options->begin(); index != options->end(); ++index) { optionsList.push_back(index->first); optionsList.push_back(static_cast(index->second)); } } // send the options client->resetOptions(); client->setOptions(optionsList); } void Server::processOptions() { const Config::ScreenOptions* options = m_config->getOptions(""); if (options == NULL) { return; } m_switchNeedsShift = false; // it seems if i don't add these m_switchNeedsControl = false; // lines, the 'reload config' option m_switchNeedsAlt = false; // doesnt' work correct. bool newRelativeMoves = m_relativeMoves; for (Config::ScreenOptions::const_iterator index = options->begin(); index != options->end(); ++index) { const OptionID id = index->first; const OptionValue value = index->second; if (id == kOptionScreenSwitchDelay) { m_switchWaitDelay = 1.0e-3 * static_cast(value); if (m_switchWaitDelay < 0.0) { m_switchWaitDelay = 0.0; } stopSwitchWait(); } else if (id == kOptionScreenSwitchTwoTap) { m_switchTwoTapDelay = 1.0e-3 * static_cast(value); if (m_switchTwoTapDelay < 0.0) { m_switchTwoTapDelay = 0.0; } stopSwitchTwoTap(); } else if (id == kOptionScreenSwitchNeedsControl) { m_switchNeedsControl = (value != 0); } else if (id == kOptionScreenSwitchNeedsShift) { m_switchNeedsShift = (value != 0); } else if (id == kOptionScreenSwitchNeedsAlt) { m_switchNeedsAlt = (value != 0); } else if (id == kOptionRelativeMouseMoves) { newRelativeMoves = (value != 0); } else if (id == kOptionClipboardSharing) { m_enableClipboard = (value != 0); if (m_enableClipboard == false) { LOG((CLOG_NOTE "clipboard sharing is disabled")); } } } if (m_relativeMoves && !newRelativeMoves) { stopRelativeMoves(); } m_relativeMoves = newRelativeMoves; } void Server::handleShapeChanged(const Event&, void* vclient) { // ignore events from unknown clients BaseClientProxy* client = static_cast(vclient); if (m_clientSet.count(client) == 0) { return; } LOG((CLOG_DEBUG "screen \"%s\" shape changed", getName(client).c_str())); // update jump coordinate SInt32 x, y; client->getCursorPos(x, y); client->setJumpCursorPos(x, y); // update the mouse coordinates if (client == m_active) { m_x = x; m_y = y; } // handle resolution change to primary screen if (client == m_primaryClient) { if (client == m_active) { onMouseMovePrimary(m_x, m_y); } else { onMouseMoveSecondary(0, 0); } } } void Server::handleClipboardGrabbed(const Event& event, void* vclient) { if (!m_enableClipboard) { return; } // ignore events from unknown clients BaseClientProxy* grabber = static_cast(vclient); if (m_clientSet.count(grabber) == 0) { return; } const IScreen::ClipboardInfo* info = static_cast(event.getData()); // ignore grab if sequence number is old. always allow primary // screen to grab. ClipboardInfo& clipboard = m_clipboards[info->m_id]; if (grabber != m_primaryClient && info->m_sequenceNumber < clipboard.m_clipboardSeqNum) { LOG((CLOG_INFO "ignored screen \"%s\" grab of clipboard %d", getName(grabber).c_str(), info->m_id)); return; } // mark screen as owning clipboard LOG((CLOG_INFO "screen \"%s\" grabbed clipboard %d from \"%s\"", getName(grabber).c_str(), info->m_id, clipboard.m_clipboardOwner.c_str())); clipboard.m_clipboardOwner = getName(grabber); clipboard.m_clipboardSeqNum = info->m_sequenceNumber; // clear the clipboard data (since it's not known at this point) if (clipboard.m_clipboard.open(0)) { clipboard.m_clipboard.empty(); clipboard.m_clipboard.close(); } clipboard.m_clipboardData = clipboard.m_clipboard.marshall(); // tell all other screens to take ownership of clipboard. tell the // grabber that it's clipboard isn't dirty. for (ClientList::iterator index = m_clients.begin(); index != m_clients.end(); ++index) { BaseClientProxy* client = index->second; if (client == grabber) { client->setClipboardDirty(info->m_id, false); } else { client->grabClipboard(info->m_id); } } } void Server::handleClipboardChanged(const Event& event, void* vclient) { // ignore events from unknown clients BaseClientProxy* sender = static_cast(vclient); if (m_clientSet.count(sender) == 0) { return; } const IScreen::ClipboardInfo* info = static_cast(event.getData()); onClipboardChanged(sender, info->m_id, info->m_sequenceNumber); } void Server::handleKeyDownEvent(const Event& event, void*) { IPlatformScreen::KeyInfo* info = static_cast(event.getData()); onKeyDown(info->m_key, info->m_mask, info->m_button, info->m_screens); } void Server::handleKeyUpEvent(const Event& event, void*) { IPlatformScreen::KeyInfo* info = static_cast(event.getData()); onKeyUp(info->m_key, info->m_mask, info->m_button, info->m_screens); } void Server::handleKeyRepeatEvent(const Event& event, void*) { IPlatformScreen::KeyInfo* info = static_cast(event.getData()); onKeyRepeat(info->m_key, info->m_mask, info->m_count, info->m_button); } void Server::handleButtonDownEvent(const Event& event, void*) { IPlatformScreen::ButtonInfo* info = static_cast(event.getData()); onMouseDown(info->m_button); } void Server::handleButtonUpEvent(const Event& event, void*) { IPlatformScreen::ButtonInfo* info = static_cast(event.getData()); onMouseUp(info->m_button); } void Server::handleMotionPrimaryEvent(const Event& event, void*) { IPlatformScreen::MotionInfo* info = static_cast(event.getData()); onMouseMovePrimary(info->m_x, info->m_y); } void Server::handleMotionSecondaryEvent(const Event& event, void*) { IPlatformScreen::MotionInfo* info = static_cast(event.getData()); onMouseMoveSecondary(info->m_x, info->m_y); } void Server::handleWheelEvent(const Event& event, void*) { IPlatformScreen::WheelInfo* info = static_cast(event.getData()); onMouseWheel(info->m_xDelta, info->m_yDelta); } void Server::handleScreensaverActivatedEvent(const Event&, void*) { onScreensaver(true); } void Server::handleScreensaverDeactivatedEvent(const Event&, void*) { onScreensaver(false); } void Server::handleSwitchWaitTimeout(const Event&, void*) { // ignore if mouse is locked to screen if (isLockedToScreen()) { LOG((CLOG_DEBUG1 "locked to screen")); stopSwitch(); return; } // switch screen switchScreen(m_switchScreen, m_switchWaitX, m_switchWaitY, false); } void Server::handleClientDisconnected(const Event&, void* vclient) { // client has disconnected. it might be an old client or an // active client. we don't care so just handle it both ways. BaseClientProxy* client = static_cast(vclient); removeActiveClient(client); removeOldClient(client); delete client; } void Server::handleClientCloseTimeout(const Event&, void* vclient) { // client took too long to disconnect. just dump it. BaseClientProxy* client = static_cast(vclient); LOG((CLOG_NOTE "forced disconnection of client \"%s\"", getName(client).c_str())); removeOldClient(client); delete client; } void Server::handleSwitchToScreenEvent(const Event& event, void*) { SwitchToScreenInfo* info = static_cast(event.getData()); ClientList::const_iterator index = m_clients.find(info->m_screen); if (index == m_clients.end()) { LOG((CLOG_DEBUG1 "screen \"%s\" not active", info->m_screen)); } else { jumpToScreen(index->second); } } void Server::handleSwitchInDirectionEvent(const Event& event, void*) { SwitchInDirectionInfo* info = static_cast(event.getData()); // jump to screen in chosen direction from center of this screen SInt32 x = m_x, y = m_y; BaseClientProxy* newScreen = getNeighbor(m_active, info->m_direction, x, y); if (newScreen == NULL) { LOG((CLOG_DEBUG1 "no neighbor %s", Config::dirName(info->m_direction))); } else { jumpToScreen(newScreen); } } void Server::handleKeyboardBroadcastEvent(const Event& event, void*) { KeyboardBroadcastInfo* info = (KeyboardBroadcastInfo*)event.getData(); // choose new state bool newState; switch (info->m_state) { case KeyboardBroadcastInfo::kOff: newState = false; break; default: case KeyboardBroadcastInfo::kOn: newState = true; break; case KeyboardBroadcastInfo::kToggle: newState = !m_keyboardBroadcasting; break; } // enter new state if (newState != m_keyboardBroadcasting || info->m_screens != m_keyboardBroadcastingScreens) { m_keyboardBroadcasting = newState; m_keyboardBroadcastingScreens = info->m_screens; LOG((CLOG_DEBUG "keyboard broadcasting %s: %s", m_keyboardBroadcasting ? "on" : "off", m_keyboardBroadcastingScreens.c_str())); } } void Server::handleLockCursorToScreenEvent(const Event& event, void*) { LockCursorToScreenInfo* info = (LockCursorToScreenInfo*)event.getData(); // choose new state bool newState; switch (info->m_state) { case LockCursorToScreenInfo::kOff: newState = false; break; default: case LockCursorToScreenInfo::kOn: newState = true; break; case LockCursorToScreenInfo::kToggle: newState = !m_lockedToScreen; break; } // enter new state if (newState != m_lockedToScreen) { m_lockedToScreen = newState; LOG((CLOG_NOTE "cursor %s current screen", m_lockedToScreen ? "locked to" : "unlocked from")); m_primaryClient->reconfigure(getActivePrimarySides()); if (!isLockedToScreenServer()) { stopRelativeMoves(); } } } void Server::handleFakeInputBeginEvent(const Event&, void*) { m_primaryClient->fakeInputBegin(); } void Server::handleFakeInputEndEvent(const Event&, void*) { m_primaryClient->fakeInputEnd(); } void Server::handleFileChunkSendingEvent(const Event& event, void*) { onFileChunkSending(event.getData()); } void Server::handleFileRecieveCompletedEvent(const Event& event, void*) { onFileRecieveCompleted(); } void Server::onClipboardChanged(BaseClientProxy* sender, ClipboardID id, UInt32 seqNum) { ClipboardInfo& clipboard = m_clipboards[id]; // ignore update if sequence number is old if (seqNum < clipboard.m_clipboardSeqNum) { LOG((CLOG_INFO "ignored screen \"%s\" update of clipboard %d (missequenced)", getName(sender).c_str(), id)); return; } // should be the expected client assert(sender == m_clients.find(clipboard.m_clipboardOwner)->second); // get data sender->getClipboard(id, &clipboard.m_clipboard); // ignore if data hasn't changed String data = clipboard.m_clipboard.marshall(); if (data == clipboard.m_clipboardData) { LOG((CLOG_DEBUG "ignored screen \"%s\" update of clipboard %d (unchanged)", clipboard.m_clipboardOwner.c_str(), id)); return; } // got new data LOG((CLOG_INFO "screen \"%s\" updated clipboard %d", clipboard.m_clipboardOwner.c_str(), id)); clipboard.m_clipboardData = data; // tell all clients except the sender that the clipboard is dirty for (ClientList::const_iterator index = m_clients.begin(); index != m_clients.end(); ++index) { BaseClientProxy* client = index->second; client->setClipboardDirty(id, client != sender); } // send the new clipboard to the active screen m_active->setClipboard(id, &clipboard.m_clipboard); } void Server::onScreensaver(bool activated) { LOG((CLOG_DEBUG "onScreenSaver %s", activated ? "activated" : "deactivated")); if (activated) { // save current screen and position m_activeSaver = m_active; m_xSaver = m_x; m_ySaver = m_y; // jump to primary screen if (m_active != m_primaryClient) { switchScreen(m_primaryClient, 0, 0, true); } } else { // jump back to previous screen and position. we must check // that the position is still valid since the screen may have // changed resolutions while the screen saver was running. if (m_activeSaver != NULL && m_activeSaver != m_primaryClient) { // check position BaseClientProxy* screen = m_activeSaver; SInt32 x, y, w, h; screen->getShape(x, y, w, h); SInt32 zoneSize = getJumpZoneSize(screen); if (m_xSaver < x + zoneSize) { m_xSaver = x + zoneSize; } else if (m_xSaver >= x + w - zoneSize) { m_xSaver = x + w - zoneSize - 1; } if (m_ySaver < y + zoneSize) { m_ySaver = y + zoneSize; } else if (m_ySaver >= y + h - zoneSize) { m_ySaver = y + h - zoneSize - 1; } // jump switchScreen(screen, m_xSaver, m_ySaver, false); } // reset state m_activeSaver = NULL; } // send message to all clients for (ClientList::const_iterator index = m_clients.begin(); index != m_clients.end(); ++index) { BaseClientProxy* client = index->second; client->screensaver(activated); } } void Server::onKeyDown(KeyID id, KeyModifierMask mask, KeyButton button, const char* screens) { LOG((CLOG_DEBUG1 "onKeyDown id=%d mask=0x%04x button=0x%04x", id, mask, button)); assert(m_active != NULL); // relay if (!m_keyboardBroadcasting && IKeyState::KeyInfo::isDefault(screens)) { m_active->keyDown(id, mask, button); } else { if (!screens && m_keyboardBroadcasting) { screens = m_keyboardBroadcastingScreens.c_str(); if (IKeyState::KeyInfo::isDefault(screens)) { screens = "*"; } } for (ClientList::const_iterator index = m_clients.begin(); index != m_clients.end(); ++index) { if (IKeyState::KeyInfo::contains(screens, index->first)) { index->second->keyDown(id, mask, button); } } } } void Server::onKeyUp(KeyID id, KeyModifierMask mask, KeyButton button, const char* screens) { LOG((CLOG_DEBUG1 "onKeyUp id=%d mask=0x%04x button=0x%04x", id, mask, button)); assert(m_active != NULL); // relay if (!m_keyboardBroadcasting && IKeyState::KeyInfo::isDefault(screens)) { m_active->keyUp(id, mask, button); } else { if (!screens && m_keyboardBroadcasting) { screens = m_keyboardBroadcastingScreens.c_str(); if (IKeyState::KeyInfo::isDefault(screens)) { screens = "*"; } } for (ClientList::const_iterator index = m_clients.begin(); index != m_clients.end(); ++index) { if (IKeyState::KeyInfo::contains(screens, index->first)) { index->second->keyUp(id, mask, button); } } } } void Server::onKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) { LOG((CLOG_DEBUG1 "onKeyRepeat id=%d mask=0x%04x count=%d button=0x%04x", id, mask, count, button)); assert(m_active != NULL); // relay m_active->keyRepeat(id, mask, count, button); } void Server::onMouseDown(ButtonID id) { LOG((CLOG_DEBUG1 "onMouseDown id=%d", id)); assert(m_active != NULL); // relay m_active->mouseDown(id); // reset this variable back to default value true m_waitDragInfoThread = true; } void Server::onMouseUp(ButtonID id) { LOG((CLOG_DEBUG1 "onMouseUp id=%d", id)); assert(m_active != NULL); // relay m_active->mouseUp(id); if (m_ignoreFileTransfer) { m_ignoreFileTransfer = false; return; } if (m_args.m_enableDragDrop) { if (!m_screen->isOnScreen()) { String& file = m_screen->getDraggingFilename(); if (!file.empty()) { sendFileToClient(file.c_str()); } } // always clear dragging filename m_screen->clearDraggingFilename(); } } bool Server::onMouseMovePrimary(SInt32 x, SInt32 y) { LOG((CLOG_DEBUG4 "onMouseMovePrimary %d,%d", x, y)); // mouse move on primary (server's) screen if (m_active != m_primaryClient) { // stale event -- we're actually on a secondary screen return false; } // save last delta m_xDelta2 = m_xDelta; m_yDelta2 = m_yDelta; // save current delta m_xDelta = x - m_x; m_yDelta = y - m_y; // save position m_x = x; m_y = y; // get screen shape SInt32 ax, ay, aw, ah; m_active->getShape(ax, ay, aw, ah); SInt32 zoneSize = getJumpZoneSize(m_active); // clamp position to screen SInt32 xc = x, yc = y; if (xc < ax + zoneSize) { xc = ax; } else if (xc >= ax + aw - zoneSize) { xc = ax + aw - 1; } if (yc < ay + zoneSize) { yc = ay; } else if (yc >= ay + ah - zoneSize) { yc = ay + ah - 1; } // see if we should change screens // when the cursor is in a corner, there may be a screen either // horizontally or vertically. check both directions. EDirection dirh = kNoDirection, dirv = kNoDirection; SInt32 xh = x, yv = y; if (x < ax + zoneSize) { xh -= zoneSize; dirh = kLeft; } else if (x >= ax + aw - zoneSize) { xh += zoneSize; dirh = kRight; } if (y < ay + zoneSize) { yv -= zoneSize; dirv = kTop; } else if (y >= ay + ah - zoneSize) { yv += zoneSize; dirv = kBottom; } if (dirh == kNoDirection && dirv == kNoDirection) { // still on local screen noSwitch(x, y); return false; } // check both horizontally and vertically EDirection dirs[] = {dirh, dirv}; SInt32 xs[] = {xh, x}, ys[] = {y, yv}; for (int i = 0; i < 2; ++i) { EDirection dir = dirs[i]; if (dir == kNoDirection) { continue; } x = xs[i], y = ys[i]; // get jump destination BaseClientProxy* newScreen = mapToNeighbor(m_active, dir, x, y); // should we switch or not? if (isSwitchOkay(newScreen, dir, x, y, xc, yc)) { if (m_args.m_enableDragDrop && m_screen->isDraggingStarted() && m_active != newScreen && m_waitDragInfoThread) { if (m_sendDragInfoThread == NULL) { m_sendDragInfoThread = new Thread( new TMethodJob( this, &Server::sendDragInfoThread, newScreen)); } return false; } // switch screen switchScreen(newScreen, x, y, false); m_waitDragInfoThread = true; return true; } } return false; } void Server::sendDragInfoThread(void* arg) { BaseClientProxy* newScreen = static_cast(arg); m_dragFileList.clear(); String& dragFileList = m_screen->getDraggingFilename(); if (!dragFileList.empty()) { DragInformation di; di.setFilename(dragFileList); m_dragFileList.push_back(di); } #if defined(__APPLE__) // on mac it seems that after faking a LMB up, system would signal back // to synergy a mouse up event, which doesn't happen on windows. as a // result, synergy would send dragging file to client twice. This variable // is used to ignore the first file sending. m_ignoreFileTransfer = true; #endif // send drag file info to client if there is any if (m_dragFileList.size() > 0) { sendDragInfo(newScreen); m_dragFileList.clear(); } m_waitDragInfoThread = false; m_sendDragInfoThread = NULL; } void Server::sendDragInfo(BaseClientProxy* newScreen) { String infoString; UInt32 fileCount = DragInformation::setupDragInfo(m_dragFileList, infoString); if (fileCount > 0) { char* info = NULL; size_t size = infoString.size(); info = new char[size]; memcpy(info, infoString.c_str(), size); LOG((CLOG_DEBUG2 "sending drag information to client")); LOG((CLOG_DEBUG3 "dragging file list: %s", info)); LOG((CLOG_DEBUG3 "dragging file list string size: %i", size)); newScreen->sendDragInfo(fileCount, info, size); } } void Server::onMouseMoveSecondary(SInt32 dx, SInt32 dy) { LOG((CLOG_DEBUG2 "onMouseMoveSecondary %+d,%+d", dx, dy)); // mouse move on secondary (client's) screen assert(m_active != NULL); if (m_active == m_primaryClient) { // stale event -- we're actually on the primary screen return; } // if doing relative motion on secondary screens and we're locked // to the screen (which activates relative moves) then send a // relative mouse motion. when we're doing this we pretend as if // the mouse isn't actually moving because we're expecting some // program on the secondary screen to warp the mouse on us, so we // have no idea where it really is. if (m_relativeMoves && isLockedToScreenServer()) { LOG((CLOG_DEBUG2 "relative move on %s by %d,%d", getName(m_active).c_str(), dx, dy)); m_active->mouseRelativeMove(dx, dy); return; } // save old position const SInt32 xOld = m_x; const SInt32 yOld = m_y; // save last delta m_xDelta2 = m_xDelta; m_yDelta2 = m_yDelta; // save current delta m_xDelta = dx; m_yDelta = dy; // accumulate motion m_x += dx; m_y += dy; // get screen shape SInt32 ax, ay, aw, ah; m_active->getShape(ax, ay, aw, ah); // find direction of neighbor and get the neighbor bool jump = true; BaseClientProxy* newScreen; do { // clamp position to screen SInt32 xc = m_x, yc = m_y; if (xc < ax) { xc = ax; } else if (xc >= ax + aw) { xc = ax + aw - 1; } if (yc < ay) { yc = ay; } else if (yc >= ay + ah) { yc = ay + ah - 1; } EDirection dir; if (m_x < ax) { dir = kLeft; } else if (m_x > ax + aw - 1) { dir = kRight; } else if (m_y < ay) { dir = kTop; } else if (m_y > ay + ah - 1) { dir = kBottom; } else { // we haven't left the screen newScreen = m_active; jump = false; // if waiting and mouse is not on the border we're waiting // on then stop waiting. also if it's not on the border // then arm the double tap. if (m_switchScreen != NULL) { bool clearWait; SInt32 zoneSize = m_primaryClient->getJumpZoneSize(); switch (m_switchDir) { case kLeft: clearWait = (m_x >= ax + zoneSize); break; case kRight: clearWait = (m_x <= ax + aw - 1 - zoneSize); break; case kTop: clearWait = (m_y >= ay + zoneSize); break; case kBottom: clearWait = (m_y <= ay + ah - 1 + zoneSize); break; default: clearWait = false; break; } if (clearWait) { // still on local screen noSwitch(m_x, m_y); } } // skip rest of block break; } // try to switch screen. get the neighbor. newScreen = mapToNeighbor(m_active, dir, m_x, m_y); // see if we should switch if (!isSwitchOkay(newScreen, dir, m_x, m_y, xc, yc)) { newScreen = m_active; jump = false; } } while (false); if (jump) { if (m_sendFileThread != NULL) { StreamChunker::interruptFile(); m_sendFileThread = NULL; } SInt32 newX = m_x; SInt32 newY = m_y; // switch screens switchScreen(newScreen, newX, newY, false); } else { // same screen. clamp mouse to edge. m_x = xOld + dx; m_y = yOld + dy; if (m_x < ax) { m_x = ax; LOG((CLOG_DEBUG2 "clamp to left of \"%s\"", getName(m_active).c_str())); } else if (m_x > ax + aw - 1) { m_x = ax + aw - 1; LOG((CLOG_DEBUG2 "clamp to right of \"%s\"", getName(m_active).c_str())); } if (m_y < ay) { m_y = ay; LOG((CLOG_DEBUG2 "clamp to top of \"%s\"", getName(m_active).c_str())); } else if (m_y > ay + ah - 1) { m_y = ay + ah - 1; LOG((CLOG_DEBUG2 "clamp to bottom of \"%s\"", getName(m_active).c_str())); } // warp cursor if it moved. if (m_x != xOld || m_y != yOld) { LOG((CLOG_DEBUG2 "move on %s to %d,%d", getName(m_active).c_str(), m_x, m_y)); m_active->mouseMove(m_x, m_y); } } } void Server::onMouseWheel(SInt32 xDelta, SInt32 yDelta) { LOG((CLOG_DEBUG1 "onMouseWheel %+d,%+d", xDelta, yDelta)); assert(m_active != NULL); // relay m_active->mouseWheel(xDelta, yDelta); } void Server::onFileChunkSending(const void* data) { FileChunk* chunk = static_cast(const_cast(data)); LOG((CLOG_DEBUG1 "sending file chunk")); assert(m_active != NULL); // relay m_active->fileChunkSending(chunk->m_chunk[0], &chunk->m_chunk[1], chunk->m_dataSize); } void Server::onFileRecieveCompleted() { if (isReceivedFileSizeValid()) { m_writeToDropDirThread = new Thread( new TMethodJob( this, &Server::writeToDropDirThread)); } } void Server::writeToDropDirThread(void*) { LOG((CLOG_DEBUG "starting write to drop dir thread")); while (m_screen->isFakeDraggingStarted()) { ARCH->sleep(.1f); } DropHelper::writeToDir(m_screen->getDropTarget(), m_fakeDragFileList, m_receivedFileData); } bool Server::addClient(BaseClientProxy* client) { String name = getName(client); if (m_clients.count(name) != 0) { return false; } // add event handlers m_events->adoptHandler(m_events->forIScreen().shapeChanged(), client->getEventTarget(), new TMethodEventJob(this, &Server::handleShapeChanged, client)); m_events->adoptHandler(m_events->forClipboard().clipboardGrabbed(), client->getEventTarget(), new TMethodEventJob(this, &Server::handleClipboardGrabbed, client)); m_events->adoptHandler(m_events->forClipboard().clipboardChanged(), client->getEventTarget(), new TMethodEventJob(this, &Server::handleClipboardChanged, client)); // add to list m_clientSet.insert(client); m_clients.insert(std::make_pair(name, client)); // initialize client data SInt32 x, y; client->getCursorPos(x, y); client->setJumpCursorPos(x, y); // tell primary client about the active sides m_primaryClient->reconfigure(getActivePrimarySides()); return true; } bool Server::removeClient(BaseClientProxy* client) { // return false if not in list ClientSet::iterator i = m_clientSet.find(client); if (i == m_clientSet.end()) { return false; } // remove event handlers m_events->removeHandler(m_events->forIScreen().shapeChanged(), client->getEventTarget()); m_events->removeHandler(m_events->forClipboard().clipboardGrabbed(), client->getEventTarget()); m_events->removeHandler(m_events->forClipboard().clipboardChanged(), client->getEventTarget()); // remove from list m_clients.erase(getName(client)); m_clientSet.erase(i); return true; } void Server::closeClient(BaseClientProxy* client, const char* msg) { assert(client != m_primaryClient); assert(msg != NULL); // send message to client. this message should cause the client // to disconnect. we add this client to the closed client list // and install a timer to remove the client if it doesn't respond // quickly enough. we also remove the client from the active // client list since we're not going to listen to it anymore. // note that this method also works on clients that are not in // the m_clients list. adoptClient() may call us with such a // client. LOG((CLOG_NOTE "disconnecting client \"%s\"", getName(client).c_str())); // send message // FIXME -- avoid type cast (kinda hard, though) ((ClientProxy*)client)->close(msg); // install timer. wait timeout seconds for client to close. double timeout = 5.0; EventQueueTimer* timer = m_events->newOneShotTimer(timeout, NULL); m_events->adoptHandler(Event::kTimer, timer, new TMethodEventJob(this, &Server::handleClientCloseTimeout, client)); // move client to closing list removeClient(client); m_oldClients.insert(std::make_pair(client, timer)); // if this client is the active screen then we have to // jump off of it forceLeaveClient(client); } void Server::closeClients(const Config& config) { // collect the clients that are connected but are being dropped // from the configuration (or who's canonical name is changing). typedef std::set RemovedClients; RemovedClients removed; for (ClientList::iterator index = m_clients.begin(); index != m_clients.end(); ++index) { if (!config.isCanonicalName(index->first)) { removed.insert(index->second); } } // don't close the primary client removed.erase(m_primaryClient); // now close them. we collect the list then close in two steps // because closeClient() modifies the collection we iterate over. for (RemovedClients::iterator index = removed.begin(); index != removed.end(); ++index) { closeClient(*index, kMsgCClose); } } void Server::removeActiveClient(BaseClientProxy* client) { if (removeClient(client)) { forceLeaveClient(client); m_events->removeHandler(m_events->forClientProxy().disconnected(), client); if (m_clients.size() == 1 && m_oldClients.empty()) { m_events->addEvent(Event(m_events->forServer().disconnected(), this)); } } } void Server::removeOldClient(BaseClientProxy* client) { OldClients::iterator i = m_oldClients.find(client); if (i != m_oldClients.end()) { m_events->removeHandler(m_events->forClientProxy().disconnected(), client); m_events->removeHandler(Event::kTimer, i->second); m_events->deleteTimer(i->second); m_oldClients.erase(i); if (m_clients.size() == 1 && m_oldClients.empty()) { m_events->addEvent(Event(m_events->forServer().disconnected(), this)); } } } void Server::forceLeaveClient(BaseClientProxy* client) { BaseClientProxy* active = (m_activeSaver != NULL) ? m_activeSaver : m_active; if (active == client) { // record new position (center of primary screen) m_primaryClient->getCursorCenter(m_x, m_y); // stop waiting to switch to this client if (active == m_switchScreen) { stopSwitch(); } // don't notify active screen since it has probably already // disconnected. LOG((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", getName(active).c_str(), getName(m_primaryClient).c_str(), m_x, m_y)); // cut over m_active = m_primaryClient; // enter new screen (unless we already have because of the // screen saver) if (m_activeSaver == NULL) { m_primaryClient->enter(m_x, m_y, m_seqNum, m_primaryClient->getToggleMask(), false); } } // if this screen had the cursor when the screen saver activated // then we can't switch back to it when the screen saver // deactivates. if (m_activeSaver == client) { m_activeSaver = NULL; } // tell primary client about the active sides m_primaryClient->reconfigure(getActivePrimarySides()); } // // Server::ClipboardInfo // Server::ClipboardInfo::ClipboardInfo() : m_clipboard(), m_clipboardData(), m_clipboardOwner(), m_clipboardSeqNum(0) { // do nothing } // // Server::LockCursorToScreenInfo // Server::LockCursorToScreenInfo* Server::LockCursorToScreenInfo::alloc(State state) { LockCursorToScreenInfo* info = (LockCursorToScreenInfo*)malloc(sizeof(LockCursorToScreenInfo)); info->m_state = state; return info; } // // Server::SwitchToScreenInfo // Server::SwitchToScreenInfo* Server::SwitchToScreenInfo::alloc(const String& screen) { SwitchToScreenInfo* info = (SwitchToScreenInfo*)malloc(sizeof(SwitchToScreenInfo) + screen.size()); strcpy(info->m_screen, screen.c_str()); return info; } // // Server::SwitchInDirectionInfo // Server::SwitchInDirectionInfo* Server::SwitchInDirectionInfo::alloc(EDirection direction) { SwitchInDirectionInfo* info = (SwitchInDirectionInfo*)malloc(sizeof(SwitchInDirectionInfo)); info->m_direction = direction; return info; } // // Server::KeyboardBroadcastInfo // Server::KeyboardBroadcastInfo* Server::KeyboardBroadcastInfo::alloc(State state) { KeyboardBroadcastInfo* info = (KeyboardBroadcastInfo*)malloc(sizeof(KeyboardBroadcastInfo)); info->m_state = state; info->m_screens[0] = '\0'; return info; } Server::KeyboardBroadcastInfo* Server::KeyboardBroadcastInfo::alloc(State state, const String& screens) { KeyboardBroadcastInfo* info = (KeyboardBroadcastInfo*)malloc(sizeof(KeyboardBroadcastInfo) + screens.size()); info->m_state = state; strcpy(info->m_screens, screens.c_str()); return info; } bool Server::isReceivedFileSizeValid() { return m_expectedFileSize == m_receivedFileData.size(); } void Server::sendFileToClient(const char* filename) { if (m_sendFileThread != NULL) { StreamChunker::interruptFile(); } m_sendFileThread = new Thread( new TMethodJob( this, &Server::sendFileThread, static_cast(const_cast(filename)))); } void Server::sendFileThread(void* data) { try { char* filename = static_cast(data); LOG((CLOG_DEBUG "sending file to client, filename=%s", filename)); StreamChunker::sendFile(filename, m_events, this); } catch (std::runtime_error error) { LOG((CLOG_ERR "failed sending file chunks, error: %s", error.what())); } m_sendFileThread = NULL; } void Server::dragInfoReceived(UInt32 fileNum, String content) { if (!m_args.m_enableDragDrop) { LOG((CLOG_DEBUG "drag drop not enabled, ignoring drag info.")); return; } DragInformation::parseDragInfo(m_fakeDragFileList, fileNum, content); m_screen->startDraggingFiles(m_fakeDragFileList); } synergy-1.8.8-stable/src/lib/server/Server.h000066400000000000000000000345541305627404700210050ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/Config.h" #include "synergy/clipboard_types.h" #include "synergy/Clipboard.h" #include "synergy/key_types.h" #include "synergy/mouse_types.h" #include "synergy/INode.h" #include "synergy/DragInformation.h" #include "synergy/ServerArgs.h" #include "base/Event.h" #include "base/Stopwatch.h" #include "base/EventTypes.h" #include "common/stdmap.h" #include "common/stdset.h" #include "common/stdvector.h" class BaseClientProxy; class EventQueueTimer; class PrimaryClient; class InputFilter; namespace synergy { class Screen; } class IEventQueue; class Thread; class ClientListener; //! Synergy server /*! This class implements the top-level server algorithms for synergy. */ class Server : public INode { public: //! Lock cursor to screen data class LockCursorToScreenInfo { public: enum State { kOff, kOn, kToggle }; static LockCursorToScreenInfo* alloc(State state = kToggle); public: State m_state; }; //! Switch to screen data class SwitchToScreenInfo { public: static SwitchToScreenInfo* alloc(const String& screen); public: // this is a C-string; this type is a variable size structure char m_screen[1]; }; //! Switch in direction data class SwitchInDirectionInfo { public: static SwitchInDirectionInfo* alloc(EDirection direction); public: EDirection m_direction; }; //! Screen connected data class ScreenConnectedInfo { public: ScreenConnectedInfo(String screen) : m_screen(screen) { } public: String m_screen; // was char[1] }; //! Keyboard broadcast data class KeyboardBroadcastInfo { public: enum State { kOff, kOn, kToggle }; static KeyboardBroadcastInfo* alloc(State state = kToggle); static KeyboardBroadcastInfo* alloc(State state, const String& screens); public: State m_state; char m_screens[1]; }; /*! Start the server with the configuration \p config and the primary client (local screen) \p primaryClient. The client retains ownership of \p primaryClient. */ Server(Config& config, PrimaryClient* primaryClient, synergy::Screen* screen, IEventQueue* events, ServerArgs const& args); ~Server(); #ifdef TEST_ENV Server() : m_mock(true), m_config(NULL) { } void setActive(BaseClientProxy* active) { m_active = active; } #endif //! @name manipulators //@{ //! Set configuration /*! Change the server's configuration. Returns true iff the new configuration was accepted (it must include the server's name). This will disconnect any clients no longer in the configuration. */ bool setConfig(const Config&); //! Add a client /*! Adds \p client to the server. The client is adopted and will be destroyed when the client disconnects or is disconnected. */ void adoptClient(BaseClientProxy* client); //! Disconnect clients /*! Disconnect clients. This tells them to disconnect but does not wait for them to actually do so. The server sends the disconnected event when they're all disconnected (or immediately if none are connected). The caller can also just destroy this object to force the disconnection. */ void disconnect(); //! Create a new thread and use it to send file to client void sendFileToClient(const char* filename); //! Received dragging information from client void dragInfoReceived(UInt32 fileNum, String content); //! Store ClientListener pointer void setListener(ClientListener* p) { m_clientListener = p; } //@} //! @name accessors //@{ //! Get number of connected clients /*! Returns the number of connected clients, including the server itself. */ UInt32 getNumClients() const; //! Get the list of connected clients /*! Set the \c list to the names of the currently connected clients. */ void getClients(std::vector& list) const; //! Return true if recieved file size is valid bool isReceivedFileSizeValid(); //! Return expected file data size size_t& getExpectedFileSize() { return m_expectedFileSize; } //! Return received file data String& getReceivedFileData() { return m_receivedFileData; } //! Return fake drag file list DragFileList getFakeDragFileList() { return m_fakeDragFileList; } //@} private: // get canonical name of client String getName(const BaseClientProxy*) const; // get the sides of the primary screen that have neighbors UInt32 getActivePrimarySides() const; // returns true iff mouse should be locked to the current screen // according to this object only, ignoring what the primary client // says. bool isLockedToScreenServer() const; // returns true iff mouse should be locked to the current screen // according to this object or the primary client. bool isLockedToScreen() const; // returns the jump zone of the client SInt32 getJumpZoneSize(BaseClientProxy*) const; // change the active screen void switchScreen(BaseClientProxy*, SInt32 x, SInt32 y, bool forScreenSaver); // jump to screen void jumpToScreen(BaseClientProxy*); // convert pixel position to fraction, using x or y depending on the // direction. float mapToFraction(BaseClientProxy*, EDirection, SInt32 x, SInt32 y) const; // convert fraction to pixel position, writing only x or y depending // on the direction. void mapToPixel(BaseClientProxy*, EDirection, float f, SInt32& x, SInt32& y) const; // returns true if the client has a neighbor anywhere along the edge // indicated by the direction. bool hasAnyNeighbor(BaseClientProxy*, EDirection) const; // lookup neighboring screen, mapping the coordinate independent of // the direction to the neighbor's coordinate space. BaseClientProxy* getNeighbor(BaseClientProxy*, EDirection, SInt32& x, SInt32& y) const; // lookup neighboring screen. given a position relative to the // source screen, find the screen we should move onto and where. // if the position is sufficiently far from the source then we // cross multiple screens. if there is no suitable screen then // return NULL and x,y are not modified. BaseClientProxy* mapToNeighbor(BaseClientProxy*, EDirection, SInt32& x, SInt32& y) const; // adjusts x and y or neither to avoid ending up in a jump zone // after entering the client in the given direction. void avoidJumpZone(BaseClientProxy*, EDirection, SInt32& x, SInt32& y) const; // test if a switch is permitted. this includes testing user // options like switch delay and tracking any state required to // implement them. returns true iff a switch is permitted. bool isSwitchOkay(BaseClientProxy* dst, EDirection, SInt32 x, SInt32 y, SInt32 xActive, SInt32 yActive); // update switch state due to a mouse move at \p x, \p y that // doesn't switch screens. void noSwitch(SInt32 x, SInt32 y); // stop switch timers void stopSwitch(); // start two tap switch timer void startSwitchTwoTap(); // arm the two tap switch timer if \p x, \p y is outside the tap zone void armSwitchTwoTap(SInt32 x, SInt32 y); // stop the two tap switch timer void stopSwitchTwoTap(); // returns true iff the two tap switch timer is started bool isSwitchTwoTapStarted() const; // returns true iff should switch because of two tap bool shouldSwitchTwoTap() const; // start delay switch timer void startSwitchWait(SInt32 x, SInt32 y); // stop delay switch timer void stopSwitchWait(); // returns true iff the delay switch timer is started bool isSwitchWaitStarted() const; // returns the corner (EScreenSwitchCornerMasks) where x,y is on the // given client. corners have the given size. UInt32 getCorner(BaseClientProxy*, SInt32 x, SInt32 y, SInt32 size) const; // stop relative mouse moves void stopRelativeMoves(); // send screen options to \c client void sendOptions(BaseClientProxy* client) const; // process options from configuration void processOptions(); // event handlers void handleShapeChanged(const Event&, void*); void handleClipboardGrabbed(const Event&, void*); void handleClipboardChanged(const Event&, void*); void handleKeyDownEvent(const Event&, void*); void handleKeyUpEvent(const Event&, void*); void handleKeyRepeatEvent(const Event&, void*); void handleButtonDownEvent(const Event&, void*); void handleButtonUpEvent(const Event&, void*); void handleMotionPrimaryEvent(const Event&, void*); void handleMotionSecondaryEvent(const Event&, void*); void handleWheelEvent(const Event&, void*); void handleScreensaverActivatedEvent(const Event&, void*); void handleScreensaverDeactivatedEvent(const Event&, void*); void handleSwitchWaitTimeout(const Event&, void*); void handleClientDisconnected(const Event&, void*); void handleClientCloseTimeout(const Event&, void*); void handleSwitchToScreenEvent(const Event&, void*); void handleSwitchInDirectionEvent(const Event&, void*); void handleKeyboardBroadcastEvent(const Event&,void*); void handleLockCursorToScreenEvent(const Event&, void*); void handleFakeInputBeginEvent(const Event&, void*); void handleFakeInputEndEvent(const Event&, void*); void handleFileChunkSendingEvent(const Event&, void*); void handleFileRecieveCompletedEvent(const Event&, void*); // event processing void onClipboardChanged(BaseClientProxy* sender, ClipboardID id, UInt32 seqNum); void onScreensaver(bool activated); void onKeyDown(KeyID, KeyModifierMask, KeyButton, const char* screens); void onKeyUp(KeyID, KeyModifierMask, KeyButton, const char* screens); void onKeyRepeat(KeyID, KeyModifierMask, SInt32, KeyButton); void onMouseDown(ButtonID); void onMouseUp(ButtonID); bool onMouseMovePrimary(SInt32 x, SInt32 y); void onMouseMoveSecondary(SInt32 dx, SInt32 dy); void onMouseWheel(SInt32 xDelta, SInt32 yDelta); void onFileChunkSending(const void* data); void onFileRecieveCompleted(); // add client to list and attach event handlers for client bool addClient(BaseClientProxy*); // remove client from list and detach event handlers for client bool removeClient(BaseClientProxy*); // close a client void closeClient(BaseClientProxy*, const char* msg); // close clients not in \p config void closeClients(const Config& config); // close all clients whether they've completed the handshake or not, // except the primary client void closeAllClients(); // remove clients from internal state void removeActiveClient(BaseClientProxy*); void removeOldClient(BaseClientProxy*); // force the cursor off of \p client void forceLeaveClient(BaseClientProxy* client); // thread funciton for sending file void sendFileThread(void*); // thread function for writing file to drop directory void writeToDropDirThread(void*); // thread function for sending drag information void sendDragInfoThread(void*); // send drag info to new client screen void sendDragInfo(BaseClientProxy* newScreen); public: bool m_mock; private: class ClipboardInfo { public: ClipboardInfo(); public: Clipboard m_clipboard; String m_clipboardData; String m_clipboardOwner; UInt32 m_clipboardSeqNum; }; // the primary screen client PrimaryClient* m_primaryClient; // all clients (including the primary client) indexed by name typedef std::map ClientList; typedef std::set ClientSet; ClientList m_clients; ClientSet m_clientSet; // all old connections that we're waiting to hangup typedef std::map OldClients; OldClients m_oldClients; // the client with focus BaseClientProxy* m_active; // the sequence number of enter messages UInt32 m_seqNum; // current mouse position (in absolute screen coordinates) on // whichever screen is active SInt32 m_x, m_y; // last mouse deltas. this is needed to smooth out double tap // on win32 which reports bogus mouse motion at the edge of // the screen when using low level hooks, synthesizing motion // in the opposite direction the mouse actually moved. SInt32 m_xDelta, m_yDelta; SInt32 m_xDelta2, m_yDelta2; // current configuration Config* m_config; // input filter (from m_config); InputFilter* m_inputFilter; // clipboard cache ClipboardInfo m_clipboards[kClipboardEnd]; // state saved when screen saver activates BaseClientProxy* m_activeSaver; SInt32 m_xSaver, m_ySaver; // common state for screen switch tests. all tests are always // trying to reach the same screen in the same direction. EDirection m_switchDir; BaseClientProxy* m_switchScreen; // state for delayed screen switching double m_switchWaitDelay; EventQueueTimer* m_switchWaitTimer; SInt32 m_switchWaitX, m_switchWaitY; // state for double-tap screen switching double m_switchTwoTapDelay; Stopwatch m_switchTwoTapTimer; bool m_switchTwoTapEngaged; bool m_switchTwoTapArmed; SInt32 m_switchTwoTapZone; // modifiers needed before switching bool m_switchNeedsShift; bool m_switchNeedsControl; bool m_switchNeedsAlt; // relative mouse move option bool m_relativeMoves; // flag whether or not we have broadcasting enabled and the screens to // which we should send broadcasted keys. bool m_keyboardBroadcasting; String m_keyboardBroadcastingScreens; // screen locking (former scroll lock) bool m_lockedToScreen; // server screen synergy::Screen* m_screen; IEventQueue* m_events; // file transfer size_t m_expectedFileSize; String m_receivedFileData; DragFileList m_dragFileList; DragFileList m_fakeDragFileList; Thread* m_sendFileThread; Thread* m_writeToDropDirThread; String m_dragFileExt; bool m_ignoreFileTransfer; bool m_enableClipboard; Thread* m_sendDragInfoThread; bool m_waitDragInfoThread; ClientListener* m_clientListener; ServerArgs m_args; }; synergy-1.8.8-stable/src/lib/shared/000077500000000000000000000000001305627404700173135ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/shared/CMakeLists.txt000066400000000000000000000016601305627404700220560ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2016 Symless Ltd. # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() add_library(shared STATIC ${sources}) include_directories( ../ ../../../ext ../../../ext/gtest-1.6.0/include ) target_link_libraries(shared arch base) synergy-1.8.8-stable/src/lib/shared/EditionType.h000066400000000000000000000015601305627404700217230ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef EDITIONTYPE_H #define EDITIONTYPE_H /* Do not reorder these! */ enum Edition { kBasic, kPro, Trial_DO_NOT_USE_OR_THERE_WILL_BE_PAIN, kUnregistered }; #endif // EDITIONTYPE_H synergy-1.8.8-stable/src/lib/shared/SerialKey.cpp000066400000000000000000000127521305627404700217160ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "SerialKey.h" #include #include #include #include #include #include #include #include using namespace std; SerialKey::SerialKey(Edition edition): m_userLimit(1), m_warnTime(ULLONG_MAX), m_expireTime(ULLONG_MAX), m_edition(edition), m_trial(false) { } SerialKey::SerialKey(std::string serial) : m_userLimit(1), m_warnTime(0), m_expireTime(0), m_edition(kBasic), m_trial(true) { string plainText = decode(serial); bool valid = false; if (!plainText.empty()) { valid = parse(plainText); } if (!valid) { throw std::runtime_error ("Invalid serial key"); } } bool SerialKey::isExpiring(time_t currentTime) const { bool result = false; if (m_trial) { if (m_warnTime <= currentTime && currentTime < m_expireTime) { result = true; } } return result; } bool SerialKey::isExpired(time_t currentTime) const { bool result = false; if (m_trial) { if (m_expireTime <= currentTime) { result = true; } } return result; } bool SerialKey::isTrial() const { return m_trial; } Edition SerialKey::edition() const { return m_edition; } std::string SerialKey::editionString() const { switch (edition()) { case kBasic: return "basic"; case kPro: return "pro"; default: { std::ostringstream oss; oss << static_cast(edition()); return oss.str(); } } } static std::string hexEncode (std::string const& str) { std::ostringstream oss; for (size_t i = 0; i < str.size(); ++i) { int c = str[i]; oss << std::setfill('0') << std::hex << std::setw(2) << std::uppercase; oss << c; } return oss.str(); } std::string SerialKey::toString() const { std::ostringstream oss; oss << "{"; if (isTrial()) { oss << "v2;trial;"; } else { oss << "v1;"; } oss << editionString() << ";"; oss << m_name << ";"; oss << m_userLimit << ";"; oss << m_email << ";"; oss << m_company << ";"; oss << (isTrial() ? m_warnTime : 0) << ";"; oss << (isTrial() ? m_expireTime : 0); oss << "}"; return hexEncode(oss.str()); } time_t SerialKey::daysLeft(time_t currentTime) const { unsigned long long timeLeft = 0; unsigned long long const day = 60 * 60 * 24; if (currentTime < m_expireTime) { timeLeft = m_expireTime - currentTime; } unsigned long long daysLeft = 0; daysLeft = timeLeft % day != 0 ? 1 : 0; return timeLeft / day + daysLeft; } std::string SerialKey::email() const { return m_email; } std::string SerialKey::decode(const std::string& serial) { static const char* const lut = "0123456789ABCDEF"; string output; size_t len = serial.length(); if (len & 1) { return output; } output.reserve(len / 2); for (size_t i = 0; i < len; i += 2) { char a = serial[i]; char b = serial[i + 1]; const char* p = std::lower_bound(lut, lut + 16, a); const char* q = std::lower_bound(lut, lut + 16, b); if (*q != b || *p != a) { return output; } output.push_back(static_cast(((p - lut) << 4) | (q - lut))); } return output; } bool SerialKey::parse(std::string plainSerial) { string parityStart = plainSerial.substr(0, 1); string parityEnd = plainSerial.substr(plainSerial.length() - 1, 1); bool valid = false; // check for parity chars { and }, record parity result, then remove them. if (parityStart == "{" && parityEnd == "}") { plainSerial = plainSerial.substr(1, plainSerial.length() - 2); // tokenize serialised subscription. vector parts; std::string::size_type pos = 0; bool look = true; while (look) { std::string::size_type start = pos; pos = plainSerial.find(";", pos); if (pos == string::npos) { pos = plainSerial.length(); look = false; } parts.push_back(plainSerial.substr(start, pos - start)); pos += 1; } if ((parts.size() == 8) && (parts.at(0).find("v1") != string::npos)) { // e.g.: {v1;basic;Bob;1;email;company name;1398297600;1398384000} m_edition = parseEdition(parts.at(1)); m_name = parts.at(2); m_trial = false; sscanf(parts.at(3).c_str(), "%d", &m_userLimit); m_email = parts.at(4); m_company = parts.at(5); sscanf(parts.at(6).c_str(), "%lld", &m_warnTime); sscanf(parts.at(7).c_str(), "%lld", &m_expireTime); valid = true; } else if ((parts.size() == 9) && (parts.at(0).find("v2") != string::npos)) { // e.g.: {v2;trial;basic;Bob;1;email;company name;1398297600;1398384000} m_trial = parts.at(1) == "trial" ? true : false; m_edition = parseEdition(parts.at(2)); m_name = parts.at(3); sscanf(parts.at(4).c_str(), "%d", &m_userLimit); m_email = parts.at(5); m_company = parts.at(6); sscanf(parts.at(7).c_str(), "%lld", &m_warnTime); sscanf(parts.at(8).c_str(), "%lld", &m_expireTime); valid = true; } } return valid; } Edition SerialKey::parseEdition(std::string const& editionStr) { Edition e = kBasic; if (editionStr == "pro") { e = kPro; } return e; } synergy-1.8.8-stable/src/lib/shared/SerialKey.h000066400000000000000000000046031305627404700213570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include #include #include "EditionType.h" #ifdef TEST_ENV #include "gtest/gtest_prod.h" #endif class SerialKey { friend bool operator== (SerialKey const&, SerialKey const&); public: explicit SerialKey(Edition edition = kUnregistered); explicit SerialKey(std::string serial); bool isExpiring(time_t currentTime) const; bool isExpired(time_t currentTime) const; bool isTrial() const; time_t daysLeft(time_t currentTime) const; std::string email() const; Edition edition() const; std::string toString() const; static std::string decode(const std::string& serial); static Edition parseEdition(const std::string& editionStr); private: bool parse(std::string plainSerial); std::string editionString() const; #ifdef TEST_ENV private: FRIEND_TEST(SerialKeyTests, parse_noParty_invalid); FRIEND_TEST(SerialKeyTests, parse_invalidPartsLenghth_invalid); FRIEND_TEST(SerialKeyTests, parse_validV1Serial_valid); FRIEND_TEST(SerialKeyTests, parse_validV2Serial_valid); #endif private: std::string m_name; std::string m_email; std::string m_company; unsigned m_userLimit; unsigned long long m_warnTime; unsigned long long m_expireTime; Edition m_edition; bool m_trial; }; inline bool operator== (SerialKey const& lhs, SerialKey const& rhs) { return (lhs.m_name == rhs.m_name) && (lhs.m_email == rhs.m_email) && (lhs.m_company == rhs.m_company) && (lhs.m_userLimit == rhs.m_userLimit) && (lhs.m_warnTime == rhs.m_warnTime) && (lhs.m_expireTime == rhs.m_expireTime) && (lhs.m_edition == rhs.m_edition) && (lhs.m_trial == rhs.m_trial); } inline bool operator!= (SerialKey const& lhs, SerialKey const& rhs) { return !(lhs == rhs); } synergy-1.8.8-stable/src/lib/synergy/000077500000000000000000000000001305627404700175455ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/synergy/App.cpp000066400000000000000000000146231305627404700207770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/App.h" #include "base/Log.h" #include "common/Version.h" #include "synergy/protocol_types.h" #include "arch/Arch.h" #include "base/XBase.h" #include "arch/XArch.h" #include "base/log_outputters.h" #include "synergy/XSynergy.h" #include "synergy/ArgsBase.h" #include "ipc/IpcServerProxy.h" #include "base/TMethodEventJob.h" #include "ipc/IpcMessage.h" #include "ipc/Ipc.h" #include "base/EventQueue.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" #include "base/IEventQueue.h" #include "base/TMethodJob.h" #endif #include #include #if WINAPI_CARBON #include #endif #if defined(__APPLE__) #include "platform/OSXDragSimulator.h" #endif App* App::s_instance = nullptr; // // App // App::App(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver, ArgsBase* args) : m_bye(&exit), m_taskBarReceiver(NULL), m_suspended(false), m_events(events), m_args(args), m_createTaskBarReceiver(createTaskBarReceiver), m_appUtil(events), m_ipcClient(nullptr) { assert(s_instance == nullptr); s_instance = this; } App::~App() { s_instance = nullptr; delete m_args; } void App::version() { char buffer[500]; sprintf( buffer, "%s %s, protocol version %d.%d\n%s", argsBase().m_pname, kVersion, kProtocolMajorVersion, kProtocolMinorVersion, kCopyright ); std::cout << buffer << std::endl; } int App::run(int argc, char** argv) { #if MAC_OS_X_VERSION_10_7 // dock hide only supported on lion :( ProcessSerialNumber psn = { 0, kCurrentProcess }; #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" GetCurrentProcess(&psn); #pragma GCC diagnostic pop TransformProcessType(&psn, kProcessTransformToBackgroundApplication); #endif // install application in to arch appUtil().adoptApp(this); // HACK: fail by default (saves us setting result in each catch) int result = kExitFailed; try { result = appUtil().run(argc, argv); } catch (XExitApp& e) { // instead of showing a nasty error, just exit with the error code. // not sure if i like this behaviour, but it's probably better than // using the exit(int) function! result = e.getCode(); } catch (std::exception& e) { LOG((CLOG_CRIT "An error occurred: %s\n", e.what())); } catch (...) { LOG((CLOG_CRIT "An unknown error occurred.\n")); } appUtil().beforeAppExit(); return result; } int App::daemonMainLoop(int, const char**) { #if SYSAPI_WIN32 SystemLogger sysLogger(daemonName(), false); #else SystemLogger sysLogger(daemonName(), true); #endif return mainLoop(); } void App::setupFileLogging() { if (argsBase().m_logFile != NULL) { m_fileLog = new FileLogOutputter(argsBase().m_logFile); CLOG->insert(m_fileLog); LOG((CLOG_DEBUG1 "logging to file (%s) enabled", argsBase().m_logFile)); } } void App::loggingFilterWarning() { if (CLOG->getFilter() > CLOG->getConsoleMaxLevel()) { if (argsBase().m_logFile == NULL) { LOG((CLOG_WARN "log messages above %s are NOT sent to console (use file logging)", CLOG->getFilterName(CLOG->getConsoleMaxLevel()))); } } } void App::initApp(int argc, const char** argv) { // parse command line parseArgs(argc, argv); ARCH->setProfileDirectory(argsBase().m_profileDirectory); ARCH->setPluginDirectory(argsBase().m_pluginDirectory); // set log filter if (!CLOG->setFilter(argsBase().m_logFilter)) { LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE, argsBase().m_pname, argsBase().m_logFilter, argsBase().m_pname)); m_bye(kExitArgs); } loggingFilterWarning(); if (argsBase().m_enableDragDrop) { LOG((CLOG_INFO "drag and drop enabled")); } // setup file logging after parsing args setupFileLogging(); // load configuration loadConfig(); if (!argsBase().m_disableTray) { // create a log buffer so we can show the latest message // as a tray icon tooltip BufferedLogOutputter* logBuffer = new BufferedLogOutputter(1000); CLOG->insert(logBuffer, true); // make the task bar receiver. the user can control this app // through the task bar. m_taskBarReceiver = m_createTaskBarReceiver(logBuffer, m_events); } } void App::initIpcClient() { m_ipcClient = new IpcClient(m_events, m_socketMultiplexer); m_ipcClient->connect(); m_events->adoptHandler( m_events->forIpcClient().messageReceived(), m_ipcClient, new TMethodEventJob(this, &App::handleIpcMessage)); } void App::cleanupIpcClient() { m_ipcClient->disconnect(); m_events->removeHandler(m_events->forIpcClient().messageReceived(), m_ipcClient); delete m_ipcClient; } void App::handleIpcMessage(const Event& e, void*) { IpcMessage* m = static_cast(e.getDataObject()); if (m->type() == kIpcShutdown) { LOG((CLOG_INFO "got ipc shutdown message")); m_events->addEvent(Event(Event::kQuit)); } } void App::runEventsLoop(void*) { m_events->loop(); #if defined(MAC_OS_X_VERSION_10_7) stopCocoaLoop(); #endif } // // MinimalApp // MinimalApp::MinimalApp() : App(NULL, NULL, new ArgsBase()) { m_arch.init(); setEvents(m_events); } MinimalApp::~MinimalApp() { } int MinimalApp::standardStartup(int argc, char** argv) { return 0; } int MinimalApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) { return 0; } void MinimalApp::startNode() { } int MinimalApp::mainLoop() { return 0; } int MinimalApp::foregroundStartup(int argc, char** argv) { return 0; } synergy::Screen* MinimalApp::createScreen() { return NULL; } void MinimalApp::loadConfig() { } bool MinimalApp::loadConfig(const String& pathname) { return false; } const char* MinimalApp::daemonInfo() const { return ""; } const char* MinimalApp::daemonName() const { return ""; } void MinimalApp::parseArgs(int argc, const char* const* argv) { } synergy-1.8.8-stable/src/lib/synergy/App.h000066400000000000000000000145701305627404700204450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "ipc/IpcClient.h" #include "synergy/IApp.h" #include "base/String.h" #include "base/Log.h" #include "base/EventQueue.h" #include "common/common.h" #if SYSAPI_WIN32 #include "synergy/win32/AppUtilWindows.h" #elif SYSAPI_UNIX #include "synergy/unix/AppUtilUnix.h" #endif class IArchTaskBarReceiver; class BufferedLogOutputter; class ILogOutputter; class FileLogOutputter; namespace synergy { class Screen; } class IEventQueue; class SocketMultiplexer; typedef IArchTaskBarReceiver* (*CreateTaskBarReceiverFunc)(const BufferedLogOutputter*, IEventQueue* events); class App : public IApp { public: App(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver, ArgsBase* args); virtual ~App(); // Returns args that are common between server and client. ArgsBase& argsBase() const { return *m_args; } // Prints the current compiled version. virtual void version(); // Prints help specific to client or server. virtual void help() = 0; // Parse command line arguments. virtual void parseArgs(int argc, const char* const* argv) = 0; int run(int argc, char** argv); int daemonMainLoop(int, const char**); virtual void loadConfig() = 0; virtual bool loadConfig(const String& pathname) = 0; // A description of the daemon (used only on Windows). virtual const char* daemonInfo() const = 0; // Function pointer for function to exit immediately. // TODO: this is old C code - use inheritance to normalize void (*m_bye)(int); static App& instance() { assert(s_instance != nullptr); return *s_instance; } // If --log was specified in args, then add a file logger. void setupFileLogging(); // If messages will be hidden (to improve performance), warn user. void loggingFilterWarning(); // Parses args, sets up file logging, and loads the config. void initApp(int argc, const char** argv); // HACK: accept non-const, but make it const anyway void initApp(int argc, char** argv) { initApp(argc, (const char**)argv); } ARCH_APP_UTIL& appUtil() { return m_appUtil; } virtual IArchTaskBarReceiver* taskBarReceiver() const { return m_taskBarReceiver; } virtual void setByeFunc(void(*bye)(int)) { m_bye = bye; } virtual void bye(int error) { m_bye(error); } virtual IEventQueue* getEvents() const { return m_events; } void setSocketMultiplexer(SocketMultiplexer* sm) { m_socketMultiplexer = sm; } SocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; } void setEvents(EventQueue& events) { m_events = &events; } private: void handleIpcMessage(const Event&, void*); protected: void initIpcClient(); void cleanupIpcClient(); void runEventsLoop(void*); IArchTaskBarReceiver* m_taskBarReceiver; bool m_suspended; IEventQueue* m_events; private: ArgsBase* m_args; static App* s_instance; FileLogOutputter* m_fileLog; CreateTaskBarReceiverFunc m_createTaskBarReceiver; ARCH_APP_UTIL m_appUtil; IpcClient* m_ipcClient; SocketMultiplexer* m_socketMultiplexer; }; class MinimalApp : public App { public: MinimalApp(); virtual ~MinimalApp(); // IApp overrides virtual int standardStartup(int argc, char** argv); virtual int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup); virtual void startNode(); virtual int mainLoop(); virtual int foregroundStartup(int argc, char** argv); virtual synergy::Screen* createScreen(); virtual void loadConfig(); virtual bool loadConfig(const String& pathname); virtual const char* daemonInfo() const; virtual const char* daemonName() const; virtual void parseArgs(int argc, const char* const* argv); private: Arch m_arch; Log m_log; EventQueue m_events; }; #if WINAPI_MSWINDOWS #define DAEMON_RUNNING(running_) ArchMiscWindows::daemonRunning(running_) #else #define DAEMON_RUNNING(running_) #endif #define HELP_COMMON_INFO_1 \ " -d, --debug filter out log messages with priority below level.\n" \ " level may be: FATAL, ERROR, WARNING, NOTE, INFO,\n" \ " DEBUG, DEBUG1, DEBUG2.\n" \ " -n, --name use screen-name instead the hostname to identify\n" \ " this screen in the configuration.\n" \ " -1, --no-restart do not try to restart on failure.\n" \ "* --restart restart the server automatically if it fails.\n" \ " -l --log write log messages to file.\n" \ " --no-tray disable the system tray icon.\n" \ " --enable-drag-drop enable file drag & drop.\n" \ " --enable-crypto enable the crypto (ssl) plugin.\n" #define HELP_COMMON_INFO_2 \ " -h, --help display this help and exit.\n" \ " --version display version information and exit.\n" #define HELP_COMMON_ARGS \ " [--name ]" \ " [--restart|--no-restart]" \ " [--debug ]" // system args (windows/unix) #if SYSAPI_UNIX // unix daemon mode args # define HELP_SYS_ARGS \ " [--daemon|--no-daemon]" # define HELP_SYS_INFO \ " -f, --no-daemon run in the foreground.\n" \ "* --daemon run as a daemon.\n" #elif SYSAPI_WIN32 // windows args # define HELP_SYS_ARGS \ " [--service ] [--relaunch] [--exit-pause]" # define HELP_SYS_INFO \ " --service manage the windows service, valid options are:\n" \ " install/uninstall/start/stop\n" \ " --relaunch persistently relaunches process in current user \n" \ " session (useful for vista and upward).\n" \ " --exit-pause wait for key press on exit, can be useful for\n" \ " reading error messages that occur on exit.\n" #endif synergy-1.8.8-stable/src/lib/synergy/AppUtil.cpp000066400000000000000000000021631305627404700216310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/AppUtil.h" AppUtil* AppUtil::s_instance = nullptr; AppUtil::AppUtil() : m_app(nullptr) { s_instance = this; } AppUtil::~AppUtil() { } void AppUtil::adoptApp(IApp* app) { app->setByeFunc(&exitAppStatic); m_app = app; } IApp& AppUtil::app() const { assert(m_app != nullptr); return *m_app; } AppUtil& AppUtil::instance() { assert(s_instance != nullptr); return *s_instance; } synergy-1.8.8-stable/src/lib/synergy/AppUtil.h000066400000000000000000000022401305627404700212720ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/IAppUtil.h" #include "synergy/XSynergy.h" class AppUtil : public IAppUtil { public: AppUtil(); virtual ~AppUtil(); virtual void adoptApp(IApp* app); IApp& app() const; virtual void exitApp(int code) { throw XExitApp(code); } static AppUtil& instance(); static void exitAppStatic(int code) { instance().exitApp(code); } virtual void beforeAppExit() {} private: IApp* m_app; static AppUtil* s_instance; }; synergy-1.8.8-stable/src/lib/synergy/ArgParser.cpp000066400000000000000000000302371305627404700221440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ArgParser.h" #include "synergy/StreamChunker.h" #include "synergy/App.h" #include "synergy/ServerArgs.h" #include "synergy/ClientArgs.h" #include "synergy/ToolArgs.h" #include "synergy/ArgsBase.h" #include "base/Log.h" #include "base/String.h" ArgsBase* ArgParser::m_argsBase = NULL; ArgParser::ArgParser(App* app) : m_app(app) { } bool ArgParser::parseServerArgs(ServerArgs& args, int argc, const char* const* argv) { setArgsBase(args); updateCommonArgs(argv); for (int i = 1; i < argc; ++i) { if (parsePlatformArg(args, argc, argv, i)) { continue; } else if (parseGenericArgs(argc, argv, i)) { continue; } else if (parseDeprecatedArgs(argc, argv, i)) { continue; } else if (isArg(i, argc, argv, "-a", "--address", 1)) { // save listen address args.m_synergyAddress = argv[++i]; } else if (isArg(i, argc, argv, "-c", "--config", 1)) { // save configuration file path args.m_configFile = argv[++i]; } else if (isArg(i, argc, argv, "", "--serial-key", 1)) { args.m_serial = SerialKey(argv[++i]); } else { LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], args.m_pname)); return false; } } if (checkUnexpectedArgs()) { return false; } return true; } bool ArgParser::parseClientArgs(ClientArgs& args, int argc, const char* const* argv) { setArgsBase(args); updateCommonArgs(argv); int i; for (i = 1; i < argc; ++i) { if (parsePlatformArg(args, argc, argv, i)) { continue; } else if (parseGenericArgs(argc, argv, i)) { continue; } else if (parseDeprecatedArgs(argc, argv, i)) { continue; } else if (isArg(i, argc, argv, NULL, "--camp")) { // ignore -- included for backwards compatibility } else if (isArg(i, argc, argv, NULL, "--no-camp")) { // ignore -- included for backwards compatibility } else if (isArg(i, argc, argv, NULL, "--yscroll", 1)) { // define scroll args.m_yscroll = atoi(argv[++i]); } else { if (i + 1 == argc) { args.m_synergyAddress = argv[i]; return true; } LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], args.m_pname)); return false; } } // exactly one non-option argument (server-address) if (i == argc) { LOG((CLOG_PRINT "%s: a server address or name is required" BYE, args.m_pname, args.m_pname)); return false; } if (checkUnexpectedArgs()) { return false; } return true; } bool ArgParser::parsePlatformArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i) { #if WINAPI_MSWINDOWS if (isArg(i, argc, argv, NULL, "--service")) { LOG((CLOG_WARN "obsolete argument --service, use synergyd instead.")); argsBase.m_shouldExit = true; } else if (isArg(i, argc, argv, NULL, "--exit-pause")) { argsBase.m_pauseOnExit = true; } else if (isArg(i, argc, argv, NULL, "--stop-on-desk-switch")) { argsBase.m_stopOnDeskSwitch = true; } else { // option not supported here return false; } return true; #elif WINAPI_XWINDOWS if (isArg(i, argc, argv, "-display", "--display", 1)) { // use alternative display argsBase.m_display = argv[++i]; } else if (isArg(i, argc, argv, NULL, "--no-xinitthreads")) { argsBase.m_disableXInitThreads = true; } else { // option not supported here return false; } return true; #elif WINAPI_CARBON // no options for carbon return false; #endif } bool ArgParser::parseToolArgs(ToolArgs& args, int argc, const char* const* argv) { for (int i = 1; i < argc; ++i) { if (isArg(i, argc, argv, NULL, "--get-active-desktop", 0)) { args.m_printActiveDesktopName = true; return true; } else if (isArg(i, argc, argv, NULL, "--login-auth", 0)) { args.m_loginAuthenticate = true; return true; } else if (isArg(i, argc, argv, NULL, "--get-installed-dir", 0)) { args.m_getInstalledDir = true; return true; } else if (isArg(i, argc, argv, NULL, "--get-profile-dir", 0)) { args.m_getProfileDir = true; return true; } else if (isArg(i, argc, argv, NULL, "--get-arch", 0)) { args.m_getArch = true; return true; } else if (isArg(i, argc, argv, NULL, "--notify-activation", 0)) { args.m_notifyActivation = true; return true; } else if (isArg(i, argc, argv, NULL, "--notify-update", 0)) { args.m_notifyUpdate = true; return true; } else { return false; } } return false; } bool ArgParser::parseGenericArgs(int argc, const char* const* argv, int& i) { if (isArg(i, argc, argv, "-d", "--debug", 1)) { // change logging level argsBase().m_logFilter = argv[++i]; } else if (isArg(i, argc, argv, "-l", "--log", 1)) { argsBase().m_logFile = argv[++i]; } else if (isArg(i, argc, argv, "-f", "--no-daemon")) { // not a daemon argsBase().m_daemon = false; } else if (isArg(i, argc, argv, NULL, "--daemon")) { // daemonize argsBase().m_daemon = true; } else if (isArg(i, argc, argv, "-n", "--name", 1)) { // save screen name argsBase().m_name = argv[++i]; } else if (isArg(i, argc, argv, "-1", "--no-restart")) { // don't try to restart argsBase().m_restartable = false; } else if (isArg(i, argc, argv, NULL, "--restart")) { // try to restart argsBase().m_restartable = true; } else if (isArg(i, argc, argv, "-z", NULL)) { argsBase().m_backend = true; } else if (isArg(i, argc, argv, NULL, "--no-hooks")) { argsBase().m_noHooks = true; } else if (isArg(i, argc, argv, "-h", "--help")) { if (m_app) { m_app->help(); } argsBase().m_shouldExit = true; } else if (isArg(i, argc, argv, NULL, "--version")) { if (m_app) { m_app->version(); } argsBase().m_shouldExit = true; } else if (isArg(i, argc, argv, NULL, "--no-tray")) { argsBase().m_disableTray = true; } else if (isArg(i, argc, argv, NULL, "--ipc")) { argsBase().m_enableIpc = true; } else if (isArg(i, argc, argv, NULL, "--server")) { // HACK: stop error happening when using portable (synergyp) } else if (isArg(i, argc, argv, NULL, "--client")) { // HACK: stop error happening when using portable (synergyp) } else if (isArg(i, argc, argv, NULL, "--enable-drag-drop")) { bool useDragDrop = true; #ifdef WINAPI_XWINDOWS useDragDrop = false; LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported on linux.")); #endif #ifdef WINAPI_MSWINDOWS OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); if (osvi.dwMajorVersion < 6) { useDragDrop = false; LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported below vista.")); } #endif if (useDragDrop) { argsBase().m_enableDragDrop = true; } } else if (isArg(i, argc, argv, NULL, "--enable-crypto")) { argsBase().m_enableCrypto = true; } else if (isArg(i, argc, argv, NULL, "--profile-dir", 1)) { argsBase().m_profileDirectory = argv[++i]; } else if (isArg(i, argc, argv, NULL, "--plugin-dir", 1)) { argsBase().m_pluginDirectory = argv[++i]; } else { // option not supported here return false; } return true; } bool ArgParser::parseDeprecatedArgs(int argc, const char* const* argv, int& i) { if (isArg(i, argc, argv, NULL, "--crypto-pass")) { LOG((CLOG_NOTE "--crypto-pass is deprecated")); i++; return true; } else if (isArg(i, argc, argv, NULL, "--res-w")) { LOG((CLOG_NOTE "--res-w is deprecated")); i++; return true; } else if (isArg(i, argc, argv, NULL, "--res-h")) { LOG((CLOG_NOTE "--res-h is deprecated")); i++; return true; } else if (isArg(i, argc, argv, NULL, "--prm-wc")) { LOG((CLOG_NOTE "--prm-wc is deprecated")); i++; return true; } else if (isArg(i, argc, argv, NULL, "--prm-hc")) { LOG((CLOG_NOTE "--prm-hc is deprecated")); i++; return true; } return false; } bool ArgParser::isArg( int argi, int argc, const char* const* argv, const char* name1, const char* name2, int minRequiredParameters) { if ((name1 != NULL && strcmp(argv[argi], name1) == 0) || (name2 != NULL && strcmp(argv[argi], name2) == 0)) { // match. check args left. if (argi + minRequiredParameters >= argc) { LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE, argsBase().m_pname, argv[argi], argsBase().m_pname)); argsBase().m_shouldExit = true; return false; } return true; } // no match return false; } void ArgParser::splitCommandString(String& command, std::vector& argv) { if (command.empty()) { return ; } size_t leftDoubleQuote = 0; size_t rightDoubleQuote = 0; searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote); size_t startPos = 0; size_t space = command.find(" ", startPos); while (space != String::npos) { bool ignoreThisSpace = false; // check if the space is between two double quotes if (space > leftDoubleQuote && space < rightDoubleQuote) { ignoreThisSpace = true; } else if (space > rightDoubleQuote){ searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote, rightDoubleQuote + 1); } if (!ignoreThisSpace) { String subString = command.substr(startPos, space - startPos); removeDoubleQuotes(subString); argv.push_back(subString); } // find next space if (ignoreThisSpace) { space = command.find(" ", rightDoubleQuote + 1); } else { startPos = space + 1; space = command.find(" ", startPos); } } String subString = command.substr(startPos, command.size()); removeDoubleQuotes(subString); argv.push_back(subString); } bool ArgParser::searchDoubleQuotes(String& command, size_t& left, size_t& right, size_t startPos) { bool result = false; left = String::npos; right = String::npos; left = command.find("\"", startPos); if (left != String::npos) { right = command.find("\"", left + 1); if (right != String::npos) { result = true; } } if (!result) { left = 0; right = 0; } return result; } void ArgParser::removeDoubleQuotes(String& arg) { // if string is surrounded by double quotes, remove them if (arg[0] == '\"' && arg[arg.size() - 1] == '\"') { arg = arg.substr(1, arg.size() - 2); } } const char** ArgParser::getArgv(std::vector& argsArray) { size_t argc = argsArray.size(); // caller is responsible for deleting the outer array only // we use the c string pointers from argsArray and assign // them to the inner array. So caller only need to use // delete[] to delete the outer array const char** argv = new const char*[argc]; for (size_t i = 0; i < argc; i++) { argv[i] = argsArray[i].c_str(); } return argv; } String ArgParser::assembleCommand(std::vector& argsArray, String ignoreArg, int parametersRequired) { String result; for (std::vector::iterator it = argsArray.begin(); it != argsArray.end(); ++it) { if (it->compare(ignoreArg) == 0) { it = it + parametersRequired; continue; } // if there is a space in this arg, use double quotes surround it if ((*it).find(" ") != String::npos) { (*it).insert(0, "\""); (*it).push_back('\"'); } result.append(*it); // add space to saperate args result.append(" "); } if (!result.empty()) { // remove the tail space result = result.substr(0, result.size() - 1); } return result; } void ArgParser::updateCommonArgs(const char* const* argv) { argsBase().m_name = ARCH->getHostName(); argsBase().m_pname = ARCH->getBasename(argv[0]); } bool ArgParser::checkUnexpectedArgs() { #if SYSAPI_WIN32 // suggest that user installs as a windows service. when launched as // service, process should automatically detect that it should run in // daemon mode. if (argsBase().m_daemon) { LOG((CLOG_ERR "the --daemon argument is not supported on windows. " "instead, install %s as a service (--service install)", argsBase().m_pname)); return true; } #endif return false; } synergy-1.8.8-stable/src/lib/synergy/ArgParser.h000066400000000000000000000042531305627404700216100ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" #include "common/stdvector.h" class ServerArgs; class ClientArgs; class ToolArgs; class ArgsBase; class App; class ArgParser { public: ArgParser(App* app); bool parseServerArgs(ServerArgs& args, int argc, const char* const* argv); bool parseClientArgs(ClientArgs& args, int argc, const char* const* argv); bool parsePlatformArg(ArgsBase& argsBase, const int& argc, const char* const* argv, int& i); bool parseToolArgs(ToolArgs& args, int argc, const char* const* argv); bool parseGenericArgs(int argc, const char* const* argv, int& i); bool parseDeprecatedArgs(int argc, const char* const* argv, int& i); void setArgsBase(ArgsBase& argsBase) { m_argsBase = &argsBase; } static bool isArg(int argi, int argc, const char* const* argv, const char* name1, const char* name2, int minRequiredParameters = 0); static void splitCommandString(String& command, std::vector& argv); static bool searchDoubleQuotes(String& command, size_t& left, size_t& right, size_t startPos = 0); static void removeDoubleQuotes(String& arg); static const char** getArgv(std::vector& argsArray); static String assembleCommand(std::vector& argsArray, String ignoreArg = "", int parametersRequired = 0); private: void updateCommonArgs(const char* const* argv); bool checkUnexpectedArgs(); static ArgsBase& argsBase() { return *m_argsBase; } private: App* m_app; static ArgsBase* m_argsBase; }; synergy-1.8.8-stable/src/lib/synergy/ArgsBase.cpp000066400000000000000000000026151305627404700217440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ArgsBase.h" ArgsBase::ArgsBase() : #if SYSAPI_WIN32 m_daemon(false), // daemon mode not supported on windows (use --service) m_debugServiceWait(false), m_pauseOnExit(false), m_stopOnDeskSwitch(false), #else m_daemon(true), // backward compatibility for unix (daemon by default) #endif #if WINAPI_XWINDOWS m_disableXInitThreads(false), #endif m_backend(false), m_restartable(true), m_noHooks(false), m_pname(NULL), m_logFilter(NULL), m_logFile(NULL), m_display(NULL), m_disableTray(false), m_enableIpc(false), m_enableDragDrop(false), m_shouldExit(false), m_synergyAddress(), m_enableCrypto(false), m_profileDirectory(""), m_pluginDirectory("") { } ArgsBase::~ArgsBase() { } synergy-1.8.8-stable/src/lib/synergy/ArgsBase.h000066400000000000000000000026151305627404700214110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" class ArgsBase { public: ArgsBase(); virtual ~ArgsBase(); public: bool m_daemon; bool m_backend; bool m_restartable; bool m_noHooks; const char* m_pname; const char* m_logFilter; const char* m_logFile; const char* m_display; String m_name; bool m_disableTray; bool m_enableIpc; bool m_enableDragDrop; #if SYSAPI_WIN32 bool m_debugServiceWait; bool m_pauseOnExit; bool m_stopOnDeskSwitch; #endif #if WINAPI_XWINDOWS bool m_disableXInitThreads; #endif bool m_shouldExit; String m_synergyAddress; bool m_enableCrypto; String m_profileDirectory; String m_pluginDirectory; }; synergy-1.8.8-stable/src/lib/synergy/CMakeLists.txt000066400000000000000000000025151305627404700223100ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") # arch if (WIN32) file(GLOB arch_headers "win32/*.h") file(GLOB arch_sources "win32/*.cpp") elseif (UNIX) file(GLOB arch_headers "unix/*.h") file(GLOB arch_sources "unix/*.cpp") endif() list(APPEND sources ${arch_sources}) list(APPEND headers ${arch_headers}) if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ../../../ext ../../../ext/gtest-1.6.0/include ) if (UNIX) include_directories( ../../.. ) endif() add_library(synergy STATIC ${sources}) if (UNIX) target_link_libraries(synergy arch client ipc net base platform mt server) endif() synergy-1.8.8-stable/src/lib/synergy/Chunk.cpp000066400000000000000000000015461305627404700213270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/Chunk.h" #include "base/String.h" Chunk::Chunk(size_t size) { m_chunk = new char[size]; memset(m_chunk, 0, size); } Chunk::~Chunk() { delete[] m_chunk; } synergy-1.8.8-stable/src/lib/synergy/Chunk.h000066400000000000000000000015201305627404700207640ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/basic_types.h" class Chunk { public: Chunk(size_t size); ~Chunk(); public: size_t m_dataSize; char* m_chunk; }; synergy-1.8.8-stable/src/lib/synergy/ClientApp.cpp000066400000000000000000000302371305627404700221350ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ClientApp.h" #include "client/Client.h" #include "synergy/ArgParser.h" #include "synergy/protocol_types.h" #include "synergy/Screen.h" #include "synergy/XScreen.h" #include "synergy/ClientArgs.h" #include "net/NetworkAddress.h" #include "net/TCPSocketFactory.h" #include "net/SocketMultiplexer.h" #include "net/XSocket.h" #include "mt/Thread.h" #include "arch/IArchTaskBarReceiver.h" #include "arch/Arch.h" #include "base/String.h" #include "base/Event.h" #include "base/IEventQueue.h" #include "base/TMethodEventJob.h" #include "base/log_outputters.h" #include "base/EventQueue.h" #include "base/TMethodJob.h" #include "base/Log.h" #include "common/Version.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" #endif #if WINAPI_MSWINDOWS #include "platform/MSWindowsScreen.h" #elif WINAPI_XWINDOWS #include "platform/XWindowsScreen.h" #elif WINAPI_CARBON #include "platform/OSXScreen.h" #endif #if defined(__APPLE__) #include "platform/OSXDragSimulator.h" #endif #include #include #define RETRY_TIME 1.0 ClientApp::ClientApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver) : App(events, createTaskBarReceiver, new ClientArgs()), m_client(NULL), m_clientScreen(NULL), m_serverAddress(NULL) { } ClientApp::~ClientApp() { } void ClientApp::parseArgs(int argc, const char* const* argv) { ArgParser argParser(this); bool result = argParser.parseClientArgs(args(), argc, argv); if (!result || args().m_shouldExit) { m_bye(kExitArgs); } else { // save server address if (!args().m_synergyAddress.empty()) { try { *m_serverAddress = NetworkAddress(args().m_synergyAddress, kDefaultPort); m_serverAddress->resolve(); } catch (XSocketAddress& e) { // allow an address that we can't look up if we're restartable. // we'll try to resolve the address each time we connect to the // server. a bad port will never get better. patch by Brent // Priddy. if (!args().m_restartable || e.getError() == XSocketAddress::kBadPort) { LOG((CLOG_PRINT "%s: %s" BYE, args().m_pname, e.what(), args().m_pname)); m_bye(kExitFailed); } } } } } void ClientApp::help() { #if WINAPI_XWINDOWS # define WINAPI_ARG \ " [--display ] [--no-xinitthreads]" # define WINAPI_INFO \ " --display connect to the X server at \n" \ " --no-xinitthreads do not call XInitThreads()\n" #else # define WINAPI_ARG # define WINAPI_INFO #endif char buffer[2000]; sprintf( buffer, "Usage: %s" " [--yscroll ]" WINAPI_ARG HELP_SYS_ARGS HELP_COMMON_ARGS " " "\n\n" "Connect to a synergy mouse/keyboard sharing server.\n" "\n" HELP_COMMON_INFO_1 WINAPI_INFO HELP_SYS_INFO " --yscroll defines the vertical scrolling delta, which is\n" " 120 by default.\n" HELP_COMMON_INFO_2 "\n" "* marks defaults.\n" "\n" "The server address is of the form: [][:]. The hostname\n" "must be the address or hostname of the server. The port overrides the\n" "default port, %d.\n", args().m_pname, kDefaultPort ); LOG((CLOG_PRINT "%s", buffer)); } const char* ClientApp::daemonName() const { #if SYSAPI_WIN32 return "Synergy Client"; #elif SYSAPI_UNIX return "synergyc"; #endif } const char* ClientApp::daemonInfo() const { #if SYSAPI_WIN32 return "Allows another computer to share it's keyboard and mouse with this computer."; #elif SYSAPI_UNIX return ""; #endif } synergy::Screen* ClientApp::createScreen() { #if WINAPI_MSWINDOWS return new synergy::Screen(new MSWindowsScreen( false, args().m_noHooks, args().m_stopOnDeskSwitch, m_events), m_events); #elif WINAPI_XWINDOWS return new synergy::Screen(new XWindowsScreen( args().m_display, false, args().m_disableXInitThreads, args().m_yscroll, m_events), m_events); #elif WINAPI_CARBON return new synergy::Screen(new OSXScreen(m_events, false), m_events); #endif } void ClientApp::updateStatus() { updateStatus(""); } void ClientApp::updateStatus(const String& msg) { if (m_taskBarReceiver) { m_taskBarReceiver->updateStatus(m_client, msg); } } void ClientApp::resetRestartTimeout() { // retry time can nolonger be changed //s_retryTime = 0.0; } double ClientApp::nextRestartTimeout() { // retry at a constant rate (Issue 52) return RETRY_TIME; /* // choose next restart timeout. we start with rapid retries // then slow down. if (s_retryTime < 1.0) { s_retryTime = 1.0; } else if (s_retryTime < 3.0) { s_retryTime = 3.0; } else { s_retryTime = 5.0; } return s_retryTime; */ } void ClientApp::handleScreenError(const Event&, void*) { LOG((CLOG_CRIT "error on screen")); m_events->addEvent(Event(Event::kQuit)); } synergy::Screen* ClientApp::openClientScreen() { synergy::Screen* screen = createScreen(); screen->setEnableDragDrop(argsBase().m_enableDragDrop); m_events->adoptHandler(m_events->forIScreen().error(), screen->getEventTarget(), new TMethodEventJob( this, &ClientApp::handleScreenError)); return screen; } void ClientApp::closeClientScreen(synergy::Screen* screen) { if (screen != NULL) { m_events->removeHandler(m_events->forIScreen().error(), screen->getEventTarget()); delete screen; } } void ClientApp::handleClientRestart(const Event&, void* vtimer) { // discard old timer EventQueueTimer* timer = static_cast(vtimer); m_events->deleteTimer(timer); m_events->removeHandler(Event::kTimer, timer); // reconnect startClient(); } void ClientApp::scheduleClientRestart(double retryTime) { // install a timer and handler to retry later LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime)); EventQueueTimer* timer = m_events->newOneShotTimer(retryTime, NULL); m_events->adoptHandler(Event::kTimer, timer, new TMethodEventJob(this, &ClientApp::handleClientRestart, timer)); } void ClientApp::handleClientConnected(const Event&, void*) { LOG((CLOG_NOTE "connected to server")); resetRestartTimeout(); updateStatus(); } void ClientApp::handleClientFailed(const Event& e, void*) { Client::FailInfo* info = static_cast(e.getData()); updateStatus(String("Failed to connect to server: ") + info->m_what); if (!args().m_restartable || !info->m_retry) { LOG((CLOG_ERR "failed to connect to server: %s", info->m_what.c_str())); m_events->addEvent(Event(Event::kQuit)); } else { LOG((CLOG_WARN "failed to connect to server: %s", info->m_what.c_str())); if (!m_suspended) { scheduleClientRestart(nextRestartTimeout()); } } delete info; } void ClientApp::handleClientDisconnected(const Event&, void*) { LOG((CLOG_NOTE "disconnected from server")); if (!args().m_restartable) { m_events->addEvent(Event(Event::kQuit)); } else if (!m_suspended) { scheduleClientRestart(nextRestartTimeout()); } updateStatus(); } Client* ClientApp::openClient(const String& name, const NetworkAddress& address, synergy::Screen* screen) { Client* client = new Client( m_events, name, address, new TCPSocketFactory(m_events, getSocketMultiplexer()), screen, args()); try { m_events->adoptHandler( m_events->forClient().connected(), client->getEventTarget(), new TMethodEventJob(this, &ClientApp::handleClientConnected)); m_events->adoptHandler( m_events->forClient().connectionFailed(), client->getEventTarget(), new TMethodEventJob(this, &ClientApp::handleClientFailed)); m_events->adoptHandler( m_events->forClient().disconnected(), client->getEventTarget(), new TMethodEventJob(this, &ClientApp::handleClientDisconnected)); } catch (std::bad_alloc &ba) { delete client; throw ba; } return client; } void ClientApp::closeClient(Client* client) { if (client == NULL) { return; } m_events->removeHandler(m_events->forClient().connected(), client); m_events->removeHandler(m_events->forClient().connectionFailed(), client); m_events->removeHandler(m_events->forClient().disconnected(), client); delete client; } int ClientApp::foregroundStartup(int argc, char** argv) { initApp(argc, argv); // never daemonize return mainLoop(); } bool ClientApp::startClient() { double retryTime; synergy::Screen* clientScreen = NULL; try { if (m_clientScreen == NULL) { clientScreen = openClientScreen(); m_client = openClient(args().m_name, *m_serverAddress, clientScreen); m_clientScreen = clientScreen; LOG((CLOG_NOTE "started client")); } m_client->connect(); updateStatus(); return true; } catch (XScreenUnavailable& e) { LOG((CLOG_WARN "secondary screen unavailable: %s", e.what())); closeClientScreen(clientScreen); updateStatus(String("secondary screen unavailable: ") + e.what()); retryTime = e.getRetryTime(); } catch (XScreenOpenFailure& e) { LOG((CLOG_CRIT "failed to start client: %s", e.what())); closeClientScreen(clientScreen); return false; } catch (XBase& e) { LOG((CLOG_CRIT "failed to start client: %s", e.what())); closeClientScreen(clientScreen); return false; } if (args().m_restartable) { scheduleClientRestart(retryTime); return true; } else { // don't try again return false; } } void ClientApp::stopClient() { closeClient(m_client); closeClientScreen(m_clientScreen); m_client = NULL; m_clientScreen = NULL; } int ClientApp::mainLoop() { // create socket multiplexer. this must happen after daemonization // on unix because threads evaporate across a fork(). SocketMultiplexer multiplexer; setSocketMultiplexer(&multiplexer); // start client, etc appUtil().startNode(); // init ipc client after node start, since create a new screen wipes out // the event queue (the screen ctors call adoptBuffer). if (argsBase().m_enableIpc) { initIpcClient(); } // run event loop. if startClient() failed we're supposed to retry // later. the timer installed by startClient() will take care of // that. DAEMON_RUNNING(true); #if defined(MAC_OS_X_VERSION_10_7) Thread thread( new TMethodJob( this, &ClientApp::runEventsLoop, NULL)); // wait until carbon loop is ready OSXScreen* screen = dynamic_cast( m_clientScreen->getPlatformScreen()); screen->waitForCarbonLoop(); runCocoaApp(); #else m_events->loop(); #endif DAEMON_RUNNING(false); // close down LOG((CLOG_DEBUG1 "stopping client")); stopClient(); updateStatus(); LOG((CLOG_NOTE "stopped client")); if (argsBase().m_enableIpc) { cleanupIpcClient(); } return kExitSuccess; } static int daemonMainLoopStatic(int argc, const char** argv) { return ClientApp::instance().daemonMainLoop(argc, argv); } int ClientApp::standardStartup(int argc, char** argv) { initApp(argc, argv); // daemonize if requested if (args().m_daemon) { return ARCH->daemonize(daemonName(), &daemonMainLoopStatic); } else { return mainLoop(); } } int ClientApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) { // general initialization m_serverAddress = new NetworkAddress; args().m_pname = ARCH->getBasename(argv[0]); // install caller's output filter if (outputter != NULL) { CLOG->insert(outputter); } int result; try { // run result = startup(argc, argv); } catch (...) { if (m_taskBarReceiver) { // done with task bar receiver delete m_taskBarReceiver; } delete m_serverAddress; throw; } return result; } void ClientApp::startNode() { // start the client. if this return false then we've failed and // we shouldn't retry. LOG((CLOG_DEBUG1 "starting client")); if (!startClient()) { m_bye(kExitFailed); } } synergy-1.8.8-stable/src/lib/synergy/ClientApp.h000066400000000000000000000051471305627404700216040ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/App.h" namespace synergy { class Screen; } class Event; class Client; class NetworkAddress; class Thread; class ClientArgs; class ClientApp : public App { public: ClientApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver); virtual ~ClientApp(); // Parse client specific command line arguments. void parseArgs(int argc, const char* const* argv); // Prints help specific to client. void help(); // Returns arguments that are common and for client. ClientArgs& args() const { return (ClientArgs&)argsBase(); } const char* daemonName() const; const char* daemonInfo() const; // TODO: move to server only (not supported on client) void loadConfig() { } bool loadConfig(const String& pathname) { return false; } int foregroundStartup(int argc, char** argv); int standardStartup(int argc, char** argv); int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup); synergy::Screen* createScreen(); void updateStatus(); void updateStatus(const String& msg); void resetRestartTimeout(); double nextRestartTimeout(); void handleScreenError(const Event&, void*); synergy::Screen* openClientScreen(); void closeClientScreen(synergy::Screen* screen); void handleClientRestart(const Event&, void* vtimer); void scheduleClientRestart(double retryTime); void handleClientConnected(const Event&, void*); void handleClientFailed(const Event& e, void*); void handleClientDisconnected(const Event&, void*); Client* openClient(const String& name, const NetworkAddress& address, synergy::Screen* screen); void closeClient(Client* client); bool startClient(); void stopClient(); int mainLoop(); void startNode(); static ClientApp& instance() { return (ClientApp&)App::instance(); } Client* getClientPtr() { return m_client; } private: Client* m_client; synergy::Screen*m_clientScreen; NetworkAddress* m_serverAddress; }; synergy-1.8.8-stable/src/lib/synergy/ClientArgs.cpp000066400000000000000000000014031305627404700223020ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ClientArgs.h" ClientArgs::ClientArgs() : m_yscroll(0) { } synergy-1.8.8-stable/src/lib/synergy/ClientArgs.h000066400000000000000000000015251305627404700217540ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/ArgsBase.h" class NetworkAddress; class ClientArgs : public ArgsBase { public: ClientArgs(); public: int m_yscroll; }; synergy-1.8.8-stable/src/lib/synergy/ClientTaskBarReceiver.cpp000066400000000000000000000055541305627404700244350ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ClientTaskBarReceiver.h" #include "client/Client.h" #include "mt/Lock.h" #include "base/String.h" #include "base/IEventQueue.h" #include "arch/Arch.h" #include "common/Version.h" // // ClientTaskBarReceiver // ClientTaskBarReceiver::ClientTaskBarReceiver(IEventQueue* events) : m_state(kNotRunning), m_events(events) { // do nothing } ClientTaskBarReceiver::~ClientTaskBarReceiver() { // do nothing } void ClientTaskBarReceiver::updateStatus(Client* client, const String& errorMsg) { { // update our status m_errorMessage = errorMsg; if (client == NULL) { if (m_errorMessage.empty()) { m_state = kNotRunning; } else { m_state = kNotWorking; } } else { m_server = client->getServerAddress().getHostname(); if (client->isConnected()) { m_state = kConnected; } else if (client->isConnecting()) { m_state = kConnecting; } else { m_state = kNotConnected; } } // let subclasses have a go onStatusChanged(client); } // tell task bar ARCH->updateReceiver(this); } ClientTaskBarReceiver::EState ClientTaskBarReceiver::getStatus() const { return m_state; } const String& ClientTaskBarReceiver::getErrorMessage() const { return m_errorMessage; } void ClientTaskBarReceiver::quit() { m_events->addEvent(Event(Event::kQuit)); } void ClientTaskBarReceiver::onStatusChanged(Client*) { // do nothing } void ClientTaskBarReceiver::lock() const { // do nothing } void ClientTaskBarReceiver::unlock() const { // do nothing } std::string ClientTaskBarReceiver::getToolTip() const { switch (m_state) { case kNotRunning: return synergy::string::sprintf("%s: Not running", kAppVersion); case kNotWorking: return synergy::string::sprintf("%s: %s", kAppVersion, m_errorMessage.c_str()); case kNotConnected: return synergy::string::sprintf("%s: Not connected: %s", kAppVersion, m_errorMessage.c_str()); case kConnecting: return synergy::string::sprintf("%s: Connecting to %s...", kAppVersion, m_server.c_str()); case kConnected: return synergy::string::sprintf("%s: Connected to %s", kAppVersion, m_server.c_str()); default: return ""; } } synergy-1.8.8-stable/src/lib/synergy/ClientTaskBarReceiver.h000066400000000000000000000046311305627404700240750ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef CCLIENTTASKBARRECEIVER_H #define CCLIENTTASKBARRECEIVER_H #include "base/String.h" #include "arch/IArchTaskBarReceiver.h" #include "base/log_outputters.h" #include "client/Client.h" class IEventQueue; //! Implementation of IArchTaskBarReceiver for the synergy server class ClientTaskBarReceiver : public IArchTaskBarReceiver { public: ClientTaskBarReceiver(IEventQueue* events); virtual ~ClientTaskBarReceiver(); //! @name manipulators //@{ //! Update status /*! Determine the status and query required information from the client. */ void updateStatus(Client*, const String& errorMsg); void updateStatus(INode* n, const String& errorMsg) { updateStatus((Client*)n, errorMsg); } //@} // IArchTaskBarReceiver overrides virtual void showStatus() = 0; virtual void runMenu(int x, int y) = 0; virtual void primaryAction() = 0; virtual void lock() const; virtual void unlock() const; virtual const Icon getIcon() const = 0; virtual std::string getToolTip() const; virtual void cleanup() {} protected: enum EState { kNotRunning, kNotWorking, kNotConnected, kConnecting, kConnected, kMaxState }; //! Get status EState getStatus() const; //! Get error message const String& getErrorMessage() const; //! Quit app /*! Causes the application to quit gracefully */ void quit(); //! Status change notification /*! Called when status changes. The default implementation does nothing. */ virtual void onStatusChanged(Client* client); private: EState m_state; String m_errorMessage; String m_server; IEventQueue* m_events; }; IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events); #endif synergy-1.8.8-stable/src/lib/synergy/Clipboard.cpp000066400000000000000000000036301305627404700221520ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/Clipboard.h" // // Clipboard // Clipboard::Clipboard() : m_open(false), m_owner(false) { open(0); empty(); close(); } Clipboard::~Clipboard() { // do nothing } bool Clipboard::empty() { assert(m_open); // clear all data for (SInt32 index = 0; index < kNumFormats; ++index) { m_data[index] = ""; m_added[index] = false; } // save time m_timeOwned = m_time; // we're the owner now m_owner = true; return true; } void Clipboard::add(EFormat format, const String& data) { assert(m_open); assert(m_owner); m_data[format] = data; m_added[format] = true; } bool Clipboard::open(Time time) const { assert(!m_open); m_open = true; m_time = time; return true; } void Clipboard::close() const { assert(m_open); m_open = false; } Clipboard::Time Clipboard::getTime() const { return m_timeOwned; } bool Clipboard::has(EFormat format) const { assert(m_open); return m_added[format]; } String Clipboard::get(EFormat format) const { assert(m_open); return m_data[format]; } void Clipboard::unmarshall(const String& data, Time time) { IClipboard::unmarshall(this, data, time); } String Clipboard::marshall() const { return IClipboard::marshall(this); } synergy-1.8.8-stable/src/lib/synergy/Clipboard.h000066400000000000000000000034761305627404700216270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/IClipboard.h" //! Memory buffer clipboard /*! This class implements a clipboard that stores data in memory. */ class Clipboard : public IClipboard { public: Clipboard(); virtual ~Clipboard(); //! @name manipulators //@{ //! Unmarshall clipboard data /*! Extract marshalled clipboard data and store it in this clipboard. Sets the clipboard time to \c time. */ void unmarshall(const String& data, Time time); //@} //! @name accessors //@{ //! Marshall clipboard data /*! Merge this clipboard's data into a single buffer that can be later unmarshalled to restore the clipboard and return the buffer. */ String marshall() const; //@} // IClipboard overrides virtual bool empty(); virtual void add(EFormat, const String& data); virtual bool open(Time) const; virtual void close() const; virtual Time getTime() const; virtual bool has(EFormat) const; virtual String get(EFormat) const; private: mutable bool m_open; mutable Time m_time; bool m_owner; Time m_timeOwned; bool m_added[kNumFormats]; String m_data[kNumFormats]; }; synergy-1.8.8-stable/src/lib/synergy/ClipboardChunk.cpp000066400000000000000000000076201305627404700231460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ClipboardChunk.h" #include "synergy/ProtocolUtil.h" #include "synergy/protocol_types.h" #include "io/IStream.h" #include "base/Log.h" #include size_t ClipboardChunk::s_expectedSize = 0; ClipboardChunk::ClipboardChunk(size_t size) : Chunk(size) { m_dataSize = size - CLIPBOARD_CHUNK_META_SIZE; } ClipboardChunk* ClipboardChunk::start( ClipboardID id, UInt32 sequence, const String& size) { size_t sizeLength = size.size(); ClipboardChunk* start = new ClipboardChunk(sizeLength + CLIPBOARD_CHUNK_META_SIZE); char* chunk = start->m_chunk; chunk[0] = id; std::memcpy (&chunk[1], &sequence, 4); chunk[5] = kDataStart; memcpy(&chunk[6], size.c_str(), sizeLength); chunk[sizeLength + CLIPBOARD_CHUNK_META_SIZE - 1] = '\0'; return start; } ClipboardChunk* ClipboardChunk::data( ClipboardID id, UInt32 sequence, const String& data) { size_t dataSize = data.size(); ClipboardChunk* chunk = new ClipboardChunk(dataSize + CLIPBOARD_CHUNK_META_SIZE); char* chunkData = chunk->m_chunk; chunkData[0] = id; std::memcpy (&chunkData[1], &sequence, 4); chunkData[5] = kDataChunk; memcpy(&chunkData[6], data.c_str(), dataSize); chunkData[dataSize + CLIPBOARD_CHUNK_META_SIZE - 1] = '\0'; return chunk; } ClipboardChunk* ClipboardChunk::end(ClipboardID id, UInt32 sequence) { ClipboardChunk* end = new ClipboardChunk(CLIPBOARD_CHUNK_META_SIZE); char* chunk = end->m_chunk; chunk[0] = id; std::memcpy (&chunk[1], &sequence, 4); chunk[5] = kDataEnd; chunk[CLIPBOARD_CHUNK_META_SIZE - 1] = '\0'; return end; } int ClipboardChunk::assemble(synergy::IStream* stream, String& dataCached, ClipboardID& id, UInt32& sequence) { UInt8 mark; String data; if (!ProtocolUtil::readf(stream, kMsgDClipboard + 4, &id, &sequence, &mark, &data)) { return kError; } if (mark == kDataStart) { s_expectedSize = synergy::string::stringToSizeType(data); LOG((CLOG_DEBUG "start receiving clipboard data")); dataCached.clear(); return kStart; } else if (mark == kDataChunk) { dataCached.append(data); return kNotFinish; } else if (mark == kDataEnd) { // validate if (id >= kClipboardEnd) { return kError; } else if (s_expectedSize != dataCached.size()) { LOG((CLOG_ERR "corrupted clipboard data, expected size=%d actual size=%d", s_expectedSize, dataCached.size())); return kError; } return kFinish; } LOG((CLOG_ERR "clipboard transmission failed: unknown error")); return kError; } void ClipboardChunk::send(synergy::IStream* stream, void* data) { ClipboardChunk* clipboardData = static_cast(data); LOG((CLOG_DEBUG1 "sending clipboard chunk")); char* chunk = clipboardData->m_chunk; ClipboardID id = chunk[0]; UInt32 sequence; std::memcpy (&sequence, &chunk[1], 4); UInt8 mark = chunk[5]; String dataChunk(&chunk[6], clipboardData->m_dataSize); switch (mark) { case kDataStart: LOG((CLOG_DEBUG2 "sending clipboard chunk start: size=%s", dataChunk.c_str())); break; case kDataChunk: LOG((CLOG_DEBUG2 "sending clipboard chunk data: size=%i", dataChunk.size())); break; case kDataEnd: LOG((CLOG_DEBUG2 "sending clipboard finished")); break; } ProtocolUtil::writef(stream, kMsgDClipboard, id, sequence, mark, &dataChunk); } synergy-1.8.8-stable/src/lib/synergy/ClipboardChunk.h000066400000000000000000000030471305627404700226120ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/Chunk.h" #include "synergy/clipboard_types.h" #include "base/String.h" #include "common/basic_types.h" #define CLIPBOARD_CHUNK_META_SIZE 7 namespace synergy { class IStream; }; class ClipboardChunk : public Chunk { public: ClipboardChunk(size_t size); static ClipboardChunk* start( ClipboardID id, UInt32 sequence, const String& size); static ClipboardChunk* data( ClipboardID id, UInt32 sequence, const String& data); static ClipboardChunk* end(ClipboardID id, UInt32 sequence); static int assemble( synergy::IStream* stream, String& dataCached, ClipboardID& id, UInt32& sequence); static void send(synergy::IStream* stream, void* data); static size_t getExpectedSize() { return s_expectedSize; } private: static size_t s_expectedSize; }; synergy-1.8.8-stable/src/lib/synergy/DaemonApp.cpp000066400000000000000000000235311305627404700221210ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // TODO: split this class into windows and unix to get rid // of all the #ifdefs! #include "synergy/DaemonApp.h" #include "synergy/App.h" #include "synergy/ArgParser.h" #include "synergy/ServerArgs.h" #include "synergy/ClientArgs.h" #include "ipc/IpcClientProxy.h" #include "ipc/IpcMessage.h" #include "ipc/IpcLogOutputter.h" #include "net/SocketMultiplexer.h" #include "arch/XArch.h" #include "base/Log.h" #include "base/TMethodJob.h" #include "base/TMethodEventJob.h" #include "base/EventQueue.h" #include "base/log_outputters.h" #include "base/Log.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" #include "arch/win32/XArchWindows.h" #include "synergy/Screen.h" #include "platform/MSWindowsScreen.h" #include "platform/MSWindowsDebugOutputter.h" #include "platform/MSWindowsWatchdog.h" #include "platform/MSWindowsEventQueueBuffer.h" #define WIN32_LEAN_AND_MEAN #include #endif #include #include #include using namespace std; DaemonApp* DaemonApp::s_instance = NULL; int mainLoopStatic() { DaemonApp::s_instance->mainLoop(true); return kExitSuccess; } int unixMainLoopStatic(int, const char**) { return mainLoopStatic(); } #if SYSAPI_WIN32 int winMainLoopStatic(int, const char**) { return ArchMiscWindows::runDaemon(mainLoopStatic); } #endif DaemonApp::DaemonApp() : m_ipcServer(nullptr), m_ipcLogOutputter(nullptr), #if SYSAPI_WIN32 m_watchdog(nullptr), #endif m_events(nullptr), m_fileLogOutputter(nullptr) { s_instance = this; } DaemonApp::~DaemonApp() { } int DaemonApp::run(int argc, char** argv) { #if SYSAPI_WIN32 // win32 instance needed for threading, etc. ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif Arch arch; arch.init(); Log log; EventQueue events; m_events = &events; bool uninstall = false; try { #if SYSAPI_WIN32 // sends debug messages to visual studio console window. log.insert(new MSWindowsDebugOutputter()); #endif // default log level to system setting. string logLevel = arch.setting("LogLevel"); if (logLevel != "") log.setFilter(logLevel.c_str()); bool foreground = false; for (int i = 1; i < argc; ++i) { string arg(argv[i]); if (arg == "/f" || arg == "-f") { foreground = true; } #if SYSAPI_WIN32 else if (arg == "/install") { uninstall = true; arch.installDaemon(); return kExitSuccess; } else if (arg == "/uninstall") { arch.uninstallDaemon(); return kExitSuccess; } #endif else { stringstream ss; ss << "Unrecognized argument: " << arg; foregroundError(ss.str().c_str()); return kExitArgs; } } if (foreground) { // run process in foreground instead of daemonizing. // useful for debugging. mainLoop(false); } else { #if SYSAPI_WIN32 arch.daemonize("Synergy", winMainLoopStatic); #elif SYSAPI_UNIX arch.daemonize("Synergy", unixMainLoopStatic); #endif } return kExitSuccess; } catch (XArch& e) { String message = e.what(); if (uninstall && (message.find("The service has not been started") != String::npos)) { // TODO: if we're keeping this use error code instead (what is it?!). // HACK: this message happens intermittently, not sure where from but // it's quite misleading for the user. they thing something has gone // horribly wrong, but it's just the service manager reporting a false // positive (the service has actually shut down in most cases). } else { foregroundError(message.c_str()); } return kExitFailed; } catch (std::exception& e) { foregroundError(e.what()); return kExitFailed; } catch (...) { foregroundError("Unrecognized error."); return kExitFailed; } } void DaemonApp::mainLoop(bool logToFile) { try { DAEMON_RUNNING(true); if (logToFile) { m_fileLogOutputter = new FileLogOutputter(logFilename().c_str()); CLOG->insert(m_fileLogOutputter); } // create socket multiplexer. this must happen after daemonization // on unix because threads evaporate across a fork(). SocketMultiplexer multiplexer; // uses event queue, must be created here. m_ipcServer = new IpcServer(m_events, &multiplexer); // send logging to gui via ipc, log system adopts outputter. m_ipcLogOutputter = new IpcLogOutputter(*m_ipcServer, kIpcClientGui, true); CLOG->insert(m_ipcLogOutputter); #if SYSAPI_WIN32 m_watchdog = new MSWindowsWatchdog(false, *m_ipcServer, *m_ipcLogOutputter); m_watchdog->setFileLogOutputter(m_fileLogOutputter); #endif m_events->adoptHandler( m_events->forIpcServer().messageReceived(), m_ipcServer, new TMethodEventJob(this, &DaemonApp::handleIpcMessage)); m_ipcServer->listen(); #if SYSAPI_WIN32 // install the platform event queue to handle service stop events. m_events->adoptBuffer(new MSWindowsEventQueueBuffer(m_events)); String command = ARCH->setting("Command"); bool elevate = ARCH->setting("Elevate") == "1"; if (command != "") { LOG((CLOG_INFO "using last known command: %s", command.c_str())); m_watchdog->setCommand(command, elevate); } m_watchdog->startAsync(); #endif m_events->loop(); #if SYSAPI_WIN32 m_watchdog->stop(); delete m_watchdog; #endif m_events->removeHandler( m_events->forIpcServer().messageReceived(), m_ipcServer); CLOG->remove(m_ipcLogOutputter); delete m_ipcLogOutputter; delete m_ipcServer; DAEMON_RUNNING(false); } catch (std::exception& e) { LOG((CLOG_CRIT "An error occurred: %s", e.what())); } catch (...) { LOG((CLOG_CRIT "An unknown error occurred.\n")); } } void DaemonApp::foregroundError(const char* message) { #if SYSAPI_WIN32 MessageBox(NULL, message, "Synergy Service", MB_OK | MB_ICONERROR); #elif SYSAPI_UNIX cerr << message << endl; #endif } std::string DaemonApp::logFilename() { string logFilename; logFilename = ARCH->setting("LogFilename"); if (logFilename.empty()) { logFilename = ARCH->getLogDirectory(); logFilename.append("/"); logFilename.append(LOG_FILENAME); } return logFilename; } void DaemonApp::handleIpcMessage(const Event& e, void*) { IpcMessage* m = static_cast(e.getDataObject()); switch (m->type()) { case kIpcCommand: { IpcCommandMessage* cm = static_cast(m); String command = cm->command(); // if empty quotes, clear. if (command == "\"\"") { command.clear(); } if (!command.empty()) { LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str())); std::vector argsArray; ArgParser::splitCommandString(command, argsArray); ArgParser argParser(NULL); const char** argv = argParser.getArgv(argsArray); ServerArgs serverArgs; ClientArgs clientArgs; int argc = static_cast(argsArray.size()); bool server = argsArray[0].find("synergys") != String::npos ? true : false; ArgsBase* argBase = NULL; if (server) { argParser.parseServerArgs(serverArgs, argc, argv); argBase = &serverArgs; } else { argParser.parseClientArgs(clientArgs, argc, argv); argBase = &clientArgs; } delete[] argv; String logLevel(argBase->m_logFilter); if (!logLevel.empty()) { try { // change log level based on that in the command string // and change to that log level now. ARCH->setting("LogLevel", logLevel); CLOG->setFilter(logLevel.c_str()); } catch (XArch& e) { LOG((CLOG_ERR "failed to save LogLevel setting, %s", e.what())); } } #if SYSAPI_WIN32 String logFilename; if (argBase->m_logFile != NULL) { logFilename = String(argBase->m_logFile); ARCH->setting("LogFilename", logFilename); m_watchdog->setFileLogOutputter(m_fileLogOutputter); command = ArgParser::assembleCommand(argsArray, "--log", 1); LOG((CLOG_DEBUG "removed log file argument and filename %s from command ", logFilename.c_str())); LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str())); } else { m_watchdog->setFileLogOutputter(NULL); } m_fileLogOutputter->setLogFilename(logFilename.c_str()); #endif } else { LOG((CLOG_DEBUG "empty command, elevate=%d", cm->elevate())); } try { // store command in system settings. this is used when the daemon // next starts. ARCH->setting("Command", command); // TODO: it would be nice to store bools/ints... ARCH->setting("Elevate", String(cm->elevate() ? "1" : "0")); } catch (XArch& e) { LOG((CLOG_ERR "failed to save settings, %s", e.what())); } #if SYSAPI_WIN32 // tell the relauncher about the new command. this causes the // relauncher to stop the existing command and start the new // command. m_watchdog->setCommand(command, cm->elevate()); #endif break; } case kIpcHello: IpcHelloMessage* hm = static_cast(m); String type; switch (hm->clientType()) { case kIpcClientGui: type = "gui"; break; case kIpcClientNode: type = "node"; break; default: type = "unknown"; break; } LOG((CLOG_DEBUG "ipc hello, type=%s", type.c_str())); #if SYSAPI_WIN32 String watchdogStatus = m_watchdog->isProcessActive() ? "ok" : "error"; LOG((CLOG_INFO "watchdog status: %s", watchdogStatus.c_str())); #endif m_ipcLogOutputter->notifyBuffer(); break; } } synergy-1.8.8-stable/src/lib/synergy/DaemonApp.h000066400000000000000000000027061305627404700215670ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "arch/Arch.h" #include "ipc/IpcServer.h" #include class Event; class IpcLogOutputter; class FileLogOutputter; #if SYSAPI_WIN32 class MSWindowsWatchdog; #endif class DaemonApp { public: DaemonApp(); virtual ~DaemonApp(); int run(int argc, char** argv); void mainLoop(bool logToFile); private: void daemonize(); void foregroundError(const char* message); std::string logFilename(); void handleIpcMessage(const Event&, void*); public: static DaemonApp* s_instance; #if SYSAPI_WIN32 MSWindowsWatchdog* m_watchdog; #endif private: IpcServer* m_ipcServer; IpcLogOutputter* m_ipcLogOutputter; IEventQueue* m_events; FileLogOutputter* m_fileLogOutputter; }; #define LOG_FILENAME "synergyd.log" synergy-1.8.8-stable/src/lib/synergy/DragInformation.cpp000066400000000000000000000071041305627404700233360ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/DragInformation.h" #include "base/Log.h" #include #include #include using namespace std; DragInformation::DragInformation() : m_filename(), m_filesize(0) { } void DragInformation::parseDragInfo(DragFileList& dragFileList, UInt32 fileNum, String data) { size_t startPos = 0; size_t findResult1 = 0; size_t findResult2 = 0; dragFileList.clear(); String slash("\\"); if (data.find("/", startPos) != string::npos) { slash = "/"; } UInt32 index = 0; while (index < fileNum) { findResult1 = data.find(',', startPos); findResult2 = data.find_last_of(slash, findResult1); if (findResult1 == startPos) { //TODO: file number does not match, something goes wrong break; } // set filename if (findResult1 - findResult2 > 1) { String filename = data.substr(findResult2 + 1, findResult1 - findResult2 - 1); DragInformation di; di.setFilename(filename); dragFileList.push_back(di); } startPos = findResult1 + 1; //set filesize findResult2 = data.find(',', startPos); if (findResult2 - findResult1 > 1) { String filesize = data.substr(findResult1 + 1, findResult2 - findResult1 - 1); size_t size = stringToNum(filesize); dragFileList.at(index).setFilesize(size); } startPos = findResult1 + 1; ++index; } LOG((CLOG_DEBUG "drag info received, total drag file number: %i", dragFileList.size())); for (size_t i = 0; i < dragFileList.size(); ++i) { LOG((CLOG_DEBUG "dragging file %i name: %s", i + 1, dragFileList.at(i).getFilename().c_str())); } } String DragInformation::getDragFileExtension(String filename) { size_t findResult = string::npos; findResult = filename.find_last_of(".", filename.size()); if (findResult != string::npos) { return filename.substr(findResult + 1, filename.size() - findResult - 1); } else { return ""; } } int DragInformation::setupDragInfo(DragFileList& fileList, String& output) { int size = static_cast(fileList.size()); for (int i = 0; i < size; ++i) { output.append(fileList.at(i).getFilename()); output.append(","); String filesize = getFileSize(fileList.at(i).getFilename()); output.append(filesize); output.append(","); } return size; } bool DragInformation::isFileValid(String filename) { bool result = false; std::fstream file(filename.c_str(), ios::in|ios::binary); if (file.is_open()) { result = true; } file. close(); return result; } size_t DragInformation::stringToNum(String& str) { istringstream iss(str.c_str()); size_t size; iss >> size; return size; } String DragInformation::getFileSize(String& filename) { std::fstream file(filename.c_str(), ios::in|ios::binary); if (!file.is_open()) { throw std::runtime_error("failed to get file size"); } // check file size file.seekg (0, std::ios::end); size_t size = (size_t)file.tellg(); stringstream ss; ss << size; file. close(); return ss.str(); } synergy-1.8.8-stable/src/lib/synergy/DragInformation.h000066400000000000000000000032301305627404700227770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/stdvector.h" #include "base/String.h" #include "base/EventTypes.h" class DragInformation; typedef std::vector DragFileList; class DragInformation { public: DragInformation(); ~DragInformation() { } String& getFilename() { return m_filename; } void setFilename(String& name) { m_filename = name; } size_t getFilesize() { return m_filesize; } void setFilesize(size_t size) { m_filesize = size; } static void parseDragInfo(DragFileList& dragFileList, UInt32 fileNum, String data); static String getDragFileExtension(String filename); // helper function to setup drag info // example: filename1,filesize1,filename2,filesize2, // return file count static int setupDragInfo(DragFileList& fileList, String& output); static bool isFileValid(String filename); private: static size_t stringToNum(String& str); static String getFileSize(String& filename); private: String m_filename; size_t m_filesize; }; synergy-1.8.8-stable/src/lib/synergy/DropHelper.cpp000066400000000000000000000031421305627404700223150ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/DropHelper.h" #include "base/Log.h" #include void DropHelper::writeToDir(const String& destination, DragFileList& fileList, String& data) { LOG((CLOG_DEBUG "dropping file, files=%i target=%s", fileList.size(), destination.c_str())); if (!destination.empty() && fileList.size() > 0) { std::fstream file; String dropTarget = destination; #ifdef SYSAPI_WIN32 dropTarget.append("\\"); #else dropTarget.append("/"); #endif dropTarget.append(fileList.at(0).getFilename()); file.open(dropTarget.c_str(), std::ios::out | std::ios::binary); if (!file.is_open()) { LOG((CLOG_ERR "drop file failed: can not open %s", dropTarget.c_str())); } file.write(data.c_str(), data.size()); file.close(); LOG((CLOG_DEBUG "%s is saved to %s", fileList.at(0).getFilename().c_str(), destination.c_str())); fileList.clear(); } else { LOG((CLOG_ERR "drop file failed: drop target is empty")); } } synergy-1.8.8-stable/src/lib/synergy/DropHelper.h000066400000000000000000000016031305627404700217620ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/DragInformation.h" #include "base/String.h" class DropHelper { public: static void writeToDir(const String& destination, DragFileList& fileList, String& data); }; synergy-1.8.8-stable/src/lib/synergy/FileChunk.cpp000066400000000000000000000101331305627404700221170ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/FileChunk.h" #include "synergy/ProtocolUtil.h" #include "synergy/protocol_types.h" #include "io/IStream.h" #include "base/Stopwatch.h" #include "base/Log.h" static const UInt16 kIntervalThreshold = 1; FileChunk::FileChunk(size_t size) : Chunk(size) { m_dataSize = size - FILE_CHUNK_META_SIZE; } FileChunk* FileChunk::start(const String& size) { size_t sizeLength = size.size(); FileChunk* start = new FileChunk(sizeLength + FILE_CHUNK_META_SIZE); char* chunk = start->m_chunk; chunk[0] = kDataStart; memcpy(&chunk[1], size.c_str(), sizeLength); chunk[sizeLength + 1] = '\0'; return start; } FileChunk* FileChunk::data(UInt8* data, size_t dataSize) { FileChunk* chunk = new FileChunk(dataSize + FILE_CHUNK_META_SIZE); char* chunkData = chunk->m_chunk; chunkData[0] = kDataChunk; memcpy(&chunkData[1], data, dataSize); chunkData[dataSize + 1] = '\0'; return chunk; } FileChunk* FileChunk::end() { FileChunk* end = new FileChunk(FILE_CHUNK_META_SIZE); char* chunk = end->m_chunk; chunk[0] = kDataEnd; chunk[1] = '\0'; return end; } int FileChunk::assemble(synergy::IStream* stream, String& dataReceived, size_t& expectedSize) { // parse UInt8 mark = 0; String content; static size_t receivedDataSize; static double elapsedTime; static Stopwatch stopwatch; if (!ProtocolUtil::readf(stream, kMsgDFileTransfer + 4, &mark, &content)) { return kError; } switch (mark) { case kDataStart: dataReceived.clear(); expectedSize = synergy::string::stringToSizeType(content); receivedDataSize = 0; elapsedTime = 0; stopwatch.reset(); if (CLOG->getFilter() >= kDEBUG2) { LOG((CLOG_DEBUG2 "recv file size=%s", content.c_str())); stopwatch.start(); } return kStart; case kDataChunk: dataReceived.append(content); if (CLOG->getFilter() >= kDEBUG2) { LOG((CLOG_DEBUG2 "recv file chunck size=%i", content.size())); double interval = stopwatch.getTime(); receivedDataSize += content.size(); LOG((CLOG_DEBUG2 "recv file interval=%f s", interval)); if (interval >= kIntervalThreshold) { double averageSpeed = receivedDataSize / interval / 1000; LOG((CLOG_DEBUG2 "recv file average speed=%f kb/s", averageSpeed)); receivedDataSize = 0; elapsedTime += interval; stopwatch.reset(); } } return kNotFinish; case kDataEnd: if (expectedSize != dataReceived.size()) { LOG((CLOG_ERR "corrupted clipboard data, expected size=%d actual size=%d", expectedSize, dataReceived.size())); return kError; } if (CLOG->getFilter() >= kDEBUG2) { LOG((CLOG_DEBUG2 "file transfer finished")); elapsedTime += stopwatch.getTime(); double averageSpeed = expectedSize / elapsedTime / 1000; LOG((CLOG_DEBUG2 "file transfer finished: total time consumed=%f s", elapsedTime)); LOG((CLOG_DEBUG2 "file transfer finished: total data received=%i kb", expectedSize / 1000)); LOG((CLOG_DEBUG2 "file transfer finished: total average speed=%f kb/s", averageSpeed)); } return kFinish; } return kError; } void FileChunk::send(synergy::IStream* stream, UInt8 mark, char* data, size_t dataSize) { String chunk(data, dataSize); switch (mark) { case kDataStart: LOG((CLOG_DEBUG2 "sending file chunk start: size=%s", data)); break; case kDataChunk: LOG((CLOG_DEBUG2 "sending file chunk: size=%i", chunk.size())); break; case kDataEnd: LOG((CLOG_DEBUG2 "sending file finished")); break; } ProtocolUtil::writef(stream, kMsgDFileTransfer, mark, &chunk); } synergy-1.8.8-stable/src/lib/synergy/FileChunk.h000066400000000000000000000024131305627404700215660ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/Chunk.h" #include "base/String.h" #include "common/basic_types.h" #define FILE_CHUNK_META_SIZE 2 namespace synergy { class IStream; }; class FileChunk : public Chunk { public: FileChunk(size_t size); static FileChunk* start(const String& size); static FileChunk* data(UInt8* data, size_t dataSize); static FileChunk* end(); static int assemble( synergy::IStream* stream, String& dataCached, size_t& expectedSize); static void send( synergy::IStream* stream, UInt8 mark, char* data, size_t dataSize); }; synergy-1.8.8-stable/src/lib/synergy/IApp.h000066400000000000000000000031351305627404700205510ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" typedef int (*StartupFunc)(int, char**); class ILogOutputter; class ArgsBase; class IArchTaskBarReceiver; namespace synergy { class Screen; } class IEventQueue; class IApp : public IInterface { public: virtual void setByeFunc(void(*bye)(int)) = 0; virtual ArgsBase& argsBase() const = 0; virtual int standardStartup(int argc, char** argv) = 0; virtual int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) = 0; virtual void startNode() = 0; virtual IArchTaskBarReceiver* taskBarReceiver() const = 0; virtual void bye(int error) = 0; virtual int mainLoop() = 0; virtual void initApp(int argc, const char** argv) = 0; virtual const char* daemonName() const = 0; virtual int foregroundStartup(int argc, char** argv) = 0; virtual synergy::Screen* createScreen() = 0; virtual IEventQueue* getEvents() const = 0; }; synergy-1.8.8-stable/src/lib/synergy/IAppUtil.h000066400000000000000000000020131305627404700214010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" #include "synergy/IApp.h" class IAppUtil : public IInterface { public: virtual void adoptApp(IApp* app) = 0; virtual IApp& app() const = 0; virtual int run(int argc, char** argv) = 0; virtual void beforeAppExit() = 0; virtual void startNode() = 0; }; synergy-1.8.8-stable/src/lib/synergy/IClient.h000066400000000000000000000123331305627404700212470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/clipboard_types.h" #include "synergy/IScreen.h" #include "synergy/key_types.h" #include "synergy/mouse_types.h" #include "synergy/option_types.h" #include "base/String.h" //! Client interface /*! This interface defines the methods necessary for the server to communicate with a client. */ class IClient : public IScreen { public: //! @name manipulators //@{ //! Enter screen /*! Enter the screen. The cursor should be warped to \p xAbs,yAbs. \p mask is the expected toggle button state and the client should update its state to match. \p forScreensaver is true iff the screen is being entered because the screen saver is starting. Subsequent clipboard events should report \p seqNum. */ virtual void enter(SInt32 xAbs, SInt32 yAbs, UInt32 seqNum, KeyModifierMask mask, bool forScreensaver) = 0; //! Leave screen /*! Leave the screen. Return false iff the user may not leave the client's screen (because, for example, a button is down). */ virtual bool leave() = 0; //! Set clipboard /*! Update the client's clipboard. This implies that the client's clipboard is now up to date. If the client's clipboard was already known to be up to date then this may do nothing. \c data has marshalled clipboard data. */ virtual void setClipboard(ClipboardID, const IClipboard*) = 0; //! Grab clipboard /*! Grab (i.e. take ownership of) the client's clipboard. Since this is called when another client takes ownership of the clipboard it implies that the client's clipboard is out of date. */ virtual void grabClipboard(ClipboardID) = 0; //! Mark clipboard dirty /*! Mark the client's clipboard as dirty (out of date) or clean (up to date). */ virtual void setClipboardDirty(ClipboardID, bool dirty) = 0; //! Notify of key press /*! Synthesize key events to generate a press of key \c id. If possible match the given modifier mask. The KeyButton identifies the physical key on the server that generated this key down. The client must ensure that a key up or key repeat that uses the same KeyButton will synthesize an up or repeat for the same client key synthesized by keyDown(). */ virtual void keyDown(KeyID id, KeyModifierMask, KeyButton) = 0; //! Notify of key repeat /*! Synthesize key events to generate a press and release of key \c id \c count times. If possible match the given modifier mask. */ virtual void keyRepeat(KeyID id, KeyModifierMask, SInt32 count, KeyButton) = 0; //! Notify of key release /*! Synthesize key events to generate a release of key \c id. If possible match the given modifier mask. */ virtual void keyUp(KeyID id, KeyModifierMask, KeyButton) = 0; //! Notify of mouse press /*! Synthesize mouse events to generate a press of mouse button \c id. */ virtual void mouseDown(ButtonID id) = 0; //! Notify of mouse release /*! Synthesize mouse events to generate a release of mouse button \c id. */ virtual void mouseUp(ButtonID id) = 0; //! Notify of mouse motion /*! Synthesize mouse events to generate mouse motion to the absolute screen position \c xAbs,yAbs. */ virtual void mouseMove(SInt32 xAbs, SInt32 yAbs) = 0; //! Notify of mouse motion /*! Synthesize mouse events to generate mouse motion by the relative amount \c xRel,yRel. */ virtual void mouseRelativeMove(SInt32 xRel, SInt32 yRel) = 0; //! Notify of mouse wheel motion /*! Synthesize mouse events to generate mouse wheel motion of \c xDelta and \c yDelta. Deltas are positive for motion away from the user or to the right and negative for motion towards the user or to the left. Each wheel click should generate a delta of +/-120. */ virtual void mouseWheel(SInt32 xDelta, SInt32 yDelta) = 0; //! Notify of screen saver change virtual void screensaver(bool activate) = 0; //! Notify of options changes /*! Reset all options to their default values. */ virtual void resetOptions() = 0; //! Notify of options changes /*! Set options to given values. Ignore unknown options and don't modify our options that aren't given in \c options. */ virtual void setOptions(const OptionsList& options) = 0; //@} //! @name accessors //@{ //! Get client name /*! Return the client's name. */ virtual String getName() const = 0; //@} // IScreen overrides virtual void* getEventTarget() const = 0; virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const = 0; virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; }; synergy-1.8.8-stable/src/lib/synergy/IClipboard.cpp000066400000000000000000000102421305627404700222600ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/IClipboard.h" #include "common/stdvector.h" // // IClipboard // void IClipboard::unmarshall(IClipboard* clipboard, const String& data, Time time) { assert(clipboard != NULL); const char* index = data.data(); if (clipboard->open(time)) { // clear existing data clipboard->empty(); // read the number of formats const UInt32 numFormats = readUInt32(index); index += 4; // read each format for (UInt32 i = 0; i < numFormats; ++i) { // get the format id IClipboard::EFormat format = static_cast(readUInt32(index)); index += 4; // get the size of the format data UInt32 size = readUInt32(index); index += 4; // save the data if it's a known format. if either the client // or server supports more clipboard formats than the other // then one of them will get a format >= kNumFormats here. if (format add(format, String(index, size)); } index += size; } // done clipboard->close(); } } String IClipboard::marshall(const IClipboard* clipboard) { // return data format: // 4 bytes => number of formats included // 4 bytes => format enum // 4 bytes => clipboard data size n // n bytes => clipboard data // back to the second 4 bytes if there is another format assert(clipboard != NULL); String data; std::vector formatData; formatData.resize(IClipboard::kNumFormats); // FIXME -- use current time if (clipboard->open(0)) { // compute size of marshalled data UInt32 size = 4; UInt32 numFormats = 0; for (UInt32 format = 0; format != IClipboard::kNumFormats; ++format) { if (clipboard->has(static_cast(format))) { ++numFormats; formatData[format] = clipboard->get(static_cast(format)); size += 4 + 4 + (UInt32)formatData[format].size(); } } // allocate space data.reserve(size); // marshall the data writeUInt32(&data, numFormats); for (UInt32 format = 0; format != IClipboard::kNumFormats; ++format) { if (clipboard->has(static_cast(format))) { writeUInt32(&data, format); writeUInt32(&data, (UInt32)formatData[format].size()); data += formatData[format]; } } clipboard->close(); } return data; } bool IClipboard::copy(IClipboard* dst, const IClipboard* src) { assert(dst != NULL); assert(src != NULL); return copy(dst, src, src->getTime()); } bool IClipboard::copy(IClipboard* dst, const IClipboard* src, Time time) { assert(dst != NULL); assert(src != NULL); bool success = false; if (src->open(time)) { if (dst->open(time)) { if (dst->empty()) { for (SInt32 format = 0; format != IClipboard::kNumFormats; ++format) { IClipboard::EFormat eFormat = (IClipboard::EFormat)format; if (src->has(eFormat)) { dst->add(eFormat, src->get(eFormat)); } } success = true; } dst->close(); } src->close(); } return success; } UInt32 IClipboard::readUInt32(const char* buf) { const unsigned char* ubuf = reinterpret_cast(buf); return (static_cast(ubuf[0]) << 24) | (static_cast(ubuf[1]) << 16) | (static_cast(ubuf[2]) << 8) | static_cast(ubuf[3]); } void IClipboard::writeUInt32(String* buf, UInt32 v) { *buf += static_cast((v >> 24) & 0xff); *buf += static_cast((v >> 16) & 0xff); *buf += static_cast((v >> 8) & 0xff); *buf += static_cast( v & 0xff); } synergy-1.8.8-stable/src/lib/synergy/IClipboard.h000066400000000000000000000121561305627404700217330ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" #include "base/EventTypes.h" #include "common/IInterface.h" //! Clipboard interface /*! This interface defines the methods common to all clipboards. */ class IClipboard : public IInterface { public: //! Timestamp type /*! Timestamp type. Timestamps are in milliseconds from some arbitrary starting time. Timestamps will wrap around to 0 after about 49 3/4 days. */ typedef UInt32 Time; //! Clipboard formats /*! The list of known clipboard formats. kNumFormats must be last and formats must be sequential starting from zero. Clipboard data set via add() and retrieved via get() must be in one of these formats. Platform dependent clipboard subclasses can and should present any suitable formats derivable from these formats. \c kText is a text format encoded in UTF-8. Newlines are LF (not CR or LF/CR). \c kBitmap is an image format. The data is a BMP file without the 14 byte header (i.e. starting at the INFOHEADER) and with the image data immediately following the 40 byte INFOHEADER. \c kHTML is a text format encoded in UTF-8 and containing a valid HTML fragment (but not necessarily a complete HTML document). Newlines are LF. */ enum EFormat { kText, //!< Text format, UTF-8, newline is LF kHTML, //!< HTML format, HTML fragment, UTF-8, newline is LF kBitmap, //!< Bitmap format, BMP 24/32bpp, BI_RGB kNumFormats //!< The number of clipboard formats }; //! @name manipulators //@{ //! Empty clipboard /*! Take ownership of the clipboard and clear all data from it. This must be called between a successful open() and close(). Return false if the clipboard ownership could not be taken; the clipboard should not be emptied in this case. */ virtual bool empty() = 0; //! Add data /*! Add data in the given format to the clipboard. May only be called after a successful empty(). */ virtual void add(EFormat, const String& data) = 0; //@} //! @name accessors //@{ //! Open clipboard /*! Open the clipboard. Return true iff the clipboard could be opened. If open() returns true then the client must call close() at some later time; if it returns false then close() must not be called. \c time should be the current time or a time in the past when the open should effectively have taken place. */ virtual bool open(Time time) const = 0; //! Close clipboard /*! Close the clipboard. close() must match a preceding successful open(). This signals that the clipboard has been filled with all the necessary data or all data has been read. It does not mean the clipboard ownership should be released (if it was taken). */ virtual void close() const = 0; //! Get time /*! Return the timestamp passed to the last successful open(). */ virtual Time getTime() const = 0; //! Check for data /*! Return true iff the clipboard contains data in the given format. Must be called between a successful open() and close(). */ virtual bool has(EFormat) const = 0; //! Get data /*! Return the data in the given format. Returns the empty string if there is no data in that format. Must be called between a successful open() and close(). */ virtual String get(EFormat) const = 0; //! Marshall clipboard data /*! Merge \p clipboard's data into a single buffer that can be later unmarshalled to restore the clipboard and return the buffer. */ static String marshall(const IClipboard* clipboard); //! Unmarshall clipboard data /*! Extract marshalled clipboard data and store it in \p clipboard. Sets the clipboard time to \c time. */ static void unmarshall(IClipboard* clipboard, const String& data, Time time); //! Copy clipboard /*! Transfers all the data in one clipboard to another. The clipboards can be of any concrete clipboard type (and they don't have to be the same type). This also sets the destination clipboard's timestamp to source clipboard's timestamp. Returns true iff the copy succeeded. */ static bool copy(IClipboard* dst, const IClipboard* src); //! Copy clipboard /*! Transfers all the data in one clipboard to another. The clipboards can be of any concrete clipboard type (and they don't have to be the same type). This also sets the timestamp to \c time. Returns true iff the copy succeeded. */ static bool copy(IClipboard* dst, const IClipboard* src, Time); //@} private: static UInt32 readUInt32(const char*); static void writeUInt32(String*, UInt32); }; synergy-1.8.8-stable/src/lib/synergy/IKeyState.cpp000066400000000000000000000073621305627404700221230ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/IKeyState.h" #include "base/EventQueue.h" #include #include // // IKeyState // IKeyState::IKeyState(IEventQueue* events) { } // // IKeyState::KeyInfo // IKeyState::KeyInfo* IKeyState::KeyInfo::alloc(KeyID id, KeyModifierMask mask, KeyButton button, SInt32 count) { KeyInfo* info = (KeyInfo*)malloc(sizeof(KeyInfo)); info->m_key = id; info->m_mask = mask; info->m_button = button; info->m_count = count; info->m_screens = NULL; info->m_screensBuffer[0] = '\0'; return info; } IKeyState::KeyInfo* IKeyState::KeyInfo::alloc(KeyID id, KeyModifierMask mask, KeyButton button, SInt32 count, const std::set& destinations) { String screens = join(destinations); // build structure KeyInfo* info = (KeyInfo*)malloc(sizeof(KeyInfo) + screens.size()); info->m_key = id; info->m_mask = mask; info->m_button = button; info->m_count = count; info->m_screens = info->m_screensBuffer; strcpy(info->m_screensBuffer, screens.c_str()); return info; } IKeyState::KeyInfo* IKeyState::KeyInfo::alloc(const KeyInfo& x) { KeyInfo* info = (KeyInfo*)malloc(sizeof(KeyInfo) + strlen(x.m_screensBuffer)); info->m_key = x.m_key; info->m_mask = x.m_mask; info->m_button = x.m_button; info->m_count = x.m_count; info->m_screens = x.m_screens ? info->m_screensBuffer : NULL; strcpy(info->m_screensBuffer, x.m_screensBuffer); return info; } bool IKeyState::KeyInfo::isDefault(const char* screens) { return (screens == NULL || screens[0] == '\0'); } bool IKeyState::KeyInfo::contains(const char* screens, const String& name) { // special cases if (isDefault(screens)) { return false; } if (screens[0] == '*') { return true; } // search String match; match.reserve(name.size() + 2); match += ":"; match += name; match += ":"; return (strstr(screens, match.c_str()) != NULL); } bool IKeyState::KeyInfo::equal(const KeyInfo* a, const KeyInfo* b) { return (a->m_key == b->m_key && a->m_mask == b->m_mask && a->m_button == b->m_button && a->m_count == b->m_count && strcmp(a->m_screensBuffer, b->m_screensBuffer) == 0); } String IKeyState::KeyInfo::join(const std::set& destinations) { // collect destinations into a string. names are surrounded by ':' // which makes searching easy. the string is empty if there are no // destinations and "*" means all destinations. String screens; for (std::set::const_iterator i = destinations.begin(); i != destinations.end(); ++i) { if (*i == "*") { screens = "*"; break; } else { if (screens.empty()) { screens = ":"; } screens += *i; screens += ":"; } } return screens; } void IKeyState::KeyInfo::split(const char* screens, std::set& dst) { dst.clear(); if (isDefault(screens)) { return; } if (screens[0] == '*') { dst.insert("*"); return; } const char* i = screens + 1; while (*i != '\0') { const char* j = strchr(i, ':'); dst.insert(String(i, j - i)); i = j + 1; } } synergy-1.8.8-stable/src/lib/synergy/IKeyState.h000066400000000000000000000110241305627404700215560ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/key_types.h" #include "base/Event.h" #include "base/String.h" #include "base/IEventQueue.h" #include "base/EventTypes.h" #include "common/stdset.h" #include "common/IInterface.h" //! Key state interface /*! This interface provides access to set and query the keyboard state and to synthesize key events. */ class IKeyState : public IInterface { public: IKeyState(IEventQueue* events); enum { kNumButtons = 0x200 }; //! Key event data class KeyInfo { public: static KeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count); static KeyInfo* alloc(KeyID, KeyModifierMask, KeyButton, SInt32 count, const std::set& destinations); static KeyInfo* alloc(const KeyInfo&); static bool isDefault(const char* screens); static bool contains(const char* screens, const String& name); static bool equal(const KeyInfo*, const KeyInfo*); static String join(const std::set& destinations); static void split(const char* screens, std::set&); public: KeyID m_key; KeyModifierMask m_mask; KeyButton m_button; SInt32 m_count; char* m_screens; char m_screensBuffer[1]; }; typedef std::set KeyButtonSet; //! @name manipulators //@{ //! Update the keyboard map /*! Causes the key state to get updated to reflect the current keyboard mapping. */ virtual void updateKeyMap() = 0; //! Update the key state /*! Causes the key state to get updated to reflect the physical keyboard state. */ virtual void updateKeyState() = 0; //! Set half-duplex mask /*! Sets which modifier toggle keys are half-duplex. A half-duplex toggle key doesn't report a key release when toggled on and doesn't report a key press when toggled off. */ virtual void setHalfDuplexMask(KeyModifierMask) = 0; //! Fake a key press /*! Synthesizes a key press event and updates the key state. */ virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button) = 0; //! Fake a key repeat /*! Synthesizes a key repeat event and updates the key state. */ virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) = 0; //! Fake a key release /*! Synthesizes a key release event and updates the key state. */ virtual bool fakeKeyUp(KeyButton button) = 0; //! Fake key releases for all fake pressed keys /*! Synthesizes a key release event for every key that is synthetically pressed and updates the key state. */ virtual void fakeAllKeysUp() = 0; //! Fake ctrl+alt+del /*! Synthesize a press of ctrl+alt+del. Return true if processing is complete and false if normal key processing should continue. */ virtual bool fakeCtrlAltDel() = 0; //! Fake a media key /*! Synthesizes a media key down and up. Only Mac would implement this by use cocoa appkit framework. */ virtual bool fakeMediaKey(KeyID id) = 0; //@} //! @name accessors //@{ //! Test if key is pressed /*! Returns true iff the given key is down. Half-duplex toggles always return false. */ virtual bool isKeyDown(KeyButton) const = 0; //! Get the active modifiers /*! Returns the modifiers that are currently active according to our shadowed state. */ virtual KeyModifierMask getActiveModifiers() const = 0; //! Get the active modifiers from OS /*! Returns the modifiers that are currently active according to the operating system. */ virtual KeyModifierMask pollActiveModifiers() const = 0; //! Get the active keyboard layout from OS /*! Returns the active keyboard layout according to the operating system. */ virtual SInt32 pollActiveGroup() const = 0; //! Get the keys currently pressed from OS /*! Adds any keys that are currently pressed according to the operating system to \p pressedKeys. */ virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0; //@} }; synergy-1.8.8-stable/src/lib/synergy/INode.h000066400000000000000000000014521305627404700207160ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/IInterface.h" class INode : IInterface { }; synergy-1.8.8-stable/src/lib/synergy/IPlatformScreen.cpp000066400000000000000000000014221305627404700233050ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless. * * 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/IPlatformScreen.h" bool IPlatformScreen::fakeMediaKey(KeyID id) { return false; } synergy-1.8.8-stable/src/lib/synergy/IPlatformScreen.h000066400000000000000000000161261305627404700227610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/DragInformation.h" #include "synergy/clipboard_types.h" #include "synergy/IScreen.h" #include "synergy/IPrimaryScreen.h" #include "synergy/ISecondaryScreen.h" #include "synergy/IKeyState.h" #include "synergy/option_types.h" class IClipboard; //! Screen interface /*! This interface defines the methods common to all platform dependent screen implementations that are used by both primary and secondary screens. */ class IPlatformScreen : public IScreen, public IPrimaryScreen, public ISecondaryScreen, public IKeyState { public: //! @name manipulators //@{ IPlatformScreen(IEventQueue* events) : IKeyState(events) { } //! Enable screen /*! Enable the screen, preparing it to report system and user events. For a secondary screen it also means preparing to synthesize events and hiding the cursor. */ virtual void enable() = 0; //! Disable screen /*! Undoes the operations in enable() and events should no longer be reported. */ virtual void disable() = 0; //! Enter screen /*! Called when the user navigates to this screen. */ virtual void enter() = 0; //! Leave screen /*! Called when the user navigates off the screen. Returns true on success, false on failure. A typical reason for failure is being unable to install the keyboard and mouse snoopers on a primary screen. Secondary screens should not fail. */ virtual bool leave() = 0; //! Set clipboard /*! Set the contents of the system clipboard indicated by \c id. */ virtual bool setClipboard(ClipboardID id, const IClipboard*) = 0; //! Check clipboard owner /*! Check ownership of all clipboards and post grab events for any that have changed. This is used as a backup in case the system doesn't reliably report clipboard ownership changes. */ virtual void checkClipboards() = 0; //! Open screen saver /*! Open the screen saver. If \c notify is true then this object must send events when the screen saver activates or deactivates until \c closeScreensaver() is called. If \c notify is false then the screen saver is disabled and restored on \c closeScreensaver(). */ virtual void openScreensaver(bool notify) = 0; //! Close screen saver /*! // Close the screen saver. Stop reporting screen saver activation and deactivation and, if the screen saver was disabled by openScreensaver(), enable the screen saver. */ virtual void closeScreensaver() = 0; //! Activate/deactivate screen saver /*! Forcibly activate the screen saver if \c activate is true otherwise forcibly deactivate it. */ virtual void screensaver(bool activate) = 0; //! Notify of options changes /*! Reset all options to their default values. */ virtual void resetOptions() = 0; //! Notify of options changes /*! Set options to given values. Ignore unknown options and don't modify options that aren't given in \c options. */ virtual void setOptions(const OptionsList& options) = 0; //! Set clipboard sequence number /*! Sets the sequence number to use in subsequent clipboard events. */ virtual void setSequenceNumber(UInt32) = 0; //! Change dragging status virtual void setDraggingStarted(bool started) = 0; //@} //! @name accessors //@{ //! Test if is primary screen /*! Return true iff this screen is a primary screen. */ virtual bool isPrimary() const = 0; //@} // IScreen overrides virtual void* getEventTarget() const = 0; virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const = 0; virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; // IPrimaryScreen overrides virtual void reconfigure(UInt32 activeSides) = 0; virtual void warpCursor(SInt32 x, SInt32 y) = 0; virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; virtual void unregisterHotKey(UInt32 id) = 0; virtual void fakeInputBegin() = 0; virtual void fakeInputEnd() = 0; virtual SInt32 getJumpZoneSize() const = 0; virtual bool isAnyMouseButtonDown(UInt32& buttonID) const = 0; virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; // ISecondaryScreen overrides virtual void fakeMouseButton(ButtonID id, bool press) = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; // IKeyState overrides virtual void updateKeyMap() = 0; virtual void updateKeyState() = 0; virtual void setHalfDuplexMask(KeyModifierMask) = 0; virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button) = 0; virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) = 0; virtual bool fakeKeyUp(KeyButton button) = 0; virtual void fakeAllKeysUp() = 0; virtual bool fakeCtrlAltDel() = 0; virtual bool fakeMediaKey(KeyID id); virtual bool isKeyDown(KeyButton) const = 0; virtual KeyModifierMask getActiveModifiers() const = 0; virtual KeyModifierMask pollActiveModifiers() const = 0; virtual SInt32 pollActiveGroup() const = 0; virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0; virtual String& getDraggingFilename() = 0; virtual void clearDraggingFilename() = 0; virtual bool isDraggingStarted() = 0; virtual bool isFakeDraggingStarted() = 0; virtual void fakeDraggingFiles(DragFileList fileList) = 0; virtual const String& getDropTarget() const = 0; protected: //! Handle system event /*! A platform screen is expected to install a handler for system events in its c'tor like so: \code m_events->adoptHandler(Event::kSystem, m_events->getSystemTarget(), new TMethodEventJob(this, &CXXXPlatformScreen::handleSystemEvent)); \endcode It should remove the handler in its d'tor. Override the \c handleSystemEvent() method to process system events. It should post the events \c IScreen as appropriate. A primary screen has further responsibilities. It should post the events in \c IPrimaryScreen as appropriate. It should also call \c onKey() on its \c KeyState whenever a key is pressed or released (but not for key repeats). And it should call \c updateKeyMap() on its \c KeyState if necessary when the keyboard mapping changes. The target of all events should be the value returned by \c getEventTarget(). */ virtual void handleSystemEvent(const Event& event, void*) = 0; }; synergy-1.8.8-stable/src/lib/synergy/IPrimaryScreen.cpp000066400000000000000000000041411305627404700231450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/IPrimaryScreen.h" #include "base/EventQueue.h" #include // // IPrimaryScreen::ButtonInfo // IPrimaryScreen::ButtonInfo* IPrimaryScreen::ButtonInfo::alloc(ButtonID id, KeyModifierMask mask) { ButtonInfo* info = (ButtonInfo*)malloc(sizeof(ButtonInfo)); info->m_button = id; info->m_mask = mask; return info; } IPrimaryScreen::ButtonInfo* IPrimaryScreen::ButtonInfo::alloc(const ButtonInfo& x) { ButtonInfo* info = (ButtonInfo*)malloc(sizeof(ButtonInfo)); info->m_button = x.m_button; info->m_mask = x.m_mask; return info; } bool IPrimaryScreen::ButtonInfo::equal(const ButtonInfo* a, const ButtonInfo* b) { return (a->m_button == b->m_button && a->m_mask == b->m_mask); } // // IPrimaryScreen::MotionInfo // IPrimaryScreen::MotionInfo* IPrimaryScreen::MotionInfo::alloc(SInt32 x, SInt32 y) { MotionInfo* info = (MotionInfo*)malloc(sizeof(MotionInfo)); info->m_x = x; info->m_y = y; return info; } // // IPrimaryScreen::WheelInfo // IPrimaryScreen::WheelInfo* IPrimaryScreen::WheelInfo::alloc(SInt32 xDelta, SInt32 yDelta) { WheelInfo* info = (WheelInfo*)malloc(sizeof(WheelInfo)); info->m_xDelta = xDelta; info->m_yDelta = yDelta; return info; } // // IPrimaryScreen::HotKeyInfo // IPrimaryScreen::HotKeyInfo* IPrimaryScreen::HotKeyInfo::alloc(UInt32 id) { HotKeyInfo* info = (HotKeyInfo*)malloc(sizeof(HotKeyInfo)); info->m_id = id; return info; } synergy-1.8.8-stable/src/lib/synergy/IPrimaryScreen.h000066400000000000000000000114641305627404700226200ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/key_types.h" #include "synergy/mouse_types.h" #include "base/Event.h" #include "base/EventTypes.h" #include "common/IInterface.h" //! Primary screen interface /*! This interface defines the methods common to all platform dependent primary screen implementations. */ class IPrimaryScreen : public IInterface { public: //! Button event data class ButtonInfo { public: static ButtonInfo* alloc(ButtonID, KeyModifierMask); static ButtonInfo* alloc(const ButtonInfo&); static bool equal(const ButtonInfo*, const ButtonInfo*); public: ButtonID m_button; KeyModifierMask m_mask; }; //! Motion event data class MotionInfo { public: static MotionInfo* alloc(SInt32 x, SInt32 y); public: SInt32 m_x; SInt32 m_y; }; //! Wheel motion event data class WheelInfo { public: static WheelInfo* alloc(SInt32 xDelta, SInt32 yDelta); public: SInt32 m_xDelta; SInt32 m_yDelta; }; //! Hot key event data class HotKeyInfo { public: static HotKeyInfo* alloc(UInt32 id); public: UInt32 m_id; }; //! @name manipulators //@{ //! Update configuration /*! This is called when the configuration has changed. \c activeSides is a bitmask of EDirectionMask indicating which sides of the primary screen are linked to clients. Override to handle the possible change in jump zones. */ virtual void reconfigure(UInt32 activeSides) = 0; //! Warp cursor /*! Warp the cursor to the absolute coordinates \c x,y. Also discard input events up to and including the warp before returning. */ virtual void warpCursor(SInt32 x, SInt32 y) = 0; //! Register a system hotkey /*! Registers a system-wide hotkey. The screen should arrange for an event to be delivered to itself when the hot key is pressed or released. When that happens the screen should post a \c getHotKeyDownEvent() or \c getHotKeyUpEvent(), respectively. The hot key is key \p key with exactly the modifiers \p mask. Returns 0 on failure otherwise an id that can be used to unregister the hotkey. A hot key is a set of modifiers and a key, which may itself be a modifier. The hot key is pressed when the hot key's modifiers and only those modifiers are logically down (active) and the key is pressed. The hot key is released when the key is released, regardless of the modifiers. The hot key event should be generated no matter what window or application has the focus. No other window or application should receive the key press or release events (they can and should see the modifier key events). When the key is a modifier, it's acceptable to allow the user to press the modifiers in any order or to require the user to press the given key last. */ virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; //! Unregister a system hotkey /*! Unregisters a previously registered hot key. */ virtual void unregisterHotKey(UInt32 id) = 0; //! Prepare to synthesize input on primary screen /*! Prepares the primary screen to receive synthesized input. We do not want to receive this synthesized input as user input so this method ensures that we ignore it. Calls to \c fakeInputBegin() may not be nested. */ virtual void fakeInputBegin() = 0; //! Done synthesizing input on primary screen /*! Undoes whatever \c fakeInputBegin() did. */ virtual void fakeInputEnd() = 0; //@} //! @name accessors //@{ //! Get jump zone size /*! Return the jump zone size, the size of the regions on the edges of the screen that cause the cursor to jump to another screen. */ virtual SInt32 getJumpZoneSize() const = 0; //! Test if mouse is pressed /*! Return true if any mouse button is currently pressed. Ideally, "current" means up to the last processed event but it can mean the current physical mouse button state. */ virtual bool isAnyMouseButtonDown(UInt32& buttonID) const = 0; //! Get cursor center position /*! Return the cursor center position which is where we park the cursor to compute cursor motion deltas and should be far from the edges of the screen, typically the center. */ virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; //@} }; synergy-1.8.8-stable/src/lib/synergy/IScreen.h000066400000000000000000000035301305627404700212470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/clipboard_types.h" #include "base/Event.h" #include "base/EventTypes.h" #include "common/IInterface.h" class IClipboard; //! Screen interface /*! This interface defines the methods common to all screens. */ class IScreen : public IInterface { public: struct ClipboardInfo { public: ClipboardID m_id; UInt32 m_sequenceNumber; }; //! @name accessors //@{ //! Get event target /*! Returns the target used for events created by this object. */ virtual void* getEventTarget() const = 0; //! Get clipboard /*! Save the contents of the clipboard indicated by \c id and return true iff successful. */ virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; //! Get screen shape /*! Return the position of the upper-left corner of the screen in \c x and \c y and the size of the screen in \c width and \c height. */ virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const = 0; //! Get cursor position /*! Return the current position of the cursor in \c x and \c y. */ virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; //@} }; synergy-1.8.8-stable/src/lib/synergy/IScreenSaver.h000066400000000000000000000036171305627404700222560ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/Event.h" #include "common/IInterface.h" //! Screen saver interface /*! This interface defines the methods common to all screen savers. */ class IScreenSaver : public IInterface { public: // note -- the c'tor/d'tor must *not* enable/disable the screen saver //! @name manipulators //@{ //! Enable screen saver /*! Enable the screen saver, restoring the screen saver settings to what they were when disable() was previously called. If disable() wasn't previously called then it should keep the current settings or use reasonable defaults. */ virtual void enable() = 0; //! Disable screen saver /*! Disable the screen saver, saving the old settings for the next call to enable(). */ virtual void disable() = 0; //! Activate screen saver /*! Activate (i.e. show) the screen saver. */ virtual void activate() = 0; //! Deactivate screen saver /*! Deactivate (i.e. hide) the screen saver, reseting the screen saver timer. */ virtual void deactivate() = 0; //@} //! @name accessors //@{ //! Test if screen saver on /*! Returns true iff the screen saver is currently active (showing). */ virtual bool isActive() const = 0; //@} }; synergy-1.8.8-stable/src/lib/synergy/ISecondaryScreen.h000066400000000000000000000033011305627404700231130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/mouse_types.h" #include "base/Event.h" #include "base/EventTypes.h" #include "common/IInterface.h" //! Secondary screen interface /*! This interface defines the methods common to all platform dependent secondary screen implementations. */ class ISecondaryScreen : public IInterface { public: //! @name accessors //@{ //! Fake mouse press/release /*! Synthesize a press or release of mouse button \c id. */ virtual void fakeMouseButton(ButtonID id, bool press) = 0; //! Fake mouse move /*! Synthesize a mouse move to the absolute coordinates \c x,y. */ virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0; //! Fake mouse move /*! Synthesize a mouse move to the relative coordinates \c dx,dy. */ virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; //! Fake mouse wheel /*! Synthesize a mouse wheel event of amount \c xDelta and \c yDelta. */ virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; //@} }; synergy-1.8.8-stable/src/lib/synergy/KeyMap.cpp000066400000000000000000001062301305627404700214410ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2005 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/KeyMap.h" #include "synergy/key_types.h" #include "base/Log.h" #include #include #include namespace synergy { KeyMap::NameToKeyMap* KeyMap::s_nameToKeyMap = NULL; KeyMap::NameToModifierMap* KeyMap::s_nameToModifierMap = NULL; KeyMap::KeyToNameMap* KeyMap::s_keyToNameMap = NULL; KeyMap::ModifierToNameMap* KeyMap::s_modifierToNameMap = NULL; KeyMap::KeyMap() : m_numGroups(0), m_composeAcrossGroups(false) { m_modifierKeyItem.m_id = kKeyNone; m_modifierKeyItem.m_group = 0; m_modifierKeyItem.m_button = 0; m_modifierKeyItem.m_required = 0; m_modifierKeyItem.m_sensitive = 0; m_modifierKeyItem.m_generates = 0; m_modifierKeyItem.m_dead = false; m_modifierKeyItem.m_lock = false; m_modifierKeyItem.m_client = 0; } KeyMap::~KeyMap() { // do nothing } void KeyMap::swap(KeyMap& x) { m_keyIDMap.swap(x.m_keyIDMap); m_modifierKeys.swap(x.m_modifierKeys); m_halfDuplex.swap(x.m_halfDuplex); m_halfDuplexMods.swap(x.m_halfDuplexMods); SInt32 tmp1 = m_numGroups; m_numGroups = x.m_numGroups; x.m_numGroups = tmp1; bool tmp2 = m_composeAcrossGroups; m_composeAcrossGroups = x.m_composeAcrossGroups; x.m_composeAcrossGroups = tmp2; } void KeyMap::addKeyEntry(const KeyItem& item) { // ignore kKeyNone if (item.m_id == kKeyNone) { return; } // resize number of groups for key SInt32 numGroups = item.m_group + 1; if (getNumGroups() > numGroups) { numGroups = getNumGroups(); } KeyGroupTable& groupTable = m_keyIDMap[item.m_id]; if (groupTable.size() < static_cast(numGroups)) { groupTable.resize(numGroups); } // make a list from the item KeyItemList items; items.push_back(item); // set group and dead key flag on the item KeyItem& newItem = items.back(); newItem.m_dead = isDeadKey(item.m_id); // mask the required bits with the sensitive bits newItem.m_required &= newItem.m_sensitive; // see if we already have this item; just return if so KeyEntryList& entries = groupTable[item.m_group]; for (size_t i = 0, n = entries.size(); i < n; ++i) { if (entries[i].size() == 1 && newItem == entries[i][0]) { return; } } // add item list entries.push_back(items); LOG((CLOG_DEBUG5 "add key: %04x %d %03x %04x (%04x %04x %04x)%s", newItem.m_id, newItem.m_group, newItem.m_button, newItem.m_client, newItem.m_required, newItem.m_sensitive, newItem.m_generates, newItem.m_dead ? " dead" : "")); } void KeyMap::addKeyAliasEntry(KeyID targetID, SInt32 group, KeyModifierMask targetRequired, KeyModifierMask targetSensitive, KeyID sourceID, KeyModifierMask sourceRequired, KeyModifierMask sourceSensitive) { // if we can already generate the target as desired then we're done. if (findCompatibleKey(targetID, group, targetRequired, targetSensitive) != NULL) { return; } // find a compatible source, preferably in the same group for (SInt32 gd = 0, n = getNumGroups(); gd < n; ++gd) { SInt32 eg = getEffectiveGroup(group, gd); const KeyItemList* sourceEntry = findCompatibleKey(sourceID, eg, sourceRequired, sourceSensitive); if (sourceEntry != NULL && sourceEntry->size() == 1) { KeyMap::KeyItem targetItem = sourceEntry->back(); targetItem.m_id = targetID; targetItem.m_group = eg; addKeyEntry(targetItem); break; } } } bool KeyMap::addKeyCombinationEntry(KeyID id, SInt32 group, const KeyID* keys, UInt32 numKeys) { // disallow kKeyNone if (id == kKeyNone) { return false; } SInt32 numGroups = group + 1; if (getNumGroups() > numGroups) { numGroups = getNumGroups(); } KeyGroupTable& groupTable = m_keyIDMap[id]; if (groupTable.size() < static_cast(numGroups)) { groupTable.resize(numGroups); } if (!groupTable[group].empty()) { // key is already in the table return false; } // convert to buttons KeyItemList items; for (UInt32 i = 0; i < numKeys; ++i) { KeyIDMap::const_iterator gtIndex = m_keyIDMap.find(keys[i]); if (gtIndex == m_keyIDMap.end()) { return false; } const KeyGroupTable& groupTable = gtIndex->second; // if we allow group switching during composition then search all // groups for keys, otherwise search just the given group. SInt32 n = 1; if (m_composeAcrossGroups) { n = (SInt32)groupTable.size(); } bool found = false; for (SInt32 gd = 0; gd < n && !found; ++gd) { SInt32 eg = (group + gd) % getNumGroups(); const KeyEntryList& entries = groupTable[eg]; for (size_t j = 0; j < entries.size(); ++j) { if (entries[j].size() == 1) { found = true; items.push_back(entries[j][0]); break; } } } if (!found) { // required key is not in keyboard group return false; } } // add key groupTable[group].push_back(items); return true; } void KeyMap::allowGroupSwitchDuringCompose() { m_composeAcrossGroups = true; } void KeyMap::addHalfDuplexButton(KeyButton button) { m_halfDuplex.insert(button); } void KeyMap::clearHalfDuplexModifiers() { m_halfDuplexMods.clear(); } void KeyMap::addHalfDuplexModifier(KeyID key) { m_halfDuplexMods.insert(key); } void KeyMap::finish() { m_numGroups = findNumGroups(); // make sure every key has the same number of groups for (KeyIDMap::iterator i = m_keyIDMap.begin(); i != m_keyIDMap.end(); ++i) { i->second.resize(m_numGroups); } // compute keys that generate each modifier setModifierKeys(); } void KeyMap::foreachKey(ForeachKeyCallback cb, void* userData) { for (KeyIDMap::iterator i = m_keyIDMap.begin(); i != m_keyIDMap.end(); ++i) { KeyGroupTable& groupTable = i->second; for (size_t group = 0; group < groupTable.size(); ++group) { KeyEntryList& entryList = groupTable[group]; for (size_t j = 0; j < entryList.size(); ++j) { KeyItemList& itemList = entryList[j]; for (size_t k = 0; k < itemList.size(); ++k) { (*cb)(i->first, static_cast(group), itemList[k], userData); } } } } } const KeyMap::KeyItem* KeyMap::mapKey(Keystrokes& keys, KeyID id, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredMask, bool isAutoRepeat) const { LOG((CLOG_DEBUG1 "mapKey %04x (%d) with mask %04x, start state: %04x", id, id, desiredMask, currentState)); // handle group change if (id == kKeyNextGroup) { keys.push_back(Keystroke(1, false, false)); return NULL; } else if (id == kKeyPrevGroup) { keys.push_back(Keystroke(-1, false, false)); return NULL; } const KeyItem* item; switch (id) { case kKeyShift_L: case kKeyShift_R: case kKeyControl_L: case kKeyControl_R: case kKeyAlt_L: case kKeyAlt_R: case kKeyMeta_L: case kKeyMeta_R: case kKeySuper_L: case kKeySuper_R: case kKeyAltGr: case kKeyCapsLock: case kKeyNumLock: case kKeyScrollLock: item = mapModifierKey(keys, id, group, activeModifiers, currentState, desiredMask, isAutoRepeat); break; case kKeySetModifiers: if (!keysForModifierState(0, group, activeModifiers, currentState, desiredMask, desiredMask, 0, keys)) { LOG((CLOG_DEBUG1 "unable to set modifiers %04x", desiredMask)); return NULL; } return &m_modifierKeyItem; case kKeyClearModifiers: if (!keysForModifierState(0, group, activeModifiers, currentState, currentState & ~desiredMask, desiredMask, 0, keys)) { LOG((CLOG_DEBUG1 "unable to clear modifiers %04x", desiredMask)); return NULL; } return &m_modifierKeyItem; default: if (isCommand(desiredMask)) { item = mapCommandKey(keys, id, group, activeModifiers, currentState, desiredMask, isAutoRepeat); } else { item = mapCharacterKey(keys, id, group, activeModifiers, currentState, desiredMask, isAutoRepeat); } break; } if (item != NULL) { LOG((CLOG_DEBUG1 "mapped to %03x, new state %04x", item->m_button, currentState)); } return item; } SInt32 KeyMap::getNumGroups() const { return m_numGroups; } SInt32 KeyMap::getEffectiveGroup(SInt32 group, SInt32 offset) const { return (group + offset + getNumGroups()) % getNumGroups(); } const KeyMap::KeyItemList* KeyMap::findCompatibleKey(KeyID id, SInt32 group, KeyModifierMask required, KeyModifierMask sensitive) const { assert(group >= 0 && group < getNumGroups()); KeyIDMap::const_iterator i = m_keyIDMap.find(id); if (i == m_keyIDMap.end()) { return NULL; } const KeyEntryList& entries = i->second[group]; for (size_t j = 0; j < entries.size(); ++j) { if ((entries[j].back().m_sensitive & sensitive) == 0 || (entries[j].back().m_required & sensitive) == (required & sensitive)) { return &entries[j]; } } return NULL; } bool KeyMap::isHalfDuplex(KeyID key, KeyButton button) const { return (m_halfDuplex.count(button) + m_halfDuplexMods.count(key) > 0); } bool KeyMap::isCommand(KeyModifierMask mask) const { return ((mask & getCommandModifiers()) != 0); } KeyModifierMask KeyMap::getCommandModifiers() const { // we currently treat ctrl, alt, meta and super as command modifiers. // some platforms may have a more limited set (OS X only needs Alt) // but this works anyway. return KeyModifierControl | KeyModifierAlt | KeyModifierAltGr | KeyModifierMeta | KeyModifierSuper; } void KeyMap::collectButtons(const ModifierToKeys& mods, ButtonToKeyMap& keys) { keys.clear(); for (ModifierToKeys::const_iterator i = mods.begin(); i != mods.end(); ++i) { keys.insert(std::make_pair(i->second.m_button, &i->second)); } } void KeyMap::initModifierKey(KeyItem& item) { item.m_generates = 0; item.m_lock = false; switch (item.m_id) { case kKeyShift_L: case kKeyShift_R: item.m_generates = KeyModifierShift; break; case kKeyControl_L: case kKeyControl_R: item.m_generates = KeyModifierControl; break; case kKeyAlt_L: case kKeyAlt_R: item.m_generates = KeyModifierAlt; break; case kKeyMeta_L: case kKeyMeta_R: item.m_generates = KeyModifierMeta; break; case kKeySuper_L: case kKeySuper_R: item.m_generates = KeyModifierSuper; break; case kKeyAltGr: item.m_generates = KeyModifierAltGr; break; case kKeyCapsLock: item.m_generates = KeyModifierCapsLock; item.m_lock = true; break; case kKeyNumLock: item.m_generates = KeyModifierNumLock; item.m_lock = true; break; case kKeyScrollLock: item.m_generates = KeyModifierScrollLock; item.m_lock = true; break; default: // not a modifier break; } } SInt32 KeyMap::findNumGroups() const { size_t max = 0; for (KeyIDMap::const_iterator i = m_keyIDMap.begin(); i != m_keyIDMap.end(); ++i) { if (i->second.size() > max) { max = i->second.size(); } } return static_cast(max); } void KeyMap::setModifierKeys() { m_modifierKeys.clear(); m_modifierKeys.resize(kKeyModifierNumBits * getNumGroups()); for (KeyIDMap::const_iterator i = m_keyIDMap.begin(); i != m_keyIDMap.end(); ++i) { const KeyGroupTable& groupTable = i->second; for (size_t g = 0; g < groupTable.size(); ++g) { const KeyEntryList& entries = groupTable[g]; for (size_t j = 0; j < entries.size(); ++j) { // skip multi-key sequences if (entries[j].size() != 1) { continue; } // skip keys that don't generate a modifier const KeyItem& item = entries[j].back(); if (item.m_generates == 0) { continue; } // add key to each indicated modifier in this group for (SInt32 b = 0; b < kKeyModifierNumBits; ++b) { // skip if item doesn't generate bit b if (((1u << b) & item.m_generates) != 0) { SInt32 mIndex = (SInt32)g * kKeyModifierNumBits + b; m_modifierKeys[mIndex].push_back(&item); } } } } } } const KeyMap::KeyItem* KeyMap::mapCommandKey(Keystrokes& keys, KeyID id, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredMask, bool isAutoRepeat) const { static const KeyModifierMask s_overrideModifiers = 0xffffu; // find KeySym in table KeyIDMap::const_iterator i = m_keyIDMap.find(id); if (i == m_keyIDMap.end()) { // unknown key LOG((CLOG_DEBUG1 "key %04x is not on keyboard", id)); return NULL; } const KeyGroupTable& keyGroupTable = i->second; // find the first key that generates this KeyID const KeyItem* keyItem = NULL; SInt32 numGroups = getNumGroups(); for (SInt32 groupOffset = 0; groupOffset < numGroups; ++groupOffset) { SInt32 effectiveGroup = getEffectiveGroup(group, groupOffset); const KeyEntryList& entryList = keyGroupTable[effectiveGroup]; for (size_t i = 0; i < entryList.size(); ++i) { if (entryList[i].size() != 1) { // ignore multikey entries continue; } // match based on shift and make sure all required modifiers, // except shift, are already in the desired mask; we're // after the right button not the right character. // we'll use desiredMask as-is, overriding the key's required // modifiers, when synthesizing this button. const KeyItem& item = entryList[i].back(); KeyModifierMask desiredShiftMask = KeyModifierShift & desiredMask; KeyModifierMask requiredIgnoreShiftMask = item.m_required & ~KeyModifierShift; if ((item.m_required & desiredShiftMask) == (item.m_sensitive & desiredShiftMask) && ((requiredIgnoreShiftMask & desiredMask) == requiredIgnoreShiftMask)) { LOG((CLOG_INFO "found key in group %d", effectiveGroup)); keyItem = &item; break; } } if (keyItem != NULL) { break; } } if (keyItem == NULL) { // no mapping for this keysym LOG((CLOG_DEBUG1 "no mapping for key %04x", id)); return NULL; } // make working copy of modifiers ModifierToKeys newModifiers = activeModifiers; KeyModifierMask newState = currentState; SInt32 newGroup = group; // don't try to change CapsLock desiredMask = (desiredMask & ~KeyModifierCapsLock) | (currentState & KeyModifierCapsLock); // add the key if (!keysForKeyItem(*keyItem, newGroup, newModifiers, newState, desiredMask, s_overrideModifiers, isAutoRepeat, keys)) { LOG((CLOG_DEBUG1 "can't map key")); keys.clear(); return NULL; } // add keystrokes to restore modifier keys if (!keysToRestoreModifiers(*keyItem, group, newModifiers, newState, activeModifiers, keys)) { LOG((CLOG_DEBUG1 "failed to restore modifiers")); keys.clear(); return NULL; } // add keystrokes to restore group if (newGroup != group) { keys.push_back(Keystroke(group, true, true)); } // save new modifiers activeModifiers = newModifiers; currentState = newState; return keyItem; } const KeyMap::KeyItem* KeyMap::mapCharacterKey(Keystrokes& keys, KeyID id, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredMask, bool isAutoRepeat) const { // find KeySym in table KeyIDMap::const_iterator i = m_keyIDMap.find(id); if (i == m_keyIDMap.end()) { // unknown key LOG((CLOG_DEBUG1 "key %04x is not on keyboard", id)); return NULL; } const KeyGroupTable& keyGroupTable = i->second; // find best key in any group, starting with the active group SInt32 keyIndex = -1; SInt32 numGroups = getNumGroups(); SInt32 groupOffset; LOG((CLOG_DEBUG1 "find best: %04x %04x", currentState, desiredMask)); for (groupOffset = 0; groupOffset < numGroups; ++groupOffset) { SInt32 effectiveGroup = getEffectiveGroup(group, groupOffset); keyIndex = findBestKey(keyGroupTable[effectiveGroup], currentState, desiredMask); if (keyIndex != -1) { LOG((CLOG_DEBUG1 "found key in group %d", effectiveGroup)); break; } } if (keyIndex == -1) { // no mapping for this keysym LOG((CLOG_DEBUG1 "no mapping for key %04x", id)); return NULL; } // get keys to press for key SInt32 effectiveGroup = getEffectiveGroup(group, groupOffset); const KeyItemList& itemList = keyGroupTable[effectiveGroup][keyIndex]; if (itemList.empty()) { return NULL; } const KeyItem& keyItem = itemList.back(); // make working copy of modifiers ModifierToKeys newModifiers = activeModifiers; KeyModifierMask newState = currentState; SInt32 newGroup = group; // add each key for (size_t j = 0; j < itemList.size(); ++j) { if (!keysForKeyItem(itemList[j], newGroup, newModifiers, newState, desiredMask, 0, isAutoRepeat, keys)) { LOG((CLOG_DEBUG1 "can't map key")); keys.clear(); return NULL; } } // add keystrokes to restore modifier keys if (!keysToRestoreModifiers(keyItem, group, newModifiers, newState, activeModifiers, keys)) { LOG((CLOG_DEBUG1 "failed to restore modifiers")); keys.clear(); return NULL; } // add keystrokes to restore group if (newGroup != group) { keys.push_back(Keystroke(group, true, true)); } // save new modifiers activeModifiers = newModifiers; currentState = newState; return &keyItem; } const KeyMap::KeyItem* KeyMap::mapModifierKey(Keystrokes& keys, KeyID id, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredMask, bool isAutoRepeat) const { return mapCharacterKey(keys, id, group, activeModifiers, currentState, desiredMask, isAutoRepeat); } SInt32 KeyMap::findBestKey(const KeyEntryList& entryList, KeyModifierMask /*currentState*/, KeyModifierMask desiredState) const { // check for an item that can accommodate the desiredState exactly for (SInt32 i = 0; i < (SInt32)entryList.size(); ++i) { const KeyItem& item = entryList[i].back(); if ((item.m_required & desiredState) == item.m_required && (item.m_required & desiredState) == (item.m_sensitive & desiredState)) { LOG((CLOG_DEBUG1 "best key index %d of %d (exact)", i + 1, entryList.size())); return i; } } // choose the item that requires the fewest modifier changes SInt32 bestCount = 32; SInt32 bestIndex = -1; for (SInt32 i = 0; i < (SInt32)entryList.size(); ++i) { const KeyItem& item = entryList[i].back(); KeyModifierMask change = ((item.m_required ^ desiredState) & item.m_sensitive); SInt32 n = getNumModifiers(change); if (n < bestCount) { bestCount = n; bestIndex = i; } } if (bestIndex != -1) { LOG((CLOG_DEBUG1 "best key index %d of %d (%d modifiers)", bestIndex + 1, entryList.size(), bestCount)); } return bestIndex; } const KeyMap::KeyItem* KeyMap::keyForModifier(KeyButton button, SInt32 group, SInt32 modifierBit) const { assert(modifierBit >= 0 && modifierBit < kKeyModifierNumBits); assert(group >= 0 && group < getNumGroups()); // find a key that generates the given modifier in the given group // but doesn't use the given button, presumably because we're trying // to generate a KeyID that's only bound the the given button. // this is important when a shift button is modified by shift; we // must use the other shift button to do the shifting. const ModifierKeyItemList& items = m_modifierKeys[group * kKeyModifierNumBits + modifierBit]; for (ModifierKeyItemList::const_iterator i = items.begin(); i != items.end(); ++i) { if ((*i)->m_button != button) { return (*i); } } return NULL; } bool KeyMap::keysForKeyItem(const KeyItem& keyItem, SInt32& group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredState, KeyModifierMask overrideModifiers, bool isAutoRepeat, Keystrokes& keystrokes) const { static const KeyModifierMask s_notRequiredMask = KeyModifierAltGr | KeyModifierNumLock | KeyModifierScrollLock; // add keystrokes to adjust the group if (group != keyItem.m_group) { group = keyItem.m_group; keystrokes.push_back(Keystroke(group, true, false)); } EKeystroke type; if (keyItem.m_dead) { // adjust modifiers for dead key if (!keysForModifierState(keyItem.m_button, group, activeModifiers, currentState, keyItem.m_required, keyItem.m_sensitive, 0, keystrokes)) { LOG((CLOG_DEBUG1 "unable to match modifier state for dead key %d", keyItem.m_button)); return false; } // press and release the dead key type = kKeystrokeClick; } else { // if this a command key then we don't have to match some of the // key's required modifiers. KeyModifierMask sensitive = keyItem.m_sensitive & ~overrideModifiers; // XXX -- must handle pressing a modifier. in particular, if we want // to synthesize a KeyID on level 1 of a KeyButton that has Shift_L // mapped to level 0 then we must release that button if it's down // (in order to satisfy a shift modifier) then press a different // button (any other button) mapped to the shift modifier and then // the Shift_L button. // match key's required state LOG((CLOG_DEBUG1 "state: %04x,%04x,%04x", currentState, keyItem.m_required, sensitive)); if (!keysForModifierState(keyItem.m_button, group, activeModifiers, currentState, keyItem.m_required, sensitive, 0, keystrokes)) { LOG((CLOG_DEBUG1 "unable to match modifier state (%04x,%04x) for key %d", keyItem.m_required, keyItem.m_sensitive, keyItem.m_button)); return false; } // match desiredState as closely as possible. we must not // change any modifiers in keyItem.m_sensitive. and if the key // is a modifier, we don't want to change that modifier. LOG((CLOG_DEBUG1 "desired state: %04x %04x,%04x,%04x", desiredState, currentState, keyItem.m_required, keyItem.m_sensitive)); if (!keysForModifierState(keyItem.m_button, group, activeModifiers, currentState, desiredState, ~(sensitive | keyItem.m_generates), s_notRequiredMask, keystrokes)) { LOG((CLOG_DEBUG1 "unable to match desired modifier state (%04x,%04x) for key %d", desiredState, ~keyItem.m_sensitive & 0xffffu, keyItem.m_button)); return false; } // repeat or press of key type = isAutoRepeat ? kKeystrokeRepeat : kKeystrokePress; } addKeystrokes(type, keyItem, activeModifiers, currentState, keystrokes); return true; } bool KeyMap::keysToRestoreModifiers(const KeyItem& keyItem, SInt32, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, const ModifierToKeys& desiredModifiers, Keystrokes& keystrokes) const { // XXX -- we're not considering modified modifiers here ModifierToKeys oldModifiers = activeModifiers; // get the pressed modifier buttons before and after ButtonToKeyMap oldKeys, newKeys; collectButtons(oldModifiers, oldKeys); collectButtons(desiredModifiers, newKeys); // release unwanted keys for (ModifierToKeys::const_iterator i = oldModifiers.begin(); i != oldModifiers.end(); ++i) { KeyButton button = i->second.m_button; if (button != keyItem.m_button && newKeys.count(button) == 0) { EKeystroke type = kKeystrokeRelease; if (i->second.m_lock) { type = kKeystrokeUnmodify; } addKeystrokes(type, i->second, activeModifiers, currentState, keystrokes); } } // press wanted keys for (ModifierToKeys::const_iterator i = desiredModifiers.begin(); i != desiredModifiers.end(); ++i) { KeyButton button = i->second.m_button; if (button != keyItem.m_button && oldKeys.count(button) == 0) { EKeystroke type = kKeystrokePress; if (i->second.m_lock) { type = kKeystrokeModify; } addKeystrokes(type, i->second, activeModifiers, currentState, keystrokes); } } return true; } bool KeyMap::keysForModifierState(KeyButton button, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask requiredState, KeyModifierMask sensitiveMask, KeyModifierMask notRequiredMask, Keystrokes& keystrokes) const { // compute which modifiers need changing KeyModifierMask flipMask = ((currentState ^ requiredState) & sensitiveMask); // if a modifier is not required then don't even try to match it. if // we don't mask out notRequiredMask then we'll try to match those // modifiers but succeed if we can't. however, this is known not // to work if the key itself is a modifier (the numlock toggle can // interfere) so we don't try to match at all. flipMask &= ~notRequiredMask; LOG((CLOG_DEBUG1 "flip: %04x (%04x vs %04x in %04x - %04x)", flipMask, currentState, requiredState, sensitiveMask & 0xffffu, notRequiredMask & 0xffffu)); if (flipMask == 0) { return true; } // fix modifiers. this is complicated by the fact that a modifier may // be sensitive to other modifiers! (who thought that up?) // // we'll assume that modifiers with higher bits are affected by modifiers // with lower bits. there's not much basis for that assumption except // that we're pretty sure shift isn't changed by other modifiers. for (SInt32 bit = kKeyModifierNumBits; bit-- > 0; ) { KeyModifierMask mask = (1u << bit); if ((flipMask & mask) == 0) { // modifier is already correct continue; } // do we want the modifier active or inactive? bool active = ((requiredState & mask) != 0); // get the KeyItem for the modifier in the group const KeyItem* keyItem = keyForModifier(button, group, bit); if (keyItem == NULL) { if ((mask & notRequiredMask) == 0) { LOG((CLOG_DEBUG1 "no key for modifier %04x", mask)); return false; } else { continue; } } // if this modifier is sensitive to modifiers then adjust those // modifiers. also check if our assumption was correct. note // that we only need to adjust the modifiers on key down. KeyModifierMask sensitive = keyItem->m_sensitive; if ((sensitive & mask) != 0) { // modifier is sensitive to itself. that makes no sense // so ignore it. LOG((CLOG_DEBUG1 "modifier %04x modified by itself", mask)); sensitive &= ~mask; } if (sensitive != 0) { if (sensitive > mask) { // our assumption is incorrect LOG((CLOG_DEBUG1 "modifier %04x modified by %04x", mask, sensitive)); return false; } if (active && !keysForModifierState(button, group, activeModifiers, currentState, keyItem->m_required, sensitive, notRequiredMask, keystrokes)) { return false; } else if (!active) { // release the modifier // XXX -- this doesn't work! if Alt and Meta are mapped // to one key and we want to release Meta we can't do // that without also releasing Alt. // need to think about support for modified modifiers. } } // current state should match required state if ((currentState & sensitive) != (keyItem->m_required & sensitive)) { LOG((CLOG_DEBUG1 "unable to match modifier state for modifier %04x (%04x vs %04x in %04x)", mask, currentState, keyItem->m_required, sensitive)); return false; } // add keystrokes EKeystroke type = active ? kKeystrokeModify : kKeystrokeUnmodify; addKeystrokes(type, *keyItem, activeModifiers, currentState, keystrokes); } return true; } void KeyMap::addKeystrokes(EKeystroke type, const KeyItem& keyItem, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, Keystrokes& keystrokes) const { KeyButton button = keyItem.m_button; UInt32 data = keyItem.m_client; switch (type) { case kKeystrokePress: keystrokes.push_back(Keystroke(button, true, false, data)); if (keyItem.m_generates != 0) { if (!keyItem.m_lock || (currentState & keyItem.m_generates) == 0) { // add modifier key and activate modifier activeModifiers.insert(std::make_pair( keyItem.m_generates, keyItem)); currentState |= keyItem.m_generates; } else { // deactivate locking modifier activeModifiers.erase(keyItem.m_generates); currentState &= ~keyItem.m_generates; } } break; case kKeystrokeRelease: keystrokes.push_back(Keystroke(button, false, false, data)); if (keyItem.m_generates != 0 && !keyItem.m_lock) { // remove key from active modifiers std::pair range = activeModifiers.equal_range(keyItem.m_generates); for (ModifierToKeys::iterator i = range.first; i != range.second; ++i) { if (i->second.m_button == button) { activeModifiers.erase(i); break; } } // if no more keys for this modifier then deactivate modifier if (activeModifiers.count(keyItem.m_generates) == 0) { currentState &= ~keyItem.m_generates; } } break; case kKeystrokeRepeat: keystrokes.push_back(Keystroke(button, false, true, data)); keystrokes.push_back(Keystroke(button, true, true, data)); // no modifier changes on key repeat break; case kKeystrokeClick: keystrokes.push_back(Keystroke(button, true, false, data)); keystrokes.push_back(Keystroke(button, false, false, data)); // no modifier changes on key click break; case kKeystrokeModify: case kKeystrokeUnmodify: if (keyItem.m_lock) { // we assume there's just one button for this modifier if (m_halfDuplex.count(button) > 0) { if (type == kKeystrokeModify) { // turn half-duplex toggle on (press) keystrokes.push_back(Keystroke(button, true, false, data)); } else { // turn half-duplex toggle off (release) keystrokes.push_back(Keystroke(button, false, false, data)); } } else { // toggle (click) keystrokes.push_back(Keystroke(button, true, false, data)); keystrokes.push_back(Keystroke(button, false, false, data)); } } else if (type == kKeystrokeModify) { // press modifier keystrokes.push_back(Keystroke(button, true, false, data)); } else { // release all the keys that generate the modifier that are // currently down std::pair range = activeModifiers.equal_range(keyItem.m_generates); for (ModifierToKeys::const_iterator i = range.first; i != range.second; ++i) { keystrokes.push_back(Keystroke(i->second.m_button, false, false, i->second.m_client)); } } if (type == kKeystrokeModify) { activeModifiers.insert(std::make_pair( keyItem.m_generates, keyItem)); currentState |= keyItem.m_generates; } else { activeModifiers.erase(keyItem.m_generates); currentState &= ~keyItem.m_generates; } break; } } SInt32 KeyMap::getNumModifiers(KeyModifierMask state) { SInt32 n = 0; for (; state != 0; state >>= 1) { if ((state & 1) != 0) { ++n; } } return n; } bool KeyMap::isDeadKey(KeyID key) { return (key == kKeyCompose || (key >= 0x0300 && key <= 0x036f)); } KeyID KeyMap::getDeadKey(KeyID key) { if (isDeadKey(key)) { // already dead return key; } switch (key) { case '`': return kKeyDeadGrave; case 0xb4u: return kKeyDeadAcute; case '^': case 0x2c6: return kKeyDeadCircumflex; case '~': case 0x2dcu: return kKeyDeadTilde; case 0xafu: return kKeyDeadMacron; case 0x2d8u: return kKeyDeadBreve; case 0x2d9u: return kKeyDeadAbovedot; case 0xa8u: return kKeyDeadDiaeresis; case 0xb0u: case 0x2dau: return kKeyDeadAbovering; case '\"': case 0x2ddu: return kKeyDeadDoubleacute; case 0x2c7u: return kKeyDeadCaron; case 0xb8u: return kKeyDeadCedilla; case 0x2dbu: return kKeyDeadOgonek; default: // unknown return kKeyNone; } } String KeyMap::formatKey(KeyID key, KeyModifierMask mask) { // initialize tables initKeyNameMaps(); String x; for (SInt32 i = 0; i < kKeyModifierNumBits; ++i) { KeyModifierMask mod = (1u << i); if ((mask & mod) != 0 && s_modifierToNameMap->count(mod) > 0) { x += s_modifierToNameMap->find(mod)->second; x += "+"; } } if (key != kKeyNone) { if (s_keyToNameMap->count(key) > 0) { x += s_keyToNameMap->find(key)->second; } // XXX -- we're assuming ASCII here else if (key >= 33 && key < 127) { x += (char)key; } else { x += synergy::string::sprintf("\\u%04x", key); } } else if (!x.empty()) { // remove trailing '+' x.erase(x.size() - 1); } return x; } bool KeyMap::parseKey(const String& x, KeyID& key) { // initialize tables initKeyNameMaps(); // parse the key key = kKeyNone; if (s_nameToKeyMap->count(x) > 0) { key = s_nameToKeyMap->find(x)->second; } // XXX -- we're assuming ASCII encoding here else if (x.size() == 1) { if (!isgraph(x[0])) { // unknown key return false; } key = (KeyID)x[0]; } else if (x.size() == 6 && x[0] == '\\' && x[1] == 'u') { // escaped unicode (\uXXXX where XXXX is a hex number) char* end; key = (KeyID)strtol(x.c_str() + 2, &end, 16); if (*end != '\0') { return false; } } else if (!x.empty()) { // unknown key return false; } return true; } bool KeyMap::parseModifiers(String& x, KeyModifierMask& mask) { // initialize tables initKeyNameMaps(); mask = 0; String::size_type tb = x.find_first_not_of(" \t", 0); while (tb != String::npos) { // get next component String::size_type te = x.find_first_of(" \t+)", tb); if (te == String::npos) { te = x.size(); } String c = x.substr(tb, te - tb); if (c.empty()) { // missing component return false; } if (s_nameToModifierMap->count(c) > 0) { KeyModifierMask mod = s_nameToModifierMap->find(c)->second; if ((mask & mod) != 0) { // modifier appears twice return false; } mask |= mod; } else { // unknown string x.erase(0, tb); String::size_type tb = x.find_first_not_of(" \t"); String::size_type te = x.find_last_not_of(" \t"); if (tb == String::npos) { x = ""; } else { x = x.substr(tb, te - tb + 1); } return true; } // check for '+' or end of string tb = x.find_first_not_of(" \t", te); if (tb != String::npos) { if (x[tb] != '+') { // expected '+' return false; } tb = x.find_first_not_of(" \t", tb + 1); } } // parsed the whole thing x = ""; return true; } void KeyMap::initKeyNameMaps() { // initialize tables if (s_nameToKeyMap == NULL) { s_nameToKeyMap = new NameToKeyMap; s_keyToNameMap = new KeyToNameMap; for (const KeyNameMapEntry* i = kKeyNameMap; i->m_name != NULL; ++i) { (*s_nameToKeyMap)[i->m_name] = i->m_id; (*s_keyToNameMap)[i->m_id] = i->m_name; } } if (s_nameToModifierMap == NULL) { s_nameToModifierMap = new NameToModifierMap; s_modifierToNameMap = new ModifierToNameMap; for (const KeyModifierNameMapEntry* i = kModifierNameMap; i->m_name != NULL; ++i) { (*s_nameToModifierMap)[i->m_name] = i->m_mask; (*s_modifierToNameMap)[i->m_mask] = i->m_name; } } } // // KeyMap::KeyItem // bool KeyMap::KeyItem::operator==(const KeyItem& x) const { return (m_id == x.m_id && m_group == x.m_group && m_button == x.m_button && m_required == x.m_required && m_sensitive == x.m_sensitive && m_generates == x.m_generates && m_dead == x.m_dead && m_lock == x.m_lock && m_client == x.m_client); } // // KeyMap::Keystroke // KeyMap::Keystroke::Keystroke(KeyButton button, bool press, bool repeat, UInt32 data) : m_type(kButton) { m_data.m_button.m_button = button; m_data.m_button.m_press = press; m_data.m_button.m_repeat = repeat; m_data.m_button.m_client = data; } KeyMap::Keystroke::Keystroke(SInt32 group, bool absolute, bool restore) : m_type(kGroup) { m_data.m_group.m_group = group; m_data.m_group.m_absolute = absolute; m_data.m_group.m_restore = restore; } } synergy-1.8.8-stable/src/lib/synergy/KeyMap.h000066400000000000000000000411721305627404700211110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2005 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/key_types.h" #include "base/String.h" #include "common/stdmap.h" #include "common/stdset.h" #include "common/stdvector.h" #include "gtest/gtest_prod.h" namespace synergy { //! Key map /*! This class provides a keyboard mapping. */ class KeyMap { public: KeyMap(); virtual ~KeyMap(); //! KeyID synthesis info /*! This structure contains the information necessary to synthesize a keystroke that generates a KeyID (stored elsewhere). \c m_sensitive lists the modifiers that the key is affected by and must therefore be in the correct state, which is listed in \c m_required. If the key is mapped to a modifier, that modifier is in \c m_generates and is not in \c m_sensitive. */ struct KeyItem { public: KeyID m_id; //!< KeyID SInt32 m_group; //!< Group for key KeyButton m_button; //!< Button to generate KeyID KeyModifierMask m_required; //!< Modifiers required for KeyID KeyModifierMask m_sensitive; //!< Modifiers key is sensitive to KeyModifierMask m_generates; //!< Modifiers key is mapped to bool m_dead; //!< \c true if this is a dead KeyID bool m_lock; //!< \c true if this locks a modifier UInt32 m_client; //!< Client data public: bool operator==(const KeyItem&) const; }; //! The KeyButtons needed to synthesize a KeyID /*! An ordered list of \c KeyItems produces a particular KeyID. If the KeyID can be synthesized directly then there is one entry in the list. If dead keys are required then they're listed first. A list is the minimal set of keystrokes necessary to synthesize the KeyID, so it doesn't include no-ops. A list does not include any modifier keys unless the KeyID is a modifier, in which case it has exactly one KeyItem for the modifier itself. */ typedef std::vector KeyItemList; //! A keystroke class Keystroke { public: enum EType { kButton, //!< Synthesize button kGroup //!< Set new group }; Keystroke(KeyButton, bool press, bool repeat, UInt32 clientData); Keystroke(SInt32 group, bool absolute, bool restore); public: struct Button { public: KeyButton m_button; //!< Button to synthesize bool m_press; //!< \c true iff press bool m_repeat; //!< \c true iff for an autorepeat UInt32 m_client; //!< Client data }; struct Group { public: SInt32 m_group; //!< Group/offset to change to/by bool m_absolute; //!< \c true iff change to, else by bool m_restore; //!< \c true iff for restoring state }; union Data { public: Button m_button; Group m_group; }; EType m_type; Data m_data; }; //! A sequence of keystrokes typedef std::vector Keystrokes; //! A mapping of a modifier to keys for that modifier typedef std::multimap ModifierToKeys; //! A set of buttons typedef std::map ButtonToKeyMap; //! Callback type for \c foreachKey typedef void (*ForeachKeyCallback)(KeyID, SInt32 group, KeyItem&, void* userData); //! @name manipulators //@{ //! Swap with another \c KeyMap virtual void swap(KeyMap&); //! Add a key entry /*! Adds \p item to the entries for the item's id and group. The \c m_dead member is set automatically. */ void addKeyEntry(const KeyItem& item); //! Add an alias key entry /*! If \p targetID with the modifiers given by \p targetRequired and \p targetSensitive is not available in group \p group then find an entry for \p sourceID with modifiers given by \p sourceRequired and \p sourceSensitive in any group with exactly one item and, if found, add a new item just like it except using id \p targetID. This effectively makes the \p sourceID an alias for \p targetID (i.e. we can generate \p targetID using \p sourceID). */ void addKeyAliasEntry(KeyID targetID, SInt32 group, KeyModifierMask targetRequired, KeyModifierMask targetSensitive, KeyID sourceID, KeyModifierMask sourceRequired, KeyModifierMask sourceSensitive); //! Add a key sequence entry /*! Adds the sequence of keys \p keys (\p numKeys elements long) to synthesize key \p id in group \p group. This looks up in the map each key in \p keys. If all are found then each key is converted to the button for that key and the buttons are added as the entry for \p id. If \p id is already in the map or at least one key in \p keys is not in the map then nothing is added and this returns \c false, otherwise it returns \c true. */ bool addKeyCombinationEntry(KeyID id, SInt32 group, const KeyID* keys, UInt32 numKeys); //! Enable composition across groups /*! If called then the keyboard map will allow switching between groups during key composition. Not all systems allow that. */ void allowGroupSwitchDuringCompose(); //! Add a half-duplex button /*! Records that button \p button is a half-duplex key. This is called when translating the system's keyboard map. It's independent of the half-duplex modifier calls. */ void addHalfDuplexButton(KeyButton button); //! Remove all half-duplex modifiers /*! Removes all half-duplex modifiers. This is called to set user configurable half-duplex settings. */ void clearHalfDuplexModifiers(); //! Add a half-duplex modifier /*! Records that modifier key \p key is half-duplex. This is called to set user configurable half-duplex settings. */ virtual void addHalfDuplexModifier(KeyID key); //! Finish adding entries /*! Called after adding entries, this does some internal housekeeping. */ virtual void finish(); //! Iterate over all added keys items /*! Calls \p cb for every key item. */ virtual void foreachKey(ForeachKeyCallback cb, void* userData); //@} //! @name accessors //@{ //! Map key press/repeat to keystrokes. /*! Converts press/repeat of key \p id in group \p group with current modifiers as given in \p currentState and the desired modifiers in \p desiredMask into the keystrokes necessary to synthesize that key event in \p keys. It returns the \c KeyItem of the key being pressed/repeated, or NULL if the key cannot be mapped. */ virtual const KeyItem* mapKey(Keystrokes& keys, KeyID id, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredMask, bool isAutoRepeat) const; //! Get number of groups /*! Returns the number of keyboard groups (independent layouts) in the map. */ SInt32 getNumGroups() const; //! Compute a group number /*! Returns the number of the group \p offset groups after group \p group. */ SInt32 getEffectiveGroup(SInt32 group, SInt32 offset) const; //! Find key entry compatible with modifiers /*! Returns the \c KeyItemList for the first entry for \p id in group \p group that is compatible with the given modifiers, or NULL if there isn't one. A button list is compatible with a modifiers if it is either insensitive to all modifiers in \p sensitive or it requires the modifiers to be in the state indicated by \p required for every modifier indicated by \p sensitive. */ const KeyItemList* findCompatibleKey(KeyID id, SInt32 group, KeyModifierMask required, KeyModifierMask sensitive) const; //! Test if modifier is half-duplex /*! Returns \c true iff modifier key \p key or button \p button is half-duplex. */ virtual bool isHalfDuplex(KeyID key, KeyButton button) const; //! Test if modifiers indicate a command /*! Returns \c true iff the modifiers in \p mask contain any command modifiers. A command modifier is used for keyboard shortcuts and hotkeys, Rather than trying to synthesize a character, a command is trying to synthesize a particular set of buttons. So it's not important to match the shift or AltGr state to achieve a character but it is important to match the modifier state exactly. */ bool isCommand(KeyModifierMask mask) const; // Get the modifiers that indicate a command /*! Returns the modifiers that when combined with other keys indicate a command (e.g. shortcut or hotkey). */ KeyModifierMask getCommandModifiers() const; //! Get buttons from modifier map /*! Put all the keys in \p modifiers into \p keys. */ static void collectButtons(const ModifierToKeys& modifiers, ButtonToKeyMap& keys); //! Set modifier key state /*! Sets the modifier key state (\c m_generates and \c m_lock) in \p item based on the \c m_id in \p item. */ static void initModifierKey(KeyItem& item); //! Test for a dead key /*! Returns \c true if \p key is a dead key. */ static bool isDeadKey(KeyID key); //! Get corresponding dead key /*! Returns the dead key corresponding to \p key if one exists, otherwise return \c kKeyNone. This returns \p key if it's already a dead key. */ static KeyID getDeadKey(KeyID key); //! Get string for a key and modifier mask /*! Converts a key and modifier mask into a string representing the combination. */ static String formatKey(KeyID key, KeyModifierMask); //! Parse a string into a key /*! Converts a string into a key. Returns \c true on success and \c false if the string cannot be parsed. */ static bool parseKey(const String&, KeyID&); //! Parse a string into a modifier mask /*! Converts a string into a modifier mask. Returns \c true on success and \c false if the string cannot be parsed. The modifiers plus any remaining leading and trailing whitespace is stripped from the input string. */ static bool parseModifiers(String&, KeyModifierMask&); //@} private: FRIEND_TEST(KeyMapTests, findBestKey_requiredDown_matchExactFirstItem); FRIEND_TEST(KeyMapTests, findBestKey_requiredAndExtraSensitiveDown_matchExactFirstItem); FRIEND_TEST(KeyMapTests, findBestKey_requiredAndExtraSensitiveDown_matchExactSecondItem); FRIEND_TEST(KeyMapTests, findBestKey_extraSensitiveDown_matchExactSecondItem); FRIEND_TEST(KeyMapTests, findBestKey_noRequiredDown_matchOneRequiredChangeItem); FRIEND_TEST(KeyMapTests, findBestKey_onlyOneRequiredDown_matchTwoRequiredChangesItem); FRIEND_TEST(KeyMapTests, findBestKey_noRequiredDown_cannotMatch); private: //! Ways to synthesize a key enum EKeystroke { kKeystrokePress, //!< Synthesize a press kKeystrokeRelease, //!< Synthesize a release kKeystrokeRepeat, //!< Synthesize an autorepeat kKeystrokeClick, //!< Synthesize a press and release kKeystrokeModify, //!< Synthesize pressing a modifier kKeystrokeUnmodify //!< Synthesize releasing a modifier }; // A list of ways to synthesize a KeyID typedef std::vector KeyEntryList; // computes the number of groups SInt32 findNumGroups() const; // computes the map of modifiers to the keys that generate the modifiers void setModifierKeys(); // maps a command key. a command key is a keyboard shortcut and we're // trying to synthesize a button press with an exact sets of modifiers, // not trying to synthesize a character. so we just need to find the // right button and synthesize the requested modifiers without regard // to what character they would synthesize. we disallow multikey // entries since they don't make sense as hotkeys. const KeyItem* mapCommandKey(Keystrokes& keys, KeyID id, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredMask, bool isAutoRepeat) const; // maps a character key. a character key is trying to synthesize a // particular KeyID and isn't entirely concerned with the modifiers // used to do it. const KeyItem* mapCharacterKey(Keystrokes& keys, KeyID id, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredMask, bool isAutoRepeat) const; // maps a modifier key const KeyItem* mapModifierKey(Keystrokes& keys, KeyID id, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredMask, bool isAutoRepeat) const; // returns the index into \p entryList of the KeyItemList requiring // the fewest modifier changes between \p currentState and // \p desiredState. SInt32 findBestKey(const KeyEntryList& entryList, KeyModifierMask currentState, KeyModifierMask desiredState) const; // gets the \c KeyItem used to synthesize the modifier who's bit is // given by \p modifierBit in group \p group and does not synthesize // the key \p button. const KeyItem* keyForModifier(KeyButton button, SInt32 group, SInt32 modifierBit) const; // fills \p keystrokes with the keys to synthesize the key in // \p keyItem taking the modifiers into account. returns \c true // iff successful and sets \p currentState to the // resulting modifier state. bool keysForKeyItem(const KeyItem& keyItem, SInt32& group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredState, KeyModifierMask overrideModifiers, bool isAutoRepeat, Keystrokes& keystrokes) const; // fills \p keystrokes with the keys to synthesize the modifiers // in \p desiredModifiers from the active modifiers listed in // \p activeModifiers not including the key in \p keyItem. // returns \c true iff successful. bool keysToRestoreModifiers(const KeyItem& keyItem, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, const ModifierToKeys& desiredModifiers, Keystrokes& keystrokes) const; // fills \p keystrokes and \p undo with the keys to change the // current modifier state in \p currentState to match the state in // \p requiredState for each modifier indicated in \p sensitiveMask. // returns \c true iff successful and sets \p currentState to the // resulting modifier state. bool keysForModifierState(KeyButton button, SInt32 group, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask requiredState, KeyModifierMask sensitiveMask, KeyModifierMask notRequiredMask, Keystrokes& keystrokes) const; // Adds keystrokes to synthesize key \p keyItem in mode \p type to // \p keystrokes and to undo the synthesis to \p undo. void addKeystrokes(EKeystroke type, const KeyItem& keyItem, ModifierToKeys& activeModifiers, KeyModifierMask& currentState, Keystrokes& keystrokes) const; // Returns the number of modifiers indicated in \p state. static SInt32 getNumModifiers(KeyModifierMask state); // Initialize key name/id maps static void initKeyNameMaps(); // not implemented KeyMap(const KeyMap&); KeyMap& operator=(const KeyMap&); private: // Ways to synthesize a KeyID over multiple keyboard groups typedef std::vector KeyGroupTable; // Table of KeyID to ways to synthesize that KeyID typedef std::map KeyIDMap; // List of KeyItems that generate a particular modifier typedef std::vector ModifierKeyItemList; // Map a modifier to the KeyItems that synthesize that modifier typedef std::vector ModifierToKeyTable; // A set of keys typedef std::set KeySet; // A set of buttons typedef std::set KeyButtonSet; // Key maps for parsing/formatting typedef std::map NameToKeyMap; typedef std::map NameToModifierMap; typedef std::map KeyToNameMap; typedef std::map ModifierToNameMap; // KeyID info KeyIDMap m_keyIDMap; SInt32 m_numGroups; ModifierToKeyTable m_modifierKeys; // composition info bool m_composeAcrossGroups; // half-duplex info KeyButtonSet m_halfDuplex; // half-duplex set by synergy KeySet m_halfDuplexMods; // half-duplex set by user // dummy KeyItem for changing modifiers KeyItem m_modifierKeyItem; // parsing/formatting tables static NameToKeyMap* s_nameToKeyMap; static NameToModifierMap* s_nameToModifierMap; static KeyToNameMap* s_keyToNameMap; static ModifierToNameMap* s_modifierToNameMap; }; } synergy-1.8.8-stable/src/lib/synergy/KeyState.cpp000066400000000000000000001055701305627404700220120ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/KeyState.h" #include "base/Log.h" #include #include #include #include static const KeyButton kButtonMask = (KeyButton)(IKeyState::kNumButtons - 1); static const KeyID s_decomposeTable[] = { // spacing version of dead keys 0x0060, 0x0300, 0x0020, 0, // grave, dead_grave, space 0x00b4, 0x0301, 0x0020, 0, // acute, dead_acute, space 0x005e, 0x0302, 0x0020, 0, // asciicircum, dead_circumflex, space 0x007e, 0x0303, 0x0020, 0, // asciitilde, dead_tilde, space 0x00a8, 0x0308, 0x0020, 0, // diaeresis, dead_diaeresis, space 0x00b0, 0x030a, 0x0020, 0, // degree, dead_abovering, space 0x00b8, 0x0327, 0x0020, 0, // cedilla, dead_cedilla, space 0x02db, 0x0328, 0x0020, 0, // ogonek, dead_ogonek, space 0x02c7, 0x030c, 0x0020, 0, // caron, dead_caron, space 0x02d9, 0x0307, 0x0020, 0, // abovedot, dead_abovedot, space 0x02dd, 0x030b, 0x0020, 0, // doubleacute, dead_doubleacute, space 0x02d8, 0x0306, 0x0020, 0, // breve, dead_breve, space 0x00af, 0x0304, 0x0020, 0, // macron, dead_macron, space // Latin-1 (ISO 8859-1) 0x00c0, 0x0300, 0x0041, 0, // Agrave, dead_grave, A 0x00c1, 0x0301, 0x0041, 0, // Aacute, dead_acute, A 0x00c2, 0x0302, 0x0041, 0, // Acircumflex, dead_circumflex, A 0x00c3, 0x0303, 0x0041, 0, // Atilde, dead_tilde, A 0x00c4, 0x0308, 0x0041, 0, // Adiaeresis, dead_diaeresis, A 0x00c5, 0x030a, 0x0041, 0, // Aring, dead_abovering, A 0x00c7, 0x0327, 0x0043, 0, // Ccedilla, dead_cedilla, C 0x00c8, 0x0300, 0x0045, 0, // Egrave, dead_grave, E 0x00c9, 0x0301, 0x0045, 0, // Eacute, dead_acute, E 0x00ca, 0x0302, 0x0045, 0, // Ecircumflex, dead_circumflex, E 0x00cb, 0x0308, 0x0045, 0, // Ediaeresis, dead_diaeresis, E 0x00cc, 0x0300, 0x0049, 0, // Igrave, dead_grave, I 0x00cd, 0x0301, 0x0049, 0, // Iacute, dead_acute, I 0x00ce, 0x0302, 0x0049, 0, // Icircumflex, dead_circumflex, I 0x00cf, 0x0308, 0x0049, 0, // Idiaeresis, dead_diaeresis, I 0x00d1, 0x0303, 0x004e, 0, // Ntilde, dead_tilde, N 0x00d2, 0x0300, 0x004f, 0, // Ograve, dead_grave, O 0x00d3, 0x0301, 0x004f, 0, // Oacute, dead_acute, O 0x00d4, 0x0302, 0x004f, 0, // Ocircumflex, dead_circumflex, O 0x00d5, 0x0303, 0x004f, 0, // Otilde, dead_tilde, O 0x00d6, 0x0308, 0x004f, 0, // Odiaeresis, dead_diaeresis, O 0x00d9, 0x0300, 0x0055, 0, // Ugrave, dead_grave, U 0x00da, 0x0301, 0x0055, 0, // Uacute, dead_acute, U 0x00db, 0x0302, 0x0055, 0, // Ucircumflex, dead_circumflex, U 0x00dc, 0x0308, 0x0055, 0, // Udiaeresis, dead_diaeresis, U 0x00dd, 0x0301, 0x0059, 0, // Yacute, dead_acute, Y 0x00e0, 0x0300, 0x0061, 0, // agrave, dead_grave, a 0x00e1, 0x0301, 0x0061, 0, // aacute, dead_acute, a 0x00e2, 0x0302, 0x0061, 0, // acircumflex, dead_circumflex, a 0x00e3, 0x0303, 0x0061, 0, // atilde, dead_tilde, a 0x00e4, 0x0308, 0x0061, 0, // adiaeresis, dead_diaeresis, a 0x00e5, 0x030a, 0x0061, 0, // aring, dead_abovering, a 0x00e7, 0x0327, 0x0063, 0, // ccedilla, dead_cedilla, c 0x00e8, 0x0300, 0x0065, 0, // egrave, dead_grave, e 0x00e9, 0x0301, 0x0065, 0, // eacute, dead_acute, e 0x00ea, 0x0302, 0x0065, 0, // ecircumflex, dead_circumflex, e 0x00eb, 0x0308, 0x0065, 0, // ediaeresis, dead_diaeresis, e 0x00ec, 0x0300, 0x0069, 0, // igrave, dead_grave, i 0x00ed, 0x0301, 0x0069, 0, // iacute, dead_acute, i 0x00ee, 0x0302, 0x0069, 0, // icircumflex, dead_circumflex, i 0x00ef, 0x0308, 0x0069, 0, // idiaeresis, dead_diaeresis, i 0x00f1, 0x0303, 0x006e, 0, // ntilde, dead_tilde, n 0x00f2, 0x0300, 0x006f, 0, // ograve, dead_grave, o 0x00f3, 0x0301, 0x006f, 0, // oacute, dead_acute, o 0x00f4, 0x0302, 0x006f, 0, // ocircumflex, dead_circumflex, o 0x00f5, 0x0303, 0x006f, 0, // otilde, dead_tilde, o 0x00f6, 0x0308, 0x006f, 0, // odiaeresis, dead_diaeresis, o 0x00f9, 0x0300, 0x0075, 0, // ugrave, dead_grave, u 0x00fa, 0x0301, 0x0075, 0, // uacute, dead_acute, u 0x00fb, 0x0302, 0x0075, 0, // ucircumflex, dead_circumflex, u 0x00fc, 0x0308, 0x0075, 0, // udiaeresis, dead_diaeresis, u 0x00fd, 0x0301, 0x0079, 0, // yacute, dead_acute, y 0x00ff, 0x0308, 0x0079, 0, // ydiaeresis, dead_diaeresis, y // Latin-2 (ISO 8859-2) 0x0104, 0x0328, 0x0041, 0, // Aogonek, dead_ogonek, A 0x013d, 0x030c, 0x004c, 0, // Lcaron, dead_caron, L 0x015a, 0x0301, 0x0053, 0, // Sacute, dead_acute, S 0x0160, 0x030c, 0x0053, 0, // Scaron, dead_caron, S 0x015e, 0x0327, 0x0053, 0, // Scedilla, dead_cedilla, S 0x0164, 0x030c, 0x0054, 0, // Tcaron, dead_caron, T 0x0179, 0x0301, 0x005a, 0, // Zacute, dead_acute, Z 0x017d, 0x030c, 0x005a, 0, // Zcaron, dead_caron, Z 0x017b, 0x0307, 0x005a, 0, // Zabovedot, dead_abovedot, Z 0x0105, 0x0328, 0x0061, 0, // aogonek, dead_ogonek, a 0x013e, 0x030c, 0x006c, 0, // lcaron, dead_caron, l 0x015b, 0x0301, 0x0073, 0, // sacute, dead_acute, s 0x0161, 0x030c, 0x0073, 0, // scaron, dead_caron, s 0x015f, 0x0327, 0x0073, 0, // scedilla, dead_cedilla, s 0x0165, 0x030c, 0x0074, 0, // tcaron, dead_caron, t 0x017a, 0x0301, 0x007a, 0, // zacute, dead_acute, z 0x017e, 0x030c, 0x007a, 0, // zcaron, dead_caron, z 0x017c, 0x0307, 0x007a, 0, // zabovedot, dead_abovedot, z 0x0154, 0x0301, 0x0052, 0, // Racute, dead_acute, R 0x0102, 0x0306, 0x0041, 0, // Abreve, dead_breve, A 0x0139, 0x0301, 0x004c, 0, // Lacute, dead_acute, L 0x0106, 0x0301, 0x0043, 0, // Cacute, dead_acute, C 0x010c, 0x030c, 0x0043, 0, // Ccaron, dead_caron, C 0x0118, 0x0328, 0x0045, 0, // Eogonek, dead_ogonek, E 0x011a, 0x030c, 0x0045, 0, // Ecaron, dead_caron, E 0x010e, 0x030c, 0x0044, 0, // Dcaron, dead_caron, D 0x0143, 0x0301, 0x004e, 0, // Nacute, dead_acute, N 0x0147, 0x030c, 0x004e, 0, // Ncaron, dead_caron, N 0x0150, 0x030b, 0x004f, 0, // Odoubleacute, dead_doubleacute, O 0x0158, 0x030c, 0x0052, 0, // Rcaron, dead_caron, R 0x016e, 0x030a, 0x0055, 0, // Uring, dead_abovering, U 0x0170, 0x030b, 0x0055, 0, // Udoubleacute, dead_doubleacute, U 0x0162, 0x0327, 0x0054, 0, // Tcedilla, dead_cedilla, T 0x0155, 0x0301, 0x0072, 0, // racute, dead_acute, r 0x0103, 0x0306, 0x0061, 0, // abreve, dead_breve, a 0x013a, 0x0301, 0x006c, 0, // lacute, dead_acute, l 0x0107, 0x0301, 0x0063, 0, // cacute, dead_acute, c 0x010d, 0x030c, 0x0063, 0, // ccaron, dead_caron, c 0x0119, 0x0328, 0x0065, 0, // eogonek, dead_ogonek, e 0x011b, 0x030c, 0x0065, 0, // ecaron, dead_caron, e 0x010f, 0x030c, 0x0064, 0, // dcaron, dead_caron, d 0x0144, 0x0301, 0x006e, 0, // nacute, dead_acute, n 0x0148, 0x030c, 0x006e, 0, // ncaron, dead_caron, n 0x0151, 0x030b, 0x006f, 0, // odoubleacute, dead_doubleacute, o 0x0159, 0x030c, 0x0072, 0, // rcaron, dead_caron, r 0x016f, 0x030a, 0x0075, 0, // uring, dead_abovering, u 0x0171, 0x030b, 0x0075, 0, // udoubleacute, dead_doubleacute, u 0x0163, 0x0327, 0x0074, 0, // tcedilla, dead_cedilla, t // Latin-3 (ISO 8859-3) 0x0124, 0x0302, 0x0048, 0, // Hcircumflex, dead_circumflex, H 0x0130, 0x0307, 0x0049, 0, // Iabovedot, dead_abovedot, I 0x011e, 0x0306, 0x0047, 0, // Gbreve, dead_breve, G 0x0134, 0x0302, 0x004a, 0, // Jcircumflex, dead_circumflex, J 0x0125, 0x0302, 0x0068, 0, // hcircumflex, dead_circumflex, h 0x011f, 0x0306, 0x0067, 0, // gbreve, dead_breve, g 0x0135, 0x0302, 0x006a, 0, // jcircumflex, dead_circumflex, j 0x010a, 0x0307, 0x0043, 0, // Cabovedot, dead_abovedot, C 0x0108, 0x0302, 0x0043, 0, // Ccircumflex, dead_circumflex, C 0x0120, 0x0307, 0x0047, 0, // Gabovedot, dead_abovedot, G 0x011c, 0x0302, 0x0047, 0, // Gcircumflex, dead_circumflex, G 0x016c, 0x0306, 0x0055, 0, // Ubreve, dead_breve, U 0x015c, 0x0302, 0x0053, 0, // Scircumflex, dead_circumflex, S 0x010b, 0x0307, 0x0063, 0, // cabovedot, dead_abovedot, c 0x0109, 0x0302, 0x0063, 0, // ccircumflex, dead_circumflex, c 0x0121, 0x0307, 0x0067, 0, // gabovedot, dead_abovedot, g 0x011d, 0x0302, 0x0067, 0, // gcircumflex, dead_circumflex, g 0x016d, 0x0306, 0x0075, 0, // ubreve, dead_breve, u 0x015d, 0x0302, 0x0073, 0, // scircumflex, dead_circumflex, s // Latin-4 (ISO 8859-4) 0x0156, 0x0327, 0x0052, 0, // Rcedilla, dead_cedilla, R 0x0128, 0x0303, 0x0049, 0, // Itilde, dead_tilde, I 0x013b, 0x0327, 0x004c, 0, // Lcedilla, dead_cedilla, L 0x0112, 0x0304, 0x0045, 0, // Emacron, dead_macron, E 0x0122, 0x0327, 0x0047, 0, // Gcedilla, dead_cedilla, G 0x0157, 0x0327, 0x0072, 0, // rcedilla, dead_cedilla, r 0x0129, 0x0303, 0x0069, 0, // itilde, dead_tilde, i 0x013c, 0x0327, 0x006c, 0, // lcedilla, dead_cedilla, l 0x0113, 0x0304, 0x0065, 0, // emacron, dead_macron, e 0x0123, 0x0327, 0x0067, 0, // gcedilla, dead_cedilla, g 0x0100, 0x0304, 0x0041, 0, // Amacron, dead_macron, A 0x012e, 0x0328, 0x0049, 0, // Iogonek, dead_ogonek, I 0x0116, 0x0307, 0x0045, 0, // Eabovedot, dead_abovedot, E 0x012a, 0x0304, 0x0049, 0, // Imacron, dead_macron, I 0x0145, 0x0327, 0x004e, 0, // Ncedilla, dead_cedilla, N 0x014c, 0x0304, 0x004f, 0, // Omacron, dead_macron, O 0x0136, 0x0327, 0x004b, 0, // Kcedilla, dead_cedilla, K 0x0172, 0x0328, 0x0055, 0, // Uogonek, dead_ogonek, U 0x0168, 0x0303, 0x0055, 0, // Utilde, dead_tilde, U 0x016a, 0x0304, 0x0055, 0, // Umacron, dead_macron, U 0x0101, 0x0304, 0x0061, 0, // amacron, dead_macron, a 0x012f, 0x0328, 0x0069, 0, // iogonek, dead_ogonek, i 0x0117, 0x0307, 0x0065, 0, // eabovedot, dead_abovedot, e 0x012b, 0x0304, 0x0069, 0, // imacron, dead_macron, i 0x0146, 0x0327, 0x006e, 0, // ncedilla, dead_cedilla, n 0x014d, 0x0304, 0x006f, 0, // omacron, dead_macron, o 0x0137, 0x0327, 0x006b, 0, // kcedilla, dead_cedilla, k 0x0173, 0x0328, 0x0075, 0, // uogonek, dead_ogonek, u 0x0169, 0x0303, 0x0075, 0, // utilde, dead_tilde, u 0x016b, 0x0304, 0x0075, 0, // umacron, dead_macron, u // Latin-8 (ISO 8859-14) 0x1e02, 0x0307, 0x0042, 0, // Babovedot, dead_abovedot, B 0x1e03, 0x0307, 0x0062, 0, // babovedot, dead_abovedot, b 0x1e0a, 0x0307, 0x0044, 0, // Dabovedot, dead_abovedot, D 0x1e80, 0x0300, 0x0057, 0, // Wgrave, dead_grave, W 0x1e82, 0x0301, 0x0057, 0, // Wacute, dead_acute, W 0x1e0b, 0x0307, 0x0064, 0, // dabovedot, dead_abovedot, d 0x1ef2, 0x0300, 0x0059, 0, // Ygrave, dead_grave, Y 0x1e1e, 0x0307, 0x0046, 0, // Fabovedot, dead_abovedot, F 0x1e1f, 0x0307, 0x0066, 0, // fabovedot, dead_abovedot, f 0x1e40, 0x0307, 0x004d, 0, // Mabovedot, dead_abovedot, M 0x1e41, 0x0307, 0x006d, 0, // mabovedot, dead_abovedot, m 0x1e56, 0x0307, 0x0050, 0, // Pabovedot, dead_abovedot, P 0x1e81, 0x0300, 0x0077, 0, // wgrave, dead_grave, w 0x1e57, 0x0307, 0x0070, 0, // pabovedot, dead_abovedot, p 0x1e83, 0x0301, 0x0077, 0, // wacute, dead_acute, w 0x1e60, 0x0307, 0x0053, 0, // Sabovedot, dead_abovedot, S 0x1ef3, 0x0300, 0x0079, 0, // ygrave, dead_grave, y 0x1e84, 0x0308, 0x0057, 0, // Wdiaeresis, dead_diaeresis, W 0x1e85, 0x0308, 0x0077, 0, // wdiaeresis, dead_diaeresis, w 0x1e61, 0x0307, 0x0073, 0, // sabovedot, dead_abovedot, s 0x0174, 0x0302, 0x0057, 0, // Wcircumflex, dead_circumflex, W 0x1e6a, 0x0307, 0x0054, 0, // Tabovedot, dead_abovedot, T 0x0176, 0x0302, 0x0059, 0, // Ycircumflex, dead_circumflex, Y 0x0175, 0x0302, 0x0077, 0, // wcircumflex, dead_circumflex, w 0x1e6b, 0x0307, 0x0074, 0, // tabovedot, dead_abovedot, t 0x0177, 0x0302, 0x0079, 0, // ycircumflex, dead_circumflex, y // Latin-9 (ISO 8859-15) 0x0178, 0x0308, 0x0059, 0, // Ydiaeresis, dead_diaeresis, Y // Compose key sequences 0x00c6, kKeyCompose, 0x0041, 0x0045, 0, // AE, A, E 0x00c1, kKeyCompose, 0x0041, 0x0027, 0, // Aacute, A, apostrophe 0x00c2, kKeyCompose, 0x0041, 0x0053, 0, // Acircumflex, A, asciicircum 0x00c3, kKeyCompose, 0x0041, 0x0022, 0, // Adiaeresis, A, quotedbl 0x00c0, kKeyCompose, 0x0041, 0x0060, 0, // Agrave, A, grave 0x00c5, kKeyCompose, 0x0041, 0x002a, 0, // Aring, A, asterisk 0x00c3, kKeyCompose, 0x0041, 0x007e, 0, // Atilde, A, asciitilde 0x00c7, kKeyCompose, 0x0043, 0x002c, 0, // Ccedilla, C, comma 0x00d0, kKeyCompose, 0x0044, 0x002d, 0, // ETH, D, minus 0x00c9, kKeyCompose, 0x0045, 0x0027, 0, // Eacute, E, apostrophe 0x00ca, kKeyCompose, 0x0045, 0x0053, 0, // Ecircumflex, E, asciicircum 0x00cb, kKeyCompose, 0x0045, 0x0022, 0, // Ediaeresis, E, quotedbl 0x00c8, kKeyCompose, 0x0045, 0x0060, 0, // Egrave, E, grave 0x00cd, kKeyCompose, 0x0049, 0x0027, 0, // Iacute, I, apostrophe 0x00ce, kKeyCompose, 0x0049, 0x0053, 0, // Icircumflex, I, asciicircum 0x00cf, kKeyCompose, 0x0049, 0x0022, 0, // Idiaeresis, I, quotedbl 0x00cc, kKeyCompose, 0x0049, 0x0060, 0, // Igrave, I, grave 0x00d1, kKeyCompose, 0x004e, 0x007e, 0, // Ntilde, N, asciitilde 0x00d3, kKeyCompose, 0x004f, 0x0027, 0, // Oacute, O, apostrophe 0x00d4, kKeyCompose, 0x004f, 0x0053, 0, // Ocircumflex, O, asciicircum 0x00d6, kKeyCompose, 0x004f, 0x0022, 0, // Odiaeresis, O, quotedbl 0x00d2, kKeyCompose, 0x004f, 0x0060, 0, // Ograve, O, grave 0x00d8, kKeyCompose, 0x004f, 0x002f, 0, // Ooblique, O, slash 0x00d5, kKeyCompose, 0x004f, 0x007e, 0, // Otilde, O, asciitilde 0x00de, kKeyCompose, 0x0054, 0x0048, 0, // THORN, T, H 0x00da, kKeyCompose, 0x0055, 0x0027, 0, // Uacute, U, apostrophe 0x00db, kKeyCompose, 0x0055, 0x0053, 0, // Ucircumflex, U, asciicircum 0x00dc, kKeyCompose, 0x0055, 0x0022, 0, // Udiaeresis, U, quotedbl 0x00d9, kKeyCompose, 0x0055, 0x0060, 0, // Ugrave, U, grave 0x00dd, kKeyCompose, 0x0059, 0x0027, 0, // Yacute, Y, apostrophe 0x00e1, kKeyCompose, 0x0061, 0x0027, 0, // aacute, a, apostrophe 0x00e2, kKeyCompose, 0x0061, 0x0053, 0, // acircumflex, a, asciicircum 0x00b4, kKeyCompose, 0x0027, 0x0027, 0, // acute, apostrophe, apostrophe 0x00e4, kKeyCompose, 0x0061, 0x0022, 0, // adiaeresis, a, quotedbl 0x00e6, kKeyCompose, 0x0061, 0x0065, 0, // ae, a, e 0x00e0, kKeyCompose, 0x0061, 0x0060, 0, // agrave, a, grave 0x00e5, kKeyCompose, 0x0061, 0x002a, 0, // aring, a, asterisk 0x0040, kKeyCompose, 0x0041, 0x0054, 0, // at, A, T 0x00e3, kKeyCompose, 0x0061, 0x007e, 0, // atilde, a, asciitilde 0x005c, kKeyCompose, 0x002f, 0x002f, 0, // backslash, slash, slash 0x007c, kKeyCompose, 0x004c, 0x0056, 0, // bar, L, V 0x007b, kKeyCompose, 0x0028, 0x002d, 0, // braceleft, parenleft, minus 0x007d, kKeyCompose, 0x0029, 0x002d, 0, // braceright, parenright, minus 0x005b, kKeyCompose, 0x0028, 0x0028, 0, // bracketleft, parenleft, parenleft 0x005d, kKeyCompose, 0x0029, 0x0029, 0, // bracketright, parenright, parenright 0x00a6, kKeyCompose, 0x0042, 0x0056, 0, // brokenbar, B, V 0x00e7, kKeyCompose, 0x0063, 0x002c, 0, // ccedilla, c, comma 0x00b8, kKeyCompose, 0x002c, 0x002c, 0, // cedilla, comma, comma 0x00a2, kKeyCompose, 0x0063, 0x002f, 0, // cent, c, slash 0x00a9, kKeyCompose, 0x0028, 0x0063, 0, // copyright, parenleft, c 0x00a4, kKeyCompose, 0x006f, 0x0078, 0, // currency, o, x 0x00b0, kKeyCompose, 0x0030, 0x0053, 0, // degree, 0, asciicircum 0x00a8, kKeyCompose, 0x0022, 0x0022, 0, // diaeresis, quotedbl, quotedbl 0x00f7, kKeyCompose, 0x003a, 0x002d, 0, // division, colon, minus 0x00e9, kKeyCompose, 0x0065, 0x0027, 0, // eacute, e, apostrophe 0x00ea, kKeyCompose, 0x0065, 0x0053, 0, // ecircumflex, e, asciicircum 0x00eb, kKeyCompose, 0x0065, 0x0022, 0, // ediaeresis, e, quotedbl 0x00e8, kKeyCompose, 0x0065, 0x0060, 0, // egrave, e, grave 0x00f0, kKeyCompose, 0x0064, 0x002d, 0, // eth, d, minus 0x00a1, kKeyCompose, 0x0021, 0x0021, 0, // exclamdown, exclam, exclam 0x00ab, kKeyCompose, 0x003c, 0x003c, 0, // guillemotleft, less, less 0x00bb, kKeyCompose, 0x003e, 0x003e, 0, // guillemotright, greater, greater 0x0023, kKeyCompose, 0x002b, 0x002b, 0, // numbersign, plus, plus 0x00ad, kKeyCompose, 0x002d, 0x002d, 0, // hyphen, minus, minus 0x00ed, kKeyCompose, 0x0069, 0x0027, 0, // iacute, i, apostrophe 0x00ee, kKeyCompose, 0x0069, 0x0053, 0, // icircumflex, i, asciicircum 0x00ef, kKeyCompose, 0x0069, 0x0022, 0, // idiaeresis, i, quotedbl 0x00ec, kKeyCompose, 0x0069, 0x0060, 0, // igrave, i, grave 0x00af, kKeyCompose, 0x002d, 0x0053, 0, // macron, minus, asciicircum 0x00ba, kKeyCompose, 0x006f, 0x005f, 0, // masculine, o, underscore 0x00b5, kKeyCompose, 0x0075, 0x002f, 0, // mu, u, slash 0x00d7, kKeyCompose, 0x0078, 0x0078, 0, // multiply, x, x 0x00a0, kKeyCompose, 0x0020, 0x0020, 0, // nobreakspace, space, space 0x00ac, kKeyCompose, 0x002c, 0x002d, 0, // notsign, comma, minus 0x00f1, kKeyCompose, 0x006e, 0x007e, 0, // ntilde, n, asciitilde 0x00f3, kKeyCompose, 0x006f, 0x0027, 0, // oacute, o, apostrophe 0x00f4, kKeyCompose, 0x006f, 0x0053, 0, // ocircumflex, o, asciicircum 0x00f6, kKeyCompose, 0x006f, 0x0022, 0, // odiaeresis, o, quotedbl 0x00f2, kKeyCompose, 0x006f, 0x0060, 0, // ograve, o, grave 0x00bd, kKeyCompose, 0x0031, 0x0032, 0, // onehalf, 1, 2 0x00bc, kKeyCompose, 0x0031, 0x0034, 0, // onequarter, 1, 4 0x00b9, kKeyCompose, 0x0031, 0x0053, 0, // onesuperior, 1, asciicircum 0x00aa, kKeyCompose, 0x0061, 0x005f, 0, // ordfeminine, a, underscore 0x00f8, kKeyCompose, 0x006f, 0x002f, 0, // oslash, o, slash 0x00f5, kKeyCompose, 0x006f, 0x007e, 0, // otilde, o, asciitilde 0x00b6, kKeyCompose, 0x0070, 0x0021, 0, // paragraph, p, exclam 0x00b7, kKeyCompose, 0x002e, 0x002e, 0, // periodcentered, period, period 0x00b1, kKeyCompose, 0x002b, 0x002d, 0, // plusminus, plus, minus 0x00bf, kKeyCompose, 0x003f, 0x003f, 0, // questiondown, question, question 0x00ae, kKeyCompose, 0x0028, 0x0072, 0, // registered, parenleft, r 0x00a7, kKeyCompose, 0x0073, 0x006f, 0, // section, s, o 0x00df, kKeyCompose, 0x0073, 0x0073, 0, // ssharp, s, s 0x00a3, kKeyCompose, 0x004c, 0x002d, 0, // sterling, L, minus 0x00fe, kKeyCompose, 0x0074, 0x0068, 0, // thorn, t, h 0x00be, kKeyCompose, 0x0033, 0x0034, 0, // threequarters, 3, 4 0x00b3, kKeyCompose, 0x0033, 0x0053, 0, // threesuperior, 3, asciicircum 0x00b2, kKeyCompose, 0x0032, 0x0053, 0, // twosuperior, 2, asciicircum 0x00fa, kKeyCompose, 0x0075, 0x0027, 0, // uacute, u, apostrophe 0x00fb, kKeyCompose, 0x0075, 0x0053, 0, // ucircumflex, u, asciicircum 0x00fc, kKeyCompose, 0x0075, 0x0022, 0, // udiaeresis, u, quotedbl 0x00f9, kKeyCompose, 0x0075, 0x0060, 0, // ugrave, u, grave 0x00fd, kKeyCompose, 0x0079, 0x0027, 0, // yacute, y, apostrophe 0x00ff, kKeyCompose, 0x0079, 0x0022, 0, // ydiaeresis, y, quotedbl 0x00a5, kKeyCompose, 0x0079, 0x003d, 0, // yen, y, equal // end of table 0 }; static const KeyID s_numpadTable[] = { kKeyKP_Space, 0x0020, kKeyKP_Tab, kKeyTab, kKeyKP_Enter, kKeyReturn, kKeyKP_F1, kKeyF1, kKeyKP_F2, kKeyF2, kKeyKP_F3, kKeyF3, kKeyKP_F4, kKeyF4, kKeyKP_Home, kKeyHome, kKeyKP_Left, kKeyLeft, kKeyKP_Up, kKeyUp, kKeyKP_Right, kKeyRight, kKeyKP_Down, kKeyDown, kKeyKP_PageUp, kKeyPageUp, kKeyKP_PageDown, kKeyPageDown, kKeyKP_End, kKeyEnd, kKeyKP_Begin, kKeyBegin, kKeyKP_Insert, kKeyInsert, kKeyKP_Delete, kKeyDelete, kKeyKP_Equal, 0x003d, kKeyKP_Multiply, 0x002a, kKeyKP_Add, 0x002b, kKeyKP_Separator, 0x002c, kKeyKP_Subtract, 0x002d, kKeyKP_Decimal, 0x002e, kKeyKP_Divide, 0x002f, kKeyKP_0, 0x0030, kKeyKP_1, 0x0031, kKeyKP_2, 0x0032, kKeyKP_3, 0x0033, kKeyKP_4, 0x0034, kKeyKP_5, 0x0035, kKeyKP_6, 0x0036, kKeyKP_7, 0x0037, kKeyKP_8, 0x0038, kKeyKP_9, 0x0039 }; // // KeyState // KeyState::KeyState(IEventQueue* events) : IKeyState(events), m_keyMapPtr(new synergy::KeyMap()), m_keyMap(*m_keyMapPtr), m_mask(0), m_events(events) { init(); } KeyState::KeyState(IEventQueue* events, synergy::KeyMap& keyMap) : IKeyState(events), m_keyMapPtr(0), m_keyMap(keyMap), m_mask(0), m_events(events) { init(); } KeyState::~KeyState() { if (m_keyMapPtr) delete m_keyMapPtr; } void KeyState::init() { memset(&m_keys, 0, sizeof(m_keys)); memset(&m_syntheticKeys, 0, sizeof(m_syntheticKeys)); memset(&m_keyClientData, 0, sizeof(m_keyClientData)); memset(&m_serverKeys, 0, sizeof(m_serverKeys)); } void KeyState::onKey(KeyButton button, bool down, KeyModifierMask newState) { // update modifier state m_mask = newState; LOG((CLOG_DEBUG1 "new mask: 0x%04x", m_mask)); // ignore bogus buttons button &= kButtonMask; if (button == 0) { return; } // update key state if (down) { m_keys[button] = 1; m_syntheticKeys[button] = 1; } else { m_keys[button] = 0; m_syntheticKeys[button] = 0; } } void KeyState::sendKeyEvent( void* target, bool press, bool isAutoRepeat, KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button) { if (m_keyMap.isHalfDuplex(key, button)) { if (isAutoRepeat) { // ignore auto-repeat on half-duplex keys } else { m_events->addEvent(Event(m_events->forIKeyState().keyDown(), target, KeyInfo::alloc(key, mask, button, 1))); m_events->addEvent(Event(m_events->forIKeyState().keyUp(), target, KeyInfo::alloc(key, mask, button, 1))); } } else { if (isAutoRepeat) { m_events->addEvent(Event(m_events->forIKeyState().keyRepeat(), target, KeyInfo::alloc(key, mask, button, count))); } else if (press) { m_events->addEvent(Event(m_events->forIKeyState().keyDown(), target, KeyInfo::alloc(key, mask, button, 1))); } else { m_events->addEvent(Event(m_events->forIKeyState().keyUp(), target, KeyInfo::alloc(key, mask, button, 1))); } } } void KeyState::updateKeyMap() { // get the current keyboard map synergy::KeyMap keyMap; getKeyMap(keyMap); m_keyMap.swap(keyMap); m_keyMap.finish(); // add special keys addCombinationEntries(); addKeypadEntries(); addAliasEntries(); } void KeyState::updateKeyState() { // reset our state memset(&m_keys, 0, sizeof(m_keys)); memset(&m_syntheticKeys, 0, sizeof(m_syntheticKeys)); memset(&m_keyClientData, 0, sizeof(m_keyClientData)); memset(&m_serverKeys, 0, sizeof(m_serverKeys)); m_activeModifiers.clear(); // get the current keyboard state KeyButtonSet keysDown; pollPressedKeys(keysDown); for (KeyButtonSet::const_iterator i = keysDown.begin(); i != keysDown.end(); ++i) { m_keys[*i] = 1; } // get the current modifier state m_mask = pollActiveModifiers(); // set active modifiers AddActiveModifierContext addModifierContext(pollActiveGroup(), m_mask, m_activeModifiers); m_keyMap.foreachKey(&KeyState::addActiveModifierCB, &addModifierContext); LOG((CLOG_DEBUG1 "modifiers on update: 0x%04x", m_mask)); } void KeyState::addActiveModifierCB(KeyID, SInt32 group, synergy::KeyMap::KeyItem& keyItem, void* vcontext) { AddActiveModifierContext* context = static_cast(vcontext); if (group == context->m_activeGroup && (keyItem.m_generates & context->m_mask) != 0) { context->m_activeModifiers.insert(std::make_pair( keyItem.m_generates, keyItem)); } } void KeyState::setHalfDuplexMask(KeyModifierMask mask) { m_keyMap.clearHalfDuplexModifiers(); if ((mask & KeyModifierCapsLock) != 0) { m_keyMap.addHalfDuplexModifier(kKeyCapsLock); } if ((mask & KeyModifierNumLock) != 0) { m_keyMap.addHalfDuplexModifier(kKeyNumLock); } if ((mask & KeyModifierScrollLock) != 0) { m_keyMap.addHalfDuplexModifier(kKeyScrollLock); } } void KeyState::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton serverID) { // if this server key is already down then this is probably a // mis-reported autorepeat. serverID &= kButtonMask; if (m_serverKeys[serverID] != 0) { fakeKeyRepeat(id, mask, 1, serverID); return; } // ignore certain keys if (isIgnoredKey(id, mask)) { LOG((CLOG_DEBUG1 "ignored key %04x %04x", id, mask)); return; } // get keys for key press Keystrokes keys; ModifierToKeys oldActiveModifiers = m_activeModifiers; const synergy::KeyMap::KeyItem* keyItem = m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, getActiveModifiersRValue(), mask, false); if (keyItem == NULL) { // a media key won't be mapped on mac, so we need to fake it in a // special way if (id == kKeyAudioDown || id == kKeyAudioUp || id == kKeyAudioMute || id == kKeyAudioPlay || id == kKeyAudioPrev || id == kKeyAudioNext || id == kKeyBrightnessDown || id == kKeyBrightnessUp ) { LOG((CLOG_DEBUG1 "emulating media key")); fakeMediaKey(id); } return; } KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers); if (localID != 0) { // note keys down ++m_keys[localID]; ++m_syntheticKeys[localID]; m_keyClientData[localID] = keyItem->m_client; m_serverKeys[serverID] = localID; } // generate key events fakeKeys(keys, 1); } bool KeyState::fakeKeyRepeat( KeyID id, KeyModifierMask mask, SInt32 count, KeyButton serverID) { serverID &= kButtonMask; // if we haven't seen this button go down then ignore it KeyButton oldLocalID = m_serverKeys[serverID]; if (oldLocalID == 0) { return false; } // get keys for key repeat Keystrokes keys; ModifierToKeys oldActiveModifiers = m_activeModifiers; const synergy::KeyMap::KeyItem* keyItem = m_keyMap.mapKey(keys, id, pollActiveGroup(), m_activeModifiers, getActiveModifiersRValue(), mask, true); if (keyItem == NULL) { return false; } KeyButton localID = (KeyButton)(keyItem->m_button & kButtonMask); if (localID == 0) { return false; } // if the KeyButton for the auto-repeat is not the same as for the // initial press then mark the initial key as released and the new // key as pressed. this can happen when we auto-repeat after a // dead key. for example, a dead accent followed by 'a' will // generate an 'a with accent' followed by a repeating 'a'. the // KeyButtons for the two KeyIDs might be different. if (localID != oldLocalID) { // replace key up with previous KeyButton but leave key down // alone so it uses the new KeyButton. for (Keystrokes::iterator index = keys.begin(); index != keys.end(); ++index) { if (index->m_type == Keystroke::kButton && index->m_data.m_button.m_button == localID) { index->m_data.m_button.m_button = oldLocalID; break; } } // note that old key is now up --m_keys[oldLocalID]; --m_syntheticKeys[oldLocalID]; // note keys down updateModifierKeyState(localID, oldActiveModifiers, m_activeModifiers); ++m_keys[localID]; ++m_syntheticKeys[localID]; m_keyClientData[localID] = keyItem->m_client; m_serverKeys[serverID] = localID; } // generate key events fakeKeys(keys, count); return true; } bool KeyState::fakeKeyUp(KeyButton serverID) { // if we haven't seen this button go down then ignore it KeyButton localID = m_serverKeys[serverID & kButtonMask]; if (localID == 0) { return false; } // get the sequence of keys to simulate key release Keystrokes keys; keys.push_back(Keystroke(localID, false, false, m_keyClientData[localID])); // note keys down --m_keys[localID]; --m_syntheticKeys[localID]; m_serverKeys[serverID] = 0; // check if this is a modifier ModifierToKeys::iterator i = m_activeModifiers.begin(); while (i != m_activeModifiers.end()) { if (i->second.m_button == localID && !i->second.m_lock) { // modifier is no longer down KeyModifierMask mask = i->first; ModifierToKeys::iterator tmp = i; ++i; m_activeModifiers.erase(tmp); if (m_activeModifiers.count(mask) == 0) { // no key for modifier is down so deactivate modifier m_mask &= ~mask; LOG((CLOG_DEBUG1 "new state %04x", m_mask)); } } else { ++i; } } // generate key events fakeKeys(keys, 1); return true; } void KeyState::fakeAllKeysUp() { Keystrokes keys; for (KeyButton i = 0; i < IKeyState::kNumButtons; ++i) { if (m_syntheticKeys[i] > 0) { keys.push_back(Keystroke(i, false, false, m_keyClientData[i])); m_keys[i] = 0; m_syntheticKeys[i] = 0; } } fakeKeys(keys, 1); memset(&m_serverKeys, 0, sizeof(m_serverKeys)); m_activeModifiers.clear(); m_mask = pollActiveModifiers(); } bool KeyState::fakeMediaKey(KeyID id) { return false; } bool KeyState::isKeyDown(KeyButton button) const { return (m_keys[button & kButtonMask] > 0); } KeyModifierMask KeyState::getActiveModifiers() const { return m_mask; } KeyModifierMask& KeyState::getActiveModifiersRValue() { return m_mask; } SInt32 KeyState::getEffectiveGroup(SInt32 group, SInt32 offset) const { return m_keyMap.getEffectiveGroup(group, offset); } bool KeyState::isIgnoredKey(KeyID key, KeyModifierMask) const { switch (key) { case kKeyCapsLock: case kKeyNumLock: case kKeyScrollLock: return true; default: return false; } } KeyButton KeyState::getButton(KeyID id, SInt32 group) const { const synergy::KeyMap::KeyItemList* items = m_keyMap.findCompatibleKey(id, group, 0, 0); if (items == NULL) { return 0; } else { return items->back().m_button; } } void KeyState::addAliasEntries() { for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { // if we can't shift any kKeyTab key in a particular group but we can // shift kKeyLeftTab then add a shifted kKeyTab entry that matches a // shifted kKeyLeftTab entry. m_keyMap.addKeyAliasEntry(kKeyTab, g, KeyModifierShift, KeyModifierShift, kKeyLeftTab, KeyModifierShift, KeyModifierShift); // if we have no kKeyLeftTab but we do have a kKeyTab that can be // shifted then add kKeyLeftTab that matches a kKeyTab. m_keyMap.addKeyAliasEntry(kKeyLeftTab, g, KeyModifierShift, KeyModifierShift, kKeyTab, 0, KeyModifierShift); // map non-breaking space to space m_keyMap.addKeyAliasEntry(0x20, g, 0, 0, 0xa0, 0, 0); } } void KeyState::addKeypadEntries() { // map every numpad key to its equivalent non-numpad key if it's not // on the keyboard. for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { for (size_t i = 0; i < sizeof(s_numpadTable) / sizeof(s_numpadTable[0]); i += 2) { m_keyMap.addKeyCombinationEntry(s_numpadTable[i], g, s_numpadTable + i + 1, 1); } } } void KeyState::addCombinationEntries() { for (SInt32 g = 0, n = m_keyMap.getNumGroups(); g < n; ++g) { // add dead and compose key composition sequences for (const KeyID* i = s_decomposeTable; *i != 0; ++i) { // count the decomposed keys for this key UInt32 numKeys = 0; for (const KeyID* j = i; *++j != 0; ) { ++numKeys; } // add an entry for this key m_keyMap.addKeyCombinationEntry(*i, g, i + 1, numKeys); // next key i += numKeys + 1; } } } void KeyState::fakeKeys(const Keystrokes& keys, UInt32 count) { // do nothing if no keys or no repeats if (count == 0 || keys.empty()) { return; } // generate key events LOG((CLOG_DEBUG1 "keystrokes:")); for (Keystrokes::const_iterator k = keys.begin(); k != keys.end(); ) { if (k->m_type == Keystroke::kButton && k->m_data.m_button.m_repeat) { // repeat from here up to but not including the next key // with m_repeat == false count times. Keystrokes::const_iterator start = k; while (count-- > 0) { // send repeating events for (k = start; k != keys.end() && k->m_type == Keystroke::kButton && k->m_data.m_button.m_repeat; ++k) { fakeKey(*k); } } // note -- k is now on the first non-repeat key after the // repeat keys, exactly where we'd like to continue from. } else { // send event fakeKey(*k); // next key ++k; } } } void KeyState::updateModifierKeyState(KeyButton button, const ModifierToKeys& oldModifiers, const ModifierToKeys& newModifiers) { // get the pressed modifier buttons before and after synergy::KeyMap::ButtonToKeyMap oldKeys, newKeys; for (ModifierToKeys::const_iterator i = oldModifiers.begin(); i != oldModifiers.end(); ++i) { oldKeys.insert(std::make_pair(i->second.m_button, &i->second)); } for (ModifierToKeys::const_iterator i = newModifiers.begin(); i != newModifiers.end(); ++i) { newKeys.insert(std::make_pair(i->second.m_button, &i->second)); } // get the modifier buttons that were pressed or released synergy::KeyMap::ButtonToKeyMap pressed, released; std::set_difference(oldKeys.begin(), oldKeys.end(), newKeys.begin(), newKeys.end(), std::inserter(released, released.end()), ButtonToKeyLess()); std::set_difference(newKeys.begin(), newKeys.end(), oldKeys.begin(), oldKeys.end(), std::inserter(pressed, pressed.end()), ButtonToKeyLess()); // update state for (synergy::KeyMap::ButtonToKeyMap::const_iterator i = released.begin(); i != released.end(); ++i) { if (i->first != button) { m_keys[i->first] = 0; m_syntheticKeys[i->first] = 0; } } for (synergy::KeyMap::ButtonToKeyMap::const_iterator i = pressed.begin(); i != pressed.end(); ++i) { if (i->first != button) { m_keys[i->first] = 1; m_syntheticKeys[i->first] = 1; m_keyClientData[i->first] = i->second->m_client; } } } // // KeyState::AddActiveModifierContext // KeyState::AddActiveModifierContext::AddActiveModifierContext( SInt32 group, KeyModifierMask mask, ModifierToKeys& activeModifiers) : m_activeGroup(group), m_mask(mask), m_activeModifiers(activeModifiers) { // do nothing } synergy-1.8.8-stable/src/lib/synergy/KeyState.h000066400000000000000000000150531305627404700214530ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/IKeyState.h" #include "synergy/KeyMap.h" //! Core key state /*! This class provides key state services. Subclasses must implement a few platform specific methods. */ class KeyState : public IKeyState { public: KeyState(IEventQueue* events); KeyState(IEventQueue* events, synergy::KeyMap& keyMap); virtual ~KeyState(); //! @name manipulators //@{ //! Handle key event /*! Sets the state of \p button to down or up and updates the current modifier state to \p newState. This method should be called by primary screens only in response to local events. For auto-repeat set \p down to \c true. Overrides must forward to the superclass. */ virtual void onKey(KeyButton button, bool down, KeyModifierMask newState); //! Post a key event /*! Posts a key event. This may adjust the event or post additional events in some circumstances. If this is overridden it must forward to the superclass. */ virtual void sendKeyEvent(void* target, bool press, bool isAutoRepeat, KeyID key, KeyModifierMask mask, SInt32 count, KeyButton button); //@} //! @name accessors //@{ //@} // IKeyState overrides virtual void updateKeyMap(); virtual void updateKeyState(); virtual void setHalfDuplexMask(KeyModifierMask); virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button); virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button); virtual bool fakeKeyUp(KeyButton button); virtual void fakeAllKeysUp(); virtual bool fakeCtrlAltDel() = 0; virtual bool fakeMediaKey(KeyID id); virtual bool isKeyDown(KeyButton) const; virtual KeyModifierMask getActiveModifiers() const; virtual KeyModifierMask pollActiveModifiers() const = 0; virtual SInt32 pollActiveGroup() const = 0; virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const = 0; SInt32 getKeyState(KeyButton keyButton) { return m_keys[keyButton]; } protected: typedef synergy::KeyMap::Keystroke Keystroke; //! @name protected manipulators //@{ //! Get the keyboard map /*! Fills \p keyMap with the current keyboard map. */ virtual void getKeyMap(synergy::KeyMap& keyMap) = 0; //! Fake a key event /*! Synthesize an event for \p keystroke. */ virtual void fakeKey(const Keystroke& keystroke) = 0; //! Get the active modifiers /*! Returns the modifiers that are currently active according to our shadowed state. The state may be modified. */ virtual KeyModifierMask& getActiveModifiersRValue(); //@} //! @name protected accessors //@{ //! Compute a group number /*! Returns the number of the group \p offset groups after group \p group. */ SInt32 getEffectiveGroup(SInt32 group, SInt32 offset) const; //! Check if key is ignored /*! Returns \c true if and only if the key should always be ignored. The default returns \c true only for the toggle keys. */ virtual bool isIgnoredKey(KeyID key, KeyModifierMask mask) const; //! Get button for a KeyID /*! Return the button mapped to key \p id in group \p group if any, otherwise returns 0. */ KeyButton getButton(KeyID id, SInt32 group) const; //@} private: typedef synergy::KeyMap::Keystrokes Keystrokes; typedef synergy::KeyMap::ModifierToKeys ModifierToKeys; public: struct AddActiveModifierContext { public: AddActiveModifierContext(SInt32 group, KeyModifierMask mask, ModifierToKeys& activeModifiers); public: SInt32 m_activeGroup; KeyModifierMask m_mask; ModifierToKeys& m_activeModifiers; private: // not implemented AddActiveModifierContext(const AddActiveModifierContext&); AddActiveModifierContext& operator=(const AddActiveModifierContext&); }; private: class ButtonToKeyLess { public: bool operator()(const synergy::KeyMap::ButtonToKeyMap::value_type& a, const synergy::KeyMap::ButtonToKeyMap::value_type b) const { return (a.first < b.first); } }; // not implemented KeyState(const KeyState&); KeyState& operator=(const KeyState&); // called by all ctors. void init(); // adds alias key sequences. these are sequences that are equivalent // to other sequences. void addAliasEntries(); // adds non-keypad key sequences for keypad KeyIDs void addKeypadEntries(); // adds key sequences for combination KeyIDs (those built using // dead keys) void addCombinationEntries(); // synthesize key events. synthesize auto-repeat events count times. void fakeKeys(const Keystrokes&, UInt32 count); // update key state to match changes to modifiers void updateModifierKeyState(KeyButton button, const ModifierToKeys& oldModifiers, const ModifierToKeys& newModifiers); // active modifiers collection callback static void addActiveModifierCB(KeyID id, SInt32 group, synergy::KeyMap::KeyItem& keyItem, void* vcontext); private: // must be declared before m_keyMap. used when this class owns the key map. synergy::KeyMap* m_keyMapPtr; // the keyboard map synergy::KeyMap& m_keyMap; // current modifier state KeyModifierMask m_mask; // the active modifiers and the buttons activating them ModifierToKeys m_activeModifiers; // current keyboard state (> 0 if pressed, 0 otherwise). this is // initialized to the keyboard state according to the system then // it tracks synthesized events. SInt32 m_keys[kNumButtons]; // synthetic keyboard state (> 0 if pressed, 0 otherwise). this // tracks the synthesized keyboard state. if m_keys[n] > 0 but // m_syntheticKeys[n] == 0 then the key was pressed locally and // not synthesized yet. SInt32 m_syntheticKeys[kNumButtons]; // client data for each pressed key UInt32 m_keyClientData[kNumButtons]; // server keyboard state. an entry is 0 if not the key isn't pressed // otherwise it's the local KeyButton synthesized for the server key. KeyButton m_serverKeys[kNumButtons]; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/synergy/PacketStreamFilter.cpp000066400000000000000000000103431305627404700240030ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/PacketStreamFilter.h" #include "base/IEventQueue.h" #include "mt/Lock.h" #include "base/TMethodEventJob.h" #include #include // // PacketStreamFilter // PacketStreamFilter::PacketStreamFilter(IEventQueue* events, synergy::IStream* stream, bool adoptStream) : StreamFilter(events, stream, adoptStream), m_size(0), m_inputShutdown(false), m_events(events) { // do nothing } PacketStreamFilter::~PacketStreamFilter() { // do nothing } void PacketStreamFilter::close() { Lock lock(&m_mutex); m_size = 0; m_buffer.pop(m_buffer.getSize()); StreamFilter::close(); } UInt32 PacketStreamFilter::read(void* buffer, UInt32 n) { if (n == 0) { return 0; } Lock lock(&m_mutex); // if not enough data yet then give up if (!isReadyNoLock()) { return 0; } // read no more than what's left in the buffered packet if (n > m_size) { n = m_size; } // read it if (buffer != NULL) { memcpy(buffer, m_buffer.peek(n), n); } m_buffer.pop(n); m_size -= n; // get next packet's size if we've finished with this packet and // there's enough data to do so. readPacketSize(); if (m_inputShutdown && m_size == 0) { m_events->addEvent(Event(m_events->forIStream().inputShutdown(), getEventTarget(), NULL)); } return n; } void PacketStreamFilter::write(const void* buffer, UInt32 count) { // write the length of the payload UInt8 length[4]; length[0] = (UInt8)((count >> 24) & 0xff); length[1] = (UInt8)((count >> 16) & 0xff); length[2] = (UInt8)((count >> 8) & 0xff); length[3] = (UInt8)( count & 0xff); getStream()->write(length, sizeof(length)); // write the payload getStream()->write(buffer, count); } void PacketStreamFilter::shutdownInput() { Lock lock(&m_mutex); m_size = 0; m_buffer.pop(m_buffer.getSize()); StreamFilter::shutdownInput(); } bool PacketStreamFilter::isReady() const { Lock lock(&m_mutex); return isReadyNoLock(); } UInt32 PacketStreamFilter::getSize() const { Lock lock(&m_mutex); return isReadyNoLock() ? m_size : 0; } bool PacketStreamFilter::isReadyNoLock() const { return (m_size != 0 && m_buffer.getSize() >= m_size); } void PacketStreamFilter::readPacketSize() { // note -- m_mutex must be locked on entry if (m_size == 0 && m_buffer.getSize() >= 4) { UInt8 buffer[4]; memcpy(buffer, m_buffer.peek(sizeof(buffer)), sizeof(buffer)); m_buffer.pop(sizeof(buffer)); m_size = ((UInt32)buffer[0] << 24) | ((UInt32)buffer[1] << 16) | ((UInt32)buffer[2] << 8) | (UInt32)buffer[3]; } } bool PacketStreamFilter::readMore() { // note if we have whole packet bool wasReady = isReadyNoLock(); // read more data char buffer[4096]; UInt32 n = getStream()->read(buffer, sizeof(buffer)); while (n > 0) { m_buffer.write(buffer, n); n = getStream()->read(buffer, sizeof(buffer)); } // if we don't yet have the next packet size then get it, // if possible. readPacketSize(); // note if we now have a whole packet bool isReady = isReadyNoLock(); // if we weren't ready before but now we are then send a // input ready event apparently from the filtered stream. return (wasReady != isReady); } void PacketStreamFilter::filterEvent(const Event& event) { if (event.getType() == m_events->forIStream().inputReady()) { Lock lock(&m_mutex); if (!readMore()) { return; } } else if (event.getType() == m_events->forIStream().inputShutdown()) { // discard this if we have buffered data Lock lock(&m_mutex); m_inputShutdown = true; if (m_size != 0) { return; } } // pass event StreamFilter::filterEvent(event); } synergy-1.8.8-stable/src/lib/synergy/PacketStreamFilter.h000066400000000000000000000031551305627404700234530ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "io/StreamFilter.h" #include "io/StreamBuffer.h" #include "mt/Mutex.h" class IEventQueue; //! Packetizing stream filter /*! Filters a stream to read and write packets. */ class PacketStreamFilter : public StreamFilter { public: PacketStreamFilter(IEventQueue* events, synergy::IStream* stream, bool adoptStream = true); ~PacketStreamFilter(); // IStream overrides virtual void close(); virtual UInt32 read(void* buffer, UInt32 n); virtual void write(const void* buffer, UInt32 n); virtual void shutdownInput(); virtual bool isReady() const; virtual UInt32 getSize() const; protected: // StreamFilter overrides virtual void filterEvent(const Event&); private: bool isReadyNoLock() const; void readPacketSize(); bool readMore(); private: Mutex m_mutex; UInt32 m_size; StreamBuffer m_buffer; bool m_inputShutdown; IEventQueue* m_events; }; synergy-1.8.8-stable/src/lib/synergy/PlatformScreen.cpp000066400000000000000000000047541305627404700232070ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/PlatformScreen.h" #include "synergy/App.h" #include "synergy/ArgsBase.h" PlatformScreen::PlatformScreen(IEventQueue* events) : IPlatformScreen(events), m_draggingStarted(false), m_fakeDraggingStarted(false) { } PlatformScreen::~PlatformScreen() { // do nothing } void PlatformScreen::updateKeyMap() { getKeyState()->updateKeyMap(); } void PlatformScreen::updateKeyState() { getKeyState()->updateKeyState(); updateButtons(); } void PlatformScreen::setHalfDuplexMask(KeyModifierMask mask) { getKeyState()->setHalfDuplexMask(mask); } void PlatformScreen::fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button) { getKeyState()->fakeKeyDown(id, mask, button); } bool PlatformScreen::fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) { return getKeyState()->fakeKeyRepeat(id, mask, count, button); } bool PlatformScreen::fakeKeyUp(KeyButton button) { return getKeyState()->fakeKeyUp(button); } void PlatformScreen::fakeAllKeysUp() { getKeyState()->fakeAllKeysUp(); } bool PlatformScreen::fakeCtrlAltDel() { return getKeyState()->fakeCtrlAltDel(); } bool PlatformScreen::isKeyDown(KeyButton button) const { return getKeyState()->isKeyDown(button); } KeyModifierMask PlatformScreen::getActiveModifiers() const { return getKeyState()->getActiveModifiers(); } KeyModifierMask PlatformScreen::pollActiveModifiers() const { return getKeyState()->pollActiveModifiers(); } SInt32 PlatformScreen::pollActiveGroup() const { return getKeyState()->pollActiveGroup(); } void PlatformScreen::pollPressedKeys(KeyButtonSet& pressedKeys) const { getKeyState()->pollPressedKeys(pressedKeys); } bool PlatformScreen::isDraggingStarted() { if (App::instance().argsBase().m_enableDragDrop) { return m_draggingStarted; } return false; } synergy-1.8.8-stable/src/lib/synergy/PlatformScreen.h000066400000000000000000000112751305627404700226500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2004 Chris Schoeneman * * This package is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * found in the file LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/IPlatformScreen.h" #include "synergy/DragInformation.h" #include "common/stdexcept.h" //! Base screen implementation /*! This screen implementation is the superclass of all other screen implementations. It implements a handful of methods and requires subclasses to implement the rest. */ class PlatformScreen : public IPlatformScreen { public: PlatformScreen(IEventQueue* events); virtual ~PlatformScreen(); // IScreen overrides virtual void* getEventTarget() const = 0; virtual bool getClipboard(ClipboardID id, IClipboard*) const = 0; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const = 0; virtual void getCursorPos(SInt32& x, SInt32& y) const = 0; // IPrimaryScreen overrides virtual void reconfigure(UInt32 activeSides) = 0; virtual void warpCursor(SInt32 x, SInt32 y) = 0; virtual UInt32 registerHotKey(KeyID key, KeyModifierMask mask) = 0; virtual void unregisterHotKey(UInt32 id) = 0; virtual void fakeInputBegin() = 0; virtual void fakeInputEnd() = 0; virtual SInt32 getJumpZoneSize() const = 0; virtual bool isAnyMouseButtonDown(UInt32& buttonID) const = 0; virtual void getCursorCenter(SInt32& x, SInt32& y) const = 0; // ISecondaryScreen overrides virtual void fakeMouseButton(ButtonID id, bool press) = 0; virtual void fakeMouseMove(SInt32 x, SInt32 y) = 0; virtual void fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const = 0; virtual void fakeMouseWheel(SInt32 xDelta, SInt32 yDelta) const = 0; // IKeyState overrides virtual void updateKeyMap(); virtual void updateKeyState(); virtual void setHalfDuplexMask(KeyModifierMask); virtual void fakeKeyDown(KeyID id, KeyModifierMask mask, KeyButton button); virtual bool fakeKeyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button); virtual bool fakeKeyUp(KeyButton button); virtual void fakeAllKeysUp(); virtual bool fakeCtrlAltDel(); virtual bool isKeyDown(KeyButton) const; virtual KeyModifierMask getActiveModifiers() const; virtual KeyModifierMask pollActiveModifiers() const; virtual SInt32 pollActiveGroup() const; virtual void pollPressedKeys(KeyButtonSet& pressedKeys) const; virtual void setDraggingStarted(bool started) { m_draggingStarted = started; } virtual bool isDraggingStarted(); virtual bool isFakeDraggingStarted() { return m_fakeDraggingStarted; } virtual String& getDraggingFilename() { return m_draggingFilename; } virtual void clearDraggingFilename() { } // IPlatformScreen overrides virtual void enable() = 0; virtual void disable() = 0; virtual void enter() = 0; virtual bool leave() = 0; virtual bool setClipboard(ClipboardID, const IClipboard*) = 0; virtual void checkClipboards() = 0; virtual void openScreensaver(bool notify) = 0; virtual void closeScreensaver() = 0; virtual void screensaver(bool activate) = 0; virtual void resetOptions() = 0; virtual void setOptions(const OptionsList& options) = 0; virtual void setSequenceNumber(UInt32) = 0; virtual bool isPrimary() const = 0; virtual void fakeDraggingFiles(DragFileList fileList) { throw std::runtime_error("fakeDraggingFiles not implemented"); } virtual const String& getDropTarget() const { throw std::runtime_error("getDropTarget not implemented"); } protected: //! Update mouse buttons /*! Subclasses must implement this method to update their internal mouse button mapping and, if desired, state tracking. */ virtual void updateButtons() = 0; //! Get the key state /*! Subclasses must implement this method to return the platform specific key state object that each subclass must have. */ virtual IKeyState* getKeyState() const = 0; // IPlatformScreen overrides virtual void handleSystemEvent(const Event& event, void*) = 0; protected: String m_draggingFilename; bool m_draggingStarted; bool m_fakeDraggingStarted; }; synergy-1.8.8-stable/src/lib/synergy/PortableTaskBarReceiver.cpp000066400000000000000000000046051305627404700247630ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/PortableTaskBarReceiver.h" #include "mt/Lock.h" #include "base/String.h" #include "base/IEventQueue.h" #include "arch/Arch.h" #include "common/Version.h" // // PortableTaskBarReceiver // PortableTaskBarReceiver::PortableTaskBarReceiver(IEventQueue* events) : m_state(kNotRunning), m_events(events) { // do nothing } PortableTaskBarReceiver::~PortableTaskBarReceiver() { // do nothing } void PortableTaskBarReceiver::updateStatus(INode* node, const String& errorMsg) { { // update our status m_errorMessage = errorMsg; if (node == NULL) { if (m_errorMessage.empty()) { m_state = kNotRunning; } else { m_state = kNotWorking; } } else { m_state = kNotConnected; } // let subclasses have a go onStatusChanged(node); } // tell task bar ARCH->updateReceiver(this); } PortableTaskBarReceiver::EState PortableTaskBarReceiver::getStatus() const { return m_state; } const String& PortableTaskBarReceiver::getErrorMessage() const { return m_errorMessage; } void PortableTaskBarReceiver::quit() { m_events->addEvent(Event(Event::kQuit)); } void PortableTaskBarReceiver::onStatusChanged(INode*) { // do nothing } void PortableTaskBarReceiver::lock() const { // do nothing } void PortableTaskBarReceiver::unlock() const { // do nothing } std::string PortableTaskBarReceiver::getToolTip() const { switch (m_state) { case kNotRunning: return synergy::string::sprintf("%s: Not running", kAppVersion); case kNotWorking: return synergy::string::sprintf("%s: %s", kAppVersion, m_errorMessage.c_str()); case kNotConnected: return synergy::string::sprintf("%s: Unknown", kAppVersion); default: return ""; } } synergy-1.8.8-stable/src/lib/synergy/PortableTaskBarReceiver.h000066400000000000000000000045501305627404700244270ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/INode.h" #include "arch/IArchTaskBarReceiver.h" #include "base/log_outputters.h" #include "base/EventTypes.h" #include "base/Event.h" #include "base/String.h" #include "common/stdvector.h" class IEventQueue; //! Implementation of IArchTaskBarReceiver for the synergy server class PortableTaskBarReceiver : public IArchTaskBarReceiver { public: PortableTaskBarReceiver(IEventQueue* events); virtual ~PortableTaskBarReceiver(); //! @name manipulators //@{ //! Update status /*! Determine the status and query required information from the server. */ void updateStatus(INode*, const String& errorMsg); //@} // IArchTaskBarReceiver overrides virtual void showStatus() = 0; virtual void runMenu(int x, int y) = 0; virtual void primaryAction() = 0; virtual void lock() const; virtual void unlock() const; virtual const Icon getIcon() const = 0; virtual std::string getToolTip() const; protected: typedef std::vector Clients; enum EState { kNotRunning, kNotWorking, kNotConnected, kConnected, kMaxState }; //! Get status EState getStatus() const; //! Get error message const String& getErrorMessage() const; //! Quit app /*! Causes the application to quit gracefully */ void quit(); //! Status change notification /*! Called when status changes. The default implementation does nothing. */ virtual void onStatusChanged(INode* node); private: EState m_state; String m_errorMessage; String m_server; Clients m_clients; IEventQueue* m_events; }; IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events); synergy-1.8.8-stable/src/lib/synergy/ProtocolUtil.cpp000066400000000000000000000312371305627404700227160ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ProtocolUtil.h" #include "io/IStream.h" #include "base/Log.h" #include "common/stdvector.h" #include #include // // ProtocolUtil // void ProtocolUtil::writef(synergy::IStream* stream, const char* fmt, ...) { assert(stream != NULL); assert(fmt != NULL); LOG((CLOG_DEBUG2 "writef(%s)", fmt)); va_list args; va_start(args, fmt); UInt32 size = getLength(fmt, args); va_end(args); va_start(args, fmt); vwritef(stream, fmt, size, args); va_end(args); } bool ProtocolUtil::readf(synergy::IStream* stream, const char* fmt, ...) { assert(stream != NULL); assert(fmt != NULL); LOG((CLOG_DEBUG2 "readf(%s)", fmt)); bool result; va_list args; va_start(args, fmt); try { vreadf(stream, fmt, args); result = true; } catch (XIO&) { result = false; } va_end(args); return result; } void ProtocolUtil::vwritef(synergy::IStream* stream, const char* fmt, UInt32 size, va_list args) { assert(stream != NULL); assert(fmt != NULL); // done if nothing to write if (size == 0) { return; } // fill buffer UInt8* buffer = new UInt8[size]; writef(buffer, fmt, args); try { // write buffer stream->write(buffer, size); LOG((CLOG_DEBUG2 "wrote %d bytes", size)); delete[] buffer; } catch (XBase&) { delete[] buffer; throw; } } void ProtocolUtil::vreadf(synergy::IStream* stream, const char* fmt, va_list args) { assert(stream != NULL); assert(fmt != NULL); // begin scanning while (*fmt) { if (*fmt == '%') { // format specifier. determine argument size. ++fmt; UInt32 len = eatLength(&fmt); switch (*fmt) { case 'i': { // check for valid length assert(len == 1 || len == 2 || len == 4); // read the data UInt8 buffer[4]; read(stream, buffer, len); // convert it void* v = va_arg(args, void*); switch (len) { case 1: // 1 byte integer *static_cast(v) = buffer[0]; LOG((CLOG_DEBUG2 "readf: read %d byte integer: %d (0x%x)", len, *static_cast(v), *static_cast(v))); break; case 2: // 2 byte integer *static_cast(v) = static_cast( (static_cast(buffer[0]) << 8) | static_cast(buffer[1])); LOG((CLOG_DEBUG2 "readf: read %d byte integer: %d (0x%x)", len, *static_cast(v), *static_cast(v))); break; case 4: // 4 byte integer *static_cast(v) = (static_cast(buffer[0]) << 24) | (static_cast(buffer[1]) << 16) | (static_cast(buffer[2]) << 8) | static_cast(buffer[3]); LOG((CLOG_DEBUG2 "readf: read %d byte integer: %d (0x%x)", len, *static_cast(v), *static_cast(v))); break; } break; } case 'I': { // check for valid length assert(len == 1 || len == 2 || len == 4); // read the vector length UInt8 buffer[4]; read(stream, buffer, 4); UInt32 n = (static_cast(buffer[0]) << 24) | (static_cast(buffer[1]) << 16) | (static_cast(buffer[2]) << 8) | static_cast(buffer[3]); // convert it void* v = va_arg(args, void*); switch (len) { case 1: // 1 byte integer for (UInt32 i = 0; i < n; ++i) { read(stream, buffer, 1); static_cast*>(v)->push_back( buffer[0]); LOG((CLOG_DEBUG2 "readf: read %d byte integer[%d]: %d (0x%x)", len, i, static_cast*>(v)->back(), static_cast*>(v)->back())); } break; case 2: // 2 byte integer for (UInt32 i = 0; i < n; ++i) { read(stream, buffer, 2); static_cast*>(v)->push_back( static_cast( (static_cast(buffer[0]) << 8) | static_cast(buffer[1]))); LOG((CLOG_DEBUG2 "readf: read %d byte integer[%d]: %d (0x%x)", len, i, static_cast*>(v)->back(), static_cast*>(v)->back())); } break; case 4: // 4 byte integer for (UInt32 i = 0; i < n; ++i) { read(stream, buffer, 4); static_cast*>(v)->push_back( (static_cast(buffer[0]) << 24) | (static_cast(buffer[1]) << 16) | (static_cast(buffer[2]) << 8) | static_cast(buffer[3])); LOG((CLOG_DEBUG2 "readf: read %d byte integer[%d]: %d (0x%x)", len, i, static_cast*>(v)->back(), static_cast*>(v)->back())); } break; } break; } case 's': { assert(len == 0); // read the string length UInt8 buffer[128]; read(stream, buffer, 4); UInt32 len = (static_cast(buffer[0]) << 24) | (static_cast(buffer[1]) << 16) | (static_cast(buffer[2]) << 8) | static_cast(buffer[3]); // use a fixed size buffer if its big enough const bool useFixed = (len <= sizeof(buffer)); // allocate a buffer to read the data UInt8* sBuffer = buffer; if (!useFixed) { sBuffer = new UInt8[len]; } // read the data try { read(stream, sBuffer, len); } catch (...) { if (!useFixed) { delete[] sBuffer; } throw; } LOG((CLOG_DEBUG2 "readf: read %d byte string", len)); // save the data String* dst = va_arg(args, String*); dst->assign((const char*)sBuffer, len); // release the buffer if (!useFixed) { delete[] sBuffer; } break; } case '%': assert(len == 0); break; default: assert(0 && "invalid format specifier"); } // next format character ++fmt; } else { // read next character char buffer[1]; read(stream, buffer, 1); // verify match if (buffer[0] != *fmt) { LOG((CLOG_DEBUG2 "readf: format mismatch: %c vs %c", *fmt, buffer[0])); throw XIOReadMismatch(); } // next format character ++fmt; } } } UInt32 ProtocolUtil::getLength(const char* fmt, va_list args) { UInt32 n = 0; while (*fmt) { if (*fmt == '%') { // format specifier. determine argument size. ++fmt; UInt32 len = eatLength(&fmt); switch (*fmt) { case 'i': assert(len == 1 || len == 2 || len == 4); (void)va_arg(args, UInt32); break; case 'I': assert(len == 1 || len == 2 || len == 4); switch (len) { case 1: len = (UInt32)(va_arg(args, std::vector*))->size() + 4; break; case 2: len = 2 * (UInt32)(va_arg(args, std::vector*))->size() + 4; break; case 4: len = 4 * (UInt32)(va_arg(args, std::vector*))->size() + 4; break; } break; case 's': assert(len == 0); len = (UInt32)(va_arg(args, String*))->size() + 4; (void)va_arg(args, UInt8*); break; case 'S': assert(len == 0); len = va_arg(args, UInt32) + 4; (void)va_arg(args, UInt8*); break; case '%': assert(len == 0); len = 1; break; default: assert(0 && "invalid format specifier"); } // accumulate size n += len; ++fmt; } else { // regular character ++n; ++fmt; } } return n; } void ProtocolUtil::writef(void* buffer, const char* fmt, va_list args) { UInt8* dst = static_cast(buffer); while (*fmt) { if (*fmt == '%') { // format specifier. determine argument size. ++fmt; UInt32 len = eatLength(&fmt); switch (*fmt) { case 'i': { const UInt32 v = va_arg(args, UInt32); switch (len) { case 1: // 1 byte integer *dst++ = static_cast(v & 0xff); break; case 2: // 2 byte integer *dst++ = static_cast((v >> 8) & 0xff); *dst++ = static_cast( v & 0xff); break; case 4: // 4 byte integer *dst++ = static_cast((v >> 24) & 0xff); *dst++ = static_cast((v >> 16) & 0xff); *dst++ = static_cast((v >> 8) & 0xff); *dst++ = static_cast( v & 0xff); break; default: assert(0 && "invalid integer format length"); return; } break; } case 'I': { switch (len) { case 1: { // 1 byte integers const std::vector* list = va_arg(args, const std::vector*); const UInt32 n = (UInt32)list->size(); *dst++ = static_cast((n >> 24) & 0xff); *dst++ = static_cast((n >> 16) & 0xff); *dst++ = static_cast((n >> 8) & 0xff); *dst++ = static_cast( n & 0xff); for (UInt32 i = 0; i < n; ++i) { *dst++ = (*list)[i]; } break; } case 2: { // 2 byte integers const std::vector* list = va_arg(args, const std::vector*); const UInt32 n = (UInt32)list->size(); *dst++ = static_cast((n >> 24) & 0xff); *dst++ = static_cast((n >> 16) & 0xff); *dst++ = static_cast((n >> 8) & 0xff); *dst++ = static_cast( n & 0xff); for (UInt32 i = 0; i < n; ++i) { const UInt16 v = (*list)[i]; *dst++ = static_cast((v >> 8) & 0xff); *dst++ = static_cast( v & 0xff); } break; } case 4: { // 4 byte integers const std::vector* list = va_arg(args, const std::vector*); const UInt32 n = (UInt32)list->size(); *dst++ = static_cast((n >> 24) & 0xff); *dst++ = static_cast((n >> 16) & 0xff); *dst++ = static_cast((n >> 8) & 0xff); *dst++ = static_cast( n & 0xff); for (UInt32 i = 0; i < n; ++i) { const UInt32 v = (*list)[i]; *dst++ = static_cast((v >> 24) & 0xff); *dst++ = static_cast((v >> 16) & 0xff); *dst++ = static_cast((v >> 8) & 0xff); *dst++ = static_cast( v & 0xff); } break; } default: assert(0 && "invalid integer vector format length"); return; } break; } case 's': { assert(len == 0); const String* src = va_arg(args, String*); const UInt32 len = (src != NULL) ? (UInt32)src->size() : 0; *dst++ = static_cast((len >> 24) & 0xff); *dst++ = static_cast((len >> 16) & 0xff); *dst++ = static_cast((len >> 8) & 0xff); *dst++ = static_cast( len & 0xff); if (len != 0) { memcpy(dst, src->data(), len); dst += len; } break; } case 'S': { assert(len == 0); const UInt32 len = va_arg(args, UInt32); const UInt8* src = va_arg(args, UInt8*); *dst++ = static_cast((len >> 24) & 0xff); *dst++ = static_cast((len >> 16) & 0xff); *dst++ = static_cast((len >> 8) & 0xff); *dst++ = static_cast( len & 0xff); memcpy(dst, src, len); dst += len; break; } case '%': assert(len == 0); *dst++ = '%'; break; default: assert(0 && "invalid format specifier"); } // next format character ++fmt; } else { // copy regular character *dst++ = *fmt++; } } } UInt32 ProtocolUtil::eatLength(const char** pfmt) { const char* fmt = *pfmt; UInt32 n = 0; for (;;) { UInt32 d; switch (*fmt) { case '0': d = 0; break; case '1': d = 1; break; case '2': d = 2; break; case '3': d = 3; break; case '4': d = 4; break; case '5': d = 5; break; case '6': d = 6; break; case '7': d = 7; break; case '8': d = 8; break; case '9': d = 9; break; default: *pfmt = fmt; return n; } n = 10 * n + d; ++fmt; } } void ProtocolUtil::read(synergy::IStream* stream, void* vbuffer, UInt32 count) { assert(stream != NULL); assert(vbuffer != NULL); UInt8* buffer = static_cast(vbuffer); while (count > 0) { // read more UInt32 n = stream->read(buffer, count); // bail if stream has hungup if (n == 0) { LOG((CLOG_DEBUG2 "unexpected disconnect in readf(), %d bytes left", count)); throw XIOEndOfStream(); } // prepare for next read buffer += n; count -= n; } } // // XIOReadMismatch // String XIOReadMismatch::getWhat() const throw() { return format("XIOReadMismatch", "ProtocolUtil::readf() mismatch"); } synergy-1.8.8-stable/src/lib/synergy/ProtocolUtil.h000066400000000000000000000063751305627404700223700ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "io/XIO.h" #include "base/EventTypes.h" #include namespace synergy { class IStream; } //! Synergy protocol utilities /*! This class provides various functions for implementing the synergy protocol. */ class ProtocolUtil { public: //! Write formatted data /*! Write formatted binary data to a stream. \c fmt consists of regular characters and format specifiers. Format specifiers begin with \%. All characters not part of a format specifier are regular and are transmitted unchanged. Format specifiers are: - \%\% -- literal `\%' - \%1i -- converts integer argument to 1 byte integer - \%2i -- converts integer argument to 2 byte integer in NBO - \%4i -- converts integer argument to 4 byte integer in NBO - \%1I -- converts std::vector* to 1 byte integers - \%2I -- converts std::vector* to 2 byte integers in NBO - \%4I -- converts std::vector* to 4 byte integers in NBO - \%s -- converts String* to stream of bytes - \%S -- converts integer N and const UInt8* to stream of N bytes */ static void writef(synergy::IStream*, const char* fmt, ...); //! Read formatted data /*! Read formatted binary data from a buffer. This performs the reverse operation of writef(). Returns true if the entire format was successfully parsed, false otherwise. Format specifiers are: - \%\% -- read (and discard) a literal `\%' - \%1i -- reads a 1 byte integer; argument is a SInt32* or UInt32* - \%2i -- reads an NBO 2 byte integer; arg is SInt32* or UInt32* - \%4i -- reads an NBO 4 byte integer; arg is SInt32* or UInt32* - \%1I -- reads 1 byte integers; arg is std::vector* - \%2I -- reads NBO 2 byte integers; arg is std::vector* - \%4I -- reads NBO 4 byte integers; arg is std::vector* - \%s -- reads bytes; argument must be a String*, \b not a char* */ static bool readf(synergy::IStream*, const char* fmt, ...); private: static void vwritef(synergy::IStream*, const char* fmt, UInt32 size, va_list); static void vreadf(synergy::IStream*, const char* fmt, va_list); static UInt32 getLength(const char* fmt, va_list); static void writef(void*, const char* fmt, va_list); static UInt32 eatLength(const char** fmt); static void read(synergy::IStream*, void*, UInt32); }; //! Mismatched read exception /*! Thrown by ProtocolUtil::readf() when the data being read does not match the format. */ class XIOReadMismatch : public XIO { public: // XBase overrides virtual String getWhat() const throw(); }; synergy-1.8.8-stable/src/lib/synergy/Screen.cpp000066400000000000000000000237201305627404700214740ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/Screen.h" #include "synergy/IPlatformScreen.h" #include "synergy/protocol_types.h" #include "base/Log.h" #include "base/IEventQueue.h" #include "server/ClientProxy.h" #include "base/TMethodEventJob.h" namespace synergy { // // Screen // Screen::Screen(IPlatformScreen* platformScreen, IEventQueue* events) : m_screen(platformScreen), m_isPrimary(platformScreen->isPrimary()), m_enabled(false), m_entered(m_isPrimary), m_screenSaverSync(true), m_fakeInput(false), m_events(events), m_mock(false), m_enableDragDrop(false) { assert(m_screen != NULL); // reset options resetOptions(); LOG((CLOG_DEBUG "opened display")); } Screen::~Screen() { if (m_mock) { return; } if (m_enabled) { disable(); } assert(!m_enabled); assert(m_entered == m_isPrimary); delete m_screen; LOG((CLOG_DEBUG "closed display")); } void Screen::enable() { assert(!m_enabled); m_screen->updateKeyMap(); m_screen->updateKeyState(); m_screen->enable(); if (m_isPrimary) { enablePrimary(); } else { enableSecondary(); } // note activation m_enabled = true; } void Screen::disable() { assert(m_enabled); if (!m_isPrimary && m_entered) { leave(); } else if (m_isPrimary && !m_entered) { enter(0); } m_screen->disable(); if (m_isPrimary) { disablePrimary(); } else { disableSecondary(); } // note deactivation m_enabled = false; } void Screen::enter(KeyModifierMask toggleMask) { assert(m_entered == false); LOG((CLOG_INFO "entering screen")); // now on screen m_entered = true; m_screen->enter(); if (m_isPrimary) { enterPrimary(); } else { enterSecondary(toggleMask); } } bool Screen::leave() { assert(m_entered == true); LOG((CLOG_INFO "leaving screen")); if (!m_screen->leave()) { return false; } if (m_isPrimary) { leavePrimary(); } else { leaveSecondary(); } // make sure our idea of clipboard ownership is correct m_screen->checkClipboards(); // now not on screen m_entered = false; return true; } void Screen::reconfigure(UInt32 activeSides) { assert(m_isPrimary); m_screen->reconfigure(activeSides); } void Screen::warpCursor(SInt32 x, SInt32 y) { assert(m_isPrimary); m_screen->warpCursor(x, y); } void Screen::setClipboard(ClipboardID id, const IClipboard* clipboard) { m_screen->setClipboard(id, clipboard); } void Screen::grabClipboard(ClipboardID id) { m_screen->setClipboard(id, NULL); } void Screen::screensaver(bool activate) { if (!m_isPrimary) { // activate/deactivation screen saver iff synchronization enabled if (m_screenSaverSync) { m_screen->screensaver(activate); } } } void Screen::keyDown(KeyID id, KeyModifierMask mask, KeyButton button) { // check for ctrl+alt+del emulation if (id == kKeyDelete && (mask & (KeyModifierControl | KeyModifierAlt)) == (KeyModifierControl | KeyModifierAlt)) { LOG((CLOG_DEBUG "emulating ctrl+alt+del press")); if (m_screen->fakeCtrlAltDel()) { return; } } m_screen->fakeKeyDown(id, mask, button); } void Screen::keyRepeat(KeyID id, KeyModifierMask mask, SInt32 count, KeyButton button) { assert(!m_isPrimary); m_screen->fakeKeyRepeat(id, mask, count, button); } void Screen::keyUp(KeyID, KeyModifierMask, KeyButton button) { m_screen->fakeKeyUp(button); } void Screen::mouseDown(ButtonID button) { m_screen->fakeMouseButton(button, true); } void Screen::mouseUp(ButtonID button) { m_screen->fakeMouseButton(button, false); } void Screen::mouseMove(SInt32 x, SInt32 y) { assert(!m_isPrimary); m_screen->fakeMouseMove(x, y); } void Screen::mouseRelativeMove(SInt32 dx, SInt32 dy) { assert(!m_isPrimary); m_screen->fakeMouseRelativeMove(dx, dy); } void Screen::mouseWheel(SInt32 xDelta, SInt32 yDelta) { assert(!m_isPrimary); m_screen->fakeMouseWheel(xDelta, yDelta); } void Screen::resetOptions() { // reset options m_halfDuplex = 0; // if screen saver synchronization was off then turn it on since // that's the default option state. if (!m_screenSaverSync) { m_screenSaverSync = true; if (!m_isPrimary) { m_screen->openScreensaver(false); } } // let screen handle its own options m_screen->resetOptions(); } void Screen::setOptions(const OptionsList& options) { // update options bool oldScreenSaverSync = m_screenSaverSync; for (UInt32 i = 0, n = (UInt32)options.size(); i < n; i += 2) { if (options[i] == kOptionScreenSaverSync) { m_screenSaverSync = (options[i + 1] != 0); LOG((CLOG_DEBUG1 "screen saver synchronization %s", m_screenSaverSync ? "on" : "off")); } else if (options[i] == kOptionHalfDuplexCapsLock) { if (options[i + 1] != 0) { m_halfDuplex |= KeyModifierCapsLock; } else { m_halfDuplex &= ~KeyModifierCapsLock; } LOG((CLOG_DEBUG1 "half-duplex caps-lock %s", ((m_halfDuplex & KeyModifierCapsLock) != 0) ? "on" : "off")); } else if (options[i] == kOptionHalfDuplexNumLock) { if (options[i + 1] != 0) { m_halfDuplex |= KeyModifierNumLock; } else { m_halfDuplex &= ~KeyModifierNumLock; } LOG((CLOG_DEBUG1 "half-duplex num-lock %s", ((m_halfDuplex & KeyModifierNumLock) != 0) ? "on" : "off")); } else if (options[i] == kOptionHalfDuplexScrollLock) { if (options[i + 1] != 0) { m_halfDuplex |= KeyModifierScrollLock; } else { m_halfDuplex &= ~KeyModifierScrollLock; } LOG((CLOG_DEBUG1 "half-duplex scroll-lock %s", ((m_halfDuplex & KeyModifierScrollLock) != 0) ? "on" : "off")); } } // update half-duplex options m_screen->setHalfDuplexMask(m_halfDuplex); // update screen saver synchronization if (!m_isPrimary && oldScreenSaverSync != m_screenSaverSync) { if (m_screenSaverSync) { m_screen->openScreensaver(false); } else { m_screen->closeScreensaver(); } } // let screen handle its own options m_screen->setOptions(options); } void Screen::setSequenceNumber(UInt32 seqNum) { m_screen->setSequenceNumber(seqNum); } UInt32 Screen::registerHotKey(KeyID key, KeyModifierMask mask) { return m_screen->registerHotKey(key, mask); } void Screen::unregisterHotKey(UInt32 id) { m_screen->unregisterHotKey(id); } void Screen::fakeInputBegin() { assert(!m_fakeInput); m_fakeInput = true; m_screen->fakeInputBegin(); } void Screen::fakeInputEnd() { assert(m_fakeInput); m_fakeInput = false; m_screen->fakeInputEnd(); } bool Screen::isOnScreen() const { return m_entered; } bool Screen::isLockedToScreen() const { // check for pressed mouse buttons // HACK: commented out as it breaks new drag drop feature UInt32 buttonID = 0; if (m_screen->isAnyMouseButtonDown(buttonID)) { if (buttonID != kButtonLeft) { LOG((CLOG_DEBUG "locked by mouse buttonID: %d", buttonID)); } if (m_enableDragDrop) { return (buttonID == kButtonLeft) ? false : true; } else { return true; } } // not locked return false; } SInt32 Screen::getJumpZoneSize() const { if (!m_isPrimary) { return 0; } else { return m_screen->getJumpZoneSize(); } } void Screen::getCursorCenter(SInt32& x, SInt32& y) const { m_screen->getCursorCenter(x, y); } KeyModifierMask Screen::getActiveModifiers() const { return m_screen->getActiveModifiers(); } KeyModifierMask Screen::pollActiveModifiers() const { return m_screen->pollActiveModifiers(); } bool Screen::isDraggingStarted() const { return m_screen->isDraggingStarted(); } bool Screen::isFakeDraggingStarted() const { return m_screen->isFakeDraggingStarted(); } void Screen::setDraggingStarted(bool started) { m_screen->setDraggingStarted(started); } void Screen::startDraggingFiles(DragFileList& fileList) { m_screen->fakeDraggingFiles(fileList); } void Screen::setEnableDragDrop(bool enabled) { m_enableDragDrop = enabled; } String& Screen::getDraggingFilename() const { return m_screen->getDraggingFilename(); } void Screen::clearDraggingFilename() { m_screen->clearDraggingFilename(); } const String& Screen::getDropTarget() const { return m_screen->getDropTarget(); } void* Screen::getEventTarget() const { return m_screen; } bool Screen::getClipboard(ClipboardID id, IClipboard* clipboard) const { return m_screen->getClipboard(id, clipboard); } void Screen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const { m_screen->getShape(x, y, w, h); } void Screen::getCursorPos(SInt32& x, SInt32& y) const { m_screen->getCursorPos(x, y); } void Screen::enablePrimary() { // get notified of screen saver activation/deactivation m_screen->openScreensaver(true); // claim screen changed size m_events->addEvent(Event(m_events->forIScreen().shapeChanged(), getEventTarget())); } void Screen::enableSecondary() { // assume primary has all clipboards for (ClipboardID id = 0; id < kClipboardEnd; ++id) { grabClipboard(id); } // disable the screen saver if synchronization is enabled if (m_screenSaverSync) { m_screen->openScreensaver(false); } } void Screen::disablePrimary() { // done with screen saver m_screen->closeScreensaver(); } void Screen::disableSecondary() { // done with screen saver m_screen->closeScreensaver(); } void Screen::enterPrimary() { // do nothing } void Screen::enterSecondary(KeyModifierMask) { // do nothing } void Screen::leavePrimary() { // we don't track keys while on the primary screen so update our // idea of them now. this is particularly to update the state of // the toggle modifiers. m_screen->updateKeyState(); } void Screen::leaveSecondary() { // release any keys we think are still down m_screen->fakeAllKeysUp(); } } synergy-1.8.8-stable/src/lib/synergy/Screen.h000066400000000000000000000221171305627404700211400ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/DragInformation.h" #include "synergy/clipboard_types.h" #include "synergy/IScreen.h" #include "synergy/key_types.h" #include "synergy/mouse_types.h" #include "synergy/option_types.h" #include "base/String.h" class IClipboard; class IPlatformScreen; class IEventQueue; namespace synergy { //! Platform independent screen /*! This is a platform independent screen. It can work as either a primary or secondary screen. */ class Screen : public IScreen { public: Screen(IPlatformScreen* platformScreen, IEventQueue* events); virtual ~Screen(); #ifdef TEST_ENV Screen() : m_mock(true) { } #endif //! @name manipulators //@{ //! Activate screen /*! Activate the screen, preparing it to report system and user events. For a secondary screen it also means disabling the screen saver if synchronizing it and preparing to synthesize events. */ virtual void enable(); //! Deactivate screen /*! Undoes the operations in activate() and events are no longer reported. It also releases keys that are logically pressed. */ virtual void disable(); //! Enter screen /*! Called when the user navigates to this screen. \p toggleMask has the toggle keys that should be turned on on the secondary screen. */ void enter(KeyModifierMask toggleMask); //! Leave screen /*! Called when the user navigates off this screen. */ bool leave(); //! Update configuration /*! This is called when the configuration has changed. \c activeSides is a bitmask of EDirectionMask indicating which sides of the primary screen are linked to clients. */ void reconfigure(UInt32 activeSides); //! Warp cursor /*! Warps the cursor to the absolute coordinates \c x,y. Also discards input events up to and including the warp before returning. */ void warpCursor(SInt32 x, SInt32 y); //! Set clipboard /*! Sets the system's clipboard contents. This is usually called soon after an enter(). */ void setClipboard(ClipboardID, const IClipboard*); //! Grab clipboard /*! Grabs (i.e. take ownership of) the system clipboard. */ void grabClipboard(ClipboardID); //! Activate/deactivate screen saver /*! Forcibly activates the screen saver if \c activate is true otherwise forcibly deactivates it. */ void screensaver(bool activate); //! Notify of key press /*! Synthesize key events to generate a press of key \c id. If possible match the given modifier mask. The KeyButton identifies the physical key on the server that generated this key down. The client must ensure that a key up or key repeat that uses the same KeyButton will synthesize an up or repeat for the same client key synthesized by keyDown(). */ void keyDown(KeyID id, KeyModifierMask, KeyButton); //! Notify of key repeat /*! Synthesize key events to generate a press and release of key \c id \c count times. If possible match the given modifier mask. */ void keyRepeat(KeyID id, KeyModifierMask, SInt32 count, KeyButton); //! Notify of key release /*! Synthesize key events to generate a release of key \c id. If possible match the given modifier mask. */ void keyUp(KeyID id, KeyModifierMask, KeyButton); //! Notify of mouse press /*! Synthesize mouse events to generate a press of mouse button \c id. */ void mouseDown(ButtonID id); //! Notify of mouse release /*! Synthesize mouse events to generate a release of mouse button \c id. */ void mouseUp(ButtonID id); //! Notify of mouse motion /*! Synthesize mouse events to generate mouse motion to the absolute screen position \c xAbs,yAbs. */ void mouseMove(SInt32 xAbs, SInt32 yAbs); //! Notify of mouse motion /*! Synthesize mouse events to generate mouse motion by the relative amount \c xRel,yRel. */ void mouseRelativeMove(SInt32 xRel, SInt32 yRel); //! Notify of mouse wheel motion /*! Synthesize mouse events to generate mouse wheel motion of \c xDelta and \c yDelta. Deltas are positive for motion away from the user or to the right and negative for motion towards the user or to the left. Each wheel click should generate a delta of +/-120. */ void mouseWheel(SInt32 xDelta, SInt32 yDelta); //! Notify of options changes /*! Resets all options to their default values. */ virtual void resetOptions(); //! Notify of options changes /*! Set options to given values. Ignores unknown options and doesn't modify options that aren't given in \c options. */ virtual void setOptions(const OptionsList& options); //! Set clipboard sequence number /*! Sets the sequence number to use in subsequent clipboard events. */ void setSequenceNumber(UInt32); //! Register a system hotkey /*! Registers a system-wide hotkey for key \p key with modifiers \p mask. Returns an id used to unregister the hotkey. */ UInt32 registerHotKey(KeyID key, KeyModifierMask mask); //! Unregister a system hotkey /*! Unregisters a previously registered hot key. */ void unregisterHotKey(UInt32 id); //! Prepare to synthesize input on primary screen /*! Prepares the primary screen to receive synthesized input. We do not want to receive this synthesized input as user input so this method ensures that we ignore it. Calls to \c fakeInputBegin() may not be nested. */ void fakeInputBegin(); //! Done synthesizing input on primary screen /*! Undoes whatever \c fakeInputBegin() did. */ void fakeInputEnd(); //! Change dragging status void setDraggingStarted(bool started); //! Fake a files dragging operation void startDraggingFiles(DragFileList& fileList); void setEnableDragDrop(bool enabled); //@} //! @name accessors //@{ //! Test if cursor on screen /*! Returns true iff the cursor is on the screen. */ bool isOnScreen() const; //! Get screen lock state /*! Returns true if there's any reason that the user should not be allowed to leave the screen (usually because a button or key is pressed). If this method returns true it logs a message as to why at the CLOG_DEBUG level. */ bool isLockedToScreen() const; //! Get jump zone size /*! Return the jump zone size, the size of the regions on the edges of the screen that cause the cursor to jump to another screen. */ SInt32 getJumpZoneSize() const; //! Get cursor center position /*! Return the cursor center position which is where we park the cursor to compute cursor motion deltas and should be far from the edges of the screen, typically the center. */ void getCursorCenter(SInt32& x, SInt32& y) const; //! Get the active modifiers /*! Returns the modifiers that are currently active according to our shadowed state. */ KeyModifierMask getActiveModifiers() const; //! Get the active modifiers from OS /*! Returns the modifiers that are currently active according to the operating system. */ KeyModifierMask pollActiveModifiers() const; //! Test if file is dragged on primary screen bool isDraggingStarted() const; //! Test if file is dragged on secondary screen bool isFakeDraggingStarted() const; //! Get the filename of the file being dragged String& getDraggingFilename() const; //! Clear the filename of the file that was dragged void clearDraggingFilename(); //! Get the drop target directory const String& getDropTarget() const; //@} // IScreen overrides virtual void* getEventTarget() const; virtual bool getClipboard(ClipboardID id, IClipboard*) const; virtual void getShape(SInt32& x, SInt32& y, SInt32& width, SInt32& height) const; virtual void getCursorPos(SInt32& x, SInt32& y) const; IPlatformScreen* getPlatformScreen() { return m_screen; } protected: void enablePrimary(); void enableSecondary(); void disablePrimary(); void disableSecondary(); void enterPrimary(); void enterSecondary(KeyModifierMask toggleMask); void leavePrimary(); void leaveSecondary(); private: // our platform dependent screen IPlatformScreen* m_screen; // true if screen is being used as a primary screen, false otherwise bool m_isPrimary; // true if screen is enabled bool m_enabled; // true if the cursor is on this screen bool m_entered; // true if screen saver should be synchronized to server bool m_screenSaverSync; // note toggle keys that toggles on up/down (false) or on // transition (true) KeyModifierMask m_halfDuplex; // true if we're faking input on a primary screen bool m_fakeInput; IEventQueue* m_events; bool m_mock; bool m_enableDragDrop; }; } synergy-1.8.8-stable/src/lib/synergy/ServerApp.cpp000066400000000000000000000515751305627404700221750ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ServerApp.h" #include "server/Server.h" #include "server/ClientListener.h" #include "server/ClientProxy.h" #include "server/PrimaryClient.h" #include "synergy/ArgParser.h" #include "synergy/Screen.h" #include "synergy/XScreen.h" #include "synergy/ServerTaskBarReceiver.h" #include "synergy/ServerArgs.h" #include "net/SocketMultiplexer.h" #include "net/TCPSocketFactory.h" #include "net/XSocket.h" #include "arch/Arch.h" #include "base/EventQueue.h" #include "base/log_outputters.h" #include "base/FunctionEventJob.h" #include "base/TMethodJob.h" #include "base/IEventQueue.h" #include "base/Log.h" #include "base/TMethodEventJob.h" #include "common/Version.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" #endif #if WINAPI_MSWINDOWS #include "platform/MSWindowsScreen.h" #elif WINAPI_XWINDOWS #include "platform/XWindowsScreen.h" #elif WINAPI_CARBON #include "platform/OSXScreen.h" #endif #if defined(__APPLE__) #include "platform/OSXDragSimulator.h" #endif #include #include #include // // ServerApp // ServerApp::ServerApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver) : App(events, createTaskBarReceiver, new ServerArgs()), m_server(NULL), m_serverState(kUninitialized), m_serverScreen(NULL), m_primaryClient(NULL), m_listener(NULL), m_timer(NULL), m_synergyAddress(NULL) { } ServerApp::~ServerApp() { } void ServerApp::parseArgs(int argc, const char* const* argv) { ArgParser argParser(this); bool result = argParser.parseServerArgs(args(), argc, argv); if (!result || args().m_shouldExit) { m_bye(kExitArgs); } else { if (!args().m_synergyAddress.empty()) { try { *m_synergyAddress = NetworkAddress(args().m_synergyAddress, kDefaultPort); m_synergyAddress->resolve(); } catch (XSocketAddress& e) { LOG((CLOG_PRINT "%s: %s" BYE, args().m_pname, e.what(), args().m_pname)); m_bye(kExitArgs); } } } } void ServerApp::help() { // window api args (windows/x-windows/carbon) #if WINAPI_XWINDOWS # define WINAPI_ARGS \ " [--display ] [--no-xinitthreads]" # define WINAPI_INFO \ " --display connect to the X server at \n" \ " --no-xinitthreads do not call XInitThreads()\n" #else # define WINAPI_ARGS # define WINAPI_INFO #endif char buffer[3000]; sprintf( buffer, "Usage: %s" " [--address
]" " [--config ]" WINAPI_ARGS HELP_SYS_ARGS HELP_COMMON_ARGS "\n\n" "Start the synergy mouse/keyboard sharing server.\n" "\n" " -a, --address
listen for clients on the given address.\n" " -c, --config use the named configuration file instead.\n" HELP_COMMON_INFO_1 WINAPI_INFO HELP_SYS_INFO HELP_COMMON_INFO_2 "\n" "* marks defaults.\n" "\n" "The argument for --address is of the form: [][:]. The\n" "hostname must be the address or hostname of an interface on the system.\n" "The default is to listen on all interfaces. The port overrides the\n" "default port, %d.\n" "\n" "If no configuration file pathname is provided then the first of the\n" "following to load successfully sets the configuration:\n" " %s\n" " %s\n", args().m_pname, kDefaultPort, ARCH->concatPath(ARCH->getUserDirectory(), USR_CONFIG_NAME).c_str(), ARCH->concatPath(ARCH->getSystemDirectory(), SYS_CONFIG_NAME).c_str() ); LOG((CLOG_PRINT "%s", buffer)); } void ServerApp::reloadSignalHandler(Arch::ESignal, void*) { IEventQueue* events = App::instance().getEvents(); events->addEvent(Event(events->forServerApp().reloadConfig(), events->getSystemTarget())); } void ServerApp::reloadConfig(const Event&, void*) { LOG((CLOG_DEBUG "reload configuration")); if (loadConfig(args().m_configFile)) { if (m_server != NULL) { m_server->setConfig(*args().m_config); } LOG((CLOG_NOTE "reloaded configuration")); } } void ServerApp::loadConfig() { bool loaded = false; // load the config file, if specified if (!args().m_configFile.empty()) { loaded = loadConfig(args().m_configFile); } // load the default configuration if no explicit file given else { // get the user's home directory String path = ARCH->getUserDirectory(); if (!path.empty()) { // complete path path = ARCH->concatPath(path, USR_CONFIG_NAME); // now try loading the user's configuration if (loadConfig(path)) { loaded = true; args().m_configFile = path; } } if (!loaded) { // try the system-wide config file path = ARCH->getSystemDirectory(); if (!path.empty()) { path = ARCH->concatPath(path, SYS_CONFIG_NAME); if (loadConfig(path)) { loaded = true; args().m_configFile = path; } } } } if (!loaded) { LOG((CLOG_PRINT "%s: no configuration available", args().m_pname)); m_bye(kExitConfig); } } bool ServerApp::loadConfig(const String& pathname) { try { // load configuration LOG((CLOG_DEBUG "opening configuration \"%s\"", pathname.c_str())); std::ifstream configStream(pathname.c_str()); if (!configStream.is_open()) { // report failure to open configuration as a debug message // since we try several paths and we expect some to be // missing. LOG((CLOG_DEBUG "cannot open configuration \"%s\"", pathname.c_str())); return false; } configStream >> *args().m_config; LOG((CLOG_DEBUG "configuration read successfully")); return true; } catch (XConfigRead& e) { // report error in configuration file LOG((CLOG_ERR "cannot read configuration \"%s\": %s", pathname.c_str(), e.what())); } return false; } void ServerApp::forceReconnect(const Event&, void*) { if (m_server != NULL) { m_server->disconnect(); } } void ServerApp::handleClientConnected(const Event&, void* vlistener) { ClientListener* listener = static_cast(vlistener); ClientProxy* client = listener->getNextClient(); if (client != NULL) { m_server->adoptClient(client); updateStatus(); } } void ServerApp::handleClientsDisconnected(const Event&, void*) { m_events->addEvent(Event(Event::kQuit)); } void ServerApp::closeServer(Server* server) { if (server == NULL) { return; } // tell all clients to disconnect server->disconnect(); // wait for clients to disconnect for up to timeout seconds double timeout = 3.0; EventQueueTimer* timer = m_events->newOneShotTimer(timeout, NULL); m_events->adoptHandler(Event::kTimer, timer, new TMethodEventJob(this, &ServerApp::handleClientsDisconnected)); m_events->adoptHandler(m_events->forServer().disconnected(), server, new TMethodEventJob(this, &ServerApp::handleClientsDisconnected)); m_events->loop(); m_events->removeHandler(Event::kTimer, timer); m_events->deleteTimer(timer); m_events->removeHandler(m_events->forServer().disconnected(), server); // done with server delete server; } void ServerApp::stopRetryTimer() { if (m_timer != NULL) { m_events->deleteTimer(m_timer); m_events->removeHandler(Event::kTimer, NULL); m_timer = NULL; } } void ServerApp::updateStatus() { updateStatus(""); } void ServerApp::updateStatus(const String& msg) { if (m_taskBarReceiver) { m_taskBarReceiver->updateStatus(m_server, msg); } } void ServerApp::closeClientListener(ClientListener* listen) { if (listen != NULL) { m_events->removeHandler(m_events->forClientListener().connected(), listen); delete listen; } } void ServerApp::stopServer() { if (m_serverState == kStarted) { closeServer(m_server); closeClientListener(m_listener); m_server = NULL; m_listener = NULL; m_serverState = kInitialized; } else if (m_serverState == kStarting) { stopRetryTimer(); m_serverState = kInitialized; } assert(m_server == NULL); assert(m_listener == NULL); } void ServerApp::closePrimaryClient(PrimaryClient* primaryClient) { delete primaryClient; } void ServerApp::closeServerScreen(synergy::Screen* screen) { if (screen != NULL) { m_events->removeHandler(m_events->forIScreen().error(), screen->getEventTarget()); m_events->removeHandler(m_events->forIScreen().suspend(), screen->getEventTarget()); m_events->removeHandler(m_events->forIScreen().resume(), screen->getEventTarget()); delete screen; } } void ServerApp::cleanupServer() { stopServer(); if (m_serverState == kInitialized) { closePrimaryClient(m_primaryClient); closeServerScreen(m_serverScreen); m_primaryClient = NULL; m_serverScreen = NULL; m_serverState = kUninitialized; } else if (m_serverState == kInitializing || m_serverState == kInitializingToStart) { stopRetryTimer(); m_serverState = kUninitialized; } assert(m_primaryClient == NULL); assert(m_serverScreen == NULL); assert(m_serverState == kUninitialized); } void ServerApp::retryHandler(const Event&, void*) { // discard old timer assert(m_timer != NULL); stopRetryTimer(); // try initializing/starting the server again switch (m_serverState) { case kUninitialized: case kInitialized: case kStarted: assert(0 && "bad internal server state"); break; case kInitializing: LOG((CLOG_DEBUG1 "retry server initialization")); m_serverState = kUninitialized; if (!initServer()) { m_events->addEvent(Event(Event::kQuit)); } break; case kInitializingToStart: LOG((CLOG_DEBUG1 "retry server initialization")); m_serverState = kUninitialized; if (!initServer()) { m_events->addEvent(Event(Event::kQuit)); } else if (m_serverState == kInitialized) { LOG((CLOG_DEBUG1 "starting server")); if (!startServer()) { m_events->addEvent(Event(Event::kQuit)); } } break; case kStarting: LOG((CLOG_DEBUG1 "retry starting server")); m_serverState = kInitialized; if (!startServer()) { m_events->addEvent(Event(Event::kQuit)); } break; } } bool ServerApp::initServer() { // skip if already initialized or initializing if (m_serverState != kUninitialized) { return true; } double retryTime; synergy::Screen* serverScreen = NULL; PrimaryClient* primaryClient = NULL; try { String name = args().m_config->getCanonicalName(args().m_name); serverScreen = openServerScreen(); primaryClient = openPrimaryClient(name, serverScreen); m_serverScreen = serverScreen; m_primaryClient = primaryClient; m_serverState = kInitialized; updateStatus(); return true; } catch (XScreenUnavailable& e) { LOG((CLOG_WARN "primary screen unavailable: %s", e.what())); closePrimaryClient(primaryClient); closeServerScreen(serverScreen); updateStatus(String("primary screen unavailable: ") + e.what()); retryTime = e.getRetryTime(); } catch (XScreenOpenFailure& e) { LOG((CLOG_CRIT "failed to start server: %s", e.what())); closePrimaryClient(primaryClient); closeServerScreen(serverScreen); return false; } catch (XBase& e) { LOG((CLOG_CRIT "failed to start server: %s", e.what())); closePrimaryClient(primaryClient); closeServerScreen(serverScreen); return false; } if (args().m_restartable) { // install a timer and handler to retry later assert(m_timer == NULL); LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime)); m_timer = m_events->newOneShotTimer(retryTime, NULL); m_events->adoptHandler(Event::kTimer, m_timer, new TMethodEventJob(this, &ServerApp::retryHandler)); m_serverState = kInitializing; return true; } else { // don't try again return false; } } synergy::Screen* ServerApp::openServerScreen() { synergy::Screen* screen = createScreen(); screen->setEnableDragDrop(argsBase().m_enableDragDrop); m_events->adoptHandler(m_events->forIScreen().error(), screen->getEventTarget(), new TMethodEventJob( this, &ServerApp::handleScreenError)); m_events->adoptHandler(m_events->forIScreen().suspend(), screen->getEventTarget(), new TMethodEventJob( this, &ServerApp::handleSuspend)); m_events->adoptHandler(m_events->forIScreen().resume(), screen->getEventTarget(), new TMethodEventJob( this, &ServerApp::handleResume)); return screen; } bool ServerApp::startServer() { // skip if already started or starting if (m_serverState == kStarting || m_serverState == kStarted) { return true; } // initialize if necessary if (m_serverState != kInitialized) { if (!initServer()) { // hard initialization failure return false; } if (m_serverState == kInitializing) { // not ready to start m_serverState = kInitializingToStart; return true; } assert(m_serverState == kInitialized); } double retryTime; ClientListener* listener = NULL; try { listener = openClientListener(args().m_config->getSynergyAddress()); m_server = openServer(*args().m_config, m_primaryClient); listener->setServer(m_server); m_server->setListener(listener); m_listener = listener; updateStatus(); LOG((CLOG_NOTE "started server, waiting for clients")); m_serverState = kStarted; return true; } catch (XSocketAddressInUse& e) { LOG((CLOG_WARN "cannot listen for clients: %s", e.what())); closeClientListener(listener); updateStatus(String("cannot listen for clients: ") + e.what()); retryTime = 10.0; } catch (XBase& e) { LOG((CLOG_CRIT "failed to start server: %s", e.what())); closeClientListener(listener); return false; } if (args().m_restartable) { // install a timer and handler to retry later assert(m_timer == NULL); LOG((CLOG_DEBUG "retry in %.0f seconds", retryTime)); m_timer = m_events->newOneShotTimer(retryTime, NULL); m_events->adoptHandler(Event::kTimer, m_timer, new TMethodEventJob(this, &ServerApp::retryHandler)); m_serverState = kStarting; return true; } else { // don't try again return false; } } synergy::Screen* ServerApp::createScreen() { #if WINAPI_MSWINDOWS return new synergy::Screen(new MSWindowsScreen( true, args().m_noHooks, args().m_stopOnDeskSwitch, m_events), m_events); #elif WINAPI_XWINDOWS return new synergy::Screen(new XWindowsScreen( args().m_display, true, args().m_disableXInitThreads, 0, m_events), m_events); #elif WINAPI_CARBON return new synergy::Screen(new OSXScreen(m_events, true), m_events); #endif } PrimaryClient* ServerApp::openPrimaryClient(const String& name, synergy::Screen* screen) { LOG((CLOG_DEBUG1 "creating primary screen")); return new PrimaryClient(name, screen); } void ServerApp::handleScreenError(const Event&, void*) { LOG((CLOG_CRIT "error on screen")); m_events->addEvent(Event(Event::kQuit)); } void ServerApp::handleSuspend(const Event&, void*) { if (!m_suspended) { LOG((CLOG_INFO "suspend")); stopServer(); m_suspended = true; } } void ServerApp::handleResume(const Event&, void*) { if (m_suspended) { LOG((CLOG_INFO "resume")); startServer(); m_suspended = false; } } ClientListener* ServerApp::openClientListener(const NetworkAddress& address) { ClientListener* listen = new ClientListener( address, new TCPSocketFactory(m_events, getSocketMultiplexer()), m_events, args().m_enableCrypto); m_events->adoptHandler( m_events->forClientListener().connected(), listen, new TMethodEventJob( this, &ServerApp::handleClientConnected, listen)); return listen; } Server* ServerApp::openServer(Config& config, PrimaryClient* primaryClient) { Server* server = new Server(config, primaryClient, m_serverScreen, m_events, args()); try { m_events->adoptHandler( m_events->forServer().disconnected(), server, new TMethodEventJob(this, &ServerApp::handleNoClients)); m_events->adoptHandler( m_events->forServer().screenSwitched(), server, new TMethodEventJob(this, &ServerApp::handleScreenSwitched)); } catch (std::bad_alloc &ba) { delete server; throw ba; } return server; } void ServerApp::handleNoClients(const Event&, void*) { updateStatus(); } void ServerApp::handleScreenSwitched(const Event& e, void*) { } int ServerApp::mainLoop() { // create socket multiplexer. this must happen after daemonization // on unix because threads evaporate across a fork(). SocketMultiplexer multiplexer; setSocketMultiplexer(&multiplexer); // if configuration has no screens then add this system // as the default if (args().m_config->begin() == args().m_config->end()) { args().m_config->addScreen(args().m_name); } // set the contact address, if provided, in the config. // otherwise, if the config doesn't have an address, use // the default. if (m_synergyAddress->isValid()) { args().m_config->setSynergyAddress(*m_synergyAddress); } else if (!args().m_config->getSynergyAddress().isValid()) { args().m_config->setSynergyAddress(NetworkAddress(kDefaultPort)); } // canonicalize the primary screen name String primaryName = args().m_config->getCanonicalName(args().m_name); if (primaryName.empty()) { LOG((CLOG_CRIT "unknown screen name `%s'", args().m_name.c_str())); return kExitFailed; } // start server, etc appUtil().startNode(); // init ipc client after node start, since create a new screen wipes out // the event queue (the screen ctors call adoptBuffer). if (argsBase().m_enableIpc) { initIpcClient(); } // handle hangup signal by reloading the server's configuration ARCH->setSignalHandler(Arch::kHANGUP, &reloadSignalHandler, NULL); m_events->adoptHandler(m_events->forServerApp().reloadConfig(), m_events->getSystemTarget(), new TMethodEventJob(this, &ServerApp::reloadConfig)); // handle force reconnect event by disconnecting clients. they'll // reconnect automatically. m_events->adoptHandler(m_events->forServerApp().forceReconnect(), m_events->getSystemTarget(), new TMethodEventJob(this, &ServerApp::forceReconnect)); // to work around the sticky meta keys problem, we'll give users // the option to reset the state of synergys m_events->adoptHandler(m_events->forServerApp().resetServer(), m_events->getSystemTarget(), new TMethodEventJob(this, &ServerApp::resetServer)); // run event loop. if startServer() failed we're supposed to retry // later. the timer installed by startServer() will take care of // that. DAEMON_RUNNING(true); #if defined(MAC_OS_X_VERSION_10_7) Thread thread( new TMethodJob( this, &ServerApp::runEventsLoop, NULL)); // wait until carbon loop is ready OSXScreen* screen = dynamic_cast( m_serverScreen->getPlatformScreen()); screen->waitForCarbonLoop(); runCocoaApp(); #else m_events->loop(); #endif DAEMON_RUNNING(false); // close down LOG((CLOG_DEBUG1 "stopping server")); m_events->removeHandler(m_events->forServerApp().forceReconnect(), m_events->getSystemTarget()); m_events->removeHandler(m_events->forServerApp().reloadConfig(), m_events->getSystemTarget()); cleanupServer(); updateStatus(); LOG((CLOG_NOTE "stopped server")); if (argsBase().m_enableIpc) { cleanupIpcClient(); } return kExitSuccess; } void ServerApp::resetServer(const Event&, void*) { LOG((CLOG_DEBUG1 "resetting server")); stopServer(); cleanupServer(); startServer(); } int ServerApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) { // general initialization m_synergyAddress = new NetworkAddress; args().m_config = new Config(m_events); args().m_pname = ARCH->getBasename(argv[0]); // install caller's output filter if (outputter != NULL) { CLOG->insert(outputter); } // run int result = startup(argc, argv); if (m_taskBarReceiver) { // done with task bar receiver delete m_taskBarReceiver; } delete args().m_config; delete m_synergyAddress; return result; } int daemonMainLoopStatic(int argc, const char** argv) { return ServerApp::instance().daemonMainLoop(argc, argv); } int ServerApp::standardStartup(int argc, char** argv) { initApp(argc, argv); // daemonize if requested if (args().m_daemon) { return ARCH->daemonize(daemonName(), daemonMainLoopStatic); } else { return mainLoop(); } } int ServerApp::foregroundStartup(int argc, char** argv) { initApp(argc, argv); // never daemonize return mainLoop(); } const char* ServerApp::daemonName() const { #if SYSAPI_WIN32 return "Synergy Server"; #elif SYSAPI_UNIX return "synergys"; #endif } const char* ServerApp::daemonInfo() const { #if SYSAPI_WIN32 return "Shares this computers mouse and keyboard with other computers."; #elif SYSAPI_UNIX return ""; #endif } void ServerApp::startNode() { // start the server. if this return false then we've failed and // we shouldn't retry. LOG((CLOG_DEBUG1 "starting server")); if (!startServer()) { m_bye(kExitFailed); } } synergy-1.8.8-stable/src/lib/synergy/ServerApp.h000066400000000000000000000074331305627404700216340ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/ArgsBase.h" #include "synergy/App.h" #include "base/String.h" #include "server/Config.h" #include "net/NetworkAddress.h" #include "arch/Arch.h" #include "arch/IArchMultithread.h" #include "synergy/ArgsBase.h" #include "base/EventTypes.h" #include enum EServerState { kUninitialized, kInitializing, kInitializingToStart, kInitialized, kStarting, kStarted }; class Server; namespace synergy { class Screen; } class ClientListener; class EventQueueTimer; class ILogOutputter; class IEventQueue; class ServerArgs; class ServerApp : public App { public: ServerApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver); virtual ~ServerApp(); // Parse server specific command line arguments. void parseArgs(int argc, const char* const* argv); // Prints help specific to server. void help(); // Returns arguments that are common and for server. ServerArgs& args() const { return (ServerArgs&)argsBase(); } const char* daemonName() const; const char* daemonInfo() const; // TODO: Document these functions. static void reloadSignalHandler(Arch::ESignal, void*); void reloadConfig(const Event&, void*); void loadConfig(); bool loadConfig(const String& pathname); void forceReconnect(const Event&, void*); void resetServer(const Event&, void*); void handleClientConnected(const Event&, void* vlistener); void handleClientsDisconnected(const Event&, void*); void closeServer(Server* server); void stopRetryTimer(); void updateStatus(); void updateStatus(const String& msg); void closeClientListener(ClientListener* listen); void stopServer(); void closePrimaryClient(PrimaryClient* primaryClient); void closeServerScreen(synergy::Screen* screen); void cleanupServer(); bool initServer(); void retryHandler(const Event&, void*); synergy::Screen* openServerScreen(); synergy::Screen* createScreen(); PrimaryClient* openPrimaryClient(const String& name, synergy::Screen* screen); void handleScreenError(const Event&, void*); void handleSuspend(const Event&, void*); void handleResume(const Event&, void*); ClientListener* openClientListener(const NetworkAddress& address); Server* openServer(Config& config, PrimaryClient* primaryClient); void handleNoClients(const Event&, void*); bool startServer(); int mainLoop(); int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup); int standardStartup(int argc, char** argv); int foregroundStartup(int argc, char** argv); void startNode(); static ServerApp& instance() { return (ServerApp&)App::instance(); } Server* getServerPtr() { return m_server; } Server* m_server; EServerState m_serverState; synergy::Screen* m_serverScreen; PrimaryClient* m_primaryClient; ClientListener* m_listener; EventQueueTimer* m_timer; NetworkAddress* m_synergyAddress; private: void handleScreenSwitched(const Event&, void* data); }; // configuration file name #if SYSAPI_WIN32 #define USR_CONFIG_NAME "synergy.sgc" #define SYS_CONFIG_NAME "synergy.sgc" #elif SYSAPI_UNIX #define USR_CONFIG_NAME ".synergy.conf" #define SYS_CONFIG_NAME "synergy.conf" #endif synergy-1.8.8-stable/src/lib/synergy/ServerArgs.cpp000066400000000000000000000014441305627404700223370ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ServerArgs.h" ServerArgs::ServerArgs() : m_configFile(), m_serial(), m_config(NULL) { } synergy-1.8.8-stable/src/lib/synergy/ServerArgs.h000066400000000000000000000016611305627404700220050ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/ArgsBase.h" #include "shared/SerialKey.h" class NetworkAddress; class Config; class ServerArgs : public ArgsBase { public: ServerArgs(); public: String m_configFile; SerialKey m_serial; Config* m_config; }; synergy-1.8.8-stable/src/lib/synergy/ServerTaskBarReceiver.cpp000066400000000000000000000053321305627404700244570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ServerTaskBarReceiver.h" #include "server/Server.h" #include "mt/Lock.h" #include "base/String.h" #include "base/IEventQueue.h" #include "arch/Arch.h" #include "common/Version.h" // // ServerTaskBarReceiver // ServerTaskBarReceiver::ServerTaskBarReceiver(IEventQueue* events) : m_state(kNotRunning), m_events(events) { // do nothing } ServerTaskBarReceiver::~ServerTaskBarReceiver() { // do nothing } void ServerTaskBarReceiver::updateStatus(Server* server, const String& errorMsg) { { // update our status m_errorMessage = errorMsg; if (server == NULL) { if (m_errorMessage.empty()) { m_state = kNotRunning; } else { m_state = kNotWorking; } } else { m_clients.clear(); server->getClients(m_clients); if (m_clients.size() <= 1) { m_state = kNotConnected; } else { m_state = kConnected; } } // let subclasses have a go onStatusChanged(server); } // tell task bar ARCH->updateReceiver(this); } ServerTaskBarReceiver::EState ServerTaskBarReceiver::getStatus() const { return m_state; } const String& ServerTaskBarReceiver::getErrorMessage() const { return m_errorMessage; } const ServerTaskBarReceiver::Clients& ServerTaskBarReceiver::getClients() const { return m_clients; } void ServerTaskBarReceiver::quit() { m_events->addEvent(Event(Event::kQuit)); } void ServerTaskBarReceiver::onStatusChanged(Server*) { // do nothing } void ServerTaskBarReceiver::lock() const { // do nothing } void ServerTaskBarReceiver::unlock() const { // do nothing } std::string ServerTaskBarReceiver::getToolTip() const { switch (m_state) { case kNotRunning: return synergy::string::sprintf("%s: Not running", kAppVersion); case kNotWorking: return synergy::string::sprintf("%s: %s", kAppVersion, m_errorMessage.c_str()); case kNotConnected: return synergy::string::sprintf("%s: Waiting for clients", kAppVersion); case kConnected: return synergy::string::sprintf("%s: Connected", kAppVersion); default: return ""; } } synergy-1.8.8-stable/src/lib/synergy/ServerTaskBarReceiver.h000066400000000000000000000047541305627404700241330ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2003 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "server/Server.h" #include "synergy/ServerApp.h" #include "arch/IArchTaskBarReceiver.h" #include "base/EventTypes.h" #include "base/String.h" #include "base/Event.h" #include "common/stdvector.h" class IEventQueue; //! Implementation of IArchTaskBarReceiver for the synergy server class ServerTaskBarReceiver : public IArchTaskBarReceiver { public: ServerTaskBarReceiver(IEventQueue* events); virtual ~ServerTaskBarReceiver(); //! @name manipulators //@{ //! Update status /*! Determine the status and query required information from the server. */ void updateStatus(Server*, const String& errorMsg); void updateStatus(INode* n, const String& errorMsg) { updateStatus((Server*)n, errorMsg); } //@} // IArchTaskBarReceiver overrides virtual void showStatus() = 0; virtual void runMenu(int x, int y) = 0; virtual void primaryAction() = 0; virtual void lock() const; virtual void unlock() const; virtual const Icon getIcon() const = 0; virtual std::string getToolTip() const; protected: typedef std::vector Clients; enum EState { kNotRunning, kNotWorking, kNotConnected, kConnected, kMaxState }; //! Get status EState getStatus() const; //! Get error message const String& getErrorMessage() const; //! Get connected clients const Clients& getClients() const; //! Quit app /*! Causes the application to quit gracefully */ void quit(); //! Status change notification /*! Called when status changes. The default implementation does nothing. */ virtual void onStatusChanged(Server* server); private: EState m_state; String m_errorMessage; Clients m_clients; IEventQueue* m_events; }; IArchTaskBarReceiver* createTaskBarReceiver(const BufferedLogOutputter* logBuffer, IEventQueue* events); synergy-1.8.8-stable/src/lib/synergy/StreamChunker.cpp000066400000000000000000000106261305627404700230310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/StreamChunker.h" #include "mt/Lock.h" #include "mt/Mutex.h" #include "synergy/FileChunk.h" #include "synergy/ClipboardChunk.h" #include "synergy/protocol_types.h" #include "base/EventTypes.h" #include "base/Event.h" #include "base/IEventQueue.h" #include "base/EventTypes.h" #include "base/Log.h" #include "base/Stopwatch.h" #include "base/String.h" #include "common/stdexcept.h" #include using namespace std; static const size_t g_chunkSize = 512 * 1024; //512kb bool StreamChunker::s_isChunkingFile = false; bool StreamChunker::s_interruptFile = false; Mutex* StreamChunker::s_interruptMutex = NULL; void StreamChunker::sendFile( char* filename, IEventQueue* events, void* eventTarget) { s_isChunkingFile = true; std::fstream file(static_cast(filename), std::ios::in | std::ios::binary); if (!file.is_open()) { throw runtime_error("failed to open file"); } // check file size file.seekg (0, std::ios::end); size_t size = (size_t)file.tellg(); // send first message (file size) String fileSize = synergy::string::sizeTypeToString(size); FileChunk* sizeMessage = FileChunk::start(fileSize); events->addEvent(Event(events->forFile().fileChunkSending(), eventTarget, sizeMessage)); // send chunk messages with a fixed chunk size size_t sentLength = 0; size_t chunkSize = g_chunkSize; file.seekg (0, std::ios::beg); while (true) { if (s_interruptFile) { s_interruptFile = false; LOG((CLOG_DEBUG "file transmission interrupted")); break; } events->addEvent(Event(events->forFile().keepAlive(), eventTarget)); // make sure we don't read too much from the mock data. if (sentLength + chunkSize > size) { chunkSize = size - sentLength; } char* chunkData = new char[chunkSize]; file.read(chunkData, chunkSize); UInt8* data = reinterpret_cast(chunkData); FileChunk* fileChunk = FileChunk::data(data, chunkSize); delete[] chunkData; events->addEvent(Event(events->forFile().fileChunkSending(), eventTarget, fileChunk)); sentLength += chunkSize; file.seekg (sentLength, std::ios::beg); if (sentLength == size) { break; } } // send last message FileChunk* end = FileChunk::end(); events->addEvent(Event(events->forFile().fileChunkSending(), eventTarget, end)); file.close(); s_isChunkingFile = false; } void StreamChunker::sendClipboard( String& data, size_t size, ClipboardID id, UInt32 sequence, IEventQueue* events, void* eventTarget) { // send first message (data size) String dataSize = synergy::string::sizeTypeToString(size); ClipboardChunk* sizeMessage = ClipboardChunk::start(id, sequence, dataSize); events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, sizeMessage)); // send clipboard chunk with a fixed size size_t sentLength = 0; size_t chunkSize = g_chunkSize; while (true) { events->addEvent(Event(events->forFile().keepAlive(), eventTarget)); // make sure we don't read too much from the mock data. if (sentLength + chunkSize > size) { chunkSize = size - sentLength; } String chunk(data.substr(sentLength, chunkSize).c_str(), chunkSize); ClipboardChunk* dataChunk = ClipboardChunk::data(id, sequence, chunk); events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, dataChunk)); sentLength += chunkSize; if (sentLength == size) { break; } } // send last message ClipboardChunk* end = ClipboardChunk::end(id, sequence); events->addEvent(Event(events->forClipboard().clipboardSending(), eventTarget, end)); LOG((CLOG_DEBUG "sent clipboard size=%d", sentLength)); } void StreamChunker::interruptFile() { if (s_isChunkingFile) { s_interruptFile = true; LOG((CLOG_INFO "previous dragged file has become invalid")); } } synergy-1.8.8-stable/src/lib/synergy/StreamChunker.h000066400000000000000000000023461305627404700224760ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/clipboard_types.h" #include "base/String.h" class IEventQueue; class Mutex; class StreamChunker { public: static void sendFile( char* filename, IEventQueue* events, void* eventTarget); static void sendClipboard( String& data, size_t size, ClipboardID id, UInt32 sequence, IEventQueue* events, void* eventTarget); static void interruptFile(); private: static bool s_isChunkingFile; static bool s_interruptFile; static Mutex* s_interruptMutex; }; synergy-1.8.8-stable/src/lib/synergy/ToolApp.cpp000066400000000000000000000110501305627404700216240ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ToolApp.h" #include "synergy/ArgParser.h" #include "arch/Arch.h" #include "base/Log.h" #include "base/String.h" #include #include #if SYSAPI_WIN32 #include "platform/MSWindowsSession.h" #endif #define JSON_URL "https://symless.com/account/json/" enum { kErrorOk, kErrorArgs, kErrorException, kErrorUnknown }; UInt32 ToolApp::run(int argc, char** argv) { if (argc <= 1) { std::cerr << "no args" << std::endl; return kErrorArgs; } try { ArgParser argParser(this); bool result = argParser.parseToolArgs(m_args, argc, argv); if (!result) { m_bye(kExitArgs); } if (m_args.m_printActiveDesktopName) { #if SYSAPI_WIN32 MSWindowsSession session; String name = session.getActiveDesktopName(); if (name.empty()) { LOG((CLOG_CRIT "failed to get active desktop name")); return kExitFailed; } else { String output = synergy::string::sprintf("activeDesktop:%s", name.c_str()); LOG((CLOG_INFO "%s", output.c_str())); } #endif } else if (m_args.m_loginAuthenticate) { loginAuth(); } else if (m_args.m_getInstalledDir) { std::cout << ARCH->getInstalledDirectory() << std::endl; } else if (m_args.m_getProfileDir) { std::cout << ARCH->getProfileDirectory() << std::endl; } else if (m_args.m_getArch) { std::cout << ARCH->getPlatformName() << std::endl; } else if (m_args.m_notifyUpdate) { notifyUpdate(); } else if (m_args.m_notifyActivation) { notifyActivation(); } else { throw XSynergy("Nothing to do"); } } catch (std::exception& e) { LOG((CLOG_CRIT "An error occurred: %s\n", e.what())); return kExitFailed; } catch (...) { LOG((CLOG_CRIT "An unknown error occurred.\n")); return kExitFailed; } #if WINAPI_XWINDOWS // HACK: avoid sigsegv on linux m_bye(kErrorOk); #endif return kErrorOk; } void ToolApp::help() { } void ToolApp::loginAuth() { String credentials; std::cin >> credentials; std::vector parts = synergy::string::splitString(credentials, ':'); size_t count = parts.size(); if (count == 2 ) { String email = parts[0]; String password = parts[1]; std::stringstream ss; ss << JSON_URL << "auth/"; ss << "?email=" << ARCH->internet().urlEncode(email); ss << "&password=" << password; std::cout << ARCH->internet().get(ss.str()) << std::endl; } else { throw XSynergy("Invalid credentials."); } } void ToolApp::notifyUpdate() { String data; std::cin >> data; std::vector parts = synergy::string::splitString(data, ':'); size_t count = parts.size(); if (count == 3) { std::stringstream ss; ss << JSON_URL << "notify/update"; ss << "?from=" << parts[0]; ss << "&to=" << parts[1]; ss << "&serial=" << parts[2]; std::cout << ARCH->internet().get(ss.str()) << std::endl; } else { throw XSynergy("Invalid update data."); } } void ToolApp::notifyActivation() { String info; std::cin >> info; std::vector parts = synergy::string::splitString(info, ':'); size_t count = parts.size(); if (count == 3 || count == 4) { String action = parts[0]; String identity = parts[1]; String macHash = parts[2]; String os; if (count == 4) { os = parts[3]; } else { os = ARCH->getOSName(); } std::stringstream ss; ss << JSON_URL << "notify/"; ss << "?action=" << action; ss << "&identity=" << ARCH->internet().urlEncode(identity); ss << "&mac=" << ARCH->internet().urlEncode(macHash); ss << "&os=" << ARCH->internet().urlEncode(ARCH->getOSName()); ss << "&arch=" << ARCH->internet().urlEncode(ARCH->getPlatformName()); try { std::cout << ARCH->internet().get(ss.str()) << std::endl; } catch (std::exception& e) { LOG((CLOG_NOTE "An error occurred during notification: %s\n", e.what())); } catch (...) { LOG((CLOG_NOTE "An unknown error occurred during notification.\n")); } } else { LOG((CLOG_NOTE "notification failed")); } } synergy-1.8.8-stable/src/lib/synergy/ToolApp.h000066400000000000000000000020031305627404700212670ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/App.h" #include "synergy/ToolArgs.h" #include "common/basic_types.h" class ToolApp : public MinimalApp { public: UInt32 run(int argc, char** argv); void help(); private: void loginAuth(); void notifyActivation(); void notifyUpdate(); private: ToolArgs m_args; }; synergy-1.8.8-stable/src/lib/synergy/ToolArgs.cpp000066400000000000000000000016501305627404700220050ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ToolArgs.h" ToolArgs::ToolArgs() : m_printActiveDesktopName(false), m_loginAuthenticate(false), m_getInstalledDir(false), m_getProfileDir(false), m_getArch(false), m_notifyActivation(false), m_notifyUpdate(false) { } synergy-1.8.8-stable/src/lib/synergy/ToolArgs.h000066400000000000000000000017341305627404700214550ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/String.h" class ToolArgs { public: ToolArgs(); public: bool m_printActiveDesktopName; bool m_loginAuthenticate; bool m_getInstalledDir; bool m_getProfileDir; bool m_getArch; bool m_notifyActivation; bool m_notifyUpdate; }; synergy-1.8.8-stable/src/lib/synergy/XScreen.cpp000066400000000000000000000026251305627404700216250ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/XScreen.h" // // XScreenOpenFailure // String XScreenOpenFailure::getWhat() const throw() { return format("XScreenOpenFailure", "unable to open screen"); } // // XScreenXInputFailure // String XScreenXInputFailure::getWhat() const throw() { return ""; } // // XScreenUnavailable // XScreenUnavailable::XScreenUnavailable(double timeUntilRetry) : m_timeUntilRetry(timeUntilRetry) { // do nothing } XScreenUnavailable::~XScreenUnavailable() _NOEXCEPT { // do nothing } double XScreenUnavailable::getRetryTime() const { return m_timeUntilRetry; } String XScreenUnavailable::getWhat() const throw() { return format("XScreenUnavailable", "unable to open screen"); } synergy-1.8.8-stable/src/lib/synergy/XScreen.h000066400000000000000000000033331305627404700212670ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/XBase.h" //! Generic screen exception XBASE_SUBCLASS(XScreen, XBase); //! Cannot open screen exception /*! Thrown when a screen cannot be opened or initialized. */ XBASE_SUBCLASS_WHAT(XScreenOpenFailure, XScreen); //! XInput exception /*! Thrown when an XInput error occurs */ XBASE_SUBCLASS_WHAT(XScreenXInputFailure, XScreen); //! Screen unavailable exception /*! Thrown when a screen cannot be opened or initialized but retrying later may be successful. */ class XScreenUnavailable : public XScreenOpenFailure { public: /*! \c timeUntilRetry is the suggested time the caller should wait until trying to open the screen again. */ XScreenUnavailable(double timeUntilRetry); virtual ~XScreenUnavailable() _NOEXCEPT; //! @name manipulators //@{ //! Get retry time /*! Returns the suggested time to wait until retrying to open the screen. */ double getRetryTime() const; //@} protected: virtual String getWhat() const throw(); private: double m_timeUntilRetry; }; synergy-1.8.8-stable/src/lib/synergy/XSynergy.cpp000066400000000000000000000044601305627404700220450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/XSynergy.h" #include "base/String.h" // // XBadClient // String XBadClient::getWhat() const throw() { return "XBadClient"; } // // XIncompatibleClient // XIncompatibleClient::XIncompatibleClient(int major, int minor) : m_major(major), m_minor(minor) { // do nothing } int XIncompatibleClient::getMajor() const throw() { return m_major; } int XIncompatibleClient::getMinor() const throw() { return m_minor; } String XIncompatibleClient::getWhat() const throw() { return format("XIncompatibleClient", "incompatible client %{1}.%{2}", synergy::string::sprintf("%d", m_major).c_str(), synergy::string::sprintf("%d", m_minor).c_str()); } // // XDuplicateClient // XDuplicateClient::XDuplicateClient(const String& name) : m_name(name) { // do nothing } const String& XDuplicateClient::getName() const throw() { return m_name; } String XDuplicateClient::getWhat() const throw() { return format("XDuplicateClient", "duplicate client %{1}", m_name.c_str()); } // // XUnknownClient // XUnknownClient::XUnknownClient(const String& name) : m_name(name) { // do nothing } const String& XUnknownClient::getName() const throw() { return m_name; } String XUnknownClient::getWhat() const throw() { return format("XUnknownClient", "unknown client %{1}", m_name.c_str()); } // // XExitApp // XExitApp::XExitApp(int code) : m_code(code) { // do nothing } int XExitApp::getCode() const throw() { return m_code; } String XExitApp::getWhat() const throw() { return format( "XExitApp", "exiting with code %{1}", synergy::string::sprintf("%d", m_code).c_str()); } synergy-1.8.8-stable/src/lib/synergy/XSynergy.h000066400000000000000000000056221305627404700215130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/XBase.h" //! Generic synergy exception XBASE_SUBCLASS(XSynergy, XBase); //! Subscription error /*! Thrown when there is a problem with the subscription. */ XBASE_SUBCLASS(XSubscription, XSynergy); //! Client error exception /*! Thrown when the client fails to follow the protocol. */ XBASE_SUBCLASS_WHAT(XBadClient, XSynergy); //! Incompatible client exception /*! Thrown when a client attempting to connect has an incompatible version. */ class XIncompatibleClient : public XSynergy { public: XIncompatibleClient(int major, int minor); //! @name accessors //@{ //! Get client's major version number int getMajor() const throw(); //! Get client's minor version number int getMinor() const throw(); //@} protected: virtual String getWhat() const throw(); private: int m_major; int m_minor; }; //! Client already connected exception /*! Thrown when a client attempting to connect is using the same name as a client that is already connected. */ class XDuplicateClient : public XSynergy { public: XDuplicateClient(const String& name); virtual ~XDuplicateClient() _NOEXCEPT { } //! @name accessors //@{ //! Get client's name virtual const String& getName() const throw(); //@} protected: virtual String getWhat() const throw(); private: String m_name; }; //! Client not in map exception /*! Thrown when a client attempting to connect is using a name that is unknown to the server. */ class XUnknownClient : public XSynergy { public: XUnknownClient(const String& name); virtual ~XUnknownClient() _NOEXCEPT { } //! @name accessors //@{ //! Get the client's name virtual const String& getName() const throw(); //@} protected: virtual String getWhat() const throw(); private: String m_name; }; //! Generic exit eception /*! Thrown when we want to abort, with the opportunity to clean up. This is a little bit of a hack, but it's a better way of exiting, than just calling exit(int). */ class XExitApp : public XSynergy { public: XExitApp(int code); virtual ~XExitApp() _NOEXCEPT { } //! Get the exit code int getCode() const throw(); protected: virtual String getWhat() const throw(); private: int m_code; }; synergy-1.8.8-stable/src/lib/synergy/clipboard_types.h000066400000000000000000000026771305627404700231150ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/basic_types.h" //! Clipboard ID /*! Type to hold a clipboard identifier. */ typedef UInt8 ClipboardID; //! @name Clipboard identifiers //@{ // clipboard identifiers. kClipboardClipboard is what is normally // considered the clipboard (e.g. the cut/copy/paste menu items // affect it). kClipboardSelection is the selection on those // platforms that can treat the selection as a clipboard (e.g. X // windows). clipboard identifiers must be sequential starting // at zero. static const ClipboardID kClipboardClipboard = 0; static const ClipboardID kClipboardSelection = 1; // the number of clipboards (i.e. one greater than the last clipboard id) static const ClipboardID kClipboardEnd = 2; //@} synergy-1.8.8-stable/src/lib/synergy/key_types.cpp000066400000000000000000000134661305627404700222770ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/key_types.h" const KeyNameMapEntry kKeyNameMap[] = { { "AltGr", kKeyAltGr }, { "Alt_L", kKeyAlt_L }, { "Alt_R", kKeyAlt_R }, { "AppMail", kKeyAppMail }, { "AppMedia", kKeyAppMedia }, { "AppUser1", kKeyAppUser1 }, { "AppUser2", kKeyAppUser2 }, { "AudioDown", kKeyAudioDown }, { "AudioMute", kKeyAudioMute }, { "AudioNext", kKeyAudioNext }, { "AudioPlay", kKeyAudioPlay }, { "AudioPrev", kKeyAudioPrev }, { "AudioStop", kKeyAudioStop }, { "AudioUp", kKeyAudioUp }, { "BackSpace", kKeyBackSpace }, { "Begin", kKeyBegin }, { "Break", kKeyBreak }, { "Cancel", kKeyCancel }, { "CapsLock", kKeyCapsLock }, { "Clear", kKeyClear }, { "Control_L", kKeyControl_L }, { "Control_R", kKeyControl_R }, { "Delete", kKeyDelete }, { "Down", kKeyDown }, { "Eject", kKeyEject }, { "End", kKeyEnd }, { "Escape", kKeyEscape }, { "Execute", kKeyExecute }, { "F1", kKeyF1 }, { "F2", kKeyF2 }, { "F3", kKeyF3 }, { "F4", kKeyF4 }, { "F5", kKeyF5 }, { "F6", kKeyF6 }, { "F7", kKeyF7 }, { "F8", kKeyF8 }, { "F9", kKeyF9 }, { "F10", kKeyF10 }, { "F11", kKeyF11 }, { "F12", kKeyF12 }, { "F13", kKeyF13 }, { "F14", kKeyF14 }, { "F15", kKeyF15 }, { "F16", kKeyF16 }, { "F17", kKeyF17 }, { "F18", kKeyF18 }, { "F19", kKeyF19 }, { "F20", kKeyF20 }, { "F21", kKeyF21 }, { "F22", kKeyF22 }, { "F23", kKeyF23 }, { "F24", kKeyF24 }, { "F25", kKeyF25 }, { "F26", kKeyF26 }, { "F27", kKeyF27 }, { "F28", kKeyF28 }, { "F29", kKeyF29 }, { "F30", kKeyF30 }, { "F31", kKeyF31 }, { "F32", kKeyF32 }, { "F33", kKeyF33 }, { "F34", kKeyF34 }, { "F35", kKeyF35 }, { "Find", kKeyFind }, { "Help", kKeyHelp }, { "Henkan", kKeyHenkan }, { "Home", kKeyHome }, { "Hyper_L", kKeyHyper_L }, { "Hyper_R", kKeyHyper_R }, { "Insert", kKeyInsert }, { "KP_0", kKeyKP_0 }, { "KP_1", kKeyKP_1 }, { "KP_2", kKeyKP_2 }, { "KP_3", kKeyKP_3 }, { "KP_4", kKeyKP_4 }, { "KP_5", kKeyKP_5 }, { "KP_6", kKeyKP_6 }, { "KP_7", kKeyKP_7 }, { "KP_8", kKeyKP_8 }, { "KP_9", kKeyKP_9 }, { "KP_Add", kKeyKP_Add }, { "KP_Begin", kKeyKP_Begin }, { "KP_Decimal", kKeyKP_Decimal }, { "KP_Delete", kKeyKP_Delete }, { "KP_Divide", kKeyKP_Divide }, { "KP_Down", kKeyKP_Down }, { "KP_End", kKeyKP_End }, { "KP_Enter", kKeyKP_Enter }, { "KP_Equal", kKeyKP_Equal }, { "KP_F1", kKeyKP_F1 }, { "KP_F2", kKeyKP_F2 }, { "KP_F3", kKeyKP_F3 }, { "KP_F4", kKeyKP_F4 }, { "KP_Home", kKeyKP_Home }, { "KP_Insert", kKeyKP_Insert }, { "KP_Left", kKeyKP_Left }, { "KP_Multiply", kKeyKP_Multiply }, { "KP_PageDown", kKeyKP_PageDown }, { "KP_PageUp", kKeyKP_PageUp }, { "KP_Right", kKeyKP_Right }, { "KP_Separator", kKeyKP_Separator }, { "KP_Space", kKeyKP_Space }, { "KP_Subtract", kKeyKP_Subtract }, { "KP_Tab", kKeyKP_Tab }, { "KP_Up", kKeyKP_Up }, { "Left", kKeyLeft }, { "LeftTab", kKeyLeftTab }, { "Linefeed", kKeyLinefeed }, { "Menu", kKeyMenu }, { "Meta_L", kKeyMeta_L }, { "Meta_R", kKeyMeta_R }, { "NumLock", kKeyNumLock }, { "PageDown", kKeyPageDown }, { "PageUp", kKeyPageUp }, { "Pause", kKeyPause }, { "Print", kKeyPrint }, { "Redo", kKeyRedo }, { "Return", kKeyReturn }, { "Right", kKeyRight }, { "ScrollLock", kKeyScrollLock }, { "Select", kKeySelect }, { "ShiftLock", kKeyShiftLock }, { "Shift_L", kKeyShift_L }, { "Shift_R", kKeyShift_R }, { "Sleep", kKeySleep }, { "Super_L", kKeySuper_L }, { "Super_R", kKeySuper_R }, { "SysReq", kKeySysReq }, { "Tab", kKeyTab }, { "Undo", kKeyUndo }, { "Up", kKeyUp }, { "WWWBack", kKeyWWWBack }, { "WWWFavorites", kKeyWWWFavorites }, { "WWWForward", kKeyWWWForward }, { "WWWHome", kKeyWWWHome }, { "WWWRefresh", kKeyWWWRefresh }, { "WWWSearch", kKeyWWWSearch }, { "WWWStop", kKeyWWWStop }, { "Zenkaku", kKeyZenkaku }, { "Space", 0x0020 }, { "Exclaim", 0x0021 }, { "DoubleQuote", 0x0022 }, { "Number", 0x0023 }, { "Dollar", 0x0024 }, { "Percent", 0x0025 }, { "Ampersand", 0x0026 }, { "Apostrophe", 0x0027 }, { "ParenthesisL", 0x0028 }, { "ParenthesisR", 0x0029 }, { "Asterisk", 0x002a }, { "Plus", 0x002b }, { "Comma", 0x002c }, { "Minus", 0x002d }, { "Period", 0x002e }, { "Slash", 0x002f }, { "Colon", 0x003a }, { "Semicolon", 0x003b }, { "Less", 0x003c }, { "Equal", 0x003d }, { "Greater", 0x003e }, { "Question", 0x003f }, { "At", 0x0040 }, { "BracketL", 0x005b }, { "Backslash", 0x005c }, { "BracketR", 0x005d }, { "Circumflex", 0x005e }, { "Underscore", 0x005f }, { "Grave", 0x0060 }, { "BraceL", 0x007b }, { "Bar", 0x007c }, { "BraceR", 0x007d }, { "Tilde", 0x007e }, { NULL, 0 }, }; const KeyModifierNameMapEntry kModifierNameMap[] = { { "Alt", KeyModifierAlt }, { "AltGr", KeyModifierAltGr }, // { "CapsLock", KeyModifierCapsLock }, { "Control", KeyModifierControl }, { "Meta", KeyModifierMeta }, // { "NumLock", KeyModifierNumLock }, // { "ScrollLock", KeyModifierScrollLock }, { "Shift", KeyModifierShift }, { "Super", KeyModifierSuper }, { NULL, 0 }, }; synergy-1.8.8-stable/src/lib/synergy/key_types.h000066400000000000000000000302311305627404700217310ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "common/basic_types.h" //! Key ID /*! Type to hold a key symbol identifier. The encoding is UTF-32, using U+E000 through U+EFFF for the various control keys (e.g. arrow keys, function keys, modifier keys, etc). */ typedef UInt32 KeyID; //! Key Code /*! Type to hold a physical key identifier. That is, it identifies a physical key on the keyboard. KeyButton 0 is reserved to be an invalid key; platforms that use 0 as a physical key identifier will have to remap that value to some arbitrary unused id. */ typedef UInt16 KeyButton; //! Modifier key mask /*! Type to hold a bitmask of key modifiers (e.g. shift keys). */ typedef UInt32 KeyModifierMask; //! Modifier key ID /*! Type to hold the id of a key modifier (e.g. a shift key). */ typedef UInt32 KeyModifierID; //! @name Modifier key masks //@{ static const KeyModifierMask KeyModifierShift = 0x0001; static const KeyModifierMask KeyModifierControl = 0x0002; static const KeyModifierMask KeyModifierAlt = 0x0004; static const KeyModifierMask KeyModifierMeta = 0x0008; static const KeyModifierMask KeyModifierSuper = 0x0010; static const KeyModifierMask KeyModifierAltGr = 0x0020; static const KeyModifierMask KeyModifierLevel5Lock = 0x0040; static const KeyModifierMask KeyModifierCapsLock = 0x1000; static const KeyModifierMask KeyModifierNumLock = 0x2000; static const KeyModifierMask KeyModifierScrollLock = 0x4000; //@} //! @name Modifier key bits //@{ static const UInt32 kKeyModifierBitNone = 16; static const UInt32 kKeyModifierBitShift = 0; static const UInt32 kKeyModifierBitControl = 1; static const UInt32 kKeyModifierBitAlt = 2; static const UInt32 kKeyModifierBitMeta = 3; static const UInt32 kKeyModifierBitSuper = 4; static const UInt32 kKeyModifierBitAltGr = 5; static const UInt32 kKeyModifierBitLevel5Lock = 6; static const UInt32 kKeyModifierBitCapsLock = 12; static const UInt32 kKeyModifierBitNumLock = 13; static const UInt32 kKeyModifierBitScrollLock = 14; static const SInt32 kKeyModifierNumBits = 16; //@} //! @name Modifier key identifiers //@{ static const KeyModifierID kKeyModifierIDNull = 0; static const KeyModifierID kKeyModifierIDShift = 1; static const KeyModifierID kKeyModifierIDControl = 2; static const KeyModifierID kKeyModifierIDAlt = 3; static const KeyModifierID kKeyModifierIDMeta = 4; static const KeyModifierID kKeyModifierIDSuper = 5; static const KeyModifierID kKeyModifierIDAltGr = 6; static const KeyModifierID kKeyModifierIDLast = 7; //@} //! @name Key identifiers //@{ // all identifiers except kKeyNone and those in 0xE000 to 0xE0FF // inclusive are equal to the corresponding X11 keysym - 0x1000. // no key static const KeyID kKeyNone = 0x0000; // TTY functions static const KeyID kKeyBackSpace = 0xEF08; /* back space, back char */ static const KeyID kKeyTab = 0xEF09; static const KeyID kKeyLinefeed = 0xEF0A; /* Linefeed, LF */ static const KeyID kKeyClear = 0xEF0B; static const KeyID kKeyReturn = 0xEF0D; /* Return, enter */ static const KeyID kKeyPause = 0xEF13; /* Pause, hold */ static const KeyID kKeyScrollLock = 0xEF14; static const KeyID kKeySysReq = 0xEF15; static const KeyID kKeyEscape = 0xEF1B; static const KeyID kKeyHenkan = 0xEF23; /* Start/Stop Conversion */ static const KeyID kKeyKana = 0xEF26; /* Kana */ static const KeyID kKeyHiraganaKatakana = 0xEF27; /* Hiragana/Katakana toggle */ static const KeyID kKeyZenkaku = 0xEF2A; /* Zenkaku/Hankaku */ static const KeyID kKeyKanzi = 0xEF2A; /* Kanzi */ static const KeyID kKeyHangul = 0xEF31; /* Hangul */ static const KeyID kKeyHanja = 0xEF34; /* Hanja */ static const KeyID kKeyDelete = 0xEFFF; /* Delete, rubout */ // cursor control static const KeyID kKeyHome = 0xEF50; static const KeyID kKeyLeft = 0xEF51; /* Move left, left arrow */ static const KeyID kKeyUp = 0xEF52; /* Move up, up arrow */ static const KeyID kKeyRight = 0xEF53; /* Move right, right arrow */ static const KeyID kKeyDown = 0xEF54; /* Move down, down arrow */ static const KeyID kKeyPageUp = 0xEF55; static const KeyID kKeyPageDown = 0xEF56; static const KeyID kKeyEnd = 0xEF57; /* EOL */ static const KeyID kKeyBegin = 0xEF58; /* BOL */ // misc functions static const KeyID kKeySelect = 0xEF60; /* Select, mark */ static const KeyID kKeyPrint = 0xEF61; static const KeyID kKeyExecute = 0xEF62; /* Execute, run, do */ static const KeyID kKeyInsert = 0xEF63; /* Insert, insert here */ static const KeyID kKeyUndo = 0xEF65; /* Undo, oops */ static const KeyID kKeyRedo = 0xEF66; /* redo, again */ static const KeyID kKeyMenu = 0xEF67; static const KeyID kKeyFind = 0xEF68; /* Find, search */ static const KeyID kKeyCancel = 0xEF69; /* Cancel, stop, abort, exit */ static const KeyID kKeyHelp = 0xEF6A; /* Help */ static const KeyID kKeyBreak = 0xEF6B; static const KeyID kKeyAltGr = 0xEF7E; /* Character set switch */ static const KeyID kKeyNumLock = 0xEF7F; // keypad static const KeyID kKeyKP_Space = 0xEF80; /* space */ static const KeyID kKeyKP_Tab = 0xEF89; static const KeyID kKeyKP_Enter = 0xEF8D; /* enter */ static const KeyID kKeyKP_F1 = 0xEF91; /* PF1, KP_A, ... */ static const KeyID kKeyKP_F2 = 0xEF92; static const KeyID kKeyKP_F3 = 0xEF93; static const KeyID kKeyKP_F4 = 0xEF94; static const KeyID kKeyKP_Home = 0xEF95; static const KeyID kKeyKP_Left = 0xEF96; static const KeyID kKeyKP_Up = 0xEF97; static const KeyID kKeyKP_Right = 0xEF98; static const KeyID kKeyKP_Down = 0xEF99; static const KeyID kKeyKP_PageUp = 0xEF9A; static const KeyID kKeyKP_PageDown = 0xEF9B; static const KeyID kKeyKP_End = 0xEF9C; static const KeyID kKeyKP_Begin = 0xEF9D; static const KeyID kKeyKP_Insert = 0xEF9E; static const KeyID kKeyKP_Delete = 0xEF9F; static const KeyID kKeyKP_Equal = 0xEFBD; /* equals */ static const KeyID kKeyKP_Multiply = 0xEFAA; static const KeyID kKeyKP_Add = 0xEFAB; static const KeyID kKeyKP_Separator= 0xEFAC; /* separator, often comma */ static const KeyID kKeyKP_Subtract = 0xEFAD; static const KeyID kKeyKP_Decimal = 0xEFAE; static const KeyID kKeyKP_Divide = 0xEFAF; static const KeyID kKeyKP_0 = 0xEFB0; static const KeyID kKeyKP_1 = 0xEFB1; static const KeyID kKeyKP_2 = 0xEFB2; static const KeyID kKeyKP_3 = 0xEFB3; static const KeyID kKeyKP_4 = 0xEFB4; static const KeyID kKeyKP_5 = 0xEFB5; static const KeyID kKeyKP_6 = 0xEFB6; static const KeyID kKeyKP_7 = 0xEFB7; static const KeyID kKeyKP_8 = 0xEFB8; static const KeyID kKeyKP_9 = 0xEFB9; // function keys static const KeyID kKeyF1 = 0xEFBE; static const KeyID kKeyF2 = 0xEFBF; static const KeyID kKeyF3 = 0xEFC0; static const KeyID kKeyF4 = 0xEFC1; static const KeyID kKeyF5 = 0xEFC2; static const KeyID kKeyF6 = 0xEFC3; static const KeyID kKeyF7 = 0xEFC4; static const KeyID kKeyF8 = 0xEFC5; static const KeyID kKeyF9 = 0xEFC6; static const KeyID kKeyF10 = 0xEFC7; static const KeyID kKeyF11 = 0xEFC8; static const KeyID kKeyF12 = 0xEFC9; static const KeyID kKeyF13 = 0xEFCA; static const KeyID kKeyF14 = 0xEFCB; static const KeyID kKeyF15 = 0xEFCC; static const KeyID kKeyF16 = 0xEFCD; static const KeyID kKeyF17 = 0xEFCE; static const KeyID kKeyF18 = 0xEFCF; static const KeyID kKeyF19 = 0xEFD0; static const KeyID kKeyF20 = 0xEFD1; static const KeyID kKeyF21 = 0xEFD2; static const KeyID kKeyF22 = 0xEFD3; static const KeyID kKeyF23 = 0xEFD4; static const KeyID kKeyF24 = 0xEFD5; static const KeyID kKeyF25 = 0xEFD6; static const KeyID kKeyF26 = 0xEFD7; static const KeyID kKeyF27 = 0xEFD8; static const KeyID kKeyF28 = 0xEFD9; static const KeyID kKeyF29 = 0xEFDA; static const KeyID kKeyF30 = 0xEFDB; static const KeyID kKeyF31 = 0xEFDC; static const KeyID kKeyF32 = 0xEFDD; static const KeyID kKeyF33 = 0xEFDE; static const KeyID kKeyF34 = 0xEFDF; static const KeyID kKeyF35 = 0xEFE0; // modifiers static const KeyID kKeyShift_L = 0xEFE1; /* Left shift */ static const KeyID kKeyShift_R = 0xEFE2; /* Right shift */ static const KeyID kKeyControl_L = 0xEFE3; /* Left control */ static const KeyID kKeyControl_R = 0xEFE4; /* Right control */ static const KeyID kKeyCapsLock = 0xEFE5; /* Caps lock */ static const KeyID kKeyShiftLock = 0xEFE6; /* Shift lock */ static const KeyID kKeyMeta_L = 0xEFE7; /* Left meta */ static const KeyID kKeyMeta_R = 0xEFE8; /* Right meta */ static const KeyID kKeyAlt_L = 0xEFE9; /* Left alt */ static const KeyID kKeyAlt_R = 0xEFEA; /* Right alt */ static const KeyID kKeySuper_L = 0xEFEB; /* Left super */ static const KeyID kKeySuper_R = 0xEFEC; /* Right super */ static const KeyID kKeyHyper_L = 0xEFED; /* Left hyper */ static const KeyID kKeyHyper_R = 0xEFEE; /* Right hyper */ // multi-key character composition static const KeyID kKeyCompose = 0xEF20; static const KeyID kKeyDeadGrave = 0x0300; static const KeyID kKeyDeadAcute = 0x0301; static const KeyID kKeyDeadCircumflex = 0x0302; static const KeyID kKeyDeadTilde = 0x0303; static const KeyID kKeyDeadMacron = 0x0304; static const KeyID kKeyDeadBreve = 0x0306; static const KeyID kKeyDeadAbovedot = 0x0307; static const KeyID kKeyDeadDiaeresis = 0x0308; static const KeyID kKeyDeadAbovering = 0x030a; static const KeyID kKeyDeadDoubleacute = 0x030b; static const KeyID kKeyDeadCaron = 0x030c; static const KeyID kKeyDeadCedilla = 0x0327; static const KeyID kKeyDeadOgonek = 0x0328; // more function and modifier keys static const KeyID kKeyLeftTab = 0xEE20; // update modifiers static const KeyID kKeySetModifiers = 0xEE06; static const KeyID kKeyClearModifiers = 0xEE07; // group change static const KeyID kKeyNextGroup = 0xEE08; static const KeyID kKeyPrevGroup = 0xEE0A; // extended keys static const KeyID kKeyEject = 0xE001; static const KeyID kKeySleep = 0xE05F; static const KeyID kKeyWWWBack = 0xE0A6; static const KeyID kKeyWWWForward = 0xE0A7; static const KeyID kKeyWWWRefresh = 0xE0A8; static const KeyID kKeyWWWStop = 0xE0A9; static const KeyID kKeyWWWSearch = 0xE0AA; static const KeyID kKeyWWWFavorites = 0xE0AB; static const KeyID kKeyWWWHome = 0xE0AC; static const KeyID kKeyAudioMute = 0xE0AD; static const KeyID kKeyAudioDown = 0xE0AE; static const KeyID kKeyAudioUp = 0xE0AF; static const KeyID kKeyAudioNext = 0xE0B0; static const KeyID kKeyAudioPrev = 0xE0B1; static const KeyID kKeyAudioStop = 0xE0B2; static const KeyID kKeyAudioPlay = 0xE0B3; static const KeyID kKeyAppMail = 0xE0B4; static const KeyID kKeyAppMedia = 0xE0B5; static const KeyID kKeyAppUser1 = 0xE0B6; static const KeyID kKeyAppUser2 = 0xE0B7; static const KeyID kKeyBrightnessDown = 0xE0B8; static const KeyID kKeyBrightnessUp = 0xE0B9; static const KeyID kKeyMissionControl = 0xE0C0; static const KeyID kKeyLaunchpad = 0xE0C1; //@} struct KeyNameMapEntry { const char* m_name; KeyID m_id; }; struct KeyModifierNameMapEntry { const char* m_name; KeyModifierMask m_mask; }; //! Key name to KeyID table /*! A table of key names to the corresponding KeyID. Only the keys listed above plus non-alphanumeric ASCII characters are in the table. The end of the table is the first pair with a NULL m_name. */ extern const struct KeyNameMapEntry kKeyNameMap[]; //! Modifier key name to KeyModifierMask table /*! A table of modifier key names to the corresponding KeyModifierMask. The end of the table is the first pair with a NULL m_name. */ extern const struct KeyModifierNameMapEntry kModifierNameMap[]; synergy-1.8.8-stable/src/lib/synergy/mouse_types.h000066400000000000000000000023501305627404700222720ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/EventTypes.h" //! Mouse button ID /*! Type to hold a mouse button identifier. */ typedef UInt8 ButtonID; //! @name Mouse button identifiers //@{ static const ButtonID kButtonNone = 0; static const ButtonID kButtonLeft = 1; static const ButtonID kButtonMiddle = 2; static const ButtonID kButtonRight = 3; static const ButtonID kButtonExtra0 = 4; static const ButtonID kMacButtonRight = 2; static const ButtonID kMacButtonMiddle = 3; //@} static const UInt8 NumButtonIDs = 5; synergy-1.8.8-stable/src/lib/synergy/option_types.h000066400000000000000000000073031305627404700224550ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/EventTypes.h" #include "common/stdvector.h" //! Option ID /*! Type to hold an option identifier. */ typedef UInt32 OptionID; //! Option Value /*! Type to hold an option value. */ typedef SInt32 OptionValue; // for now, options are just pairs of integers typedef std::vector OptionsList; // macro for packing 4 character strings into 4 byte integers #define OPTION_CODE(_s) \ (static_cast(static_cast(_s[0]) << 24) | \ static_cast(static_cast(_s[1]) << 16) | \ static_cast(static_cast(_s[2]) << 8) | \ static_cast(static_cast(_s[3]) )) //! @name Option identifiers //@{ static const OptionID kOptionHalfDuplexCapsLock = OPTION_CODE("HDCL"); static const OptionID kOptionHalfDuplexNumLock = OPTION_CODE("HDNL"); static const OptionID kOptionHalfDuplexScrollLock = OPTION_CODE("HDSL"); static const OptionID kOptionModifierMapForShift = OPTION_CODE("MMFS"); static const OptionID kOptionModifierMapForControl = OPTION_CODE("MMFC"); static const OptionID kOptionModifierMapForAlt = OPTION_CODE("MMFA"); static const OptionID kOptionModifierMapForAltGr = OPTION_CODE("MMFG"); static const OptionID kOptionModifierMapForMeta = OPTION_CODE("MMFM"); static const OptionID kOptionModifierMapForSuper = OPTION_CODE("MMFR"); static const OptionID kOptionHeartbeat = OPTION_CODE("HART"); static const OptionID kOptionScreenSwitchCorners = OPTION_CODE("SSCM"); static const OptionID kOptionScreenSwitchCornerSize = OPTION_CODE("SSCS"); static const OptionID kOptionScreenSwitchDelay = OPTION_CODE("SSWT"); static const OptionID kOptionScreenSwitchTwoTap = OPTION_CODE("SSTT"); static const OptionID kOptionScreenSwitchNeedsShift = OPTION_CODE("SSNS"); static const OptionID kOptionScreenSwitchNeedsControl = OPTION_CODE("SSNC"); static const OptionID kOptionScreenSwitchNeedsAlt = OPTION_CODE("SSNA"); static const OptionID kOptionScreenSaverSync = OPTION_CODE("SSVR"); static const OptionID kOptionXTestXineramaUnaware = OPTION_CODE("XTXU"); static const OptionID kOptionScreenPreserveFocus = OPTION_CODE("SFOC"); static const OptionID kOptionRelativeMouseMoves = OPTION_CODE("MDLT"); static const OptionID kOptionWin32KeepForeground = OPTION_CODE("_KFW"); static const OptionID kOptionClipboardSharing = OPTION_CODE("CLPS"); //@} //! @name Screen switch corner enumeration //@{ enum EScreenSwitchCorners { kNoCorner, kTopLeft, kTopRight, kBottomLeft, kBottomRight, kFirstCorner = kTopLeft, kLastCorner = kBottomRight }; //@} //! @name Screen switch corner masks //@{ enum EScreenSwitchCornerMasks { kNoCornerMask = 0, kTopLeftMask = 1 << (kTopLeft - kFirstCorner), kTopRightMask = 1 << (kTopRight - kFirstCorner), kBottomLeftMask = 1 << (kBottomLeft - kFirstCorner), kBottomRightMask = 1 << (kBottomRight - kFirstCorner), kAllCornersMask = kTopLeftMask | kTopRightMask | kBottomLeftMask | kBottomRightMask }; //@} #undef OPTION_CODE synergy-1.8.8-stable/src/lib/synergy/protocol_types.cpp000066400000000000000000000043341305627404700233420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/protocol_types.h" const char* kMsgHello = "Synergy%2i%2i"; const char* kMsgHelloBack = "Synergy%2i%2i%s"; const char* kMsgCNoop = "CNOP"; const char* kMsgCClose = "CBYE"; const char* kMsgCEnter = "CINN%2i%2i%4i%2i"; const char* kMsgCLeave = "COUT"; const char* kMsgCClipboard = "CCLP%1i%4i"; const char* kMsgCScreenSaver = "CSEC%1i"; const char* kMsgCResetOptions = "CROP"; const char* kMsgCInfoAck = "CIAK"; const char* kMsgCKeepAlive = "CALV"; const char* kMsgDKeyDown = "DKDN%2i%2i%2i"; const char* kMsgDKeyDown1_0 = "DKDN%2i%2i"; const char* kMsgDKeyRepeat = "DKRP%2i%2i%2i%2i"; const char* kMsgDKeyRepeat1_0 = "DKRP%2i%2i%2i"; const char* kMsgDKeyUp = "DKUP%2i%2i%2i"; const char* kMsgDKeyUp1_0 = "DKUP%2i%2i"; const char* kMsgDMouseDown = "DMDN%1i"; const char* kMsgDMouseUp = "DMUP%1i"; const char* kMsgDMouseMove = "DMMV%2i%2i"; const char* kMsgDMouseRelMove = "DMRM%2i%2i"; const char* kMsgDMouseWheel = "DMWM%2i%2i"; const char* kMsgDMouseWheel1_0 = "DMWM%2i"; const char* kMsgDClipboard = "DCLP%1i%4i%1i%s"; const char* kMsgDInfo = "DINF%2i%2i%2i%2i%2i%2i%2i"; const char* kMsgDSetOptions = "DSOP%4I"; const char* kMsgDFileTransfer = "DFTR%1i%s"; const char* kMsgDDragInfo = "DDRG%2i%s"; const char* kMsgQInfo = "QINF"; const char* kMsgEIncompatible = "EICV%2i%2i"; const char* kMsgEBusy = "EBSY"; const char* kMsgEUnknown = "EUNK"; const char* kMsgEBad = "EBAD"; synergy-1.8.8-stable/src/lib/synergy/protocol_types.h000066400000000000000000000251121305627404700230040ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/EventTypes.h" // protocol version number // 1.0: initial protocol // 1.1: adds KeyCode to key press, release, and repeat // 1.2: adds mouse relative motion // 1.3: adds keep alive and deprecates heartbeats, // adds horizontal mouse scrolling // 1.4: adds crypto support // 1.5: adds file transfer and removes home brew crypto // 1.6: adds clipboard streaming // NOTE: with new version, synergy minor version should increment static const SInt16 kProtocolMajorVersion = 1; static const SInt16 kProtocolMinorVersion = 6; // default contact port number static const UInt16 kDefaultPort = 24800; // maximum total length for greeting returned by client static const UInt32 kMaxHelloLength = 1024; // time between kMsgCKeepAlive (in seconds). a non-positive value disables // keep alives. this is the default rate that can be overridden using an // option. static const double kKeepAliveRate = 3.0; // number of skipped kMsgCKeepAlive messages that indicates a problem static const double kKeepAlivesUntilDeath = 3.0; // obsolete heartbeat stuff static const double kHeartRate = -1.0; static const double kHeartBeatsUntilDeath = 3.0; // direction constants enum EDirection { kNoDirection, kLeft, kRight, kTop, kBottom, kFirstDirection = kLeft, kLastDirection = kBottom, kNumDirections = kLastDirection - kFirstDirection + 1 }; enum EDirectionMask { kNoDirMask = 0, kLeftMask = 1 << kLeft, kRightMask = 1 << kRight, kTopMask = 1 << kTop, kBottomMask = 1 << kBottom }; // Data transfer constants enum EDataTransfer { kDataStart = 1, kDataChunk = 2, kDataEnd = 3 }; // Data received constants enum EDataReceived { kStart, kNotFinish, kFinish, kError }; // // message codes (trailing NUL is not part of code). in comments, $n // refers to the n'th argument (counting from one). message codes are // always 4 bytes optionally followed by message specific parameters // except those for the greeting handshake. // // // positions and sizes are signed 16 bit integers. // // // greeting handshake messages // // say hello to client; primary -> secondary // $1 = protocol major version number supported by server. $2 = // protocol minor version number supported by server. extern const char* kMsgHello; // respond to hello from server; secondary -> primary // $1 = protocol major version number supported by client. $2 = // protocol minor version number supported by client. $3 = client // name. extern const char* kMsgHelloBack; // // command codes // // no operation; secondary -> primary extern const char* kMsgCNoop; // close connection; primary -> secondary extern const char* kMsgCClose; // enter screen: primary -> secondary // entering screen at screen position $1 = x, $2 = y. x,y are // absolute screen coordinates. $3 = sequence number, which is // used to order messages between screens. the secondary screen // must return this number with some messages. $4 = modifier key // mask. this will have bits set for each toggle modifier key // that is activated on entry to the screen. the secondary screen // should adjust its toggle modifiers to reflect that state. extern const char* kMsgCEnter; // leave screen: primary -> secondary // leaving screen. the secondary screen should send clipboard // data in response to this message for those clipboards that // it has grabbed (i.e. has sent a kMsgCClipboard for and has // not received a kMsgCClipboard for with a greater sequence // number) and that were grabbed or have changed since the // last leave. extern const char* kMsgCLeave; // grab clipboard: primary <-> secondary // sent by screen when some other app on that screen grabs a // clipboard. $1 = the clipboard identifier, $2 = sequence number. // secondary screens must use the sequence number passed in the // most recent kMsgCEnter. the primary always sends 0. extern const char* kMsgCClipboard; // screensaver change: primary -> secondary // screensaver on primary has started ($1 == 1) or closed ($1 == 0) extern const char* kMsgCScreenSaver; // reset options: primary -> secondary // client should reset all of its options to their defaults. extern const char* kMsgCResetOptions; // resolution change acknowledgment: primary -> secondary // sent by primary in response to a secondary screen's kMsgDInfo. // this is sent for every kMsgDInfo, whether or not the primary // had sent a kMsgQInfo. extern const char* kMsgCInfoAck; // keep connection alive: primary <-> secondary // sent by the server periodically to verify that connections are still // up and running. clients must reply in kind on receipt. if the server // gets an error sending the message or does not receive a reply within // a reasonable time then the server disconnects the client. if the // client doesn't receive these (or any message) periodically then it // should disconnect from the server. the appropriate interval is // defined by an option. extern const char* kMsgCKeepAlive; // // data codes // // key pressed: primary -> secondary // $1 = KeyID, $2 = KeyModifierMask, $3 = KeyButton // the KeyButton identifies the physical key on the primary used to // generate this key. the secondary should note the KeyButton along // with the physical key it uses to generate the key press. on // release, the secondary can then use the primary's KeyButton to // find its corresponding physical key and release it. this is // necessary because the KeyID on release may not be the KeyID of // the press. this can happen with combining (dead) keys or if // the keyboard layouts are not identical and the user releases // a modifier key before releasing the modified key. extern const char* kMsgDKeyDown; // key pressed 1.0: same as above but without KeyButton extern const char* kMsgDKeyDown1_0; // key auto-repeat: primary -> secondary // $1 = KeyID, $2 = KeyModifierMask, $3 = number of repeats, $4 = KeyButton extern const char* kMsgDKeyRepeat; // key auto-repeat 1.0: same as above but without KeyButton extern const char* kMsgDKeyRepeat1_0; // key released: primary -> secondary // $1 = KeyID, $2 = KeyModifierMask, $3 = KeyButton extern const char* kMsgDKeyUp; // key released 1.0: same as above but without KeyButton extern const char* kMsgDKeyUp1_0; // mouse button pressed: primary -> secondary // $1 = ButtonID extern const char* kMsgDMouseDown; // mouse button released: primary -> secondary // $1 = ButtonID extern const char* kMsgDMouseUp; // mouse moved: primary -> secondary // $1 = x, $2 = y. x,y are absolute screen coordinates. extern const char* kMsgDMouseMove; // relative mouse move: primary -> secondary // $1 = dx, $2 = dy. dx,dy are motion deltas. extern const char* kMsgDMouseRelMove; // mouse scroll: primary -> secondary // $1 = xDelta, $2 = yDelta. the delta should be +120 for one tick forward // (away from the user) or right and -120 for one tick backward (toward // the user) or left. extern const char* kMsgDMouseWheel; // mouse vertical scroll: primary -> secondary // like as kMsgDMouseWheel except only sends $1 = yDelta. extern const char* kMsgDMouseWheel1_0; // clipboard data: primary <-> secondary // $2 = sequence number, $3 = mark $4 = clipboard data. the sequence number // is 0 when sent by the primary. secondary screens should use the // sequence number from the most recent kMsgCEnter. $1 = clipboard // identifier. extern const char* kMsgDClipboard; // client data: secondary -> primary // $1 = coordinate of leftmost pixel on secondary screen, // $2 = coordinate of topmost pixel on secondary screen, // $3 = width of secondary screen in pixels, // $4 = height of secondary screen in pixels, // $5 = size of warp zone, (obsolete) // $6, $7 = the x,y position of the mouse on the secondary screen. // // the secondary screen must send this message in response to the // kMsgQInfo message. it must also send this message when the // screen's resolution changes. in this case, the secondary screen // should ignore any kMsgDMouseMove messages until it receives a // kMsgCInfoAck in order to prevent attempts to move the mouse off // the new screen area. extern const char* kMsgDInfo; // set options: primary -> secondary // client should set the given option/value pairs. $1 = option/value // pairs. extern const char* kMsgDSetOptions; // file data: primary <-> secondary // transfer file data. A mark is used in the first byte. // 0 means the content followed is the file size. // 1 means the content followed is the chunk data. // 2 means the file transfer is finished. extern const char* kMsgDFileTransfer; // drag infomation: primary <-> secondary // transfer drag infomation. The first 2 bytes are used for storing // the number of dragging objects. Then the following string consists // of each object's directory. extern const char* kMsgDDragInfo; // // query codes // // query screen info: primary -> secondary // client should reply with a kMsgDInfo. extern const char* kMsgQInfo; // // error codes // // incompatible versions: primary -> secondary // $1 = major version of primary, $2 = minor version of primary. extern const char* kMsgEIncompatible; // name provided when connecting is already in use: primary -> secondary extern const char* kMsgEBusy; // unknown client: primary -> secondary // name provided when connecting is not in primary's screen // configuration map. extern const char* kMsgEUnknown; // protocol violation: primary -> secondary // primary should disconnect after sending this message. extern const char* kMsgEBad; // // structures // //! Screen information /*! This class contains information about a screen. */ class ClientInfo { public: //! Screen position /*! The position of the upper-left corner of the screen. This is typically 0,0. */ SInt32 m_x, m_y; //! Screen size /*! The size of the screen in pixels. */ SInt32 m_w, m_h; //! Obsolete (jump zone size) SInt32 obsolete1; //! Mouse position /*! The current location of the mouse cursor. */ SInt32 m_mx, m_my; }; synergy-1.8.8-stable/src/lib/synergy/unix/000077500000000000000000000000001305627404700205305ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/synergy/unix/AppUtilUnix.cpp000066400000000000000000000022231305627404700234550ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/unix/AppUtilUnix.h" #include "synergy/ArgsBase.h" AppUtilUnix::AppUtilUnix(IEventQueue* events) { } AppUtilUnix::~AppUtilUnix() { } int standardStartupStatic(int argc, char** argv) { return AppUtil::instance().app().standardStartup(argc, argv); } int AppUtilUnix::run(int argc, char** argv) { return app().runInner(argc, argv, NULL, &standardStartupStatic); } void AppUtilUnix::startNode() { app().startNode(); } synergy-1.8.8-stable/src/lib/synergy/unix/AppUtilUnix.h000066400000000000000000000017411305627404700231260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/AppUtil.h" #define ARCH_APP_UTIL AppUtilUnix class IEventQueue; class AppUtilUnix : public AppUtil { public: AppUtilUnix(IEventQueue* events); virtual ~AppUtilUnix(); int run(int argc, char** argv); void startNode(); }; synergy-1.8.8-stable/src/lib/synergy/win32/000077500000000000000000000000001305627404700205075ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/synergy/win32/AppUtilWindows.cpp000066400000000000000000000110471305627404700241470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/win32/AppUtilWindows.h" #include "synergy/Screen.h" #include "synergy/ArgsBase.h" #include "synergy/App.h" #include "synergy/XSynergy.h" #include "platform/MSWindowsScreen.h" #include "arch/win32/XArchWindows.h" #include "arch/win32/ArchMiscWindows.h" #include "arch/IArchTaskBarReceiver.h" #include "base/Log.h" #include "base/log_outputters.h" #include "base/IEventQueue.h" #include "base/Event.h" #include "base/EventQueue.h" #include "common/Version.h" #include #include #include AppUtilWindows::AppUtilWindows(IEventQueue* events) : m_events(events), m_exitMode(kExitModeNormal) { if (SetConsoleCtrlHandler((PHANDLER_ROUTINE)consoleHandler, TRUE) == FALSE) { throw XArch(new XArchEvalWindows()); } } AppUtilWindows::~AppUtilWindows() { } BOOL WINAPI AppUtilWindows::consoleHandler(DWORD) { LOG((CLOG_INFO "got shutdown signal")); IEventQueue* events = AppUtil::instance().app().getEvents(); events->addEvent(Event(Event::kQuit)); return TRUE; } static int mainLoopStatic() { return AppUtil::instance().app().mainLoop(); } int AppUtilWindows::daemonNTMainLoop(int argc, const char** argv) { app().initApp(argc, argv); debugServiceWait(); // NB: what the hell does this do?! app().argsBase().m_backend = false; return ArchMiscWindows::runDaemon(mainLoopStatic); } void AppUtilWindows::exitApp(int code) { switch (m_exitMode) { case kExitModeDaemon: ArchMiscWindows::daemonFailed(code); break; default: throw XExitApp(code); } } int daemonNTMainLoopStatic(int argc, const char** argv) { return AppUtilWindows::instance().daemonNTMainLoop(argc, argv); } int AppUtilWindows::daemonNTStartup(int, char**) { SystemLogger sysLogger(app().daemonName(), false); m_exitMode = kExitModeDaemon; return ARCH->daemonize(app().daemonName(), daemonNTMainLoopStatic); } static int daemonNTStartupStatic(int argc, char** argv) { return AppUtilWindows::instance().daemonNTStartup(argc, argv); } static int foregroundStartupStatic(int argc, char** argv) { return AppUtil::instance().app().foregroundStartup(argc, argv); } void AppUtilWindows::beforeAppExit() { // this can be handy for debugging, since the application is launched in // a new console window, and will normally close on exit (making it so // that we can't see error messages). if (app().argsBase().m_pauseOnExit) { std::cout << std::endl << "press any key to exit..." << std::endl; int c = _getch(); } } int AppUtilWindows::run(int argc, char** argv) { OSVERSIONINFO osvi; ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&osvi); if (osvi.dwMajorVersion < 5 || (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion < 1)) { throw std::runtime_error("synergy only supports windows xp and above."); } // record window instance for tray icon, etc ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); MSWindowsScreen::init(ArchMiscWindows::instanceWin32()); Thread::getCurrentThread().setPriority(-14); StartupFunc startup; if (ArchMiscWindows::wasLaunchedAsService()) { startup = &daemonNTStartupStatic; } else { startup = &foregroundStartupStatic; app().argsBase().m_daemon = false; } return app().runInner(argc, argv, NULL, startup); } AppUtilWindows& AppUtilWindows::instance() { return (AppUtilWindows&)AppUtil::instance(); } void AppUtilWindows::debugServiceWait() { if (app().argsBase().m_debugServiceWait) { while(true) { // this code is only executed when the process is launched via the // windows service controller (and --debug-service-wait arg is // used). to debug, set a breakpoint on this line so that // execution is delayed until the debugger is attached. ARCH->sleep(1); LOG((CLOG_INFO "waiting for debugger to attach")); } } } void AppUtilWindows::startNode() { app().startNode(); } synergy-1.8.8-stable/src/lib/synergy/win32/AppUtilWindows.h000066400000000000000000000026561305627404700236220ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/AppUtil.h" #include "base/String.h" #define WIN32_LEAN_AND_MEAN #include "Windows.h" #define ARCH_APP_UTIL AppUtilWindows class IEventQueue; enum AppExitMode { kExitModeNormal, kExitModeDaemon }; class AppUtilWindows : public AppUtil { public: AppUtilWindows(IEventQueue* events); virtual ~AppUtilWindows(); int daemonNTStartup(int, char**); int daemonNTMainLoop(int argc, const char** argv); void debugServiceWait(); int run(int argc, char** argv); void exitApp(int code); void beforeAppExit(); static AppUtilWindows& instance(); void startNode(); private: AppExitMode m_exitMode; IEventQueue* m_events; static BOOL WINAPI consoleHandler(DWORD Event); }; synergy-1.8.8-stable/src/lib/synwinhk/000077500000000000000000000000001305627404700177175ustar00rootroot00000000000000synergy-1.8.8-stable/src/lib/synwinhk/CMakeLists.txt000066400000000000000000000025061305627404700224620ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2013-2016 Symless Ltd. # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.cpp") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../ ) add_library(synwinhk SHARED ${sources}) # copy the dlls (and supporting files) from the lib dir to # the bin dir, so that synergyc and synergys can easily find them. # we should leave the other libraries compiling to the lib dir, # so that the bin dir remains tidy. the path is relative to the # build dir (in this case, that's: build\src\lib\platform). add_custom_command( TARGET synwinhk POST_BUILD COMMAND xcopy /Y /Q ..\\..\\..\\..\\lib\\${CMAKE_CFG_INTDIR}\\synwinhk.* ..\\..\\..\\..\\bin\\${CMAKE_CFG_INTDIR}\\ ) synergy-1.8.8-stable/src/lib/synwinhk/synwinhk.cpp000066400000000000000000000713161305627404700223050ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synwinhk/synwinhk.h" #include "synergy/protocol_types.h" #include #include #if _MSC_VER >= 1400 // VS2005 hack - we don't use assert here because we don't want to link with the CRT. #undef assert #if _DEBUG #define assert(_X_) if (!(_X_)) __debugbreak() #else #define assert(_X_) __noop() #endif // VS2005 is a bit more smart than VC6 and optimize simple copy loop to // intrinsic memcpy. #pragma function(memcpy) #endif // // debugging compile flag. when not zero the server doesn't grab // the keyboard when the mouse leaves the server screen. this // makes it possible to use the debugger (via the keyboard) when // all user input would normally be caught by the hook procedures. // #define NO_GRAB_KEYBOARD 0 // // debugging compile flag. when not zero the server will not // install low level hooks. // #define NO_LOWLEVEL_HOOKS 0 // // extra mouse wheel stuff // enum EWheelSupport { kWheelNone, kWheelOld, kWheelWin2000, kWheelModern }; // declare extended mouse hook struct. useable on win2k typedef struct tagMOUSEHOOKSTRUCTWin2000 { MOUSEHOOKSTRUCT mhs; DWORD mouseData; } MOUSEHOOKSTRUCTWin2000; #if !defined(SM_MOUSEWHEELPRESENT) #define SM_MOUSEWHEELPRESENT 75 #endif // 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 0x0080 #define MOUSEEVENTF_XUP 0x0100 #define XBUTTON1 0x0001 #define XBUTTON2 0x0002 #endif // // globals // #if defined(_MSC_VER) #pragma comment(linker, "-section:shared,rws") #pragma data_seg("shared") #endif // all data in this shared section *must* be initialized static HINSTANCE g_hinstance = NULL; static DWORD g_processID = 0; static EWheelSupport g_wheelSupport = kWheelNone; static UINT g_wmMouseWheel = 0; static DWORD g_threadID = 0; static HHOOK g_keyboard = NULL; static HHOOK g_mouse = NULL; static HHOOK g_getMessage = NULL; static HHOOK g_keyboardLL = NULL; static HHOOK g_mouseLL = NULL; static bool g_screenSaver = false; static EHookMode g_mode = kHOOK_DISABLE; static UInt32 g_zoneSides = 0; static SInt32 g_zoneSize = 0; static SInt32 g_xScreen = 0; static SInt32 g_yScreen = 0; static SInt32 g_wScreen = 0; static SInt32 g_hScreen = 0; static WPARAM g_deadVirtKey = 0; static WPARAM g_deadRelease = 0; static LPARAM g_deadLParam = 0; static BYTE g_deadKeyState[256] = { 0 }; static BYTE g_keyState[256] = { 0 }; static DWORD g_hookThread = 0; static bool g_fakeInput = false; #if defined(_MSC_VER) #pragma data_seg() #endif // keep linker quiet about floating point stuff. we don't use any // floating point operations but our includes may define some // (unused) floating point values. #ifndef _DEBUG extern "C" { int _fltused=0; } #endif #if !NO_GRAB_KEYBOARD static WPARAM makeKeyMsg(UINT virtKey, char c, bool noAltGr) { return MAKEWPARAM(MAKEWORD(virtKey & 0xff, (BYTE)c), noAltGr ? 1 : 0); } static void keyboardGetState(BYTE keys[256], DWORD vkCode, bool kf_up) { // we have to use GetAsyncKeyState() rather than GetKeyState() because // we don't pass through most keys so the event synchronous state // doesn't get updated. we do that because certain modifier keys have // side effects, like alt and the windows key. if (vkCode < 0 || vkCode >= 256) { return; } // Keep track of key state on our own in case GetAsyncKeyState() fails g_keyState[vkCode] = kf_up ? 0 : 0x80; g_keyState[VK_SHIFT] = g_keyState[VK_LSHIFT] | g_keyState[VK_RSHIFT]; SHORT key; // Test whether GetAsyncKeyState() is being honest with us key = GetAsyncKeyState(vkCode); if (key & 0x80) { // The only time we know for sure that GetAsyncKeyState() is working // is when it tells us that the current key is down. // In this case, update g_keyState to reflect what GetAsyncKeyState() // is telling us, just in case we have gotten out of sync for (int i = 0; i < 256; ++i) { key = GetAsyncKeyState(i); g_keyState[i] = (BYTE)((key < 0) ? 0x80u : 0); } } // copy g_keyState to keys for (int i = 0; i < 256; ++i) { keys[i] = g_keyState[i]; } key = GetKeyState(VK_CAPITAL); keys[VK_CAPITAL] = (BYTE)(((key < 0) ? 0x80 : 0) | (key & 1)); } static bool doKeyboardHookHandler(WPARAM wParam, LPARAM lParam) { DWORD vkCode = static_cast(wParam); bool kf_up = (lParam & (KF_UP << 16)) != 0; // check for special events indicating if we should start or stop // passing events through and not report them to the server. this // is used to allow the server to synthesize events locally but // not pick them up as user events. if (wParam == SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY && ((lParam >> 16) & 0xffu) == SYNERGY_HOOK_FAKE_INPUT_SCANCODE) { // update flag g_fakeInput = ((lParam & 0x80000000u) == 0); PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, 0xff000000u | wParam, lParam); // discard event return true; } // if we're expecting fake input then just pass the event through // and do not forward to the server if (g_fakeInput) { PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, 0xfe000000u | wParam, lParam); return false; } // VK_RSHIFT may be sent with an extended scan code but right shift // is not an extended key so we reset that bit. if (wParam == VK_RSHIFT) { lParam &= ~0x01000000u; } // tell server about event PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam, lParam); // ignore dead key release if ((g_deadVirtKey == wParam || g_deadRelease == wParam) && (lParam & 0x80000000u) != 0) { g_deadRelease = 0; PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam | 0x04000000, lParam); return false; } // we need the keyboard state for ToAscii() BYTE keys[256]; keyboardGetState(keys, vkCode, kf_up); // ToAscii() maps ctrl+letter to the corresponding control code // and ctrl+backspace to delete. we don't want those translations // so clear the control modifier state. however, if we want to // simulate AltGr (which is ctrl+alt) then we must not clear it. UINT control = keys[VK_CONTROL] | keys[VK_LCONTROL] | keys[VK_RCONTROL]; UINT menu = keys[VK_MENU] | keys[VK_LMENU] | keys[VK_RMENU]; if ((control & 0x80) == 0 || (menu & 0x80) == 0) { keys[VK_LCONTROL] = 0; keys[VK_RCONTROL] = 0; keys[VK_CONTROL] = 0; } else { keys[VK_LCONTROL] = 0x80; keys[VK_RCONTROL] = 0x80; keys[VK_CONTROL] = 0x80; keys[VK_LMENU] = 0x80; keys[VK_RMENU] = 0x80; keys[VK_MENU] = 0x80; } // ToAscii() needs to know if a menu is active for some reason. // we don't know and there doesn't appear to be any way to find // out. so we'll just assume a menu is active if the menu key // is down. // FIXME -- figure out some way to check if a menu is active UINT flags = 0; if ((menu & 0x80) != 0) flags |= 1; // if we're on the server screen then just pass numpad keys with alt // key down as-is. we won't pick up the resulting character but the // local app will. if on a client screen then grab keys as usual; // if the client is a windows system it'll synthesize the expected // character. if not then it'll probably just do nothing. if (g_mode != kHOOK_RELAY_EVENTS) { // we don't use virtual keys because we don't know what the // state of the numlock key is. we'll hard code the scan codes // instead. hopefully this works across all keyboards. UINT sc = (lParam & 0x01ff0000u) >> 16; if (menu && (sc >= 0x47u && sc <= 0x52u && sc != 0x4au && sc != 0x4eu)) { return false; } } WORD c = 0; // map the key event to a character. we have to put the dead // key back first and this has the side effect of removing it. if (g_deadVirtKey != 0) { if (ToAscii((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16, g_deadKeyState, &c, flags) == 2) { // If ToAscii returned 2, it means that we accidentally removed // a double dead key instead of restoring it. Thus, we call // ToAscii again with the same parameters to restore the // internal dead key state. ToAscii((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16, g_deadKeyState, &c, flags); // We need to keep track of this because g_deadVirtKey will be // cleared later on; this would cause the dead key release to // incorrectly restore the dead key state. g_deadRelease = g_deadVirtKey; } } UINT scanCode = ((lParam & 0x10ff0000u) >> 16); int n = ToAscii((UINT)wParam, scanCode, keys, &c, flags); // if mapping failed and ctrl and alt are pressed then try again // with both not pressed. this handles the case where ctrl and // alt are being used as individual modifiers rather than AltGr. // we note that's the case in the message sent back to synergy // because there's no simple way to deduce it after the fact. // we have to put the dead key back first, if there was one. bool noAltGr = false; if (n == 0 && (control & 0x80) != 0 && (menu & 0x80) != 0) { noAltGr = true; PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam | 0x05000000, lParam); if (g_deadVirtKey != 0) { if (ToAscii((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16, g_deadKeyState, &c, flags) == 2) { ToAscii((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16, g_deadKeyState, &c, flags); g_deadRelease = g_deadVirtKey; } } BYTE keys2[256]; for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) { keys2[i] = keys[i]; } keys2[VK_LCONTROL] = 0; keys2[VK_RCONTROL] = 0; keys2[VK_CONTROL] = 0; keys2[VK_LMENU] = 0; keys2[VK_RMENU] = 0; keys2[VK_MENU] = 0; n = ToAscii((UINT)wParam, scanCode, keys2, &c, flags); } PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, wParam | ((c & 0xff) << 8) | ((n & 0xff) << 16) | 0x06000000, lParam); WPARAM charAndVirtKey = 0; bool clearDeadKey = false; switch (n) { default: // key is a dead key if (lParam & 0x80000000u) // This handles the obscure situation where a key has been // pressed which is both a dead key and a normal character // depending on which modifiers have been pressed. We // break here to prevent it from being considered a dead // key. break; g_deadVirtKey = wParam; g_deadLParam = lParam; for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++i) { g_deadKeyState[i] = keys[i]; } break; case 0: // key doesn't map to a character. this can happen if // non-character keys are pressed after a dead key. charAndVirtKey = makeKeyMsg((UINT)wParam, (char)0, noAltGr); break; case 1: // key maps to a character composed with dead key charAndVirtKey = makeKeyMsg((UINT)wParam, (char)LOBYTE(c), noAltGr); clearDeadKey = true; break; case 2: { // previous dead key not composed. send a fake key press // and release for the dead key to our window. WPARAM deadCharAndVirtKey = makeKeyMsg((UINT)g_deadVirtKey, (char)LOBYTE(c), noAltGr); PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, deadCharAndVirtKey, g_deadLParam & 0x7fffffffu); PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, deadCharAndVirtKey, g_deadLParam | 0x80000000u); // use uncomposed character charAndVirtKey = makeKeyMsg((UINT)wParam, (char)HIBYTE(c), noAltGr); clearDeadKey = true; break; } } // put back the dead key, if any, for the application to use if (g_deadVirtKey != 0) { ToAscii((UINT)g_deadVirtKey, (g_deadLParam & 0x10ff0000u) >> 16, g_deadKeyState, &c, flags); } // clear out old dead key state if (clearDeadKey) { g_deadVirtKey = 0; g_deadLParam = 0; } // forward message to our window. do this whether or not we're // forwarding events to clients because this'll keep our thread's // key state table up to date. that's important for querying // the scroll lock toggle state. // XXX -- with hot keys for actions we may only need to do this when // forwarding. if (charAndVirtKey != 0) { PostThreadMessage(g_threadID, SYNERGY_MSG_DEBUG, charAndVirtKey | 0x07000000, lParam); PostThreadMessage(g_threadID, SYNERGY_MSG_KEY, charAndVirtKey, lParam); } if (g_mode == kHOOK_RELAY_EVENTS) { // let certain keys pass through switch (wParam) { case VK_CAPITAL: case VK_NUMLOCK: case VK_SCROLL: // pass event on. we want to let these through to // the window proc because otherwise the keyboard // lights may not stay synchronized. break; case VK_HANGUL: // pass these modifiers if using a low level hook, discard // them if not. if (g_hookThread == 0) { return true; } break; default: // discard return true; } } return false; } static bool keyboardHookHandler(WPARAM wParam, LPARAM lParam) { return doKeyboardHookHandler(wParam, lParam); } #endif static bool doMouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) { switch (wParam) { 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_LBUTTONUP: case WM_MBUTTONUP: case WM_RBUTTONUP: case WM_XBUTTONUP: case WM_NCLBUTTONDOWN: case WM_NCMBUTTONDOWN: case WM_NCRBUTTONDOWN: case WM_NCXBUTTONDOWN: case WM_NCLBUTTONDBLCLK: case WM_NCMBUTTONDBLCLK: case WM_NCRBUTTONDBLCLK: case WM_NCXBUTTONDBLCLK: case WM_NCLBUTTONUP: case WM_NCMBUTTONUP: case WM_NCRBUTTONUP: case WM_NCXBUTTONUP: // always relay the event. eat it if relaying. PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_BUTTON, wParam, data); return (g_mode == kHOOK_RELAY_EVENTS); case WM_MOUSEWHEEL: if (g_mode == kHOOK_RELAY_EVENTS) { // relay event PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, data, 0); } return (g_mode == kHOOK_RELAY_EVENTS); case WM_NCMOUSEMOVE: case WM_MOUSEMOVE: if (g_mode == kHOOK_RELAY_EVENTS) { // relay and eat event PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); return true; } else if (g_mode == kHOOK_WATCH_JUMP_ZONE) { // low level hooks can report bogus mouse positions that are // outside of the screen. jeez. naturally we end up getting // fake motion in the other direction to get the position back // on the screen, which plays havoc with switch on double tap. // Server deals with that. we'll clamp positions onto the // screen. also, if we discard events for positions outside // of the screen then the mouse appears to get a bit jerky // near the edge. we can either accept that or pass the bogus // events. we'll try passing the events. bool bogus = false; if (x < g_xScreen) { x = g_xScreen; bogus = true; } else if (x >= g_xScreen + g_wScreen) { x = g_xScreen + g_wScreen - 1; bogus = true; } if (y < g_yScreen) { y = g_yScreen; bogus = true; } else if (y >= g_yScreen + g_hScreen) { y = g_yScreen + g_hScreen - 1; bogus = true; } // check for mouse inside jump zone bool inside = false; if (!inside && (g_zoneSides & kLeftMask) != 0) { inside = (x < g_xScreen + g_zoneSize); } if (!inside && (g_zoneSides & kRightMask) != 0) { inside = (x >= g_xScreen + g_wScreen - g_zoneSize); } if (!inside && (g_zoneSides & kTopMask) != 0) { inside = (y < g_yScreen + g_zoneSize); } if (!inside && (g_zoneSides & kBottomMask) != 0) { inside = (y >= g_yScreen + g_hScreen - g_zoneSize); } // relay the event PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y); // if inside and not bogus then eat the event return inside && !bogus; } } // pass the event return false; } static bool mouseHookHandler(WPARAM wParam, SInt32 x, SInt32 y, SInt32 data) { return doMouseHookHandler(wParam, x, y, data); } #if !NO_GRAB_KEYBOARD static LRESULT CALLBACK keyboardHook(int code, WPARAM wParam, LPARAM lParam) { if (code >= 0) { // handle the message if (keyboardHookHandler(wParam, lParam)) { return 1; } } return CallNextHookEx(g_keyboard, code, wParam, lParam); } #endif static LRESULT CALLBACK mouseHook(int code, WPARAM wParam, LPARAM lParam) { if (code >= 0) { // decode message const MOUSEHOOKSTRUCT* info = (const MOUSEHOOKSTRUCT*)lParam; SInt32 x = (SInt32)info->pt.x; SInt32 y = (SInt32)info->pt.y; SInt32 w = 0; if (wParam == WM_MOUSEWHEEL) { // win2k and other systems supporting WM_MOUSEWHEEL in // the mouse hook are gratuitously different (and poorly // documented). if a low-level mouse hook is in place // it should capture these events so we'll never see // them. switch (g_wheelSupport) { case kWheelModern: w = static_cast(LOWORD(info->dwExtraInfo)); break; case kWheelWin2000: { const MOUSEHOOKSTRUCTWin2000* info2k = (const MOUSEHOOKSTRUCTWin2000*)lParam; w = static_cast(HIWORD(info2k->mouseData)); break; } default: break; } } // handle the message. note that we don't handle X buttons // here. that's okay because they're only supported on // win2k and winxp and up and on those platforms we'll get // get the mouse events through the low level hook. if (mouseHookHandler(wParam, x, y, w)) { return 1; } } return CallNextHookEx(g_mouse, code, wParam, lParam); } static LRESULT CALLBACK getMessageHook(int code, WPARAM wParam, LPARAM lParam) { if (code >= 0) { if (g_screenSaver) { MSG* msg = reinterpret_cast(lParam); if (msg->message == WM_SYSCOMMAND && msg->wParam == SC_SCREENSAVE) { // broadcast screen saver started message PostThreadMessage(g_threadID, SYNERGY_MSG_SCREEN_SAVER, TRUE, 0); } } if (g_mode == kHOOK_RELAY_EVENTS) { MSG* msg = reinterpret_cast(lParam); if (g_wheelSupport == kWheelOld && msg->message == g_wmMouseWheel) { // post message to our window PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_WHEEL, static_cast(msg->wParam & 0xffffu), 0); // zero out the delta in the message so it's (hopefully) // ignored msg->wParam = 0; } } } return CallNextHookEx(g_getMessage, code, wParam, lParam); } #if (_WIN32_WINNT >= 0x0400) && defined(_MSC_VER) && !NO_LOWLEVEL_HOOKS // // low-level keyboard hook -- this allows us to capture and handle // alt+tab, alt+esc, ctrl+esc, and windows key hot keys. on the down // side, key repeats are not reported to us. // #if !NO_GRAB_KEYBOARD static LRESULT CALLBACK keyboardLLHook(int code, WPARAM wParam, LPARAM lParam) { if (code >= 0) { // decode the message KBDLLHOOKSTRUCT* info = reinterpret_cast(lParam); WPARAM wParam = info->vkCode; LPARAM lParam = 1; // repeat code lParam |= (info->scanCode << 16); // scan code if (info->flags & LLKHF_EXTENDED) { lParam |= (1lu << 24); // extended key } if (info->flags & LLKHF_ALTDOWN) { lParam |= (1lu << 29); // context code } if (info->flags & LLKHF_UP) { lParam |= (1lu << 31); // transition } // FIXME -- bit 30 should be set if key was already down but // we don't know that info. as a result we'll never generate // key repeat events. // handle the message if (keyboardHookHandler(wParam, lParam)) { return 1; } } return CallNextHookEx(g_keyboardLL, code, wParam, lParam); } #endif // // low-level mouse hook -- this allows us to capture and handle mouse // events very early. the earlier the better. // static LRESULT CALLBACK mouseLLHook(int code, WPARAM wParam, LPARAM lParam) { if (code >= 0) { // decode the message MSLLHOOKSTRUCT* info = reinterpret_cast(lParam); SInt32 x = static_cast(info->pt.x); SInt32 y = static_cast(info->pt.y); SInt32 w = static_cast(HIWORD(info->mouseData)); // handle the message if (mouseHookHandler(wParam, x, y, w)) { return 1; } } return CallNextHookEx(g_mouseLL, code, wParam, lParam); } #endif static EWheelSupport getWheelSupport() { // get operating system OSVERSIONINFO info; info.dwOSVersionInfoSize = sizeof(info); if (!GetVersionEx(&info)) { return kWheelNone; } // see if modern wheel is present if (GetSystemMetrics(SM_MOUSEWHEELPRESENT)) { // note if running on win2k if (info.dwPlatformId == VER_PLATFORM_WIN32_NT && info.dwMajorVersion == 5 && info.dwMinorVersion == 0) { return kWheelWin2000; } return kWheelModern; } // not modern. see if we've got old-style support. #if defined(MSH_WHEELSUPPORT) UINT wheelSupportMsg = RegisterWindowMessage(MSH_WHEELSUPPORT); HWND wheelSupportWindow = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE); if (wheelSupportWindow != NULL && wheelSupportMsg != 0) { if (SendMessage(wheelSupportWindow, wheelSupportMsg, 0, 0) != 0) { g_wmMouseWheel = RegisterWindowMessage(MSH_MOUSEWHEEL); if (g_wmMouseWheel != 0) { return kWheelOld; } } } #endif // assume modern. we don't do anything special in this case // except respond to WM_MOUSEWHEEL messages. GetSystemMetrics() // can apparently return FALSE even if a mouse wheel is present // though i'm not sure exactly when it does that (WinME returns // FALSE for my logitech USB trackball). return kWheelModern; } // // external functions // BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) { DisableThreadLibraryCalls(instance); if (g_processID == 0) { g_hinstance = instance; g_processID = GetCurrentProcessId(); } } else if (reason == DLL_PROCESS_DETACH) { if (g_processID == GetCurrentProcessId()) { uninstall(); uninstallScreenSaver(); g_processID = 0; g_hinstance = NULL; } } return TRUE; } extern "C" { // VS2005 hack to not link with the CRT #if _MSC_VER >= 1400 BOOL WINAPI _DllMainCRTStartup( HINSTANCE instance, DWORD reason, LPVOID lpreserved) { return DllMain(instance, reason, lpreserved); } // VS2005 is a bit more bright than VC6 and optimize simple copy loop to // intrinsic memcpy. void * __cdecl memcpy(void * _Dst, const void * _Src, size_t _MaxCount) { void * _DstBackup = _Dst; switch (_MaxCount & 3) { case 3: ((char*)_Dst)[0] = ((char*)_Src)[0]; ++(char*&)_Dst; ++(char*&)_Src; --_MaxCount; case 2: ((char*)_Dst)[0] = ((char*)_Src)[0]; ++(char*&)_Dst; ++(char*&)_Src; --_MaxCount; case 1: ((char*)_Dst)[0] = ((char*)_Src)[0]; ++(char*&)_Dst; ++(char*&)_Src; --_MaxCount; break; case 0: break; default: __assume(0); break; } // I think it's faster on intel to deference than modify the pointer. const size_t max = _MaxCount / sizeof(UINT_PTR); for (size_t i = 0; i < max; ++i) { ((UINT_PTR*)_Dst)[i] = ((UINT_PTR*)_Src)[i]; } (UINT_PTR*&)_Dst += max; (UINT_PTR*&)_Src += max; switch (_MaxCount & 3) { case 3: ((char*)_Dst)[0] = ((char*)_Src)[0]; ++(char*&)_Dst; ++(char*&)_Src; case 2: ((char*)_Dst)[0] = ((char*)_Src)[0]; ++(char*&)_Dst; ++(char*&)_Src; case 1: ((char*)_Dst)[0] = ((char*)_Src)[0]; ++(char*&)_Dst; ++(char*&)_Src; break; case 0: break; default: __assume(0); break; } return _DstBackup; } #endif int init(DWORD threadID) { assert(g_hinstance != NULL); // try to open process that last called init() to see if it's // still running or if it died without cleaning up. if (g_processID != 0 && g_processID != GetCurrentProcessId()) { HANDLE process = OpenProcess(STANDARD_RIGHTS_REQUIRED, FALSE, g_processID); if (process != NULL) { // old process (probably) still exists so refuse to // reinitialize this DLL (and thus steal it from the // old process). int result = CloseHandle(process); if (result == false) { return 0; } } // clean up after old process. the system should've already // removed the hooks so we just need to reset our state. g_hinstance = GetModuleHandle(_T("synwinhk")); g_processID = GetCurrentProcessId(); g_wheelSupport = kWheelNone; g_threadID = 0; g_keyboard = NULL; g_mouse = NULL; g_getMessage = NULL; g_keyboardLL = NULL; g_mouseLL = NULL; g_screenSaver = false; } // save thread id. we'll post messages to this thread's // message queue. g_threadID = threadID; // set defaults g_mode = kHOOK_DISABLE; g_zoneSides = 0; g_zoneSize = 0; g_xScreen = 0; g_yScreen = 0; g_wScreen = 0; g_hScreen = 0; return 1; } int cleanup(void) { assert(g_hinstance != NULL); if (g_processID == GetCurrentProcessId()) { g_threadID = 0; } return 1; } EHookResult install() { assert(g_hinstance != NULL); assert(g_keyboard == NULL); assert(g_mouse == NULL); assert(g_getMessage == NULL || g_screenSaver); // must be initialized if (g_threadID == 0) { return kHOOK_FAILED; } // discard old dead keys g_deadVirtKey = 0; g_deadLParam = 0; // reset fake input flag g_fakeInput = false; // check for mouse wheel support g_wheelSupport = getWheelSupport(); // install GetMessage hook (unless already installed) if (g_wheelSupport == kWheelOld && g_getMessage == NULL) { g_getMessage = SetWindowsHookEx(WH_GETMESSAGE, &getMessageHook, g_hinstance, 0); } // install low-level hooks. we require that they both get installed. #if (_WIN32_WINNT >= 0x0400) && defined(_MSC_VER) && !NO_LOWLEVEL_HOOKS g_mouseLL = SetWindowsHookEx(WH_MOUSE_LL, &mouseLLHook, g_hinstance, 0); #if !NO_GRAB_KEYBOARD g_keyboardLL = SetWindowsHookEx(WH_KEYBOARD_LL, &keyboardLLHook, g_hinstance, 0); if (g_mouseLL == NULL || g_keyboardLL == NULL) { if (g_keyboardLL != NULL) { UnhookWindowsHookEx(g_keyboardLL); g_keyboardLL = NULL; } if (g_mouseLL != NULL) { UnhookWindowsHookEx(g_mouseLL); g_mouseLL = NULL; } } #endif #endif // install regular hooks if (g_mouseLL == NULL) { g_mouse = SetWindowsHookEx(WH_MOUSE, &mouseHook, g_hinstance, 0); } #if !NO_GRAB_KEYBOARD if (g_keyboardLL == NULL) { g_keyboard = SetWindowsHookEx(WH_KEYBOARD, &keyboardHook, g_hinstance, 0); } #endif // check that we got all the hooks we wanted if ((g_getMessage == NULL && g_wheelSupport == kWheelOld) || #if !NO_GRAB_KEYBOARD (g_keyboardLL == NULL && g_keyboard == NULL) || #endif (g_mouseLL == NULL && g_mouse == NULL)) { uninstall(); return kHOOK_FAILED; } if (g_keyboardLL != NULL || g_mouseLL != NULL) { g_hookThread = GetCurrentThreadId(); return kHOOK_OKAY_LL; } return kHOOK_OKAY; } int uninstall(void) { assert(g_hinstance != NULL); // discard old dead keys g_deadVirtKey = 0; g_deadLParam = 0; // uninstall hooks if (g_keyboardLL != NULL) { UnhookWindowsHookEx(g_keyboardLL); g_keyboardLL = NULL; } if (g_mouseLL != NULL) { UnhookWindowsHookEx(g_mouseLL); g_mouseLL = NULL; } if (g_keyboard != NULL) { UnhookWindowsHookEx(g_keyboard); g_keyboard = NULL; } if (g_mouse != NULL) { UnhookWindowsHookEx(g_mouse); g_mouse = NULL; } if (g_getMessage != NULL && !g_screenSaver) { UnhookWindowsHookEx(g_getMessage); g_getMessage = NULL; } g_wheelSupport = kWheelNone; return 1; } int installScreenSaver(void) { assert(g_hinstance != NULL); // must be initialized if (g_threadID == 0) { return 0; } // generate screen saver messages g_screenSaver = true; // install hook unless it's already installed if (g_getMessage == NULL) { g_getMessage = SetWindowsHookEx(WH_GETMESSAGE, &getMessageHook, g_hinstance, 0); } return (g_getMessage != NULL) ? 1 : 0; } int uninstallScreenSaver(void) { assert(g_hinstance != NULL); // uninstall hook unless the mouse wheel hook is installed if (g_getMessage != NULL && g_wheelSupport != kWheelOld) { UnhookWindowsHookEx(g_getMessage); g_getMessage = NULL; } // screen saver hook is no longer installed g_screenSaver = false; return 1; } void setSides(UInt32 sides) { g_zoneSides = sides; } void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize) { g_zoneSize = jumpZoneSize; g_xScreen = x; g_yScreen = y; g_wScreen = w; g_hScreen = h; } void setMode(EHookMode mode) { if (mode == g_mode) { // no change return; } g_mode = mode; } } synergy-1.8.8-stable/src/lib/synwinhk/synwinhk.h000066400000000000000000000060721305627404700217470ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once // hack: vs2005 doesn't declare _WIN32_WINNT, so we need to hard code it. // however, some say that this should be hard coded since it defines the // target system, but since this is suposed to compile on pre-XP, maybe // we should just leave it like this. #if _MSC_VER == 1400 #define _WIN32_WINNT 0x0400 #endif #include "base/EventTypes.h" #define WIN32_LEAN_AND_MEAN #include #if defined(synwinhk_EXPORTS) #define CSYNERGYHOOK_API __declspec(dllexport) #else #define CSYNERGYHOOK_API __declspec(dllimport) #endif #define SYNERGY_MSG_MARK WM_APP + 0x0011 // mark id; #define SYNERGY_MSG_KEY WM_APP + 0x0012 // vk code; key data #define SYNERGY_MSG_MOUSE_BUTTON WM_APP + 0x0013 // button msg; #define SYNERGY_MSG_MOUSE_WHEEL WM_APP + 0x0014 // delta; #define SYNERGY_MSG_MOUSE_MOVE WM_APP + 0x0015 // x; y #define SYNERGY_MSG_POST_WARP WM_APP + 0x0016 // ; #define SYNERGY_MSG_PRE_WARP WM_APP + 0x0017 // x; y #define SYNERGY_MSG_SCREEN_SAVER WM_APP + 0x0018 // activated; #define SYNERGY_MSG_DEBUG WM_APP + 0x0019 // data, data #define SYNERGY_MSG_INPUT_FIRST SYNERGY_MSG_KEY #define SYNERGY_MSG_INPUT_LAST SYNERGY_MSG_PRE_WARP #define SYNERGY_HOOK_LAST_MSG SYNERGY_MSG_DEBUG #define SYNERGY_HOOK_FAKE_INPUT_VIRTUAL_KEY VK_CANCEL #define SYNERGY_HOOK_FAKE_INPUT_SCANCODE 0 extern "C" { enum EHookResult { kHOOK_FAILED, kHOOK_OKAY, kHOOK_OKAY_LL }; enum EHookMode { kHOOK_DISABLE, kHOOK_WATCH_JUMP_ZONE, kHOOK_RELAY_EVENTS }; typedef int (*InitFunc)(DWORD targetQueueThreadID); typedef int (*CleanupFunc)(void); typedef EHookResult (*InstallFunc)(void); typedef int (*UninstallFunc)(void); typedef int (*InstallScreenSaverFunc)(void); typedef int (*UninstallScreenSaverFunc)(void); typedef void (*SetSidesFunc)(UInt32); typedef void (*SetZoneFunc)(SInt32, SInt32, SInt32, SInt32, SInt32); typedef void (*SetModeFunc)(int); CSYNERGYHOOK_API int init(DWORD); CSYNERGYHOOK_API int cleanup(void); CSYNERGYHOOK_API EHookResult install(void); CSYNERGYHOOK_API int uninstall(void); CSYNERGYHOOK_API int installScreenSaver(void); CSYNERGYHOOK_API int uninstallScreenSaver(void); CSYNERGYHOOK_API void setSides(UInt32 sides); CSYNERGYHOOK_API void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize); CSYNERGYHOOK_API void setMode(EHookMode mode); } synergy-1.8.8-stable/src/micro/000077500000000000000000000000001305627404700164105ustar00rootroot00000000000000synergy-1.8.8-stable/src/micro/CMakeLists.txt000066400000000000000000000015341305627404700211530ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2012 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB headers "*.h") file(GLOB sources "*.c") if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() add_library(micro STATIC ${sources}) synergy-1.8.8-stable/src/micro/COPYING.zlib000066400000000000000000000017001305627404700204000ustar00rootroot00000000000000uSynergy client -- Implementation for the embedded Synergy client library Copyright (c) 2012 Alex Evans This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. synergy-1.8.8-stable/src/micro/uSynergy.c000066400000000000000000000447551305627404700204200ustar00rootroot00000000000000/* uSynergy client -- Implementation for the embedded Synergy client library version 1.0.0, July 7th, 2012 Copyright (c) 2012 Alex Evans This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include "uSynergy.h" #include #include //--------------------------------------------------------------------------------------------------------------------- // Internal helpers //--------------------------------------------------------------------------------------------------------------------- /** @brief Read 16 bit integer in network byte order and convert to native byte order **/ static int16_t sNetToNative16(const unsigned char *value) { #ifdef USYNERGY_LITTLE_ENDIAN return value[1] | (value[0] << 8); #else return value[0] | (value[1] << 8); #endif } /** @brief Read 32 bit integer in network byte order and convert to native byte order **/ static int32_t sNetToNative32(const unsigned char *value) { #ifdef USYNERGY_LITTLE_ENDIAN return value[3] | (value[2] << 8) | (value[1] << 16) | (value[0] << 24); #else return value[0] | (value[1] << 8) | (value[2] << 16) | (value[3] << 24); #endif } /** @brief Trace text to client **/ static void sTrace(uSynergyContext *context, const char* text) { // Don't trace if we don't have a trace function if (context->m_traceFunc != 0L) context->m_traceFunc(context->m_cookie, text); } /** @brief Add string to reply packet **/ static void sAddString(uSynergyContext *context, const char *string) { size_t len = strlen(string); memcpy(context->m_replyCur, string, len); context->m_replyCur += len; } /** @brief Add uint8 to reply packet **/ static void sAddUInt8(uSynergyContext *context, uint8_t value) { *context->m_replyCur++ = value; } /** @brief Add uint16 to reply packet **/ static void sAddUInt16(uSynergyContext *context, uint16_t value) { uint8_t *reply = context->m_replyCur; *reply++ = (uint8_t)(value >> 8); *reply++ = (uint8_t)value; context->m_replyCur = reply; } /** @brief Add uint32 to reply packet **/ static void sAddUInt32(uSynergyContext *context, uint32_t value) { uint8_t *reply = context->m_replyCur; *reply++ = (uint8_t)(value >> 24); *reply++ = (uint8_t)(value >> 16); *reply++ = (uint8_t)(value >> 8); *reply++ = (uint8_t)value; context->m_replyCur = reply; } /** @brief Send reply packet **/ static uSynergyBool sSendReply(uSynergyContext *context) { // Set header size uint8_t *reply_buf = context->m_replyBuffer; uint32_t reply_len = (uint32_t)(context->m_replyCur - reply_buf); /* Total size of reply */ uint32_t body_len = reply_len - 4; /* Size of body */ uSynergyBool ret; reply_buf[0] = (uint8_t)(body_len >> 24); reply_buf[1] = (uint8_t)(body_len >> 16); reply_buf[2] = (uint8_t)(body_len >> 8); reply_buf[3] = (uint8_t)body_len; // Send reply ret = context->m_sendFunc(context->m_cookie, context->m_replyBuffer, reply_len); // Reset reply buffer write pointer context->m_replyCur = context->m_replyBuffer+4; return ret; } /** @brief Call mouse callback after a mouse event **/ static void sSendMouseCallback(uSynergyContext *context) { // Skip if no callback is installed if (context->m_mouseCallback == 0L) return; // Send callback context->m_mouseCallback(context->m_cookie, context->m_mouseX, context->m_mouseY, context->m_mouseWheelX, context->m_mouseWheelY, context->m_mouseButtonLeft, context->m_mouseButtonRight, context->m_mouseButtonMiddle); } /** @brief Send keyboard callback when a key has been pressed or released **/ static void sSendKeyboardCallback(uSynergyContext *context, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat) { // Skip if no callback is installed if (context->m_keyboardCallback == 0L) return; // Send callback context->m_keyboardCallback(context->m_cookie, key, modifiers, down, repeat); } /** @brief Send joystick callback **/ static void sSendJoystickCallback(uSynergyContext *context, uint8_t joyNum) { int8_t *sticks; // Skip if no callback is installed if (context->m_joystickCallback == 0L) return; // Send callback sticks = context->m_joystickSticks[joyNum]; context->m_joystickCallback(context->m_cookie, joyNum, context->m_joystickButtons[joyNum], sticks[0], sticks[1], sticks[2], sticks[3]); } /** @brief Parse a single client message, update state, send callbacks and send replies **/ #define USYNERGY_IS_PACKET(pkt_id) memcmp(message+4, pkt_id, 4)==0 static void sProcessMessage(uSynergyContext *context, const uint8_t *message) { // We have a packet! if (memcmp(message+4, "Synergy", 7)==0) { // Welcome message // kMsgHello = "Synergy%2i%2i" // kMsgHelloBack = "Synergy%2i%2i%s" sAddString(context, "Synergy"); sAddUInt16(context, USYNERGY_PROTOCOL_MAJOR); sAddUInt16(context, USYNERGY_PROTOCOL_MINOR); sAddUInt32(context, (uint32_t)strlen(context->m_clientName)); sAddString(context, context->m_clientName); if (!sSendReply(context)) { // Send reply failed, let's try to reconnect sTrace(context, "SendReply failed, trying to reconnect in a second"); context->m_connected = USYNERGY_FALSE; context->m_sleepFunc(context->m_cookie, 1000); } else { // Let's assume we're connected char buffer[256+1]; sprintf(buffer, "Connected as client \"%s\"", context->m_clientName); sTrace(context, buffer); context->m_hasReceivedHello = USYNERGY_TRUE; } return; } else if (USYNERGY_IS_PACKET("QINF")) { // Screen info. Reply with DINF // kMsgQInfo = "QINF" // kMsgDInfo = "DINF%2i%2i%2i%2i%2i%2i%2i" uint16_t x = 0, y = 0, warp = 0; sAddString(context, "DINF"); sAddUInt16(context, x); sAddUInt16(context, y); sAddUInt16(context, context->m_clientWidth); sAddUInt16(context, context->m_clientHeight); sAddUInt16(context, warp); sAddUInt16(context, 0); // mx? sAddUInt16(context, 0); // my? sSendReply(context); return; } else if (USYNERGY_IS_PACKET("CIAK")) { // Do nothing? // kMsgCInfoAck = "CIAK" return; } else if (USYNERGY_IS_PACKET("CROP")) { // Do nothing? // kMsgCResetOptions = "CROP" return; } else if (USYNERGY_IS_PACKET("CINN")) { // Screen enter. Reply with CNOP // kMsgCEnter = "CINN%2i%2i%4i%2i" // Obtain the Synergy sequence number context->m_sequenceNumber = sNetToNative32(message + 12); context->m_isCaptured = USYNERGY_TRUE; // Call callback if (context->m_screenActiveCallback != 0L) context->m_screenActiveCallback(context->m_cookie, USYNERGY_TRUE); } else if (USYNERGY_IS_PACKET("COUT")) { // Screen leave // kMsgCLeave = "COUT" context->m_isCaptured = USYNERGY_FALSE; // Call callback if (context->m_screenActiveCallback != 0L) context->m_screenActiveCallback(context->m_cookie, USYNERGY_FALSE); } else if (USYNERGY_IS_PACKET("DMDN")) { // Mouse down // kMsgDMouseDown = "DMDN%1i" char btn = message[8]-1; if (btn==2) context->m_mouseButtonRight = USYNERGY_TRUE; else if (btn==1) context->m_mouseButtonMiddle = USYNERGY_TRUE; else context->m_mouseButtonLeft = USYNERGY_TRUE; sSendMouseCallback(context); } else if (USYNERGY_IS_PACKET("DMUP")) { // Mouse up // kMsgDMouseUp = "DMUP%1i" char btn = message[8]-1; if (btn==2) context->m_mouseButtonRight = USYNERGY_FALSE; else if (btn==1) context->m_mouseButtonMiddle = USYNERGY_FALSE; else context->m_mouseButtonLeft = USYNERGY_FALSE; sSendMouseCallback(context); } else if (USYNERGY_IS_PACKET("DMMV")) { // Mouse move. Reply with CNOP // kMsgDMouseMove = "DMMV%2i%2i" context->m_mouseX = sNetToNative16(message+8); context->m_mouseY = sNetToNative16(message+10); sSendMouseCallback(context); } else if (USYNERGY_IS_PACKET("DMWM")) { // Mouse wheel // kMsgDMouseWheel = "DMWM%2i%2i" // kMsgDMouseWheel1_0 = "DMWM%2i" context->m_mouseWheelX += sNetToNative16(message+8); context->m_mouseWheelY += sNetToNative16(message+10); sSendMouseCallback(context); } else if (USYNERGY_IS_PACKET("DKDN")) { // Key down // kMsgDKeyDown = "DKDN%2i%2i%2i" // kMsgDKeyDown1_0 = "DKDN%2i%2i" //uint16_t id = sNetToNative16(message+8); uint16_t mod = sNetToNative16(message+10); uint16_t key = sNetToNative16(message+12); sSendKeyboardCallback(context, key, mod, USYNERGY_TRUE, USYNERGY_FALSE); } else if (USYNERGY_IS_PACKET("DKRP")) { // Key repeat // kMsgDKeyRepeat = "DKRP%2i%2i%2i%2i" // kMsgDKeyRepeat1_0 = "DKRP%2i%2i%2i" uint16_t mod = sNetToNative16(message+10); // uint16_t count = sNetToNative16(message+12); uint16_t key = sNetToNative16(message+14); sSendKeyboardCallback(context, key, mod, USYNERGY_TRUE, USYNERGY_TRUE); } else if (USYNERGY_IS_PACKET("DKUP")) { // Key up // kMsgDKeyUp = "DKUP%2i%2i%2i" // kMsgDKeyUp1_0 = "DKUP%2i%2i" //uint16 id=Endian::sNetToNative(sbuf[4]); uint16_t mod = sNetToNative16(message+10); uint16_t key = sNetToNative16(message+12); sSendKeyboardCallback(context, key, mod, USYNERGY_FALSE, USYNERGY_FALSE); } else if (USYNERGY_IS_PACKET("DGBT")) { // Joystick buttons // kMsgDGameButtons = "DGBT%1i%2i"; uint8_t joy_num = message[8]; if (joy_numm_joystickButtons[joy_num] = (message[9] << 8) | message[10]; sSendJoystickCallback(context, joy_num); } } else if (USYNERGY_IS_PACKET("DGST")) { // Joystick sticks // kMsgDGameSticks = "DGST%1i%1i%1i%1i%1i"; uint8_t joy_num = message[8]; if (joy_numm_joystickSticks[joy_num], message+9, 4); sSendJoystickCallback(context, joy_num); } } else if (USYNERGY_IS_PACKET("DSOP")) { // Set options // kMsgDSetOptions = "DSOP%4I" } else if (USYNERGY_IS_PACKET("CALV")) { // Keepalive, reply with CALV and then CNOP // kMsgCKeepAlive = "CALV" sAddString(context, "CALV"); sSendReply(context); // now reply with CNOP } else if (USYNERGY_IS_PACKET("DCLP")) { // Clipboard message // kMsgDClipboard = "DCLP%1i%4i%s" // // The clipboard message contains: // 1 uint32: The size of the message // 4 chars: The identifier ("DCLP") // 1 uint8: The clipboard index // 1 uint32: The sequence number. It's zero, because this message is always coming from the server? // 1 uint32: The total size of the remaining 'string' (as per the Synergy %s string format (which is 1 uint32 for size followed by a char buffer (not necessarily null terminated)). // 1 uint32: The number of formats present in the message // And then 'number of formats' times the following: // 1 uint32: The format of the clipboard data // 1 uint32: The size n of the clipboard data // n uint8: The clipboard data const uint8_t * parse_msg = message+17; uint32_t num_formats = sNetToNative32(parse_msg); parse_msg += 4; for (; num_formats; num_formats--) { // Parse clipboard format header uint32_t format = sNetToNative32(parse_msg); uint32_t size = sNetToNative32(parse_msg+4); parse_msg += 8; // Call callback if (context->m_clipboardCallback) context->m_clipboardCallback(context->m_cookie, format, parse_msg, size); parse_msg += size; } } else { // Unknown packet, could be any of these // kMsgCNoop = "CNOP" // kMsgCClose = "CBYE" // kMsgCClipboard = "CCLP%1i%4i" // kMsgCScreenSaver = "CSEC%1i" // kMsgDKeyRepeat = "DKRP%2i%2i%2i%2i" // kMsgDKeyRepeat1_0 = "DKRP%2i%2i%2i" // kMsgDMouseRelMove = "DMRM%2i%2i" // kMsgEIncompatible = "EICV%2i%2i" // kMsgEBusy = "EBSY" // kMsgEUnknown = "EUNK" // kMsgEBad = "EBAD" char buffer[64]; sprintf(buffer, "Unknown packet '%c%c%c%c'", message[4], message[5], message[6], message[7]); sTrace(context, buffer); return; } // Reply with CNOP maybe? sAddString(context, "CNOP"); sSendReply(context); } #undef USYNERGY_IS_PACKET /** @brief Mark context as being disconnected **/ static void sSetDisconnected(uSynergyContext *context) { context->m_connected = USYNERGY_FALSE; context->m_hasReceivedHello = USYNERGY_FALSE; context->m_isCaptured = USYNERGY_FALSE; context->m_replyCur = context->m_replyBuffer + 4; context->m_sequenceNumber = 0; } /** @brief Update a connected context **/ static void sUpdateContext(uSynergyContext *context) { /* Receive data (blocking) */ int receive_size = USYNERGY_RECEIVE_BUFFER_SIZE - context->m_receiveOfs; int num_received = 0; int packlen = 0; if (context->m_receiveFunc(context->m_cookie, context->m_receiveBuffer + context->m_receiveOfs, receive_size, &num_received) == USYNERGY_FALSE) { /* Receive failed, let's try to reconnect */ char buffer[128]; sprintf(buffer, "Receive failed (%d bytes asked, %d bytes received), trying to reconnect in a second", receive_size, num_received); sTrace(context, buffer); sSetDisconnected(context); context->m_sleepFunc(context->m_cookie, 1000); return; } context->m_receiveOfs += num_received; /* If we didn't receive any data then we're probably still polling to get connected and therefore not getting any data back. To avoid overloading the system with a Synergy thread that would hammer on polling, we let it rest for a bit if there's no data. */ if (num_received == 0) context->m_sleepFunc(context->m_cookie, 500); /* Check for timeouts */ if (context->m_hasReceivedHello) { uint32_t cur_time = context->m_getTimeFunc(); if (num_received == 0) { /* Timeout after 2 secs of inactivity (we received no CALV) */ if ((cur_time - context->m_lastMessageTime) > USYNERGY_IDLE_TIMEOUT) sSetDisconnected(context); } else context->m_lastMessageTime = cur_time; } /* Eat packets */ for (;;) { /* Grab packet length and bail out if the packet goes beyond the end of the buffer */ packlen = sNetToNative32(context->m_receiveBuffer); if (packlen+4 > context->m_receiveOfs) break; /* Process message */ sProcessMessage(context, context->m_receiveBuffer); /* Move packet to front of buffer */ memmove(context->m_receiveBuffer, context->m_receiveBuffer+packlen+4, context->m_receiveOfs-packlen-4); context->m_receiveOfs -= packlen+4; } /* Throw away over-sized packets */ if (packlen > USYNERGY_RECEIVE_BUFFER_SIZE) { /* Oversized packet, ditch tail end */ char buffer[128]; sprintf(buffer, "Oversized packet: '%c%c%c%c' (length %d)", context->m_receiveBuffer[4], context->m_receiveBuffer[5], context->m_receiveBuffer[6], context->m_receiveBuffer[7], packlen); sTrace(context, buffer); num_received = context->m_receiveOfs-4; // 4 bytes for the size field while (num_received != packlen) { int buffer_left = packlen - num_received; int to_receive = buffer_left < USYNERGY_RECEIVE_BUFFER_SIZE ? buffer_left : USYNERGY_RECEIVE_BUFFER_SIZE; int ditch_received = 0; if (context->m_receiveFunc(context->m_cookie, context->m_receiveBuffer, to_receive, &ditch_received) == USYNERGY_FALSE) { /* Receive failed, let's try to reconnect */ sTrace(context, "Receive failed, trying to reconnect in a second"); sSetDisconnected(context); context->m_sleepFunc(context->m_cookie, 1000); break; } else { num_received += ditch_received; } } context->m_receiveOfs = 0; } } //--------------------------------------------------------------------------------------------------------------------- // Public interface //--------------------------------------------------------------------------------------------------------------------- /** @brief Initialize uSynergy context **/ void uSynergyInit(uSynergyContext *context) { /* Zero memory */ memset(context, 0, sizeof(uSynergyContext)); /* Initialize to default state */ sSetDisconnected(context); } /** @brief Update uSynergy **/ void uSynergyUpdate(uSynergyContext *context) { if (context->m_connected) { /* Update context, receive data, call callbacks */ sUpdateContext(context); } else { /* Try to connect */ if (context->m_connectFunc(context->m_cookie)) context->m_connected = USYNERGY_TRUE; } } /** @brief Send clipboard data **/ void uSynergySendClipboard(uSynergyContext *context, const char *text) { // Calculate maximum size that will fit in a reply packet uint32_t overhead_size = 4 + /* Message size */ 4 + /* Message ID */ 1 + /* Clipboard index */ 4 + /* Sequence number */ 4 + /* Rest of message size (because it's a Synergy string from here on) */ 4 + /* Number of clipboard formats */ 4 + /* Clipboard format */ 4; /* Clipboard data length */ uint32_t max_length = USYNERGY_REPLY_BUFFER_SIZE - overhead_size; // Clip text to max length uint32_t text_length = (uint32_t)strlen(text); if (text_length > max_length) { char buffer[128]; sprintf(buffer, "Clipboard buffer too small, clipboard truncated at %d characters", max_length); sTrace(context, buffer); text_length = max_length; } // Assemble packet sAddString(context, "DCLP"); sAddUInt8(context, 0); /* Clipboard index */ sAddUInt32(context, context->m_sequenceNumber); sAddUInt32(context, 4+4+4+text_length); /* Rest of message size: numFormats, format, length, data */ sAddUInt32(context, 1); /* Number of formats (only text for now) */ sAddUInt32(context, USYNERGY_CLIPBOARD_FORMAT_TEXT); sAddUInt32(context, text_length); sAddString(context, text); sSendReply(context); } synergy-1.8.8-stable/src/micro/uSynergy.h000066400000000000000000000403441305627404700204130ustar00rootroot00000000000000/* uSynergy client -- Interface for the embedded Synergy client library version 1.0.0, July 7th, 2012 Copyright (C) 2012-2016 Symless Ltd. Copyright (c) 2012 Alex Evans This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ #include #ifdef __cplusplus extern "C" { #endif //--------------------------------------------------------------------------------------------------------------------- // Configuration //--------------------------------------------------------------------------------------------------------------------- /** @brief Determine endianness **/ #if defined(USYNERGY_LITTLE_ENDIAN) && defined(USYNERGY_BIG_ENDIAN) /* Ambiguous: both endians specified */ #error "Can't define both USYNERGY_LITTLE_ENDIAN and USYNERGY_BIG_ENDIAN" #elif !defined(USYNERGY_LITTLE_ENDIAN) && !defined(USYNERGY_BIG_ENDIAN) /* Attempt to auto detect */ #if defined(__LITTLE_ENDIAN__) || defined(LITTLE_ENDIAN) #define USYNERGY_LITTLE_ENDIAN #elif defined(__BIG_ENDIAN__) || defined(BIG_ENDIAN) || (_BYTE_ORDER == _BIG_ENDIAN) #define USYNERGY_BIG_ENDIAN #else #error "Can't detect endian-nes, please defined either USYNERGY_LITTLE_ENDIAN or USYNERGY_BIG_ENDIAN"; #endif #else /* User-specified endian-nes, nothing to do for us */ #endif //--------------------------------------------------------------------------------------------------------------------- // Types and Constants //--------------------------------------------------------------------------------------------------------------------- /** @brief Boolean type **/ typedef int uSynergyBool; #define USYNERGY_FALSE 0 /* False value */ #define USYNERGY_TRUE 1 /* True value */ /** @brief User context type The uSynergyCookie type is an opaque type that is used by uSynergy to communicate to the client. It is passed along to callback functions as context. **/ typedef struct { int ignored; } * uSynergyCookie; /** @brief Clipboard types **/ enum uSynergyClipboardFormat { USYNERGY_CLIPBOARD_FORMAT_TEXT = 0, /* Text format, UTF-8, newline is LF */ USYNERGY_CLIPBOARD_FORMAT_BITMAP = 1, /* Bitmap format, BMP 24/32bpp, BI_RGB */ USYNERGY_CLIPBOARD_FORMAT_HTML = 2, /* HTML format, HTML fragment, UTF-8, newline is LF */ }; /** @brief Constants and limits **/ #define USYNERGY_NUM_JOYSTICKS 4 /* Maximum number of supported joysticks */ #define USYNERGY_PROTOCOL_MAJOR 1 /* Major protocol version */ #define USYNERGY_PROTOCOL_MINOR 4 /* Minor protocol version */ #define USYNERGY_IDLE_TIMEOUT 2000 /* Timeout in milliseconds before reconnecting */ #define USYNERGY_TRACE_BUFFER_SIZE 1024 /* Maximum length of traced message */ #define USYNERGY_REPLY_BUFFER_SIZE 1024 /* Maximum size of a reply packet */ #define USYNERGY_RECEIVE_BUFFER_SIZE 4096 /* Maximum size of an incoming packet */ /** @brief Keyboard constants **/ #define USYNERGY_MODIFIER_SHIFT 0x0001 /* Shift key modifier */ #define USYNERGY_MODIFIER_CTRL 0x0002 /* Ctrl key modifier */ #define USYNERGY_MODIFIER_ALT 0x0004 /* Alt key modifier */ #define USYNERGY_MODIFIER_META 0x0008 /* Meta key modifier */ #define USYNERGY_MODIFIER_WIN 0x0010 /* Windows key modifier */ #define USYNERGY_MODIFIER_ALT_GR 0x0020 /* AltGr key modifier */ #define USYNERGY_MODIFIER_LEVEL5LOCK 0x0040 /* Level5Lock key modifier */ #define USYNERGY_MODIFIER_CAPSLOCK 0x1000 /* CapsLock key modifier */ #define USYNERGY_MODIFIER_NUMLOCK 0x2000 /* NumLock key modifier */ #define USYNERGY_MODIFIER_SCROLLOCK 0x4000 /* ScrollLock key modifier */ //--------------------------------------------------------------------------------------------------------------------- // Functions and Callbacks //--------------------------------------------------------------------------------------------------------------------- /** @brief Connect function This function is called when uSynergy needs to connect to the host. It doesn't imply a network implementation or destination address, that must all be handled on the user side. The function should return USYNERGY_TRUE if a connection was established or USYNERGY_FALSE if it could not connect. When network errors occur (e.g. uSynergySend or uSynergyReceive fail) then the connect call will be called again so the implementation of the function must close any old connections and clean up resources before retrying. @param cookie Cookie supplied in the Synergy context **/ typedef uSynergyBool (*uSynergyConnectFunc)(uSynergyCookie cookie); /** @brief Send function This function is called when uSynergy needs to send something over the default connection. It should return USYNERGY_TRUE if sending succeeded and USYNERGY_FALSE otherwise. This function should block until the send operation is completed. @param cookie Cookie supplied in the Synergy context @param buffer Address of buffer to send @param length Length of buffer to send **/ typedef uSynergyBool (*uSynergySendFunc)(uSynergyCookie cookie, const uint8_t *buffer, int length); /** @brief Receive function This function is called when uSynergy needs to receive data from the default connection. It should return USYNERGY_TRUE if receiving data succeeded and USYNERGY_FALSE otherwise. This function should block until data has been received and wait for data to become available. If @a outLength is set to 0 upon completion it is assumed that the connection is alive, but still in a connecting state and needs time to settle. @param cookie Cookie supplied in the Synergy context @param buffer Address of buffer to receive data into @param maxLength Maximum amount of bytes to write into the receive buffer @param outLength Address of integer that receives the actual amount of bytes written into @a buffer **/ typedef uSynergyBool (*uSynergyReceiveFunc)(uSynergyCookie cookie, uint8_t *buffer, int maxLength, int* outLength); /** @brief Thread sleep function This function is called when uSynergy wants to suspend operation for a while before retrying an operation. It is mostly used when a socket times out or disconnect occurs to prevent uSynergy from continuously hammering a network connection in case the network is down. @param cookie Cookie supplied in the Synergy context @param timeMs Time to sleep the current thread (in milliseconds) **/ typedef void (*uSynergySleepFunc)(uSynergyCookie cookie, int timeMs); /** @brief Get time function This function is called when uSynergy needs to know the current time. This is used to determine when timeouts have occured. The time base should be a cyclic millisecond time value. @returns Time value in milliseconds **/ typedef uint32_t (*uSynergyGetTimeFunc)(); /** @brief Trace function This function is called when uSynergy wants to trace something. It is optional to show these messages, but they are often useful when debugging. uSynergy only traces major events like connecting and disconnecting. Usually only a single trace is shown when the connection is established and no more trace are called. @param cookie Cookie supplied in the Synergy context @param text Text to be traced **/ typedef void (*uSynergyTraceFunc)(uSynergyCookie cookie, const char *text); /** @brief Screen active callback This callback is called when Synergy makes the screen active or inactive. This callback is usually sent when the mouse enters or leaves the screen. @param cookie Cookie supplied in the Synergy context @param active Activation flag, 1 if the screen has become active, 0 if the screen has become inactive **/ typedef void (*uSynergyScreenActiveCallback)(uSynergyCookie cookie, uSynergyBool active); /** @brief Mouse callback This callback is called when a mouse events happens. The mouse X and Y position, wheel and button state is communicated in the message. It's up to the user to interpret if this is a mouse up, down, double-click or other message. @param cookie Cookie supplied in the Synergy context @param x Mouse X position @param y Mouse Y position @param wheelX Mouse wheel X position @param wheelY Mouse wheel Y position @param buttonLeft Left button pressed status, 0 for released, 1 for pressed @param buttonMiddle Middle button pressed status, 0 for released, 1 for pressed @param buttonRight Right button pressed status, 0 for released, 1 for pressed **/ typedef void (*uSynergyMouseCallback)(uSynergyCookie cookie, uint16_t x, uint16_t y, int16_t wheelX, int16_t wheelY, uSynergyBool buttonLeft, uSynergyBool buttonRight, uSynergyBool buttonMiddle); /** @brief Key event callback This callback is called when a key is pressed or released. @param cookie Cookie supplied in the Synergy context @param key Key code of key that was pressed or released @param modifiers Status of modifier keys (alt, shift, etc.) @param down Down or up status, 1 is key is pressed down, 0 if key is released (up) @param repeat Repeat flag, 1 if the key is down because the key is repeating, 0 if the key is initially pressed by the user **/ typedef void (*uSynergyKeyboardCallback)(uSynergyCookie cookie, uint16_t key, uint16_t modifiers, uSynergyBool down, uSynergyBool repeat); /** @brief Joystick event callback This callback is called when a joystick stick or button changes. It is possible that multiple callbacks are fired when different sticks or buttons change as these are individual messages in the packet stream. Each callback will contain all the valid state for the different axes and buttons. The last callback received will represent the most current joystick state. @param cookie Cookie supplied in the Synergy context @param joyNum Joystick number, always in the range [0 ... USYNERGY_NUM_JOYSTICKS> @param buttons Button pressed mask @param leftStickX Left stick X position, in range [-127 ... 127] @param leftStickY Left stick Y position, in range [-127 ... 127] @param rightStickX Right stick X position, in range [-127 ... 127] @param rightStickY Right stick Y position, in range [-127 ... 127] **/ typedef void (*uSynergyJoystickCallback)(uSynergyCookie cookie, uint8_t joyNum, uint16_t buttons, int8_t leftStickX, int8_t leftStickY, int8_t rightStickX, int8_t rightStickY); /** @brief Clipboard event callback This callback is called when something is placed on the clipboard. Multiple callbacks may be fired for multiple clipboard formats if they are supported. The data provided is read-only and may not be modified by the application. @param cookie Cookie supplied in the Synergy context @param format Clipboard format @param data Memory area containing the clipboard raw data @param size Size of clipboard data **/ typedef void (*uSynergyClipboardCallback)(uSynergyCookie cookie, enum uSynergyClipboardFormat format, const uint8_t *data, uint32_t size); //--------------------------------------------------------------------------------------------------------------------- // Context //--------------------------------------------------------------------------------------------------------------------- /** @brief uSynergy context **/ typedef struct { /* Mandatory configuration data, filled in by client */ uSynergyConnectFunc m_connectFunc; /* Connect function */ uSynergySendFunc m_sendFunc; /* Send data function */ uSynergyReceiveFunc m_receiveFunc; /* Receive data function */ uSynergySleepFunc m_sleepFunc; /* Thread sleep function */ uSynergyGetTimeFunc m_getTimeFunc; /* Get current time function */ const char* m_clientName; /* Name of Synergy Screen / Client */ uint16_t m_clientWidth; /* Width of screen */ uint16_t m_clientHeight; /* Height of screen */ /* Optional configuration data, filled in by client */ uSynergyCookie m_cookie; /* Cookie pointer passed to callback functions (can be NULL) */ uSynergyTraceFunc m_traceFunc; /* Function for tracing status (can be NULL) */ uSynergyScreenActiveCallback m_screenActiveCallback; /* Callback for entering and leaving screen */ uSynergyMouseCallback m_mouseCallback; /* Callback for mouse events */ uSynergyKeyboardCallback m_keyboardCallback; /* Callback for keyboard events */ uSynergyJoystickCallback m_joystickCallback; /* Callback for joystick events */ uSynergyClipboardCallback m_clipboardCallback; /* Callback for clipboard events */ /* State data, used internall by client, initialized by uSynergyInit() */ uSynergyBool m_connected; /* Is our socket connected? */ uSynergyBool m_hasReceivedHello; /* Have we received a 'Hello' from the server? */ uSynergyBool m_isCaptured; /* Is Synergy active (i.e. this client is receiving input messages?) */ uint32_t m_lastMessageTime; /* Time at which last message was received */ uint32_t m_sequenceNumber; /* Packet sequence number */ uint8_t m_receiveBuffer[USYNERGY_RECEIVE_BUFFER_SIZE]; /* Receive buffer */ int m_receiveOfs; /* Receive buffer offset */ uint8_t m_replyBuffer[USYNERGY_REPLY_BUFFER_SIZE]; /* Reply buffer */ uint8_t* m_replyCur; /* Write offset into reply buffer */ uint16_t m_mouseX; /* Mouse X position */ uint16_t m_mouseY; /* Mouse Y position */ int16_t m_mouseWheelX; /* Mouse wheel X position */ int16_t m_mouseWheelY; /* Mouse wheel Y position */ uSynergyBool m_mouseButtonLeft; /* Mouse left button */ uSynergyBool m_mouseButtonRight; /* Mouse right button */ uSynergyBool m_mouseButtonMiddle; /* Mouse middle button */ int8_t m_joystickSticks[USYNERGY_NUM_JOYSTICKS][4]; /* Joystick stick position in 2 axes for 2 sticks */ uint16_t m_joystickButtons[USYNERGY_NUM_JOYSTICKS]; /* Joystick button state */ } uSynergyContext; //--------------------------------------------------------------------------------------------------------------------- // Interface //--------------------------------------------------------------------------------------------------------------------- /** @brief Initialize uSynergy context This function initializes @a context for use. Call this function directly after creating the context, before filling in any configuration data in it. Not calling this function will cause undefined behavior. @param context Context to be initialized **/ extern void uSynergyInit(uSynergyContext *context); /** @brief Update uSynergy This function updates uSynergy and does the bulk of the work. It does connection management, receiving data, reconnecting after errors or timeouts and so on. It assumes that networking operations are blocking and it can suspend the current thread if it needs to wait. It is best practice to call uSynergyUpdate from a background thread so it is responsive. Because uSynergy relies mostly on blocking calls it will mostly stay in thread sleep state waiting for system mutexes and won't eat much memory. uSynergyUpdate doesn't do any memory allocations or have any side effects beyond those of the callbacks it calls. @param context Context to be updated **/ extern void uSynergyUpdate(uSynergyContext *context); /** @brief Send clipboard data This function sets new clipboard data and sends it to the server. Use this function if your client cuts or copies data onto the clipboard that it needs to share with the server. Currently there is only support for plaintext, but HTML and image data could be supported with some effort. @param context Context to send clipboard data to @param text Text to set to the clipboard **/ extern void uSynergySendClipboard(uSynergyContext *context, const char *text); #ifdef __cplusplus }; #endif synergy-1.8.8-stable/src/setup/000077500000000000000000000000001305627404700164375ustar00rootroot00000000000000synergy-1.8.8-stable/src/setup/win32/000077500000000000000000000000001305627404700174015ustar00rootroot00000000000000synergy-1.8.8-stable/src/setup/win32/Include.wxi000066400000000000000000000021011305627404700215070ustar00rootroot00000000000000 synergy-1.8.8-stable/src/setup/win32/Product.wxs000066400000000000000000000142751305627404700215750ustar00rootroot00000000000000 = 602)]]> NOT LEGACY_UNINSTALL_EXISTS NOT Installed synergy-1.8.8-stable/src/setup/win32/synergy.sln000066400000000000000000000022721305627404700216220ustar00rootroot00000000000000 Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "synergy", "synergy.wixproj", "{D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Debug|x86.ActiveCfg = Debug|x86 {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Debug|x86.Build.0 = Debug|x86 {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Debug|x64.ActiveCfg = Debug|x64 {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Debug|x64.Build.0 = Debug|x64 {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Release|x86.ActiveCfg = Release|x86 {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Release|x86.Build.0 = Release|x86 {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Release|x64.ActiveCfg = Release|x64 {D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal synergy-1.8.8-stable/src/setup/win32/synergy.wixproj000066400000000000000000000030641305627404700225300ustar00rootroot00000000000000 3.8 {d4ba9f39-6a35-4c8f-9cb2-67fcbe5cab17} 2.0 synergy Package $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets ..\..\..\bin\$(Configuration)\ ..\..\..\build\wix\obj\$(Configuration)\ $(WixExtDir)\WixFirewallExtension.dll WixFirewallExtension $(WixExtDir)\WixUtilExtension.dll WixUtilExtension C:\Program Files (x86)\WiX Toolset v3.8\bin\WixUIExtension.dll WixUIExtension synergy-1.8.8-stable/src/test/000077500000000000000000000000001305627404700162565ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/CMakeLists.txt000066400000000000000000000022621305627404700210200ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2011 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . include_directories( ../../ext/gtest-1.6.0 ../../ext/gtest-1.6.0/include ../../ext/gmock-1.6.0 ../../ext/gmock-1.6.0/include) add_library(gtest STATIC ../../ext/gtest-1.6.0/src/gtest-all.cc) add_library(gmock STATIC ../../ext/gmock-1.6.0/src/gmock-all.cc) if (UNIX) # ignore warnings in gtest and gmock set_target_properties(gtest PROPERTIES COMPILE_FLAGS "-w") set_target_properties(gmock PROPERTIES COMPILE_FLAGS "-w") endif() add_subdirectory(integtests) add_subdirectory(unittests) synergy-1.8.8-stable/src/test/global/000077500000000000000000000000001305627404700175165ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/global/TestEventQueue.cpp000066400000000000000000000027441305627404700231570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "test/global/TestEventQueue.h" #include "base/Log.h" #include "base/TMethodEventJob.h" #include "base/SimpleEventQueueBuffer.h" #include "common/stdexcept.h" void TestEventQueue::raiseQuitEvent() { addEvent(Event(Event::kQuit)); } void TestEventQueue::initQuitTimeout(double timeout) { assert(m_quitTimeoutTimer == nullptr); m_quitTimeoutTimer = newOneShotTimer(timeout, NULL); adoptHandler(Event::kTimer, m_quitTimeoutTimer, new TMethodEventJob( this, &TestEventQueue::handleQuitTimeout)); } void TestEventQueue::cleanupQuitTimeout() { removeHandler(Event::kTimer, m_quitTimeoutTimer); delete m_quitTimeoutTimer; m_quitTimeoutTimer = nullptr; } void TestEventQueue::handleQuitTimeout(const Event&, void* vclient) { throw std::runtime_error("test event queue timeout"); } synergy-1.8.8-stable/src/test/global/TestEventQueue.h000066400000000000000000000021321305627404700226130ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/EventQueue.h" class EventQueueTimer; class TestEventQueue : public EventQueue { public: TestEventQueue() : m_quitTimeoutTimer(nullptr) { } void handleQuitTimeout(const Event&, void* vclient); void raiseQuitEvent(); void initQuitTimeout(double timeout); void cleanupQuitTimeout(); private: void timeoutThread(void*); private: EventQueueTimer* m_quitTimeoutTimer; }; synergy-1.8.8-stable/src/test/global/gmock.h000066400000000000000000000023331305627404700207700ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once // HACK: gcc on osx106 doesn't give you an easy way to hide warnings // from included headers, so use the system_header pragma. the downside // is that everything in the header file following this also has warnings // ignored, so we need to put it in a separate header file. #if __APPLE__ # pragma GCC system_header #endif // gmock includes gtest which has a warning on osx106 (signed/unsigned // int compare), so include our special header here first to silence // the warning. #include "test/global/gtest.h" #include synergy-1.8.8-stable/src/test/global/gtest.h000066400000000000000000000021401305627404700210120ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once // HACK: gcc on osx106 doesn't give you an easy way to hide warnings // from included headers, so use the system_header pragma. the downside // is that everything in the header file following this also has warnings // ignored, so we need to put it in a separate header file. #if __APPLE__ # pragma GCC system_header #endif // gtest has a warning on osx106 (signed/unsigned int compare). #include synergy-1.8.8-stable/src/test/guitests/000077500000000000000000000000001305627404700201255ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/guitests/guitests.pro000066400000000000000000000006241305627404700225200ustar00rootroot00000000000000QT += network QT -= gui TARGET = guitests CONFIG += qtestlib CONFIG += console CONFIG -= app_bundle TEMPLATE = app INCLUDEPATH += ../../gui/src SOURCES += src/main.cpp \ src/VersionCheckerTests.cpp HEADERS += src/VersionCheckerTests.h \ src/VersionChecker.h win32 { Debug:DESTDIR = ../../../bin/Debug Release:DESTDIR = ../../../bin/Release } else:DESTDIR = ../../../bin synergy-1.8.8-stable/src/test/guitests/src/000077500000000000000000000000001305627404700207145ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/guitests/src/VersionCheckerTests.cpp000066400000000000000000000034651305627404700253650ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "VersionCheckerTests.h" #include "VersionChecker.cpp" #include "../../gui/tmp/debug/moc_VersionChecker.cpp" #include void VersionCheckerTests::compareVersions() { VersionChecker versionChecker; // compare majors QCOMPARE(versionChecker.compareVersions("1.0.0", "2.0.0"), 1); QCOMPARE(versionChecker.compareVersions("2.0.0", "1.0.0"), -1); QCOMPARE(versionChecker.compareVersions("1.0.0", "1.0.0"), 0); QCOMPARE(versionChecker.compareVersions("1.4.8", "2.4.7"), 1); QCOMPARE(versionChecker.compareVersions("2.4.7", "1.4.8"), -1); // compare minors QCOMPARE(versionChecker.compareVersions("1.3.0", "1.4.0"), 1); QCOMPARE(versionChecker.compareVersions("1.4.0", "1.3.0"), -1); QCOMPARE(versionChecker.compareVersions("1.4.0", "1.4.0"), 0); QCOMPARE(versionChecker.compareVersions("1.3.8", "1.4.7"), 1); QCOMPARE(versionChecker.compareVersions("1.4.7", "1.3.8"), -1); // compare revs QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.8"), 1); QCOMPARE(versionChecker.compareVersions("1.4.8", "1.4.7"), -1); QCOMPARE(versionChecker.compareVersions("1.4.7", "1.4.7"), 0); } synergy-1.8.8-stable/src/test/guitests/src/VersionCheckerTests.h000066400000000000000000000015351305627404700250260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "QObject.h" class VersionCheckerTests : public QObject { Q_OBJECT private slots: void compareVersions(); }; synergy-1.8.8-stable/src/test/guitests/src/main.cpp000066400000000000000000000016211305627404700223440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include "VersionCheckerTests.h" int main(int argc, char *argv[]) { VersionCheckerTests versionCheckerTests; QTest::qExec(&versionCheckerTests, argc, argv); } synergy-1.8.8-stable/src/test/integtests/000077500000000000000000000000001305627404700204475ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/integtests/CMakeLists.txt000066400000000000000000000042441305627404700232130ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB_RECURSE headers "*.h") file(GLOB_RECURSE sources "*.cpp") # remove platform files (specific platform added later). file(GLOB_RECURSE remove_platform "platform/*") list(REMOVE_ITEM headers ${remove_platform}) list(REMOVE_ITEM sources ${remove_platform}) # platform if (WIN32) file(GLOB platform_sources "platform/MSWindows*.cpp") file(GLOB platform_headers "platform/MSWindows*.h") elseif (APPLE) file(GLOB platform_sources "platform/OSX*.cpp") file(GLOB platform_headers "platform/OSX*.h") elseif (UNIX) file(GLOB platform_sources "platform/XWindows*.cpp") file(GLOB platform_headers "platform/XWindows*.h") endif() list(APPEND sources ${platform_sources}) list(APPEND headers ${platform_headers}) file(GLOB_RECURSE global_headers "../../test/global/*.h") file(GLOB_RECURSE global_sources "../../test/global/*.cpp") list(APPEND headers ${global_headers}) list(APPEND sources ${global_sources}) file(GLOB_RECURSE mock_headers "../../test/mock/*.h") file(GLOB_RECURSE mock_sources "../../test/mock/*.cpp") list(APPEND headers ${mock_headers}) list(APPEND sources ${mock_sources}) if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() include_directories( ../../ ../../lib/ ../../../ext/gtest-1.6.0/include ../../../ext/gmock-1.6.0/include ) if (UNIX) include_directories( ../../.. ) endif() add_executable(integtests ${sources}) target_link_libraries(integtests arch base client common io ipc mt net platform server synergy gtest gmock ${libs} ${OPENSSL_LIBS}) synergy-1.8.8-stable/src/test/integtests/Main.cpp000066400000000000000000000044711305627404700220450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/Arch.h" #include "base/Log.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" #endif #include "test/global/gtest.h" #include #include #define LOCK_TIMEOUT 30 using namespace std; void lock(string lockFile); void unlock(string lockFile); int main(int argc, char **argv) { #if SYSAPI_WIN32 // record window instance for tray icon, etc ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif Arch arch; arch.init(); Log log; log.setFilter(kDEBUG2); string lockFile; for (int i = 0; i < argc; i++) { if (string(argv[i]).compare("--lock-file") == 0) { lockFile = argv[i + 1]; } } if (!lockFile.empty()) { lock(lockFile); } testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); if (!lockFile.empty()) { unlock(lockFile); } // gtest seems to randomly finish with error codes (e.g. -1, -1073741819) // even when no tests have failed. not sure what causes this, but it // happens on all platforms and keeps leading to false positives. // according to the documentation, 1 is a failure, so we should be // able to trust that code. return (result == 1) ? 1 : 0; } void lock(string lockFile) { double start = ARCH->time(); // keep checking until timeout is reached. while ((ARCH->time() - start) < LOCK_TIMEOUT) { ifstream is(lockFile.c_str()); bool noLock = !is; is.close(); if (noLock) { break; } // check every second if file has gone. ARCH->sleep(1); } // write empty lock file. ofstream os(lockFile.c_str()); os.close(); } void unlock(string lockFile) { remove(lockFile.c_str()); } synergy-1.8.8-stable/src/test/integtests/arch/000077500000000000000000000000001305627404700213645ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/integtests/arch/ArchInternetTests.cpp000066400000000000000000000022161305627404700255020ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/Arch.h" #include "test/global/gtest.h" #define TEST_URL "https://symless.com/tests/?testString" //#define TEST_URL "http://localhost/synergy/tests/?testString" TEST(ArchInternetTests, get) { ARCH_INTERNET internet; String result = internet.get(TEST_URL); ASSERT_EQ("Hello world!", result); } TEST(ArchInternetTests, urlEncode) { ARCH_INTERNET internet; String result = internet.urlEncode("hello=+&world"); ASSERT_EQ("hello%3D%2B%26world", result); } synergy-1.8.8-stable/src/test/integtests/ipc/000077500000000000000000000000001305627404700212225ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/integtests/ipc/IpcTests.cpp000066400000000000000000000145761305627404700235010ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2012 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // TODO: fix, tests failing intermittently on mac. #ifndef WINAPI_CARBON #define TEST_ENV #include "test/global/TestEventQueue.h" #include "ipc/IpcServer.h" #include "ipc/IpcClient.h" #include "ipc/IpcServerProxy.h" #include "ipc/IpcMessage.h" #include "ipc/IpcClientProxy.h" #include "ipc/Ipc.h" #include "net/SocketMultiplexer.h" #include "mt/Thread.h" #include "arch/Arch.h" #include "base/TMethodJob.h" #include "base/String.h" #include "base/Log.h" #include "base/EventQueue.h" #include "base/TMethodEventJob.h" #include "test/global/gtest.h" #define TEST_IPC_PORT 24802 class IpcTests : public ::testing::Test { public: IpcTests(); virtual ~IpcTests(); void connectToServer_handleMessageReceived(const Event&, void*); void sendMessageToServer_serverHandleMessageReceived(const Event&, void*); void sendMessageToClient_serverHandleClientConnected(const Event&, void*); void sendMessageToClient_clientHandleMessageReceived(const Event&, void*); public: SocketMultiplexer m_multiplexer; bool m_connectToServer_helloMessageReceived; bool m_connectToServer_hasClientNode; IpcServer* m_connectToServer_server; String m_sendMessageToServer_receivedString; String m_sendMessageToClient_receivedString; IpcClient* m_sendMessageToServer_client; IpcServer* m_sendMessageToClient_server; TestEventQueue m_events; }; TEST_F(IpcTests, connectToServer) { SocketMultiplexer socketMultiplexer; IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); server.listen(); m_connectToServer_server = &server; m_events.adoptHandler( m_events.forIpcServer().messageReceived(), &server, new TMethodEventJob( this, &IpcTests::connectToServer_handleMessageReceived)); IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); client.connect(); m_events.initQuitTimeout(5); m_events.loop(); m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); m_events.cleanupQuitTimeout(); EXPECT_EQ(true, m_connectToServer_helloMessageReceived); EXPECT_EQ(true, m_connectToServer_hasClientNode); } TEST_F(IpcTests, sendMessageToServer) { SocketMultiplexer socketMultiplexer; IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); server.listen(); // event handler sends "test" command to server. m_events.adoptHandler( m_events.forIpcServer().messageReceived(), &server, new TMethodEventJob( this, &IpcTests::sendMessageToServer_serverHandleMessageReceived)); IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); client.connect(); m_sendMessageToServer_client = &client; m_events.initQuitTimeout(5); m_events.loop(); m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); m_events.cleanupQuitTimeout(); EXPECT_EQ("test", m_sendMessageToServer_receivedString); } TEST_F(IpcTests, sendMessageToClient) { SocketMultiplexer socketMultiplexer; IpcServer server(&m_events, &socketMultiplexer, TEST_IPC_PORT); server.listen(); m_sendMessageToClient_server = &server; // event handler sends "test" log line to client. m_events.adoptHandler( m_events.forIpcServer().messageReceived(), &server, new TMethodEventJob( this, &IpcTests::sendMessageToClient_serverHandleClientConnected)); IpcClient client(&m_events, &socketMultiplexer, TEST_IPC_PORT); client.connect(); m_events.adoptHandler( m_events.forIpcClient().messageReceived(), &client, new TMethodEventJob( this, &IpcTests::sendMessageToClient_clientHandleMessageReceived)); m_events.initQuitTimeout(5); m_events.loop(); m_events.removeHandler(m_events.forIpcServer().messageReceived(), &server); m_events.removeHandler(m_events.forIpcClient().messageReceived(), &client); m_events.cleanupQuitTimeout(); EXPECT_EQ("test", m_sendMessageToClient_receivedString); } IpcTests::IpcTests() : m_connectToServer_helloMessageReceived(false), m_connectToServer_hasClientNode(false), m_connectToServer_server(nullptr), m_sendMessageToClient_server(nullptr), m_sendMessageToServer_client(nullptr) { } IpcTests::~IpcTests() { } void IpcTests::connectToServer_handleMessageReceived(const Event& e, void*) { IpcMessage* m = static_cast(e.getDataObject()); if (m->type() == kIpcHello) { m_connectToServer_hasClientNode = m_connectToServer_server->hasClients(kIpcClientNode); m_connectToServer_helloMessageReceived = true; m_events.raiseQuitEvent(); } } void IpcTests::sendMessageToServer_serverHandleMessageReceived(const Event& e, void*) { IpcMessage* m = static_cast(e.getDataObject()); if (m->type() == kIpcHello) { LOG((CLOG_DEBUG "client said hello, sending test to server")); IpcCommandMessage m("test", true); m_sendMessageToServer_client->send(m); } else if (m->type() == kIpcCommand) { IpcCommandMessage* cm = static_cast(m); LOG((CLOG_DEBUG "got ipc command message, %d", cm->command().c_str())); m_sendMessageToServer_receivedString = cm->command(); m_events.raiseQuitEvent(); } } void IpcTests::sendMessageToClient_serverHandleClientConnected(const Event& e, void*) { IpcMessage* m = static_cast(e.getDataObject()); if (m->type() == kIpcHello) { LOG((CLOG_DEBUG "client said hello, sending test to client")); IpcLogLineMessage m("test"); m_sendMessageToClient_server->send(m, kIpcClientNode); } } void IpcTests::sendMessageToClient_clientHandleMessageReceived(const Event& e, void*) { IpcMessage* m = static_cast(e.getDataObject()); if (m->type() == kIpcLogLine) { IpcLogLineMessage* llm = static_cast(m); LOG((CLOG_DEBUG "got ipc log message, %d", llm->logLine().c_str())); m_sendMessageToClient_receivedString = llm->logLine(); m_events.raiseQuitEvent(); } } #endif // WINAPI_CARBON synergy-1.8.8-stable/src/test/integtests/net/000077500000000000000000000000001305627404700212355ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/integtests/net/NetworkTests.cpp000066400000000000000000000375401305627404700244260ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // TODO: fix, tests failing intermittently on mac. #ifndef WINAPI_CARBON #define TEST_ENV #include "test/mock/server/MockConfig.h" #include "test/mock/server/MockPrimaryClient.h" #include "test/mock/synergy/MockScreen.h" #include "test/mock/server/MockInputFilter.h" #include "test/global/TestEventQueue.h" #include "server/Server.h" #include "server/ClientListener.h" #include "server/ClientProxy.h" #include "client/Client.h" #include "synergy/FileChunk.h" #include "synergy/StreamChunker.h" #include "net/SocketMultiplexer.h" #include "net/NetworkAddress.h" #include "net/TCPSocketFactory.h" #include "mt/Thread.h" #include "base/TMethodEventJob.h" #include "base/TMethodJob.h" #include "base/Log.h" #include "common/stdexcept.h" #include "test/global/gtest.h" #include #include #include #include using namespace std; using ::testing::_; using ::testing::NiceMock; using ::testing::Return; using ::testing::Invoke; #define TEST_PORT 24803 #define TEST_HOST "localhost" const size_t kMockDataSize = 1024 * 1024 * 10; // 10MB const UInt16 kMockDataChunkIncrement = 1024; // 1KB const char* kMockFilename = "NetworkTests.mock"; const size_t kMockFileSize = 1024 * 1024 * 10; // 10MB void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h); void getCursorPos(SInt32& x, SInt32& y); UInt8* newMockData(size_t size); void createFile(fstream& file, const char* filename, size_t size); class NetworkTests : public ::testing::Test { public: NetworkTests() : m_mockData(NULL), m_mockDataSize(0), m_mockFileSize(0) { m_mockData = newMockData(kMockDataSize); createFile(m_mockFile, kMockFilename, kMockFileSize); } ~NetworkTests() { remove(kMockFilename); delete[] m_mockData; } void sendMockData(void* eventTarget); void sendToClient_mockData_handleClientConnected(const Event&, void* vlistener); void sendToClient_mockData_fileRecieveCompleted(const Event&, void*); void sendToClient_mockFile_handleClientConnected(const Event&, void* vlistener); void sendToClient_mockFile_fileRecieveCompleted(const Event& event, void*); void sendToServer_mockData_handleClientConnected(const Event&, void* vlistener); void sendToServer_mockData_fileRecieveCompleted(const Event& event, void*); void sendToServer_mockFile_handleClientConnected(const Event&, void* vlistener); void sendToServer_mockFile_fileRecieveCompleted(const Event& event, void*); public: TestEventQueue m_events; UInt8* m_mockData; size_t m_mockDataSize; fstream m_mockFile; size_t m_mockFileSize; }; TEST_F(NetworkTests, sendToClient_mockData) { // server and client NetworkAddress serverAddress(TEST_HOST, TEST_PORT); serverAddress.resolve(); // server SocketMultiplexer serverSocketMultiplexer; TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; NiceMock serverInputFilter; m_events.adoptHandler( m_events.forClientListener().connected(), &listener, new TMethodEventJob( this, &NetworkTests::sendToClient_mockData_handleClientConnected, &listener)); ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); ServerArgs serverArgs; serverArgs.m_enableDragDrop = true; Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); server.m_mock = true; listener.setServer(&server); // client NiceMock clientScreen; SocketMultiplexer clientSocketMultiplexer; TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ClientArgs clientArgs; clientArgs.m_enableDragDrop = true; clientArgs.m_enableCrypto = false; Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); m_events.adoptHandler( m_events.forFile().fileRecieveCompleted(), &client, new TMethodEventJob( this, &NetworkTests::sendToClient_mockData_fileRecieveCompleted)); client.connect(); m_events.initQuitTimeout(10); m_events.loop(); m_events.removeHandler(m_events.forClientListener().connected(), &listener); m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &client); m_events.cleanupQuitTimeout(); } TEST_F(NetworkTests, sendToClient_mockFile) { // server and client NetworkAddress serverAddress(TEST_HOST, TEST_PORT); serverAddress.resolve(); // server SocketMultiplexer serverSocketMultiplexer; TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; NiceMock serverInputFilter; m_events.adoptHandler( m_events.forClientListener().connected(), &listener, new TMethodEventJob( this, &NetworkTests::sendToClient_mockFile_handleClientConnected, &listener)); ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); ServerArgs serverArgs; serverArgs.m_enableDragDrop = true; Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); server.m_mock = true; listener.setServer(&server); // client NiceMock clientScreen; SocketMultiplexer clientSocketMultiplexer; TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ClientArgs clientArgs; clientArgs.m_enableDragDrop = true; clientArgs.m_enableCrypto = false; Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); m_events.adoptHandler( m_events.forFile().fileRecieveCompleted(), &client, new TMethodEventJob( this, &NetworkTests::sendToClient_mockFile_fileRecieveCompleted)); client.connect(); m_events.initQuitTimeout(10); m_events.loop(); m_events.removeHandler(m_events.forClientListener().connected(), &listener); m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &client); m_events.cleanupQuitTimeout(); } TEST_F(NetworkTests, sendToServer_mockData) { // server and client NetworkAddress serverAddress(TEST_HOST, TEST_PORT); serverAddress.resolve(); // server SocketMultiplexer serverSocketMultiplexer; TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; NiceMock serverInputFilter; ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); ServerArgs serverArgs; serverArgs.m_enableDragDrop = true; Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); server.m_mock = true; listener.setServer(&server); // client NiceMock clientScreen; SocketMultiplexer clientSocketMultiplexer; TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ClientArgs clientArgs; clientArgs.m_enableDragDrop = true; clientArgs.m_enableCrypto = false; Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); m_events.adoptHandler( m_events.forClientListener().connected(), &listener, new TMethodEventJob( this, &NetworkTests::sendToServer_mockData_handleClientConnected, &client)); m_events.adoptHandler( m_events.forFile().fileRecieveCompleted(), &server, new TMethodEventJob( this, &NetworkTests::sendToServer_mockData_fileRecieveCompleted)); client.connect(); m_events.initQuitTimeout(10); m_events.loop(); m_events.removeHandler(m_events.forClientListener().connected(), &listener); m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &server); m_events.cleanupQuitTimeout(); } TEST_F(NetworkTests, sendToServer_mockFile) { // server and client NetworkAddress serverAddress(TEST_HOST, TEST_PORT); serverAddress.resolve(); // server SocketMultiplexer serverSocketMultiplexer; TCPSocketFactory* serverSocketFactory = new TCPSocketFactory(&m_events, &serverSocketMultiplexer); ClientListener listener(serverAddress, serverSocketFactory, &m_events, false); NiceMock serverScreen; NiceMock primaryClient; NiceMock serverConfig; NiceMock serverInputFilter; ON_CALL(serverConfig, isScreen(_)).WillByDefault(Return(true)); ON_CALL(serverConfig, getInputFilter()).WillByDefault(Return(&serverInputFilter)); ServerArgs serverArgs; serverArgs.m_enableDragDrop = true; Server server(serverConfig, &primaryClient, &serverScreen, &m_events, serverArgs); server.m_mock = true; listener.setServer(&server); // client NiceMock clientScreen; SocketMultiplexer clientSocketMultiplexer; TCPSocketFactory* clientSocketFactory = new TCPSocketFactory(&m_events, &clientSocketMultiplexer); ON_CALL(clientScreen, getShape(_, _, _, _)).WillByDefault(Invoke(getScreenShape)); ON_CALL(clientScreen, getCursorPos(_, _)).WillByDefault(Invoke(getCursorPos)); ClientArgs clientArgs; clientArgs.m_enableDragDrop = true; clientArgs.m_enableCrypto = false; Client client(&m_events, "stub", serverAddress, clientSocketFactory, &clientScreen, clientArgs); m_events.adoptHandler( m_events.forClientListener().connected(), &listener, new TMethodEventJob( this, &NetworkTests::sendToServer_mockFile_handleClientConnected, &client)); m_events.adoptHandler( m_events.forFile().fileRecieveCompleted(), &server, new TMethodEventJob( this, &NetworkTests::sendToServer_mockFile_fileRecieveCompleted)); client.connect(); m_events.initQuitTimeout(10); m_events.loop(); m_events.removeHandler(m_events.forClientListener().connected(), &listener); m_events.removeHandler(m_events.forFile().fileRecieveCompleted(), &server); m_events.cleanupQuitTimeout(); } void NetworkTests::sendToClient_mockData_handleClientConnected(const Event&, void* vlistener) { ClientListener* listener = static_cast(vlistener); Server* server = listener->getServer(); ClientProxy* client = listener->getNextClient(); if (client == NULL) { throw runtime_error("client is null"); } BaseClientProxy* bcp = client; server->adoptClient(bcp); server->setActive(bcp); sendMockData(server); } void NetworkTests::sendToClient_mockData_fileRecieveCompleted(const Event& event, void*) { Client* client = static_cast(event.getTarget()); EXPECT_TRUE(client->isReceivedFileSizeValid()); m_events.raiseQuitEvent(); } void NetworkTests::sendToClient_mockFile_handleClientConnected(const Event&, void* vlistener) { ClientListener* listener = static_cast(vlistener); Server* server = listener->getServer(); ClientProxy* client = listener->getNextClient(); if (client == NULL) { throw runtime_error("client is null"); } BaseClientProxy* bcp = client; server->adoptClient(bcp); server->setActive(bcp); server->sendFileToClient(kMockFilename); } void NetworkTests::sendToClient_mockFile_fileRecieveCompleted(const Event& event, void*) { Client* client = static_cast(event.getTarget()); EXPECT_TRUE(client->isReceivedFileSizeValid()); m_events.raiseQuitEvent(); } void NetworkTests::sendToServer_mockData_handleClientConnected(const Event&, void* vclient) { Client* client = static_cast(vclient); sendMockData(client); } void NetworkTests::sendToServer_mockData_fileRecieveCompleted(const Event& event, void*) { Server* server = static_cast(event.getTarget()); EXPECT_TRUE(server->isReceivedFileSizeValid()); m_events.raiseQuitEvent(); } void NetworkTests::sendToServer_mockFile_handleClientConnected(const Event&, void* vclient) { Client* client = static_cast(vclient); client->sendFileToServer(kMockFilename); } void NetworkTests::sendToServer_mockFile_fileRecieveCompleted(const Event& event, void*) { Server* server = static_cast(event.getTarget()); EXPECT_TRUE(server->isReceivedFileSizeValid()); m_events.raiseQuitEvent(); } void NetworkTests::sendMockData(void* eventTarget) { // send first message (file size) String size = synergy::string::sizeTypeToString(kMockDataSize); FileChunk* sizeMessage = FileChunk::start(size); m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, sizeMessage)); // send chunk messages with incrementing chunk size size_t lastSize = 0; size_t sentLength = 0; while (true) { size_t dataSize = lastSize + kMockDataChunkIncrement; // make sure we don't read too much from the mock data. if (sentLength + dataSize > kMockDataSize) { dataSize = kMockDataSize - sentLength; } // first byte is the chunk mark, last is \0 FileChunk* chunk = FileChunk::data(m_mockData, dataSize); m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, chunk)); sentLength += dataSize; lastSize = dataSize; if (sentLength == kMockDataSize) { break; } } // send last message FileChunk* transferFinished = FileChunk::end(); m_events.addEvent(Event(m_events.forFile().fileChunkSending(), eventTarget, transferFinished)); } UInt8* newMockData(size_t size) { UInt8* buffer = new UInt8[size]; UInt8* data = buffer; const UInt8 head[] = "mock head... "; size_t headSize = sizeof(head) - 1; const UInt8 tail[] = "... mock tail"; size_t tailSize = sizeof(tail) - 1; const UInt8 synergyRocks[] = "synergy\0 rocks! "; size_t synergyRocksSize = sizeof(synergyRocks) - 1; memcpy(data, head, headSize); data += headSize; size_t times = (size - headSize - tailSize) / synergyRocksSize; for (size_t i = 0; i < times; ++i) { memcpy(data, synergyRocks, synergyRocksSize); data += synergyRocksSize; } size_t remainder = (size - headSize - tailSize) % synergyRocksSize; if (remainder != 0) { memset(data, '.', remainder); data += remainder; } memcpy(data, tail, tailSize); return buffer; } void createFile(fstream& file, const char* filename, size_t size) { UInt8* buffer = newMockData(size); file.open(filename, ios::out | ios::binary); if (!file.is_open()) { throw runtime_error("file not open"); } file.write(reinterpret_cast(buffer), size); file.close(); delete[] buffer; } void getScreenShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) { x = 0; y = 0; w = 1; h = 1; } void getCursorPos(SInt32& x, SInt32& y) { x = 0; y = 0; } #endif // WINAPI_CARBON synergy-1.8.8-stable/src/test/integtests/platform/000077500000000000000000000000001305627404700222735ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/integtests/platform/MSWindowsClipboardTests.cpp000066400000000000000000000124651305627404700275440ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/MSWindowsClipboard.h" #include "platform/IMSWindowsClipboardFacade.h" #include "test/global/gmock.h" #include "test/global/gtest.h" class MSWindowsClipboardTests : public ::testing::Test { protected: virtual void SetUp() { emptyClipboard(); } virtual void TearDown() { emptyClipboard(); } private: void emptyClipboard() { MSWindowsClipboard clipboard(NULL); clipboard.open(0); clipboard.empty(); } }; class MockFacade : public IMSWindowsClipboardFacade { public: MOCK_METHOD2(write, void(HANDLE, UINT)); }; TEST_F(MSWindowsClipboardTests, emptyUnowned_openCalled_returnsTrue) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); bool actual = clipboard.emptyUnowned(); EXPECT_EQ(true, actual); } TEST_F(MSWindowsClipboardTests, empty_openCalled_returnsTrue) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); bool actual = clipboard.empty(); EXPECT_EQ(true, actual); } TEST_F(MSWindowsClipboardTests, empty_singleFormat_hasReturnsFalse) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); clipboard.add(MSWindowsClipboard::kText, "synergy rocks!"); clipboard.empty(); bool actual = clipboard.has(MSWindowsClipboard::kText); EXPECT_EQ(false, actual); } TEST_F(MSWindowsClipboardTests, add_newValue_valueWasStored) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("synergy rocks!", actual); } TEST_F(MSWindowsClipboardTests, add_newValue_writeWasCalled) { MockFacade facade; EXPECT_CALL(facade, write(testing::_, testing::_)); MSWindowsClipboard clipboard(NULL); clipboard.setFacade(facade); clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); } TEST_F(MSWindowsClipboardTests, add_replaceValue_valueWasReplaced) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("maxivista sucks", actual); } TEST_F(MSWindowsClipboardTests, open_timeIsZero_returnsTrue) { MSWindowsClipboard clipboard(NULL); bool actual = clipboard.open(0); EXPECT_EQ(true, actual); } TEST_F(MSWindowsClipboardTests, open_timeIsOne_returnsTrue) { MSWindowsClipboard clipboard(NULL); bool actual = clipboard.open(1); EXPECT_EQ(true, actual); } TEST_F(MSWindowsClipboardTests, close_isOpen_noErrors) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); clipboard.close(); // can't assert anything } // looks like this test may fail intermittently: // * http://buildbot.symless.com:8000/builders/trunk-win32/builds/246/steps/shell_3/logs/stdio /*TEST_F(MSWindowsClipboardTests, getTime_openWithNoEmpty_returnsOne) { MSWindowsClipboard clipboard(NULL); clipboard.open(1); MSWindowsClipboard::Time actual = clipboard.getTime(); // this behavior is different to that of Clipboard which only // returns the value passed into open(t) after empty() is called. EXPECT_EQ(1, actual); }*/ // this also fails intermittently: // http://buildbot.symless.com:8000/builders/trunk-win32/builds/266/steps/shell_3/logs/stdio /*TEST_F(MSWindowsClipboardTests, getTime_openAndEmpty_returnsOne) { MSWindowsClipboard clipboard(NULL); clipboard.open(1); clipboard.empty(); MSWindowsClipboard::Time actual = clipboard.getTime(); EXPECT_EQ(1, actual); }*/ TEST_F(MSWindowsClipboardTests, has_withFormatAdded_returnsTrue) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); clipboard.empty(); clipboard.add(IClipboard::kText, "synergy rocks!"); bool actual = clipboard.has(IClipboard::kText); EXPECT_EQ(true, actual); } TEST_F(MSWindowsClipboardTests, has_withNoFormats_returnsFalse) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); clipboard.empty(); bool actual = clipboard.has(IClipboard::kText); EXPECT_EQ(false, actual); } TEST_F(MSWindowsClipboardTests, get_withNoFormats_returnsEmpty) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); clipboard.empty(); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("", actual); } TEST_F(MSWindowsClipboardTests, get_withFormatAdded_returnsExpected) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); clipboard.empty(); clipboard.add(IClipboard::kText, "synergy rocks!"); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("synergy rocks!", actual); } TEST_F(MSWindowsClipboardTests, isOwnedBySynergy_defaultState_noError) { MSWindowsClipboard clipboard(NULL); clipboard.open(0); bool actual = clipboard.isOwnedBySynergy(); EXPECT_EQ(true, actual); } synergy-1.8.8-stable/src/test/integtests/platform/MSWindowsKeyStateTests.cpp000066400000000000000000000102421305627404700273650ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define TEST_ENV #include "test/mock/synergy/MockEventQueue.h" #include "test/mock/synergy/MockKeyMap.h" #include "platform/MSWindowsKeyState.h" #include "platform/MSWindowsDesks.h" #include "platform/MSWindowsScreen.h" #include "platform/MSWindowsScreenSaver.h" #include "base/TMethodJob.h" #include "test/global/gtest.h" #include "test/global/gmock.h" // wParam = flags, HIBYTE(lParam) = virtual key, LOBYTE(lParam) = scan code #define SYNERGY_MSG_FAKE_KEY SYNERGY_HOOK_LAST_MSG + 4 using ::testing::_; using ::testing::NiceMock; class MSWindowsKeyStateTests : public ::testing::Test { protected: virtual void SetUp() { m_hook.loadLibrary(); m_screensaver = new MSWindowsScreenSaver(); } virtual void TearDown() { delete m_screensaver; } MSWindowsDesks* newDesks(IEventQueue* eventQueue) { return new MSWindowsDesks( true, false, m_hook.getInstance(), m_screensaver, eventQueue, new TMethodJob( this, &MSWindowsKeyStateTests::updateKeysCB), false); } void* getEventTarget() const { return const_cast(this); } private: void updateKeysCB(void*) { } IScreenSaver* m_screensaver; MSWindowsHook m_hook; }; TEST_F(MSWindowsKeyStateTests, disable_eventQueueNotUsed) { NiceMock eventQueue; MSWindowsDesks* desks = newDesks(&eventQueue); MockKeyMap keyMap; MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap); EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(0); keyState.disable(); delete desks; } TEST_F(MSWindowsKeyStateTests, testAutoRepeat_noRepeatAndButtonIsZero_resultIsTrue) { NiceMock eventQueue; MSWindowsDesks* desks = newDesks(&eventQueue); MockKeyMap keyMap; MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap); keyState.setLastDown(1); bool actual = keyState.testAutoRepeat(true, false, 1); ASSERT_TRUE(actual); delete desks; } TEST_F(MSWindowsKeyStateTests, testAutoRepeat_pressFalse_lastDownIsZero) { NiceMock eventQueue; MSWindowsDesks* desks = newDesks(&eventQueue); MockKeyMap keyMap; MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap); keyState.setLastDown(1); keyState.testAutoRepeat(false, false, 1); ASSERT_EQ(0, keyState.getLastDown()); delete desks; } TEST_F(MSWindowsKeyStateTests, saveModifiers_noModifiers_savedModifiers0) { NiceMock eventQueue; MSWindowsDesks* desks = newDesks(&eventQueue); MockKeyMap keyMap; MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap); keyState.saveModifiers(); ASSERT_EQ(0, keyState.getSavedModifiers()); delete desks; } TEST_F(MSWindowsKeyStateTests, testKoreanLocale_inputModeKey_resultCorrectKeyID) { NiceMock eventQueue; MSWindowsDesks* desks = newDesks(&eventQueue); MockKeyMap keyMap; MSWindowsKeyState keyState(desks, getEventTarget(), &eventQueue, keyMap); keyState.setKeyLayout((HKL)0x00000412u); // for ko-KR local ID ASSERT_EQ(0xEF31, keyState.getKeyID(0x15u, 0x1f2u)); // VK_HANGUL from Hangul key ASSERT_EQ(0xEF34, keyState.getKeyID(0x19u, 0x1f1u)); // VK_HANJA from Hanja key ASSERT_EQ(0xEF31, keyState.getKeyID(0x15u, 0x11du)); // VK_HANGUL from R-Alt key ASSERT_EQ(0xEF34, keyState.getKeyID(0x19u, 0x138u)); // VK_HANJA from R-Ctrl key keyState.setKeyLayout((HKL)0x00000411); // for ja-jp locale ID ASSERT_EQ(0xEF26, keyState.getKeyID(0x15u, 0x1du)); // VK_KANA ASSERT_EQ(0xEF2A, keyState.getKeyID(0x19u, 0x38u)); // VK_KANJI delete desks; } synergy-1.8.8-stable/src/test/integtests/platform/OSXClipboardTests.cpp000066400000000000000000000072531305627404700263220ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXClipboard.h" #include "test/global/gtest.h" #include TEST(OSXClipboardTests, empty_openCalled_returnsTrue) { OSXClipboard clipboard; clipboard.open(0); bool actual = clipboard.empty(); EXPECT_EQ(true, actual); } TEST(OSXClipboardTests, empty_singleFormat_hasReturnsFalse) { OSXClipboard clipboard; clipboard.open(0); clipboard.add(OSXClipboard::kText, "synergy rocks!"); clipboard.empty(); bool actual = clipboard.has(OSXClipboard::kText); EXPECT_EQ(false, actual); } TEST(OSXClipboardTests, add_newValue_valueWasStored) { OSXClipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("synergy rocks!", actual); } TEST(OSXClipboardTests, add_replaceValue_valueWasReplaced) { OSXClipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("maxivista sucks", actual); } TEST(OSXClipboardTests, open_timeIsZero_returnsTrue) { OSXClipboard clipboard; bool actual = clipboard.open(0); EXPECT_EQ(true, actual); } TEST(OSXClipboardTests, open_timeIsOne_returnsTrue) { OSXClipboard clipboard; bool actual = clipboard.open(1); EXPECT_EQ(true, actual); } TEST(OSXClipboardTests, close_isOpen_noErrors) { OSXClipboard clipboard; clipboard.open(0); clipboard.close(); // can't assert anything } TEST(OSXClipboardTests, getTime_openWithNoEmpty_returnsOne) { OSXClipboard clipboard; clipboard.open(1); OSXClipboard::Time actual = clipboard.getTime(); // this behavior is different to that of Clipboard which only // returns the value passed into open(t) after empty() is called. EXPECT_EQ((UInt32)1, actual); } TEST(OSXClipboardTests, getTime_openAndEmpty_returnsOne) { OSXClipboard clipboard; clipboard.open(1); clipboard.empty(); OSXClipboard::Time actual = clipboard.getTime(); EXPECT_EQ((UInt32)1, actual); } TEST(OSXClipboardTests, has_withFormatAdded_returnsTrue) { OSXClipboard clipboard; clipboard.open(0); clipboard.empty(); clipboard.add(IClipboard::kText, "synergy rocks!"); bool actual = clipboard.has(IClipboard::kText); EXPECT_EQ(true, actual); } TEST(OSXClipboardTests, has_withNoFormats_returnsFalse) { OSXClipboard clipboard; clipboard.open(0); clipboard.empty(); bool actual = clipboard.has(IClipboard::kText); EXPECT_EQ(false, actual); } TEST(OSXClipboardTests, get_withNoFormats_returnsEmpty) { OSXClipboard clipboard; clipboard.open(0); clipboard.empty(); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("", actual); } TEST(OSXClipboardTests, get_withFormatAdded_returnsExpected) { OSXClipboard clipboard; clipboard.open(0); clipboard.empty(); clipboard.add(IClipboard::kText, "synergy rocks!"); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("synergy rocks!", actual); } synergy-1.8.8-stable/src/test/integtests/platform/OSXKeyStateTests.cpp000066400000000000000000000064461305627404700261570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "test/mock/synergy/MockKeyMap.h" #include "test/mock/synergy/MockEventQueue.h" #include "platform/OSXKeyState.h" #include "base/Log.h" #include "test/global/gtest.h" #include "test/global/gmock.h" #define SHIFT_ID_L kKeyShift_L #define SHIFT_ID_R kKeyShift_R #define SHIFT_BUTTON 57 #define A_CHAR_ID 0x00000061 #define A_CHAR_BUTTON 001 class OSXKeyStateTests : public ::testing::Test { public: static bool isKeyPressed(const OSXKeyState& keyState, KeyButton button); }; // fakeAndPoll_shift seems to always fail on osx10.6 #if __MAC_OS_X_VERSION_MIN_REQUIRED > 1060 TEST_F(OSXKeyStateTests, fakeAndPoll_shift) { synergy::KeyMap keyMap; MockEventQueue eventQueue; OSXKeyState keyState(&eventQueue, keyMap); keyState.updateKeyMap(); keyState.fakeKeyDown(SHIFT_ID_L, 0, 1); EXPECT_TRUE(isKeyPressed(keyState, SHIFT_BUTTON)); keyState.fakeKeyUp(1); EXPECT_TRUE(!isKeyPressed(keyState, SHIFT_BUTTON)); keyState.fakeKeyDown(SHIFT_ID_R, 0, 2); EXPECT_TRUE(isKeyPressed(keyState, SHIFT_BUTTON)); keyState.fakeKeyUp(2); EXPECT_TRUE(!isKeyPressed(keyState, SHIFT_BUTTON)); } TEST_F(OSXKeyStateTests, fakeAndPoll_charKey) { synergy::KeyMap keyMap; MockEventQueue eventQueue; OSXKeyState keyState(&eventQueue, keyMap); keyState.updateKeyMap(); keyState.fakeKeyDown(A_CHAR_ID, 0, 1); EXPECT_TRUE(isKeyPressed(keyState, A_CHAR_BUTTON)); keyState.fakeKeyUp(1); EXPECT_TRUE(!isKeyPressed(keyState, A_CHAR_BUTTON)); // HACK: delete the key in case it was typed into a text editor. // we should really set focus to an invisible window. keyState.fakeKeyDown(kKeyBackSpace, 0, 2); keyState.fakeKeyUp(2); } TEST_F(OSXKeyStateTests, fakeAndPoll_charKeyAndModifier) { synergy::KeyMap keyMap; MockEventQueue eventQueue; OSXKeyState keyState(&eventQueue, keyMap); keyState.updateKeyMap(); keyState.fakeKeyDown(A_CHAR_ID, KeyModifierShift, 1); EXPECT_TRUE(isKeyPressed(keyState, A_CHAR_BUTTON)); keyState.fakeKeyUp(1); EXPECT_TRUE(!isKeyPressed(keyState, A_CHAR_BUTTON)); // HACK: delete the key in case it was typed into a text editor. // we should really set focus to an invisible window. keyState.fakeKeyDown(kKeyBackSpace, 0, 2); keyState.fakeKeyUp(2); } bool OSXKeyStateTests::isKeyPressed(const OSXKeyState& keyState, KeyButton button) { // HACK: allow os to realize key state changes. ARCH->sleep(.2); IKeyState::KeyButtonSet pressed; keyState.pollPressedKeys(pressed); IKeyState::KeyButtonSet::const_iterator it; for (it = pressed.begin(); it != pressed.end(); ++it) { LOG((CLOG_DEBUG "checking key %d", *it)); if (*it == button) { return true; } } return false; } #endif synergy-1.8.8-stable/src/test/integtests/platform/OSXScreenTests.cpp000066400000000000000000000025171305627404700256400ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "platform/OSXScreen.h" #include "arch/Arch.h" #include "base/EventQueue.h" #include "test/global/gtest.h" // disabling these tests - the return value of CGCursorIsVisible is unreliable. /* TEST(OSXScreenTests, hideCursor_notPrimary) { EventQueue queue; OSXScreen screen(true, false); screen.hideCursor(); EXPECT_EQ(false, CGCursorIsVisible()); // workaround for screen class race condition. ARCH->sleep(.1f); } TEST(OSXScreenTests, showCursor_notPrimary) { EventQueue queue; OSXScreen screen(false, false); screen.showCursor(); EXPECT_EQ(true, CGCursorIsVisible()); // workaround for screen class race condition. ARCH->sleep(.1f); } */ synergy-1.8.8-stable/src/test/integtests/platform/XWindowsClipboardTests.cpp000066400000000000000000000075571305627404700274420ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // TODO: fix tests - compile error on linux #if 0 #include "platform/XWindowsClipboard.h" #include "test/global/gtest.h" #include class CXWindowsClipboardTests : public ::testing::Test { protected: virtual void SetUp() { m_display = XOpenDisplay(NULL); int screen = DefaultScreen(m_display); Window root = XRootWindow(m_display, screen); XSetWindowAttributes attr; attr.do_not_propagate_mask = 0; attr.override_redirect = True; attr.cursor = Cursor(); m_window = XCreateWindow( m_display, root, 0, 0, 1, 1, 0, 0, InputOnly, CopyFromParent, 0, &attr); } virtual void TearDown() { XDestroyWindow(m_display, m_window); XCloseDisplay(m_display); } CXWindowsClipboard& createClipboard() { CXWindowsClipboard* clipboard; clipboard = new CXWindowsClipboard(m_display, m_window, 0); clipboard->open(0); // needed to empty the clipboard clipboard->empty(); // needed to own the clipboard return *clipboard; } Display* m_display; Window m_window; }; TEST_F(CXWindowsClipboardTests, empty_openCalled_returnsTrue) { CXWindowsClipboard clipboard = createClipboard(); bool actual = clipboard.empty(); EXPECT_EQ(true, actual); } TEST_F(CXWindowsClipboardTests, empty_singleFormat_hasReturnsFalse) { CXWindowsClipboard clipboard = createClipboard(); clipboard.add(CXWindowsClipboard::kText, "synergy rocks!"); clipboard.empty(); bool actual = clipboard.has(CXWindowsClipboard::kText); EXPECT_FALSE(actual); } TEST_F(CXWindowsClipboardTests, add_newValue_valueWasStored) { CXWindowsClipboard clipboard = createClipboard(); clipboard.add(IClipboard::kText, "synergy rocks!"); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("synergy rocks!", actual); } TEST_F(CXWindowsClipboardTests, add_replaceValue_valueWasReplaced) { CXWindowsClipboard clipboard = createClipboard(); clipboard.add(IClipboard::kText, "synergy rocks!"); clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("maxivista sucks", actual); } TEST_F(CXWindowsClipboardTests, close_isOpen_noErrors) { CXWindowsClipboard clipboard = createClipboard(); // clipboard opened in createClipboard() clipboard.close(); // can't assert anything } TEST_F(CXWindowsClipboardTests, has_withFormatAdded_returnsTrue) { CXWindowsClipboard clipboard = createClipboard(); clipboard.add(IClipboard::kText, "synergy rocks!"); bool actual = clipboard.has(IClipboard::kText); EXPECT_EQ(true, actual); } TEST_F(CXWindowsClipboardTests, has_withNoFormats_returnsFalse) { CXWindowsClipboard clipboard = createClipboard(); bool actual = clipboard.has(IClipboard::kText); EXPECT_FALSE(actual); } TEST_F(CXWindowsClipboardTests, get_withNoFormats_returnsEmpty) { CXWindowsClipboard clipboard = createClipboard(); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("", actual); } TEST_F(CXWindowsClipboardTests, get_withFormatAdded_returnsExpected) { CXWindowsClipboard clipboard = createClipboard(); clipboard.add(IClipboard::kText, "synergy rocks!"); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("synergy rocks!", actual); } #endif synergy-1.8.8-stable/src/test/integtests/platform/XWindowsKeyStateTests.cpp000066400000000000000000000133511305627404700272610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define TEST_ENV #include "test/mock/synergy/MockKeyMap.h" #include "test/mock/synergy/MockEventQueue.h" #include "platform/XWindowsKeyState.h" #include "base/Log.h" #define XK_LATIN1 #define XK_MISCELLANY #include #if HAVE_XKB_EXTENSION # include #endif #include "test/global/gtest.h" #include "test/global/gmock.h" #include class XWindowsKeyStateTests : public ::testing::Test { protected: XWindowsKeyStateTests() : m_display(NULL) { } ~XWindowsKeyStateTests() { if (m_display != NULL) { LOG((CLOG_DEBUG "closing display")); XCloseDisplay(m_display); } } virtual void SetUp() { // open the display only once for the entire test suite if (this->m_display == NULL) { LOG((CLOG_DEBUG "opening display")); this->m_display = XOpenDisplay(NULL); ASSERT_TRUE(this->m_display != NULL) << "unable to open display: " << errno; } } virtual void TearDown() { } Display* m_display; }; TEST_F(XWindowsKeyStateTests, setActiveGroup_pollAndSet_groupIsZero) { MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); keyState.setActiveGroup(XWindowsKeyState::kGroupPollAndSet); ASSERT_EQ(0, keyState.group()); } TEST_F(XWindowsKeyStateTests, setActiveGroup_poll_groupIsNotSet) { MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); keyState.setActiveGroup(XWindowsKeyState::kGroupPoll); ASSERT_LE(-1, keyState.group()); } TEST_F(XWindowsKeyStateTests, setActiveGroup_customGroup_groupWasSet) { MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); keyState.setActiveGroup(1); ASSERT_EQ(1, keyState.group()); } TEST_F(XWindowsKeyStateTests, mapModifiersFromX_zeroState_zeroMask) { MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); int mask = keyState.mapModifiersFromX(0); ASSERT_EQ(0, mask); } TEST_F(XWindowsKeyStateTests, mapModifiersToX_zeroMask_resultIsTrue) { MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); unsigned int modifiers = 0; bool result = keyState.mapModifiersToX(0, modifiers); ASSERT_TRUE(result); } TEST_F(XWindowsKeyStateTests, fakeCtrlAltDel_default_returnsFalse) { MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); bool result = keyState.fakeCtrlAltDel(); ASSERT_FALSE(result); } TEST_F(XWindowsKeyStateTests, pollActiveModifiers_defaultState_returnsZero) { MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); KeyModifierMask actual = keyState.pollActiveModifiers(); ASSERT_EQ(0, actual); } #if 0 // TODO: fix, causes sigsegv TEST_F(XWindowsKeyStateTests, pollActiveModifiers_shiftKeyDownThenUp_masksAreCorrect) { MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); // set mock modifier mapping std::fill(keyState.modifierFromX().begin(), keyState.modifierFromX().end(), 0); keyState.modifierFromX()[ShiftMapIndex] = KeyModifierShift; KeyCode key = XKeysymToKeycode(m_display, XK_Shift_L); // fake shift key down (without using synergy) XTestFakeKeyEvent(m_display, key, true, CurrentTime); // function under test (1st call) KeyModifierMask modDown = keyState.pollActiveModifiers(); // fake shift key up (without using synergy) XTestFakeKeyEvent(m_display, key, false, CurrentTime); // function under test (2nd call) KeyModifierMask modUp = keyState.pollActiveModifiers(); EXPECT_TRUE((modDown & KeyModifierShift) == KeyModifierShift) << "shift key not in mask - key was not pressed"; EXPECT_TRUE((modUp & KeyModifierShift) == 0) << "shift key still in mask - make sure no keys are being held down"; } #endif TEST_F(XWindowsKeyStateTests, pollActiveGroup_defaultState_returnsZero) { MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); SInt32 actual = keyState.pollActiveGroup(); ASSERT_EQ(0, actual); } TEST_F(XWindowsKeyStateTests, pollActiveGroup_positiveGroup_returnsGroup) { MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); keyState.group(3); SInt32 actual = keyState.pollActiveGroup(); ASSERT_EQ(3, actual); } TEST_F(XWindowsKeyStateTests, pollActiveGroup_xkb_areEqual) { #if HAVE_XKB_EXTENSION MockKeyMap keyMap; MockEventQueue eventQueue; XWindowsKeyState keyState( m_display, true, &eventQueue, keyMap); // reset the group keyState.group(-1); XkbStateRec state; // compare pollActiveGroup() with XkbGetState() if (XkbGetState(m_display, XkbUseCoreKbd, &state) == Success) { SInt32 actual = keyState.pollActiveGroup(); ASSERT_EQ(state.group, actual); } else { FAIL() << "XkbGetState() returned error " << errno; } #else SUCCEED() << "Xkb extension not installed"; #endif } synergy-1.8.8-stable/src/test/integtests/platform/XWindowsScreenSaverTests.cpp000066400000000000000000000026031305627404700277460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // TODO: fix tests #if 0 #include "test/mock/synergy/MockEventQueue.h" #include "platform/XWindowsScreenSaver.h" #include "test/global/gtest.h" #include using ::testing::_; // TODO: not working on build machine for some reason TEST(CXWindowsScreenSaverTests, activate_defaultScreen_todo) { Display* display = XOpenDisplay(":0.0"); Window window = DefaultRootWindow(display); MockEventQueue eventQueue; EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(1); CXWindowsScreenSaver screenSaver( display, window, NULL, &eventQueue); screenSaver.activate(); bool isActive = screenSaver.isActive(); screenSaver.deactivate(); ASSERT_EQ(true, isActive); } #endif synergy-1.8.8-stable/src/test/integtests/platform/XWindowsScreenTests.cpp000066400000000000000000000024411305627404700267450ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "test/mock/synergy/MockEventQueue.h" #include "platform/XWindowsScreen.h" #include "test/global/gtest.h" using ::testing::_; TEST(CXWindowsScreenTests, fakeMouseMove_nonPrimary_getCursorPosValuesCorrect) { MockEventQueue eventQueue; EXPECT_CALL(eventQueue, adoptHandler(_, _, _)).Times(2); EXPECT_CALL(eventQueue, adoptBuffer(_)).Times(2); EXPECT_CALL(eventQueue, removeHandler(_, _)).Times(2); XWindowsScreen screen( ":0.0", false, false, 0, &eventQueue); screen.fakeMouseMove(10, 20); int x, y; screen.getCursorPos(x, y); ASSERT_EQ(10, x); ASSERT_EQ(20, y); } synergy-1.8.8-stable/src/test/mock/000077500000000000000000000000001305627404700172075ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/mock/io/000077500000000000000000000000001305627404700176165ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/mock/io/MockStream.h000066400000000000000000000026541305627404700220430ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "io/IStream.h" #include "test/global/gmock.h" class IEventQueue; class MockStream : public synergy::IStream { public: MockStream() { } MOCK_METHOD0(close, void()); MOCK_METHOD2(read, UInt32(void*, UInt32)); MOCK_METHOD2(write, void(const void*, UInt32)); MOCK_METHOD0(flush, void()); MOCK_METHOD0(shutdownInput, void()); MOCK_METHOD0(shutdownOutput, void()); MOCK_METHOD0(getInputReadyEvent, Event::Type()); MOCK_METHOD0(getOutputErrorEvent, Event::Type()); MOCK_METHOD0(getInputShutdownEvent, Event::Type()); MOCK_METHOD0(getOutputShutdownEvent, Event::Type()); MOCK_CONST_METHOD0(getEventTarget, void*()); MOCK_CONST_METHOD0(isReady, bool()); MOCK_CONST_METHOD0(getSize, UInt32()); }; synergy-1.8.8-stable/src/test/mock/ipc/000077500000000000000000000000001305627404700177625ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/mock/ipc/MockIpcServer.h000066400000000000000000000032551305627404700226540ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "ipc/IpcServer.h" #include "ipc/IpcMessage.h" #include "arch/Arch.h" #include "test/global/gmock.h" using ::testing::_; using ::testing::Invoke; class IEventQueue; class MockIpcServer : public IpcServer { public: MockIpcServer() : m_sendCond(ARCH->newCondVar()), m_sendMutex(ARCH->newMutex()) { } ~MockIpcServer() { if (m_sendCond != NULL) { ARCH->closeCondVar(m_sendCond); } if (m_sendMutex != NULL) { ARCH->closeMutex(m_sendMutex); } } MOCK_METHOD0(listen, void()); MOCK_METHOD2(send, void(const IpcMessage&, EIpcClientType)); MOCK_CONST_METHOD1(hasClients, bool(EIpcClientType)); void delegateToFake() { ON_CALL(*this, send(_, _)).WillByDefault(Invoke(this, &MockIpcServer::mockSend)); } void waitForSend() { ARCH->waitCondVar(m_sendCond, m_sendMutex, 5); } private: void mockSend(const IpcMessage&, EIpcClientType) { ArchMutexLock lock(m_sendMutex); ARCH->broadcastCondVar(m_sendCond); } ArchCond m_sendCond; ArchMutex m_sendMutex; }; synergy-1.8.8-stable/src/test/mock/server/000077500000000000000000000000001305627404700205155ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/mock/server/MockConfig.h000066400000000000000000000016751305627404700227160ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #define TEST_ENV #include "server/Config.h" #include "test/global/gmock.h" class MockConfig : public Config { public: MockConfig() : Config() { } MOCK_METHOD0(getInputFilter, InputFilter*()); MOCK_CONST_METHOD1(isScreen, bool(const String&)); }; synergy-1.8.8-stable/src/test/mock/server/MockInputFilter.h000066400000000000000000000016041305627404700237460ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #define TEST_ENV #include "server/InputFilter.h" #include "test/global/gmock.h" class MockInputFilter : public InputFilter { public: MOCK_METHOD1(setPrimaryClient, void(PrimaryClient*)); }; synergy-1.8.8-stable/src/test/mock/server/MockPrimaryClient.h000066400000000000000000000025711305627404700242670ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #define TEST_ENV #include "server/PrimaryClient.h" #include "base/String.h" #include "test/global/gmock.h" class MockPrimaryClient : public PrimaryClient { public: MOCK_CONST_METHOD0(getEventTarget, void*()); MOCK_CONST_METHOD2(getCursorPos, void(SInt32&, SInt32&)); MOCK_CONST_METHOD2(setJumpCursorPos, void(SInt32, SInt32)); MOCK_METHOD1(reconfigure, void(UInt32)); MOCK_METHOD0(resetOptions, void()); MOCK_METHOD1(setOptions, void(const OptionsList&)); MOCK_METHOD0(enable, void()); MOCK_METHOD0(disable, void()); MOCK_METHOD2(registerHotKey, UInt32(KeyID, KeyModifierMask)); MOCK_CONST_METHOD0(getToggleMask, KeyModifierMask()); MOCK_METHOD1(unregisterHotKey, void(UInt32)); }; synergy-1.8.8-stable/src/test/mock/server/MockServer.h000066400000000000000000000015561305627404700227550ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #define TEST_ENV #include "server/Server.h" #include "test/global/gmock.h" class IEventQueue; class MockServer : public Server { public: MockServer() : Server() { } }; synergy-1.8.8-stable/src/test/mock/synergy/000077500000000000000000000000001305627404700207075ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/mock/synergy/MockApp.h000066400000000000000000000026471305627404700224230ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #define TEST_ENV #include "synergy/App.h" #include "test/global/gmock.h" class MockApp : public App { public: MockApp() : App(NULL, NULL, NULL) { } MOCK_METHOD0(help, void()); MOCK_METHOD0(loadConfig, void()); MOCK_METHOD1(loadConfig, bool(const String&)); MOCK_CONST_METHOD0(daemonInfo, const char*()); MOCK_CONST_METHOD0(daemonName, const char*()); MOCK_METHOD2(parseArgs, void(int, const char* const*)); MOCK_METHOD0(version, void()); MOCK_METHOD2(standardStartup, int(int, char**)); MOCK_METHOD4(runInner, int(int, char**, ILogOutputter*, StartupFunc)); MOCK_METHOD0(startNode, void()); MOCK_METHOD0(mainLoop, int()); MOCK_METHOD2(foregroundStartup, int(int, char**)); MOCK_METHOD0(createScreen, synergy::Screen*()); }; synergy-1.8.8-stable/src/test/mock/synergy/MockArgParser.h000066400000000000000000000017411305627404700235630ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #define TEST_ENV #include "synergy/ArgParser.h" #include "test/global/gmock.h" class MockArgParser : public ArgParser { public: MockArgParser() : ArgParser(NULL) { } MOCK_METHOD3(parseGenericArgs, bool(int, const char* const*, int&)); MOCK_METHOD0(checkUnexpectedArgs, bool()); }; synergy-1.8.8-stable/src/test/mock/synergy/MockEventQueue.h000066400000000000000000000055031305627404700237630ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "base/IEventQueue.h" #include "test/global/gmock.h" class MockEventQueue : public IEventQueue { public: MOCK_METHOD0(loop, void()); MOCK_METHOD2(newOneShotTimer, EventQueueTimer*(double, void*)); MOCK_METHOD2(newTimer, EventQueueTimer*(double, void*)); MOCK_METHOD2(getEvent, bool(Event&, double)); MOCK_METHOD1(adoptBuffer, void(IEventQueueBuffer*)); MOCK_METHOD2(registerTypeOnce, Event::Type(Event::Type&, const char*)); MOCK_METHOD1(removeHandlers, void(void*)); MOCK_METHOD1(registerType, Event::Type(const char*)); MOCK_CONST_METHOD0(isEmpty, bool()); MOCK_METHOD3(adoptHandler, void(Event::Type, void*, IEventJob*)); MOCK_METHOD1(getTypeName, const char*(Event::Type)); MOCK_METHOD1(addEvent, void(const Event&)); MOCK_METHOD2(removeHandler, void(Event::Type, void*)); MOCK_METHOD1(dispatchEvent, bool(const Event&)); MOCK_CONST_METHOD2(getHandler, IEventJob*(Event::Type, void*)); MOCK_METHOD1(deleteTimer, void(EventQueueTimer*)); MOCK_CONST_METHOD1(getRegisteredType, Event::Type(const String&)); MOCK_METHOD0(getSystemTarget, void*()); MOCK_METHOD0(forClient, ClientEvents&()); MOCK_METHOD0(forIStream, IStreamEvents&()); MOCK_METHOD0(forIpcClient, IpcClientEvents&()); MOCK_METHOD0(forIpcClientProxy, IpcClientProxyEvents&()); MOCK_METHOD0(forIpcServer, IpcServerEvents&()); MOCK_METHOD0(forIpcServerProxy, IpcServerProxyEvents&()); MOCK_METHOD0(forIDataSocket, IDataSocketEvents&()); MOCK_METHOD0(forIListenSocket, IListenSocketEvents&()); MOCK_METHOD0(forISocket, ISocketEvents&()); MOCK_METHOD0(forOSXScreen, OSXScreenEvents&()); MOCK_METHOD0(forClientListener, ClientListenerEvents&()); MOCK_METHOD0(forClientProxy, ClientProxyEvents&()); MOCK_METHOD0(forClientProxyUnknown, ClientProxyUnknownEvents&()); MOCK_METHOD0(forServer, ServerEvents&()); MOCK_METHOD0(forServerApp, ServerAppEvents&()); MOCK_METHOD0(forIKeyState, IKeyStateEvents&()); MOCK_METHOD0(forIPrimaryScreen, IPrimaryScreenEvents&()); MOCK_METHOD0(forIScreen, IScreenEvents&()); MOCK_METHOD0(forClipboard, ClipboardEvents&()); MOCK_METHOD0(forFile, FileEvents&()); MOCK_CONST_METHOD0(waitForReady, void()); }; synergy-1.8.8-stable/src/test/mock/synergy/MockKeyMap.h000066400000000000000000000023241305627404700230610ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/KeyMap.h" #include "test/global/gmock.h" class MockKeyMap : public synergy::KeyMap { public: MOCK_METHOD1(swap, void(KeyMap&)); MOCK_METHOD0(finish, void()); MOCK_METHOD2(foreachKey, void(ForeachKeyCallback, void*)); MOCK_METHOD1(addHalfDuplexModifier, void(KeyID)); MOCK_CONST_METHOD2(isHalfDuplex, bool(KeyID, KeyButton)); MOCK_CONST_METHOD7(mapKey, const KeyMap::KeyItem*( Keystrokes&, KeyID, SInt32, ModifierToKeys&, KeyModifierMask&, KeyModifierMask, bool)); }; synergy-1.8.8-stable/src/test/mock/synergy/MockKeyState.h000066400000000000000000000034221305627404700234240ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #include "synergy/KeyState.h" #include "test/global/gmock.h" class MockKeyMap; class MockEventQueue; // NOTE: do not mock methods that are not pure virtual. this mock exists only // to provide an implementation of the KeyState abstract class. class MockKeyState : public KeyState { public: MockKeyState(const MockEventQueue& eventQueue) : KeyState((IEventQueue*)&eventQueue) { } MockKeyState(const MockEventQueue& eventQueue, const MockKeyMap& keyMap) : KeyState((IEventQueue*)&eventQueue, (synergy::KeyMap&)keyMap) { } MOCK_CONST_METHOD0(pollActiveGroup, SInt32()); MOCK_CONST_METHOD0(pollActiveModifiers, KeyModifierMask()); MOCK_METHOD0(fakeCtrlAltDel, bool()); MOCK_METHOD1(getKeyMap, void(synergy::KeyMap&)); MOCK_METHOD1(fakeKey, void(const Keystroke&)); MOCK_METHOD1(fakeMediaKey, bool(KeyID)); MOCK_CONST_METHOD1(pollPressedKeys, void(KeyButtonSet&)); }; typedef ::testing::NiceMock KeyStateImpl; typedef UInt32 KeyID; typedef void (*ForeachKeyCallback)( KeyID, SInt32 group, synergy::KeyMap::KeyItem&, void* userData); synergy-1.8.8-stable/src/test/mock/synergy/MockScreen.h000066400000000000000000000022121305627404700231060ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2013-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #pragma once #define TEST_ENV #include "synergy/Screen.h" #include "test/global/gmock.h" class MockScreen : public synergy::Screen { public: MockScreen() : synergy::Screen() { } MOCK_METHOD0(disable, void()); MOCK_CONST_METHOD4(getShape, void(SInt32&, SInt32&, SInt32&, SInt32&)); MOCK_CONST_METHOD2(getCursorPos, void(SInt32&, SInt32&)); MOCK_METHOD0(resetOptions, void()); MOCK_METHOD1(setOptions, void(const OptionsList&)); MOCK_METHOD0(enable, void()); }; synergy-1.8.8-stable/src/test/unittests/000077500000000000000000000000001305627404700203205ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/unittests/CMakeLists.txt000066400000000000000000000042051305627404700230610ustar00rootroot00000000000000# synergy -- mouse and keyboard sharing utility # Copyright (C) 2012-2016 Symless Ltd. # Copyright (C) 2009 Nick Bolton # # 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 LICENSE 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. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . file(GLOB_RECURSE headers "*.h") file(GLOB_RECURSE sources "*.cpp") file(GLOB_RECURSE remove_platform "platform/*") list(REMOVE_ITEM headers ${remove_platform}) list(REMOVE_ITEM sources ${remove_platform}) file(GLOB_RECURSE global_headers "../../test/global/*.h") file(GLOB_RECURSE global_sources "../../test/global/*.cpp") list(APPEND headers ${global_headers}) list(APPEND sources ${global_sources}) file(GLOB_RECURSE mock_headers "../../test/mock/*.h") file(GLOB_RECURSE mock_sources "../../test/mock/*.cpp") list(APPEND headers ${mock_headers}) list(APPEND sources ${mock_sources}) # platform if (WIN32) file(GLOB platform_sources "platform/MSWindows*.cpp") file(GLOB platform_headers "platform/MSWindows*.h") elseif (APPLE) file(GLOB platform_sources "platform/OSX*.cpp") file(GLOB platform_headers "platform/OSX*.h") elseif (UNIX) file(GLOB platform_sources "platform/XWindows*.cpp") file(GLOB platform_headers "platform/XWindows*.h") endif() list(APPEND sources ${platform_headers}) list(APPEND headers ${platform_sources}) include_directories( ../../ ../../lib/ ../../../ext/gtest-1.6.0/include ../../../ext/gmock-1.6.0/include ../../../ext ) if (UNIX) include_directories( ../../.. ) endif() if (SYNERGY_ADD_HEADERS) list(APPEND sources ${headers}) endif() add_executable(unittests ${sources}) target_link_libraries(unittests arch base client server common io net platform server synergy mt ipc gtest gmock shared ${libs} ${OPENSSL_LIBS}) synergy-1.8.8-stable/src/test/unittests/Main.cpp000066400000000000000000000027531305627404700217170ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "arch/Arch.h" #include "base/Log.h" #if SYSAPI_WIN32 #include "arch/win32/ArchMiscWindows.h" #endif #include "test/global/gtest.h" int main(int argc, char **argv) { #if SYSAPI_WIN32 // HACK: shouldn't be needed, but logging fails without this. ArchMiscWindows::setInstanceWin32(GetModuleHandle(NULL)); #endif Arch arch; arch.init(); Log log; log.setFilter(kDEBUG4); testing::InitGoogleTest(&argc, argv); // gtest seems to randomly finish with error codes (e.g. -1, -1073741819) // even when no tests have failed. not sure what causes this, but it // happens on all platforms and keeps leading to false positives. // according to the documentation, 1 is a failure, so we should be // able to trust that code. return (RUN_ALL_TESTS() == 1) ? 1 : 0; } synergy-1.8.8-stable/src/test/unittests/base/000077500000000000000000000000001305627404700212325ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/unittests/base/StringTests.cpp000066400000000000000000000077511305627404700242410ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "base/String.h" #include "test/global/gtest.h" using namespace synergy; TEST(StringTests, format_formatWithArguments_formatedString) { const char* format = "%%%{1}=%{2}"; const char* arg1 = "answer"; const char* arg2 = "42"; String result = string::format(format, arg1, arg2); EXPECT_EQ("%answer=42", result); } TEST(StringTests, findReplaceAll_inputString_replacedString) { String subject = "foobar"; String find = "bar"; String replace = "baz"; string::findReplaceAll(subject, find, replace); EXPECT_EQ("foobaz", subject); } TEST(StringTests, sprintf_formatWithArgument_formatedString) { const char* format = "%s=%d"; const char* arg1 = "answer"; int arg2 = 42; String result = string::sprintf(format, arg1, arg2); EXPECT_EQ("answer=42", result); } TEST(StringTests, toHex_plaintext_hexString) { String subject = "foobar"; int width = 2; string::toHex(subject, width); EXPECT_EQ("666f6f626172", subject); } TEST(StringTests, uppercase_lowercaseInput_uppercaseOutput) { String subject = "12foo3BaR"; string::uppercase(subject); EXPECT_EQ("12FOO3BAR", subject); } TEST(StringTests, removeChar_inputString_removeAllSpecifiedCharactors) { String subject = "foobar"; const char c = 'o'; string::removeChar(subject, c); EXPECT_EQ("fbar", subject); } TEST(StringTests, intToString_inputInt_outputString) { size_t value = 123; String number = string::sizeTypeToString(value); EXPECT_EQ("123", number); } TEST(StringTests, stringToUint_inputString_outputInt) { String number = "123"; size_t value = string::stringToSizeType(number); EXPECT_EQ(123, value); } TEST(StringTests, splitString_twoSeparator_returnThreeParts) { String string = "stub1:stub2:stub3"; std::vector results = string::splitString(string, ':'); EXPECT_EQ(3, results.size()); EXPECT_EQ("stub1", results[0]); EXPECT_EQ("stub2", results[1]); EXPECT_EQ("stub3", results[2]); } TEST(StringTests, splitString_oneSeparator_returnTwoParts) { String string = "stub1:stub2"; std::vector results = string::splitString(string, ':'); EXPECT_EQ(2, results.size()); EXPECT_EQ("stub1", results[0]); EXPECT_EQ("stub2", results[1]); } TEST(StringTests, splitString_noSeparator_returnOriginalString) { String string = "stub1"; std::vector results = string::splitString(string, ':'); EXPECT_EQ(1, results.size()); EXPECT_EQ("stub1", results[0]); } TEST(StringTests, splitString_emptyString_returnEmptyVector) { String string; std::vector results = string::splitString(string, ':'); EXPECT_EQ(0, results.size()); } TEST(StringTests, splitString_tailSeparator_returnTwoParts) { String string = "stub1:stub2:"; std::vector results = string::splitString(string, ':'); EXPECT_EQ(2, results.size()); EXPECT_EQ("stub1", results[0]); EXPECT_EQ("stub2", results[1]); } TEST(StringTests, splitString_headSeparator_returnTwoParts) { String string = ":stub1:stub2"; std::vector results = string::splitString(string, ':'); EXPECT_EQ(2, results.size()); EXPECT_EQ("stub1", results[0]); EXPECT_EQ("stub2", results[1]); } TEST(StringTests, splitString_headAndTailSeparators_returnTwoParts) { String string = ":stub1:stub2:"; std::vector results = string::splitString(string, ':'); EXPECT_EQ(2, results.size()); EXPECT_EQ("stub1", results[0]); EXPECT_EQ("stub2", results[1]); } synergy-1.8.8-stable/src/test/unittests/ipc/000077500000000000000000000000001305627404700210735ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/unittests/ipc/IpcLogOutputterTests.cpp000066400000000000000000000122331305627404700257340ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define TEST_ENV #include "test/mock/ipc/MockIpcServer.h" #include "mt/Thread.h" #include "ipc/IpcLogOutputter.h" #include "base/String.h" #include "common/common.h" #include "test/global/gmock.h" #include "test/global/gtest.h" // HACK: ipc logging only used on windows anyway #if WINAPI_MSWINDOWS using ::testing::_; using ::testing::Return; using ::testing::Matcher; using ::testing::MatcherCast; using ::testing::Property; using ::testing::StrEq; using ::testing::AtLeast; using namespace synergy; inline const Matcher IpcLogLineMessageEq(const String& s) { const Matcher m( Property(&IpcLogLineMessage::logLine, StrEq(s))); return MatcherCast(m); } TEST(IpcLogOutputterTests, write_threadingEnabled_bufferIsSent) { MockIpcServer mockServer; mockServer.delegateToFake(); ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); EXPECT_CALL(mockServer, hasClients(_)).Times(AtLeast(3)); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\n"), _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\n"), _)).Times(1); IpcLogOutputter outputter(mockServer, kIpcClientUnknown, true); outputter.write(kNOTE, "mock 1"); mockServer.waitForSend(); outputter.write(kNOTE, "mock 2"); mockServer.waitForSend(); } TEST(IpcLogOutputterTests, write_overBufferMaxSize_firstLineTruncated) { MockIpcServer mockServer; ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); EXPECT_CALL(mockServer, hasClients(_)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 2\nmock 3\n"), _)).Times(1); IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); outputter.bufferMaxSize(2); // log more lines than the buffer can contain outputter.write(kNOTE, "mock 1"); outputter.write(kNOTE, "mock 2"); outputter.write(kNOTE, "mock 3"); outputter.sendBuffer(); } TEST(IpcLogOutputterTests, write_underBufferMaxSize_allLinesAreSent) { MockIpcServer mockServer; ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); EXPECT_CALL(mockServer, hasClients(_)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), _)).Times(1); IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); outputter.bufferMaxSize(2); // log more lines than the buffer can contain outputter.write(kNOTE, "mock 1"); outputter.write(kNOTE, "mock 2"); outputter.sendBuffer(); } // HACK: temporarily disable this intermittently failing unit test. // when the build machine is under heavy load, a race condition // usually happens. #if 0 TEST(IpcLogOutputterTests, write_overBufferRateLimit_lastLineTruncated) { MockIpcServer mockServer; ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); EXPECT_CALL(mockServer, hasClients(_)).Times(2); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 4\nmock 5\n"), _)).Times(1); IpcLogOutputter outputter(mockServer, false); outputter.bufferRateLimit(2, 1); // 1s // log 1 more line than the buffer can accept in time limit. outputter.write(kNOTE, "mock 1"); outputter.write(kNOTE, "mock 2"); outputter.write(kNOTE, "mock 3"); outputter.sendBuffer(); // after waiting the time limit send another to make sure // we can log after the time limit passes. // HACK: sleep causes the unit test to fail intermittently, // so lets try 100ms (there must be a better way to solve this) ARCH->sleep(2); // 2s outputter.write(kNOTE, "mock 4"); outputter.write(kNOTE, "mock 5"); outputter.write(kNOTE, "mock 6"); outputter.sendBuffer(); } #endif TEST(IpcLogOutputterTests, write_underBufferRateLimit_allLinesAreSent) { MockIpcServer mockServer; ON_CALL(mockServer, hasClients(_)).WillByDefault(Return(true)); EXPECT_CALL(mockServer, hasClients(_)).Times(2); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 1\nmock 2\n"), _)).Times(1); EXPECT_CALL(mockServer, send(IpcLogLineMessageEq("mock 3\nmock 4\n"), _)).Times(1); IpcLogOutputter outputter(mockServer, kIpcClientUnknown, false); outputter.bufferRateLimit(4, 1); // 1s (should be plenty of time) // log 1 more line than the buffer can accept in time limit. outputter.write(kNOTE, "mock 1"); outputter.write(kNOTE, "mock 2"); outputter.sendBuffer(); // after waiting the time limit send another to make sure // we can log after the time limit passes. outputter.write(kNOTE, "mock 3"); outputter.write(kNOTE, "mock 4"); outputter.sendBuffer(); } #endif // WINAPI_MSWINDOWS synergy-1.8.8-stable/src/test/unittests/platform/000077500000000000000000000000001305627404700221445ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/unittests/platform/OSXKeyStateTests.cpp000066400000000000000000000036501305627404700260220ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "test/mock/synergy/MockKeyMap.h" #include "test/mock/synergy/MockEventQueue.h" #include "platform/OSXKeyState.h" #include "test/global/gtest.h" #include "test/global/gmock.h" TEST(OSXKeyStateTests, mapModifiersFromOSX_OSXMask_returnSynergyMask) { synergy::KeyMap keyMap; MockEventQueue eventQueue; OSXKeyState keyState(&eventQueue, keyMap); KeyModifierMask outMask = 0; UInt32 shiftMask = 0 | kCGEventFlagMaskShift; outMask = keyState.mapModifiersFromOSX(shiftMask); EXPECT_EQ(KeyModifierShift, outMask); UInt32 ctrlMask = 0 | kCGEventFlagMaskControl; outMask = keyState.mapModifiersFromOSX(ctrlMask); EXPECT_EQ(KeyModifierControl, outMask); UInt32 altMask = 0 | kCGEventFlagMaskAlternate; outMask = keyState.mapModifiersFromOSX(altMask); EXPECT_EQ(KeyModifierAlt, outMask); UInt32 cmdMask = 0 | kCGEventFlagMaskCommand; outMask = keyState.mapModifiersFromOSX(cmdMask); EXPECT_EQ(KeyModifierSuper, outMask); UInt32 capsMask = 0 | kCGEventFlagMaskAlphaShift; outMask = keyState.mapModifiersFromOSX(capsMask); EXPECT_EQ(KeyModifierCapsLock, outMask); UInt32 numMask = 0 | kCGEventFlagMaskNumericPad; outMask = keyState.mapModifiersFromOSX(numMask); EXPECT_EQ(KeyModifierNumLock, outMask); } synergy-1.8.8-stable/src/test/unittests/shared/000077500000000000000000000000001305627404700215665ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/unittests/shared/SerialKeyTests.cpp000066400000000000000000000116331305627404700252110ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless Inc. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #define TEST_ENV #include "shared/SerialKey.h" #include "test/global/gtest.h" TEST(SerialKeyTests, decode_empty_returnEmptyString) { std::string plainText = SerialKey::decode(""); EXPECT_EQ(0, plainText.size()); } TEST(SerialKeyTests, decode_invalidDigit_returnEmptyString) { std::string plainText = SerialKey::decode("MOCKZ"); EXPECT_EQ(0, plainText.size()); } TEST(SerialKeyTests, decode_validSerial_returnPlainText) { std::string plainText = SerialKey::decode("53796E6572677920726F636B7321"); EXPECT_EQ("Synergy rocks!", plainText); } TEST(SerialKeyTests, parse_noParty_invalid) { SerialKey serial; bool r = serial.parse("MOCK"); EXPECT_FALSE(r); } TEST(SerialKeyTests, parse_invalidPartsLenghth_invalid) { SerialKey serial; bool r = serial.parse("{Synergy;Rocks}"); EXPECT_FALSE(r); } TEST(SerialKeyTests, parse_validV1Serial_valid) { SerialKey serial; bool r = serial.parse("{v1;basic;Bob;1;email;company name;0;86400}"); EXPECT_EQ(true, r); EXPECT_EQ(kBasic, serial.edition()); EXPECT_FALSE(serial.isExpired(0)); EXPECT_EQ(true, serial.daysLeft(0)); EXPECT_FALSE(serial.isExpiring(1)); } TEST(SerialKeyTests, parse_validV2Serial_valid) { SerialKey serial; bool r = serial.parse("{v2;trial;pro;Bob;1;email;company name;0;86400}"); EXPECT_EQ(true, r); EXPECT_EQ(kPro, serial.edition()); EXPECT_FALSE(serial.isExpired(0)); EXPECT_EQ(true, serial.daysLeft(0)); EXPECT_EQ(true, serial.isExpiring(1)); EXPECT_EQ(true, serial.isTrial()); } TEST(SerialKeyTests, isExpiring_validV2TrialBasicSerial_returnFalse) { // {v2;trial;basic;Bob;1;email;company name;1;86400} SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B313B38363430307D"); EXPECT_EQ(true, serial.isTrial()); EXPECT_FALSE(serial.isExpiring(0)); EXPECT_EQ(kBasic, serial.edition()); } TEST(SerialKeyTests, isExpiring_expiringV2TrialBasicSerial_returnTrue) { // {v2;trial;basic;Bob;1;email;company name;0;86400} SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); EXPECT_EQ(true, serial.isTrial()); EXPECT_EQ(true, serial.isExpiring(1)); } TEST(SerialKeyTests, isExpiring_expiredV2TrialBasicSerial_returnFalse) { // {v2;trial;basic;Bob;1;email;company name;0;86400} SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); EXPECT_EQ(true, serial.isTrial()); EXPECT_FALSE(serial.isExpiring(86401)); } TEST(SerialKeyTests, isExpired_validV2TrialBasicSerial_returnFalse) { // {v2;trial;basic;Bob;1;email;company name;0;86400} SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); EXPECT_EQ(true, serial.isTrial()); EXPECT_FALSE(serial.isExpired(0)); } TEST(SerialKeyTests, isExpired_expiringV2TrialBasicSerial_returnFalse) { // {v2;trial;basic;Bob;1;email;company name;0;86400} SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); EXPECT_EQ(true, serial.isTrial()); EXPECT_FALSE(serial.isExpired(1)); } TEST(SerialKeyTests, isExpired_expiredV2TrialBasicSerial_returnTrue) { // {v2;trial;basic;Bob;1;email;company name;0;86400} SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); EXPECT_EQ(true, serial.isTrial()); EXPECT_EQ(true, serial.isExpired(86401)); } TEST(SerialKeyTests, daysLeft_validExactlyOneDayV2TrialBasicSerial_returnOne) { // {v2;trial;basic;Bob;1;email;company name;0;86400} SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); EXPECT_EQ(1, serial.daysLeft(0)); } TEST(SerialKeyTests, daysLeft_validWithinOneDayV2TrialBasicSerial_returnOne) { // {v2;trial;basic;Bob;1;email;company name;0;86400} SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); EXPECT_EQ(1, serial.daysLeft(1)); } TEST(SerialKeyTests, daysLeft_expiredV2TrialBasicSerial_returnZero) { // {v2;trial;basic;Bob;1;email;company name;0;86400} SerialKey serial("7B76323B747269616C3B62617369633B426F623B313B656D61696C3B636F6D70616E79206E616D653B303B38363430307D"); EXPECT_EQ(0, serial.daysLeft(86401)); } synergy-1.8.8-stable/src/test/unittests/synergy/000077500000000000000000000000001305627404700220205ustar00rootroot00000000000000synergy-1.8.8-stable/src/test/unittests/synergy/ArgParserTests.cpp000066400000000000000000000120561305627404700254410ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ArgParser.h" #include "synergy/ArgsBase.h" #include "test/global/gtest.h" TEST(ArgParserTests, isArg_abbreviationsArg_returnTrue) { int i = 1; const int argc = 2; const char* argv[argc] = { "stub", "-t" }; bool result = ArgParser::isArg(i, argc, argv, "-t", NULL); EXPECT_EQ(true, result); } TEST(ArgParserTests, isArg_fullArg_returnTrue) { int i = 1; const int argc = 2; const char* argv[argc] = { "stub", "--test" }; bool result = ArgParser::isArg(i, argc, argv, NULL, "--test"); EXPECT_EQ(true, result); } TEST(ArgParserTests, isArg_missingArgs_returnFalse) { int i = 1; const int argc = 2; const char* argv[argc] = { "stub", "-t" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); bool result = ArgParser::isArg(i, argc, argv, "-t", NULL, 1); EXPECT_FALSE(result); EXPECT_EQ(true, argsBase.m_shouldExit); } TEST(ArgParserTests, searchDoubleQuotes_doubleQuotedArg_returnTrue) { String command("\"stub\""); size_t left = 0; size_t right = 0; bool result = ArgParser::searchDoubleQuotes(command, left, right); EXPECT_EQ(true, result); EXPECT_EQ(0, left); EXPECT_EQ(5, right); } TEST(ArgParserTests, searchDoubleQuotes_noDoubleQuotedArg_returnfalse) { String command("stub"); size_t left = 0; size_t right = 0; bool result = ArgParser::searchDoubleQuotes(command, left, right); EXPECT_FALSE(result); EXPECT_EQ(0, left); EXPECT_EQ(0, right); } TEST(ArgParserTests, searchDoubleQuotes_oneDoubleQuoteArg_returnfalse) { String command("\"stub"); size_t left = 0; size_t right = 0; bool result = ArgParser::searchDoubleQuotes(command, left, right); EXPECT_FALSE(result); EXPECT_EQ(0, left); EXPECT_EQ(0, right); } TEST(ArgParserTests, splitCommandString_oneArg_returnArgv) { String command("stub"); std::vector argv; ArgParser::splitCommandString(command, argv); EXPECT_EQ(1, argv.size()); EXPECT_EQ("stub", argv.at(0)); } TEST(ArgParserTests, splitCommandString_twoArgs_returnArgv) { String command("stub1 stub2"); std::vector argv; ArgParser::splitCommandString(command, argv); EXPECT_EQ(2, argv.size()); EXPECT_EQ("stub1", argv.at(0)); EXPECT_EQ("stub2", argv.at(1)); } TEST(ArgParserTests, splitCommandString_doubleQuotedArgs_returnArgv) { String command("\"stub1\" stub2 \"stub3\""); std::vector argv; ArgParser::splitCommandString(command, argv); EXPECT_EQ(3, argv.size()); EXPECT_EQ("stub1", argv.at(0)); EXPECT_EQ("stub2", argv.at(1)); EXPECT_EQ("stub3", argv.at(2)); } TEST(ArgParserTests, splitCommandString_spaceDoubleQuotedArgs_returnArgv) { String command("\"stub1\" stub2 \"stub3 space\""); std::vector argv; ArgParser::splitCommandString(command, argv); EXPECT_EQ(3, argv.size()); EXPECT_EQ("stub1", argv.at(0)); EXPECT_EQ("stub2", argv.at(1)); EXPECT_EQ("stub3 space", argv.at(2)); } TEST(ArgParserTests, getArgv_stringArray_return2DArray) { std::vector argArray; argArray.push_back("stub1"); argArray.push_back("stub2"); argArray.push_back("stub3 space"); const char** argv = ArgParser::getArgv(argArray); String row1(argv[0]); String row2(argv[1]); String row3(argv[2]); EXPECT_EQ("stub1", row1); EXPECT_EQ("stub2", row2); EXPECT_EQ("stub3 space", row3); delete[] argv; } TEST(ArgParserTests, assembleCommand_stringArray_returnCommand) { std::vector argArray; argArray.push_back("stub1"); argArray.push_back("stub2"); String command = ArgParser::assembleCommand(argArray); EXPECT_EQ("stub1 stub2", command); } TEST(ArgParserTests, assembleCommand_ignoreSecondArg_returnCommand) { std::vector argArray; argArray.push_back("stub1"); argArray.push_back("stub2"); String command = ArgParser::assembleCommand(argArray, "stub2"); EXPECT_EQ("stub1", command); } TEST(ArgParserTests, assembleCommand_ignoreSecondArgWithOneParameter_returnCommand) { std::vector argArray; argArray.push_back("stub1"); argArray.push_back("stub2"); argArray.push_back("stub3"); argArray.push_back("stub4"); String command = ArgParser::assembleCommand(argArray, "stub2", 1); EXPECT_EQ("stub1 stub4", command); } TEST(ArgParserTests, assembleCommand_stringArrayWithSpace_returnCommand) { std::vector argArray; argArray.push_back("stub1 space"); argArray.push_back("stub2"); argArray.push_back("stub3 space"); String command = ArgParser::assembleCommand(argArray); EXPECT_EQ("\"stub1 space\" stub2 \"stub3 space\"", command); } synergy-1.8.8-stable/src/test/unittests/synergy/ClientArgsParsingTests.cpp000066400000000000000000000061471305627404700271360ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ArgParser.h" #include "synergy/ClientArgs.h" #include "test/mock/synergy/MockArgParser.h" #include "test/global/gtest.h" using ::testing::_; using ::testing::Invoke; using ::testing::NiceMock; bool client_stubParseGenericArgs(int, const char* const*, int&) { return false; } bool client_stubCheckUnexpectedArgs() { return false; } TEST(ClientArgsParsingTests, parseClientArgs_yScrollArg_setYScroll) { NiceMock argParser; ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); ClientArgs clientArgs; const int argc = 3; const char* kYScrollCmd[argc] = { "stub", "--yscroll", "1" }; argParser.parseClientArgs(clientArgs, argc, kYScrollCmd); EXPECT_EQ(1, clientArgs.m_yscroll); } TEST(ClientArgsParsingTests, parseClientArgs_addressArg_setSynergyAddress) { NiceMock argParser; ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); ClientArgs clientArgs; const int argc = 2; const char* kAddressCmd[argc] = { "stub", "mock_address" }; bool result = argParser.parseClientArgs(clientArgs, argc, kAddressCmd); EXPECT_EQ("mock_address", clientArgs.m_synergyAddress); EXPECT_EQ(true, result); } TEST(ClientArgsParsingTests, parseClientArgs_noAddressArg_returnFalse) { NiceMock argParser; ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); ClientArgs clientArgs; const int argc = 1; const char* kNoAddressCmd[argc] = { "stub" }; bool result = argParser.parseClientArgs(clientArgs, argc, kNoAddressCmd); EXPECT_FALSE(result); } TEST(ClientArgsParsingTests, parseClientArgs_unrecognizedArg_returnFalse) { NiceMock argParser; ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs)); ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs)); ClientArgs clientArgs; const int argc = 3; const char* kUnrecognizedCmd[argc] = { "stub", "mock_arg", "mock_address"}; bool result = argParser.parseClientArgs(clientArgs, argc, kUnrecognizedCmd); EXPECT_FALSE(result); } synergy-1.8.8-stable/src/test/unittests/synergy/ClipboardChunkTests.cpp000066400000000000000000000046451305627404700264500ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ClipboardChunk.h" #include "synergy/protocol_types.h" #include "test/global/gtest.h" TEST(ClipboardChunkTests, start_formatStartChunk) { ClipboardID id = 0; UInt32 sequence = 0; String mockDataSize("10"); ClipboardChunk* chunk = ClipboardChunk::start(id, sequence, mockDataSize); UInt32 temp_m_chunk; memcpy(&temp_m_chunk, &(chunk->m_chunk[1]), 4); EXPECT_EQ(id, chunk->m_chunk[0]); EXPECT_EQ(sequence, temp_m_chunk); EXPECT_EQ(kDataStart, chunk->m_chunk[5]); EXPECT_EQ('1', chunk->m_chunk[6]); EXPECT_EQ('0', chunk->m_chunk[7]); EXPECT_EQ('\0', chunk->m_chunk[8]); delete chunk; } TEST(ClipboardChunkTests, data_formatDataChunk) { ClipboardID id = 0; UInt32 sequence = 1; String mockData("mock data"); ClipboardChunk* chunk = ClipboardChunk::data(id, sequence, mockData); UInt32 temp_m_chunk; memcpy(&temp_m_chunk, &(chunk->m_chunk[1]), 4); EXPECT_EQ(id, chunk->m_chunk[0]); EXPECT_EQ(sequence, temp_m_chunk); EXPECT_EQ(kDataChunk, chunk->m_chunk[5]); EXPECT_EQ('m', chunk->m_chunk[6]); EXPECT_EQ('o', chunk->m_chunk[7]); EXPECT_EQ('c', chunk->m_chunk[8]); EXPECT_EQ('k', chunk->m_chunk[9]); EXPECT_EQ(' ', chunk->m_chunk[10]); EXPECT_EQ('d', chunk->m_chunk[11]); EXPECT_EQ('a', chunk->m_chunk[12]); EXPECT_EQ('t', chunk->m_chunk[13]); EXPECT_EQ('a', chunk->m_chunk[14]); EXPECT_EQ('\0', chunk->m_chunk[15]); delete chunk; } TEST(ClipboardChunkTests, end_formatDataChunk) { ClipboardID id = 1; UInt32 sequence = 1; ClipboardChunk* chunk = ClipboardChunk::end(id, sequence); UInt32 temp_m_chunk; memcpy(&temp_m_chunk, &(chunk->m_chunk[1]), 4); EXPECT_EQ(id, chunk->m_chunk[0]); EXPECT_EQ(sequence, temp_m_chunk); EXPECT_EQ(kDataEnd, chunk->m_chunk[5]); EXPECT_EQ('\0', chunk->m_chunk[6]); delete chunk; } synergy-1.8.8-stable/src/test/unittests/synergy/ClipboardTests.cpp000066400000000000000000000237051305627404700254550ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/Clipboard.h" #include "test/global/gtest.h" TEST(ClipboardTests, empty_openCalled_returnsTrue) { Clipboard clipboard; clipboard.open(0); bool actual = clipboard.empty(); EXPECT_EQ(true, actual); } TEST(ClipboardTests, empty_singleFormat_hasReturnsFalse) { Clipboard clipboard; clipboard.open(0); clipboard.add(Clipboard::kText, "synergy rocks!"); clipboard.empty(); bool actual = clipboard.has(Clipboard::kText); EXPECT_FALSE(actual); } TEST(ClipboardTests, add_newValue_valueWasStored) { Clipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("synergy rocks!", actual); } TEST(ClipboardTests, add_replaceValue_valueWasReplaced) { Clipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); clipboard.add(IClipboard::kText, "maxivista sucks"); // haha, just kidding. String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("maxivista sucks", actual); } TEST(ClipboardTests, open_timeIsZero_returnsTrue) { Clipboard clipboard; bool actual = clipboard.open(0); EXPECT_EQ(true, actual); } TEST(ClipboardTests, open_timeIsOne_returnsTrue) { Clipboard clipboard; bool actual = clipboard.open(1); EXPECT_EQ(true, actual); } TEST(ClipboardTests, close_isOpen_noErrors) { Clipboard clipboard; clipboard.open(0); clipboard.close(); // can't assert anything } TEST(ClipboardTests, getTime_openWithNoEmpty_returnsZero) { Clipboard clipboard; clipboard.open(1); Clipboard::Time actual = clipboard.getTime(); EXPECT_EQ(0, actual); } TEST(ClipboardTests, getTime_openAndEmpty_returnsOne) { Clipboard clipboard; clipboard.open(1); clipboard.empty(); Clipboard::Time actual = clipboard.getTime(); EXPECT_EQ(1, actual); } TEST(ClipboardTests, has_withFormatAdded_returnsTrue) { Clipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); bool actual = clipboard.has(IClipboard::kText); EXPECT_EQ(true, actual); } TEST(ClipboardTests, has_withNoFormats_returnsFalse) { Clipboard clipboard; clipboard.open(0); bool actual = clipboard.has(IClipboard::kText); EXPECT_FALSE(actual); } TEST(ClipboardTests, get_withNoFormats_returnsEmpty) { Clipboard clipboard; clipboard.open(0); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("", actual); } TEST(ClipboardTests, get_withFormatAdded_returnsExpected) { Clipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("synergy rocks!", actual); } TEST(ClipboardTests, marshall_addNotCalled_firstCharIsZero) { Clipboard clipboard; String actual = clipboard.marshall(); // seems to return "\0\0\0\0" but EXPECT_EQ can't assert this, // so instead, just assert that first char is '\0'. EXPECT_EQ(0, (int)actual[0]); } TEST(ClipboardTests, marshall_withTextAdded_typeCharIsText) { Clipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); clipboard.close(); String actual = clipboard.marshall(); // string contains other data, but 8th char should be kText. EXPECT_EQ(IClipboard::kText, (int)actual[7]); } TEST(ClipboardTests, marshall_withTextAdded_lastSizeCharIs14) { Clipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); // 14 chars clipboard.close(); String actual = clipboard.marshall(); EXPECT_EQ(14, (int)actual[11]); } // TODO: there's some integer -> char encoding going on here. i find it // hard to believe that the clipboard is the only thing doing this. maybe // we should refactor this stuff out of the clipboard. TEST(ClipboardTests, marshall_withTextSize285_sizeCharsValid) { // 285 chars String data; data.append("Synergy is Free and Open Source Software that lets you "); data.append("easily share your mouse and keyboard between multiple "); data.append("computers, where each computer has it's own display. No "); data.append("special hardware is required, all you need is a local area "); data.append("network. Synergy is supported on Windows, Mac OS X and Linux."); Clipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, data); clipboard.close(); String actual = clipboard.marshall(); // 4 asserts here, but that's ok because we're really just asserting 1 // thing. the 32-bit size value is split into 4 chars. if the size is 285 // (29 more than the 8-bit max size), the last char "rolls over" to 29 // (this is caused by a bit-wise & on 0xff and 8-bit truncation). each // char before the last stores a bit-shifted version of the number, each // 1 more power than the last, which is done by bit-shifting [0] by 24, // [1] by 16, [2] by 8 ([3] is not bit-shifted). EXPECT_EQ(0, actual[8]); // 285 >> 24 = 285 / (256^3) = 0 EXPECT_EQ(0, actual[9]); // 285 >> 16 = 285 / (256^2) = 0 EXPECT_EQ(1, actual[10]); // 285 >> 8 = 285 / (256^1) = 1(.11328125) EXPECT_EQ(29, actual[11]); // 285 - 256 = 29 } TEST(ClipboardTests, marshall_withHtmlAdded_typeCharIsHtml) { Clipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kHTML, "html sucks"); clipboard.close(); String actual = clipboard.marshall(); // string contains other data, but 8th char should be kHTML. EXPECT_EQ(IClipboard::kHTML, (int)actual[7]); } TEST(ClipboardTests, marshall_withHtmlAndText_has2Formats) { Clipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks"); clipboard.add(IClipboard::kHTML, "html sucks"); clipboard.close(); String actual = clipboard.marshall(); // the number of formats is stored inside the first 4 chars. // the writeUInt32 function right-aligns numbers in 4 chars, // so if you right align 2, it will be "\0\0\0\2" in a string. // we assert that the char at the 4th index is 2 (the number of // formats that we've added). EXPECT_EQ(2, (int)actual[3]); } TEST(ClipboardTests, marshall_withTextAdded_endsWithAdded) { Clipboard clipboard; clipboard.open(0); clipboard.add(IClipboard::kText, "synergy rocks!"); clipboard.close(); String actual = clipboard.marshall(); // string contains other data, but should end in the string we added. EXPECT_EQ("synergy rocks!", actual.substr(12)); } TEST(ClipboardTests, unmarshall_emptyData_hasTextIsFalse) { Clipboard clipboard; String data; data += (char)0; data += (char)0; data += (char)0; data += (char)0; // 0 formats added clipboard.unmarshall(data, 0); clipboard.open(0); bool actual = clipboard.has(IClipboard::kText); EXPECT_FALSE(actual); } TEST(ClipboardTests, unmarshall_withTextSize285_getTextIsValid) { Clipboard clipboard; // 285 chars String text; text.append("Synergy is Free and Open Source Software that lets you "); text.append("easily share your mouse and keyboard between multiple "); text.append("computers, where each computer has it's own display. No "); text.append("special hardware is required, all you need is a local area "); text.append("network. Synergy is supported on Windows, Mac OS X and Linux."); String data; data += (char)0; data += (char)0; data += (char)0; data += (char)1; // 1 format added data += (char)0; data += (char)0; data += (char)0; data += (char)IClipboard::kText; data += (char)0; // 285 >> 24 = 285 / (256^3) = 0 data += (char)0; // 285 >> 16 = 285 / (256^2) = 0 data += (char)1; // 285 >> 8 = 285 / (256^1) = 1(.11328125) data += (char)29; // 285 - 256 = 29 data += text; clipboard.unmarshall(data, 0); clipboard.open(0); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ(text, actual); } TEST(ClipboardTests, unmarshall_withTextAndHtml_getTextIsValid) { Clipboard clipboard; String data; data += (char)0; data += (char)0; data += (char)0; data += (char)2; // 2 formats added data += (char)0; data += (char)0; data += (char)0; data += (char)IClipboard::kText; data += (char)0; data += (char)0; data += (char)0; data += (char)14; data += "synergy rocks!"; data += (char)0; data += (char)0; data += (char)0; data += (char)IClipboard::kHTML; data += (char)0; data += (char)0; data += (char)0; data += (char)10; data += "html sucks"; clipboard.unmarshall(data, 0); clipboard.open(0); String actual = clipboard.get(IClipboard::kText); EXPECT_EQ("synergy rocks!", actual); } TEST(ClipboardTests, unmarshall_withTextAndHtml_getHtmlIsValid) { Clipboard clipboard; String data; data += (char)0; data += (char)0; data += (char)0; data += (char)2; // 2 formats added data += (char)0; data += (char)0; data += (char)0; data += (char)IClipboard::kText; data += (char)0; data += (char)0; data += (char)0; data += (char)14; data += "synergy rocks!"; data += (char)0; data += (char)0; data += (char)0; data += (char)IClipboard::kHTML; data += (char)0; data += (char)0; data += (char)0; data += (char)10; data += "html sucks"; clipboard.unmarshall(data, 0); clipboard.open(0); String actual = clipboard.get(IClipboard::kHTML); EXPECT_EQ("html sucks", actual); } TEST(ClipboardTests, copy_withSingleText_clipboardsAreEqual) { Clipboard clipboard1; clipboard1.open(0); clipboard1.add(Clipboard::kText, "synergy rocks!"); clipboard1.close(); Clipboard clipboard2; Clipboard::copy(&clipboard2, &clipboard1); clipboard2.open(0); String actual = clipboard2.get(Clipboard::kText); EXPECT_EQ("synergy rocks!", actual); } synergy-1.8.8-stable/src/test/unittests/synergy/DeprecatedArgsParsingTests.cpp000066400000000000000000000026541305627404700277570ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2015-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ArgParser.h" #include "test/global/gtest.h" using namespace synergy; TEST(DeprecatedArgsParsingTests, parseDeprecatedArgs_cryptoPass_returnTrue) { int i = 1; const int argc = 3; const char* kCryptoPassCmd[argc] = { "stub", "--crypto-pass", "mock_pass" }; ArgParser argParser(NULL); bool result = argParser.parseDeprecatedArgs(argc, kCryptoPassCmd, i); EXPECT_EQ(true, result); EXPECT_EQ(2, i); } TEST(DeprecatedArgsParsingTests, parseDeprecatedArgs_cryptoPass_returnFalse) { int i = 1; const int argc = 3; const char* kCryptoPassCmd[argc] = { "stub", "--mock-arg", "mock_value" }; ArgParser argParser(NULL); bool result = argParser.parseDeprecatedArgs(argc, kCryptoPassCmd, i); EXPECT_FALSE(result); EXPECT_EQ(1, i); } synergy-1.8.8-stable/src/test/unittests/synergy/GenericArgsParsingTests.cpp000066400000000000000000000162421305627404700272710ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ArgParser.h" #include "synergy/ArgsBase.h" #include "test/mock/synergy/MockApp.h" #include "test/global/gtest.h" using namespace synergy; using ::testing::_; using ::testing::Invoke; using ::testing::NiceMock; bool g_helpShowed = false; bool g_versionShowed = false; void showMockHelp() { g_helpShowed = true; } void showMockVersion() { g_versionShowed = true; } TEST(GenericArgsParsingTests, parseGenericArgs_logLevelCmd_setLogLevel) { int i = 1; const int argc = 3; const char* kLogLevelCmd[argc] = { "stub", "--debug", "DEBUG" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kLogLevelCmd, i); String logFilter(argsBase.m_logFilter); EXPECT_EQ("DEBUG", logFilter); EXPECT_EQ(2, i); } TEST(GenericArgsParsingTests, parseGenericArgs_logFileCmd_saveLogFilename) { int i = 1; const int argc = 3; const char* kLogFileCmd[argc] = { "stub", "--log", "mock_filename" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kLogFileCmd, i); String logFile(argsBase.m_logFile); EXPECT_EQ("mock_filename", logFile); EXPECT_EQ(2, i); } TEST(GenericArgsParsingTests, parseGenericArgs_logFileCmdWithSpace_saveLogFilename) { int i = 1; const int argc = 3; const char* kLogFileCmdWithSpace[argc] = { "stub", "--log", "mo ck_filename" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kLogFileCmdWithSpace, i); String logFile(argsBase.m_logFile); EXPECT_EQ("mo ck_filename", logFile); EXPECT_EQ(2, i); } TEST(GenericArgsParsingTests, parseGenericArgs_noDeamonCmd_daemonFalse) { int i = 1; const int argc = 2; const char* kNoDeamonCmd[argc] = { "stub", "-f" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kNoDeamonCmd, i); EXPECT_FALSE(argsBase.m_daemon); EXPECT_EQ(1, i); } TEST(GenericArgsParsingTests, parseGenericArgs_deamonCmd_daemonTrue) { int i = 1; const int argc = 2; const char* kDeamonCmd[argc] = { "stub", "--daemon" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kDeamonCmd, i); EXPECT_EQ(true, argsBase.m_daemon); EXPECT_EQ(1, i); } TEST(GenericArgsParsingTests, parseGenericArgs_nameCmd_saveName) { int i = 1; const int argc = 3; const char* kNameCmd[argc] = { "stub", "--name", "mock" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kNameCmd, i); EXPECT_EQ("mock", argsBase.m_name); EXPECT_EQ(2, i); } TEST(GenericArgsParsingTests, parseGenericArgs_noRestartCmd_restartFalse) { int i = 1; const int argc = 2; const char* kNoRestartCmd[argc] = { "stub", "--no-restart" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kNoRestartCmd, i); EXPECT_FALSE(argsBase.m_restartable); EXPECT_EQ(1, i); } TEST(GenericArgsParsingTests, parseGenericArgs_restartCmd_restartTrue) { int i = 1; const int argc = 2; const char* kRestartCmd[argc] = { "stub", "--restart" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kRestartCmd, i); EXPECT_EQ(true, argsBase.m_restartable); EXPECT_EQ(1, i); } TEST(GenericArgsParsingTests, parseGenericArgs_backendCmd_backendTrue) { int i = 1; const int argc = 2; const char* kBackendCmd[argc] = { "stub", "-z" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kBackendCmd, i); EXPECT_EQ(true, argsBase.m_backend); EXPECT_EQ(1, i); } TEST(GenericArgsParsingTests, parseGenericArgs_noHookCmd_noHookTrue) { int i = 1; const int argc = 2; const char* kNoHookCmd[argc] = { "stub", "--no-hooks" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kNoHookCmd, i); EXPECT_EQ(true, argsBase.m_noHooks); EXPECT_EQ(1, i); } TEST(GenericArgsParsingTests, parseGenericArgs_helpCmd_showHelp) { g_helpShowed = false; int i = 1; const int argc = 2; const char* kHelpCmd[argc] = { "stub", "--help" }; NiceMock app; ArgParser argParser(&app); ArgsBase argsBase; argParser.setArgsBase(argsBase); ON_CALL(app, help()).WillByDefault(Invoke(showMockHelp)); argParser.parseGenericArgs(argc, kHelpCmd, i); EXPECT_EQ(true, g_helpShowed); EXPECT_EQ(1, i); } TEST(GenericArgsParsingTests, parseGenericArgs_versionCmd_showVersion) { g_versionShowed = false; int i = 1; const int argc = 2; const char* kVersionCmd[argc] = { "stub", "--version" }; NiceMock app; ArgParser argParser(&app); ArgsBase argsBase; argParser.setArgsBase(argsBase); ON_CALL(app, version()).WillByDefault(Invoke(showMockVersion)); argParser.parseGenericArgs(argc, kVersionCmd, i); EXPECT_EQ(true, g_versionShowed); EXPECT_EQ(1, i); } TEST(GenericArgsParsingTests, parseGenericArgs_noTrayCmd_disableTrayTrue) { int i = 1; const int argc = 2; const char* kNoTrayCmd[argc] = { "stub", "--no-tray" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kNoTrayCmd, i); EXPECT_EQ(true, argsBase.m_disableTray); EXPECT_EQ(1, i); } TEST(GenericArgsParsingTests, parseGenericArgs_ipcCmd_enableIpcTrue) { int i = 1; const int argc = 2; const char* kIpcCmd[argc] = { "stub", "--ipc" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kIpcCmd, i); EXPECT_EQ(true, argsBase.m_enableIpc); EXPECT_EQ(1, i); } #ifndef WINAPI_XWINDOWS TEST(GenericArgsParsingTests, parseGenericArgs_dragDropCmdOnNonLinux_enableDragDropTrue) { int i = 1; const int argc = 2; const char* kDragDropCmd[argc] = { "stub", "--enable-drag-drop" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kDragDropCmd, i); EXPECT_EQ(true, argsBase.m_enableDragDrop); EXPECT_EQ(1, i); } #endif #ifdef WINAPI_XWINDOWS TEST(GenericArgsParsingTests, parseGenericArgs_dragDropCmdOnLinux_enableDragDropFalse) { int i = 1; const int argc = 2; const char* kDragDropCmd[argc] = { "stub", "--enable-drag-drop" }; ArgParser argParser(NULL); ArgsBase argsBase; argParser.setArgsBase(argsBase); argParser.parseGenericArgs(argc, kDragDropCmd, i); EXPECT_FALSE(argsBase.m_enableDragDrop); EXPECT_EQ(1, i); } #endif synergy-1.8.8-stable/src/test/unittests/synergy/KeyMapTests.cpp000066400000000000000000000141411305627404700247360ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2016 Symless * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/KeyMap.h" #include "test/global/gtest.h" #include "test/global/gmock.h" using ::testing::_; using ::testing::NiceMock; using ::testing::Invoke; using ::testing::Return; using ::testing::ReturnRef; using ::testing::SaveArg; namespace synergy { TEST(KeyMapTests, findBestKey_requiredDown_matchExactFirstItem) { KeyMap keyMap; KeyMap::KeyEntryList entryList; KeyMap::KeyItemList itemList; KeyMap::KeyItem item; item.m_required = KeyModifierShift; item.m_sensitive = KeyModifierShift; KeyModifierMask currentState = KeyModifierShift; KeyModifierMask desiredState = KeyModifierShift; itemList.push_back(item); entryList.push_back(itemList); EXPECT_EQ(0, keyMap.findBestKey(entryList, currentState, desiredState)); } TEST(KeyMapTests, findBestKey_requiredAndExtraSensitiveDown_matchExactFirstItem) { KeyMap keyMap; KeyMap::KeyEntryList entryList; KeyMap::KeyItemList itemList; KeyMap::KeyItem item; item.m_required = KeyModifierShift; item.m_sensitive = KeyModifierShift | KeyModifierAlt; KeyModifierMask currentState = KeyModifierShift; KeyModifierMask desiredState = KeyModifierShift; itemList.push_back(item); entryList.push_back(itemList); EXPECT_EQ(0, keyMap.findBestKey(entryList, currentState, desiredState)); } TEST(KeyMapTests, findBestKey_requiredAndExtraSensitiveDown_matchExactSecondItem) { KeyMap keyMap; KeyMap::KeyEntryList entryList; KeyMap::KeyItemList itemList1; KeyMap::KeyItem item1; item1.m_required = KeyModifierAlt; item1.m_sensitive = KeyModifierShift | KeyModifierAlt; KeyMap::KeyItemList itemList2; KeyMap::KeyItem item2; item2.m_required = KeyModifierShift; item2.m_sensitive = KeyModifierShift | KeyModifierAlt; KeyModifierMask currentState = KeyModifierShift; KeyModifierMask desiredState = KeyModifierShift; itemList1.push_back(item1); itemList2.push_back(item2); entryList.push_back(itemList1); entryList.push_back(itemList2); EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState)); } TEST(KeyMapTests, findBestKey_extraSensitiveDown_matchExactSecondItem) { KeyMap keyMap; KeyMap::KeyEntryList entryList; KeyMap::KeyItemList itemList1; KeyMap::KeyItem item1; item1.m_required = 0; item1.m_sensitive = KeyModifierAlt; KeyMap::KeyItemList itemList2; KeyMap::KeyItem item2; item2.m_required = 0; item2.m_sensitive = KeyModifierShift; KeyModifierMask currentState = KeyModifierAlt; KeyModifierMask desiredState = KeyModifierAlt; itemList1.push_back(item1); itemList2.push_back(item2); entryList.push_back(itemList1); entryList.push_back(itemList2); EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState)); } TEST(KeyMapTests, findBestKey_noRequiredDown_matchOneRequiredChangeItem) { KeyMap keyMap; KeyMap::KeyEntryList entryList; KeyMap::KeyItemList itemList1; KeyMap::KeyItem item1; item1.m_required = KeyModifierShift | KeyModifierAlt; item1.m_sensitive = KeyModifierShift | KeyModifierAlt; KeyMap::KeyItemList itemList2; KeyMap::KeyItem item2; item2.m_required = KeyModifierShift; item2.m_sensitive = KeyModifierShift | KeyModifierAlt; KeyModifierMask currentState = 0; KeyModifierMask desiredState = 0; itemList1.push_back(item1); itemList2.push_back(item2); entryList.push_back(itemList1); entryList.push_back(itemList2); EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState)); } TEST(KeyMapTests, findBestKey_onlyOneRequiredDown_matchTwoRequiredChangesItem) { KeyMap keyMap; KeyMap::KeyEntryList entryList; KeyMap::KeyItemList itemList1; KeyMap::KeyItem item1; item1.m_required = KeyModifierShift | KeyModifierAlt | KeyModifierControl; item1.m_sensitive = KeyModifierShift | KeyModifierAlt | KeyModifierControl; KeyMap::KeyItemList itemList2; KeyMap::KeyItem item2; item2.m_required = KeyModifierShift| KeyModifierAlt; item2.m_sensitive = KeyModifierShift | KeyModifierAlt | KeyModifierControl; KeyModifierMask currentState = 0; KeyModifierMask desiredState = 0; itemList1.push_back(item1); itemList2.push_back(item2); entryList.push_back(itemList1); entryList.push_back(itemList2); EXPECT_EQ(1, keyMap.findBestKey(entryList, currentState, desiredState)); } TEST(KeyMapTests, findBestKey_noRequiredDown_cannotMatch) { KeyMap keyMap; KeyMap::KeyEntryList entryList; KeyMap::KeyItemList itemList; KeyMap::KeyItem item; item.m_required = 0xffffffff; item.m_sensitive = 0xffffffff; KeyModifierMask currentState = 0; KeyModifierMask desiredState = 0; itemList.push_back(item); entryList.push_back(itemList); EXPECT_EQ(-1, keyMap.findBestKey(entryList, currentState, desiredState)); } TEST(KeyMapTests, isCommand_shiftMask_returnFalse) { KeyMap keyMap; KeyModifierMask mask= KeyModifierShift; EXPECT_FALSE(keyMap.isCommand(mask)); } TEST(KeyMapTests, isCommand_controlMask_returnTrue) { KeyMap keyMap; KeyModifierMask mask= KeyModifierControl; EXPECT_EQ(true, keyMap.isCommand(mask)); } TEST(KeyMapTests, isCommand_alternateMask_returnTrue) { KeyMap keyMap; KeyModifierMask mask= KeyModifierAlt; EXPECT_EQ(true, keyMap.isCommand(mask)); } TEST(KeyMapTests, isCommand_alternateGraphicMask_returnTrue) { KeyMap keyMap; KeyModifierMask mask= KeyModifierAltGr; EXPECT_EQ(true, keyMap.isCommand(mask)); } TEST(KeyMapTests, isCommand_metaMask_returnTrue) { KeyMap keyMap; KeyModifierMask mask= KeyModifierMeta; EXPECT_EQ(true, keyMap.isCommand(mask)); } TEST(KeyMapTests, isCommand_superMask_returnTrue) { KeyMap keyMap; KeyModifierMask mask= KeyModifierSuper; EXPECT_EQ(true, keyMap.isCommand(mask)); } } synergy-1.8.8-stable/src/test/unittests/synergy/KeyStateTests.cpp000066400000000000000000000320411305627404700253000ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2012-2016 Symless Ltd. * Copyright (C) 2011 Nick Bolton * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "test/mock/synergy/MockKeyState.h" #include "test/mock/synergy/MockEventQueue.h" #include "test/mock/synergy/MockKeyMap.h" #include "test/global/gtest.h" #include "test/global/gmock.h" using ::testing::_; using ::testing::NiceMock; using ::testing::Invoke; using ::testing::Return; using ::testing::ReturnRef; using ::testing::SaveArg; void stubPollPressedKeys(IKeyState::KeyButtonSet& pressedKeys); void assertMaskIsOne(ForeachKeyCallback cb, void* userData); const synergy::KeyMap::KeyItem* stubMapKey( synergy::KeyMap::Keystrokes& keys, KeyID id, SInt32 group, synergy::KeyMap::ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredMask, bool isAutoRepeat); synergy::KeyMap::Keystroke s_stubKeystroke(1, false, false); synergy::KeyMap::KeyItem s_stubKeyItem; TEST(CKeyStateTests, onKey_aKeyDown_keyStateOne) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); keyState.onKey(1, true, KeyModifierAlt); EXPECT_EQ(1, keyState.getKeyState(1)); } TEST(KeyStateTests, onKey_aKeyUp_keyStateZero) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); keyState.onKey(1, false, KeyModifierAlt); EXPECT_EQ(0, keyState.getKeyState(1)); } TEST(KeyStateTests, onKey_invalidKey_keyStateZero) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); keyState.onKey(0, true, KeyModifierAlt); EXPECT_EQ(0, keyState.getKeyState(0)); } TEST(KeyStateTests, sendKeyEvent_halfDuplexAndRepeat_addEventNotCalled) { NiceMock keyMap; NiceMock eventQueue; KeyStateImpl keyState(eventQueue, keyMap); ON_CALL(keyMap, isHalfDuplex(_, _)).WillByDefault(Return(true)); EXPECT_CALL(eventQueue, addEvent(_)).Times(0); keyState.sendKeyEvent(NULL, false, true, kKeyCapsLock, 0, 0, 0); } TEST(KeyStateTests, sendKeyEvent_halfDuplex_addEventCalledTwice) { NiceMock keyMap; NiceMock eventQueue; KeyStateImpl keyState(eventQueue, keyMap); IKeyStateEvents keyStateEvents; keyStateEvents.setEvents(&eventQueue); ON_CALL(keyMap, isHalfDuplex(_, _)).WillByDefault(Return(true)); ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); EXPECT_CALL(eventQueue, addEvent(_)).Times(2); keyState.sendKeyEvent(NULL, false, false, kKeyCapsLock, 0, 0, 0); } TEST(KeyStateTests, sendKeyEvent_keyRepeat_addEventCalledOnce) { NiceMock keyMap; NiceMock eventQueue; KeyStateImpl keyState(eventQueue, keyMap); IKeyStateEvents keyStateEvents; keyStateEvents.setEvents(&eventQueue); ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); EXPECT_CALL(eventQueue, addEvent(_)).Times(1); keyState.sendKeyEvent(NULL, false, true, 1, 0, 0, 0); } TEST(KeyStateTests, sendKeyEvent_keyDown_addEventCalledOnce) { NiceMock keyMap; NiceMock eventQueue; KeyStateImpl keyState(eventQueue, keyMap); IKeyStateEvents keyStateEvents; keyStateEvents.setEvents(&eventQueue); ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); EXPECT_CALL(eventQueue, addEvent(_)).Times(1); keyState.sendKeyEvent(NULL, true, false, 1, 0, 0, 0); } TEST(KeyStateTests, sendKeyEvent_keyUp_addEventCalledOnce) { NiceMock keyMap; NiceMock eventQueue; KeyStateImpl keyState(eventQueue, keyMap); IKeyStateEvents keyStateEvents; keyStateEvents.setEvents(&eventQueue); ON_CALL(eventQueue, forIKeyState()).WillByDefault(ReturnRef(keyStateEvents)); EXPECT_CALL(eventQueue, addEvent(_)).Times(1); keyState.sendKeyEvent(NULL, false, false, 1, 0, 0, 0); } TEST(KeyStateTests, updateKeyMap_mockKeyMap_keyMapGotMock) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); // key map member gets a new key map via swap() EXPECT_CALL(keyMap, swap(_)); keyState.updateKeyMap(); } TEST(KeyStateTests, updateKeyState_pollInsertsSingleKey_keyIsDown) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); ON_CALL(keyState, pollPressedKeys(_)).WillByDefault(Invoke(stubPollPressedKeys)); keyState.updateKeyState(); bool actual = keyState.isKeyDown(1); ASSERT_TRUE(actual); } TEST(KeyStateTests, updateKeyState_pollDoesNothing_keyNotSet) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); keyState.updateKeyState(); bool actual = keyState.isKeyDown(1); ASSERT_FALSE(actual); } TEST(KeyStateTests, updateKeyState_activeModifiers_maskSet) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(KeyModifierAlt)); keyState.updateKeyState(); KeyModifierMask actual = keyState.getActiveModifiers(); ASSERT_EQ(KeyModifierAlt, actual); } TEST(KeyStateTests, updateKeyState_activeModifiers_maskNotSet) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); keyState.updateKeyState(); KeyModifierMask actual = keyState.getActiveModifiers(); ASSERT_EQ(0, actual); } TEST(KeyStateTests, updateKeyState_activeModifiers_keyMapGotModifers) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(1)); ON_CALL(keyMap, foreachKey(_, _)).WillByDefault(Invoke(assertMaskIsOne)); // key map gets new modifiers via foreachKey() EXPECT_CALL(keyMap, foreachKey(_, _)); keyState.updateKeyState(); } TEST(KeyStateTests, setHalfDuplexMask_capsLock_halfDuplexCapsLockAdded) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyCapsLock)); keyState.setHalfDuplexMask(KeyModifierCapsLock); } TEST(KeyStateTests, setHalfDuplexMask_numLock_halfDuplexNumLockAdded) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyNumLock)); keyState.setHalfDuplexMask(KeyModifierNumLock); } TEST(KeyStateTests, setHalfDuplexMask_scrollLock_halfDuplexScollLockAdded) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); EXPECT_CALL(keyMap, addHalfDuplexModifier(kKeyScrollLock)); keyState.setHalfDuplexMask(KeyModifierScrollLock); } TEST(KeyStateTests, fakeKeyDown_serverKeyAlreadyDown_fakeKeyCalledTwice) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); s_stubKeyItem.m_client = 0; s_stubKeyItem.m_button = 1; ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); // 2 calls to fakeKeyDown should still call fakeKey, even though // repeated keys are handled differently. EXPECT_CALL(keyState, fakeKey(_)).Times(2); // call twice to simulate server key already down (a misreported autorepeat). keyState.fakeKeyDown(1, 0, 0); keyState.fakeKeyDown(1, 0, 0); } TEST(KeyStateTests, fakeKeyDown_isIgnoredKey_fakeKeyNotCalled) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); EXPECT_CALL(keyState, fakeKey(_)).Times(0); keyState.fakeKeyDown(kKeyCapsLock, 0, 0); } TEST(KeyStateTests, fakeKeyDown_mapReturnsKeystrokes_fakeKeyCalled) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); s_stubKeyItem.m_button = 0; s_stubKeyItem.m_client = 0; ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); EXPECT_CALL(keyState, fakeKey(_)).Times(1); keyState.fakeKeyDown(1, 0, 0); } TEST(KeyStateTests, fakeKeyRepeat_invalidKey_returnsFalse) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); bool actual = keyState.fakeKeyRepeat(0, 0, 0, 0); ASSERT_FALSE(actual); } TEST(KeyStateTests, fakeKeyRepeat_nullKey_returnsFalse) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); // set the key to down (we need to make mapKey return a valid key to do this). synergy::KeyMap::KeyItem keyItem; keyItem.m_client = 0; keyItem.m_button = 1; ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(&keyItem)); keyState.fakeKeyDown(1, 0, 0); // change mapKey to return NULL so that fakeKeyRepeat exits early. synergy::KeyMap::KeyItem* nullKeyItem = NULL; ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(nullKeyItem)); bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0); ASSERT_FALSE(actual); } TEST(KeyStateTests, fakeKeyRepeat_invalidButton_returnsFalse) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); // set the key to down (we need to make mapKey return a valid key to do this). synergy::KeyMap::KeyItem keyItem; keyItem.m_client = 0; keyItem.m_button = 1; // set to 1 to make fakeKeyDown work. ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(&keyItem)); keyState.fakeKeyDown(1, 0, 0); // change button to 0 so that fakeKeyRepeat will return early. keyItem.m_button = 0; ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Return(&keyItem)); bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0); ASSERT_FALSE(actual); } TEST(KeyStateTests, fakeKeyRepeat_validKey_returnsTrue) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); s_stubKeyItem.m_client = 0; s_stubKeystroke.m_type = synergy::KeyMap::Keystroke::kButton; s_stubKeystroke.m_data.m_button.m_button = 2; // set the button to 1 for fakeKeyDown call s_stubKeyItem.m_button = 1; ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); keyState.fakeKeyDown(1, 0, 0); // change the button to 2 s_stubKeyItem.m_button = 2; ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); bool actual = keyState.fakeKeyRepeat(1, 0, 0, 0); ASSERT_TRUE(actual); } TEST(KeyStateTests, fakeKeyUp_buttonNotDown_returnsFalse) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); bool actual = keyState.fakeKeyUp(0); ASSERT_FALSE(actual); } TEST(KeyStateTests, fakeKeyUp_buttonAlreadyDown_returnsTrue) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); // press alt down so we get full coverage. ON_CALL(keyState, pollActiveModifiers()).WillByDefault(Return(KeyModifierAlt)); keyState.updateKeyState(); // press button 1 down. s_stubKeyItem.m_button = 1; ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); keyState.fakeKeyDown(1, 0, 1); // this takes the button id, which is the 3rd arg of fakeKeyDown bool actual = keyState.fakeKeyUp(1); ASSERT_TRUE(actual); } TEST(KeyStateTests, fakeAllKeysUp_keysWereDown_keysAreUp) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); // press button 1 down. s_stubKeyItem.m_button = 1; ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); keyState.fakeKeyDown(1, 0, 1); // method under test keyState.fakeAllKeysUp(); bool actual = keyState.isKeyDown(1); ASSERT_FALSE(actual); } TEST(KeyStateTests, isKeyDown_keyDown_returnsTrue) { NiceMock keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); // press button 1 down. s_stubKeyItem.m_button = 1; ON_CALL(keyMap, mapKey(_, _, _, _, _, _, _)).WillByDefault(Invoke(stubMapKey)); keyState.fakeKeyDown(1, 0, 1); // method under test bool actual = keyState.isKeyDown(1); ASSERT_TRUE(actual); } TEST(KeyStateTests, isKeyDown_noKeysDown_returnsFalse) { MockKeyMap keyMap; MockEventQueue eventQueue; KeyStateImpl keyState(eventQueue, keyMap); // method under test bool actual = keyState.isKeyDown(1); ASSERT_FALSE(actual); } void stubPollPressedKeys(IKeyState::KeyButtonSet& pressedKeys) { pressedKeys.insert(1); } void assertMaskIsOne(ForeachKeyCallback cb, void* userData) { ASSERT_EQ(1, ((KeyState::AddActiveModifierContext*)userData)->m_mask); } const synergy::KeyMap::KeyItem* stubMapKey( synergy::KeyMap::Keystrokes& keys, KeyID id, SInt32 group, synergy::KeyMap::ModifierToKeys& activeModifiers, KeyModifierMask& currentState, KeyModifierMask desiredMask, bool isAutoRepeat) { keys.push_back(s_stubKeystroke); return &s_stubKeyItem; } synergy-1.8.8-stable/src/test/unittests/synergy/ServerArgsParsingTests.cpp000066400000000000000000000041341305627404700271600ustar00rootroot00000000000000/* * synergy -- mouse and keyboard sharing utility * Copyright (C) 2014-2016 Symless Ltd. * * 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 LICENSE 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. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "synergy/ArgParser.h" #include "synergy/ServerArgs.h" #include "test/mock/synergy/MockArgParser.h" #include "test/global/gtest.h" using ::testing::_; using ::testing::Invoke; using ::testing::NiceMock; bool server_stubParseGenericArgs(int, const char* const*, int&) { return false; } bool server_stubCheckUnexpectedArgs() { return false; } TEST(ServerArgsParsingTests, parseServerArgs_addressArg_setSynergyAddress) { NiceMock argParser; ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs)); ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); ServerArgs serverArgs; const int argc = 3; const char* kAddressCmd[argc] = { "stub", "--address", "mock_address" }; argParser.parseServerArgs(serverArgs, argc, kAddressCmd); EXPECT_EQ("mock_address", serverArgs.m_synergyAddress); } TEST(ServerArgsParsingTests, parseServerArgs_configArg_setConfigFile) { NiceMock argParser; ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs)); ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs)); ServerArgs serverArgs; const int argc = 3; const char* kConfigCmd[argc] = { "stub", "--config", "mock_configFile" }; argParser.parseServerArgs(serverArgs, argc, kConfigCmd); EXPECT_EQ("mock_configFile", serverArgs.m_configFile); }