commit
b2173efbae
|
@ -293,12 +293,7 @@ if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||||
${OPENSSL_ROOT}/lib/libcrypto.lib
|
${OPENSSL_ROOT}/lib/libcrypto.lib
|
||||||
)
|
)
|
||||||
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||||
#Try use 1.1 for the latest features. otherwise use the default
|
set (OPENSSL_ROOT /usr/local/opt/openssl)
|
||||||
IF(EXISTS /usr/local/opt/openssl@1.1)
|
|
||||||
set (OPENSSL_ROOT /usr/local/opt/openssl@1.1)
|
|
||||||
else()
|
|
||||||
set (OPENSSL_ROOT /usr/local/opt/openssl)
|
|
||||||
endif()
|
|
||||||
include_directories (BEFORE SYSTEM ${OPENSSL_ROOT}/include)
|
include_directories (BEFORE SYSTEM ${OPENSSL_ROOT}/include)
|
||||||
set (OPENSSL_LIBS
|
set (OPENSSL_LIBS
|
||||||
${OPENSSL_ROOT}/lib/libssl.a
|
${OPENSSL_ROOT}/lib/libssl.a
|
||||||
|
@ -325,7 +320,7 @@ macro (configure_files srcDir destDir)
|
||||||
set (sourceFilePath ${srcDir}/${sourceFile})
|
set (sourceFilePath ${srcDir}/${sourceFile})
|
||||||
if (IS_DIRECTORY ${sourceFilePath})
|
if (IS_DIRECTORY ${sourceFilePath})
|
||||||
message (STATUS "Copying directory ${sourceFile}")
|
message (STATUS "Copying directory ${sourceFile}")
|
||||||
make_directory (${destDir/${sourceFile})
|
make_directory (${destDir}/${sourceFile})
|
||||||
else()
|
else()
|
||||||
message (STATUS "Copying file ${sourceFile}")
|
message (STATUS "Copying file ${sourceFile}")
|
||||||
configure_file (${sourceFilePath} ${destDir}/${sourceFile} COPYONLY)
|
configure_file (${sourceFilePath} ${destDir}/${sourceFile} COPYONLY)
|
||||||
|
@ -349,10 +344,10 @@ macro(generate_versionfile)
|
||||||
"export SYNERGY_VERSION_STAGE=\"${SYNERGY_VERSION_STAGE}\"\n")
|
"export SYNERGY_VERSION_STAGE=\"${SYNERGY_VERSION_STAGE}\"\n")
|
||||||
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||||
FILE(WRITE ${CMAKE_BINARY_DIR}/version.bat
|
FILE(WRITE ${CMAKE_BINARY_DIR}/version.bat
|
||||||
"SET SYNERGY_VERSION_MAJOR=\"${SYNERGY_VERSION_MAJOR}\"\n"
|
"SET SYNERGY_VERSION_MAJOR=${SYNERGY_VERSION_MAJOR}\n"
|
||||||
"SET SYNERGY_VERSION_MINOR=\"${SYNERGY_VERSION_MINOR}\"\n"
|
"SET SYNERGY_VERSION_MINOR=${SYNERGY_VERSION_MINOR}\n"
|
||||||
"SET SYNERGY_VERSION_PATCH=\"${SYNERGY_VERSION_PATCH}\"\n"
|
"SET SYNERGY_VERSION_PATCH=${SYNERGY_VERSION_PATCH}\n"
|
||||||
"SET SYNERGY_VERSION_STAGE=\"${SYNERGY_VERSION_STAGE}\"\n")
|
"SET SYNERGY_VERSION_STAGE=${SYNERGY_VERSION_STAGE}\n")
|
||||||
endif()
|
endif()
|
||||||
endmacro(generate_versionfile)
|
endmacro(generate_versionfile)
|
||||||
|
|
||||||
|
@ -377,8 +372,9 @@ endif()
|
||||||
#
|
#
|
||||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
if (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||||
message (STATUS "Configuring the v1 installer")
|
message (STATUS "Configuring the v1 installer")
|
||||||
configure_files (${CMAKE_CURRENT_SOURCE_DIR}/dist/wix ${CMAKE_BINARY_DIR}/installer)
|
|
||||||
generate_versionfile()
|
generate_versionfile()
|
||||||
|
set(QT_PATH $ENV{CMAKE_PREFIX_PATH})
|
||||||
|
configure_files (${CMAKE_CURRENT_SOURCE_DIR}/dist/wix ${CMAKE_BINARY_DIR}/installer)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
21
ChangeLog
21
ChangeLog
|
@ -1,3 +1,24 @@
|
||||||
|
v1.11.0-stable
|
||||||
|
==============
|
||||||
|
|
||||||
|
Bug fixes:
|
||||||
|
- #6575 Service start error on Windows
|
||||||
|
- #6570 Hotkey capture of ctrl and cmd swapped on macOS
|
||||||
|
- #6569 Unable to run on macOS 10.15 Catalina
|
||||||
|
- #6566 Debug message output mistakenly as info message
|
||||||
|
- #6561 Debian buster no longer supports CA key length of 1024
|
||||||
|
- #6556 Function missing error from OpenSSL/TLS
|
||||||
|
- #5959 User interface failed to load local fingerprint
|
||||||
|
- #5294 Cursor lockout at Windows server login screen
|
||||||
|
|
||||||
|
Enhancements:
|
||||||
|
- #6588 Version number header with update check
|
||||||
|
- #4957 Server fails to start up due to synwinhk.dll is in use
|
||||||
|
|
||||||
|
Features:
|
||||||
|
- #6518 Key combination that will force a server restart
|
||||||
|
|
||||||
|
|
||||||
v1.10.3-stable
|
v1.10.3-stable
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,8 @@ cmake_minimum_required (VERSION 3.4)
|
||||||
#
|
#
|
||||||
|
|
||||||
set (SYNERGY_VERSION_MAJOR 1)
|
set (SYNERGY_VERSION_MAJOR 1)
|
||||||
set (SYNERGY_VERSION_MINOR 10)
|
set (SYNERGY_VERSION_MINOR 11)
|
||||||
set (SYNERGY_VERSION_PATCH 3)
|
set (SYNERGY_VERSION_PATCH 0)
|
||||||
set (SYNERGY_VERSION_STAGE "stable")
|
set (SYNERGY_VERSION_STAGE "stable")
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
<Include>
|
<Include>
|
||||||
<?define Name="Synergy" ?>
|
<?define Name="Synergy" ?>
|
||||||
<?define Version="@SYNERGY_VERSION@" ?>
|
<?define Version="@SYNERGY_VERSION@" ?>
|
||||||
<?define QtVersion="5.9.5" ?> <!-- TODO: Configure this externally //-->
|
|
||||||
<?define Author="Symless Ltd" ?>
|
<?define Author="Symless Ltd" ?>
|
||||||
<?define BinPath="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@/$(var.Configuration)" ?>
|
<?define BinPath="@CMAKE_RUNTIME_OUTPUT_DIRECTORY@/$(var.Configuration)" ?>
|
||||||
<?define ResPath="@CMAKE_CURRENT_SOURCE_DIR@/res" ?>
|
<?define ResPath="@CMAKE_CURRENT_SOURCE_DIR@/res" ?>
|
||||||
|
@ -11,15 +10,14 @@
|
||||||
<?define ProgramFilesFolder="ProgramFiles64Folder" ?>
|
<?define ProgramFilesFolder="ProgramFiles64Folder" ?>
|
||||||
<?define PlatformSimpleName="64-bit" ?>
|
<?define PlatformSimpleName="64-bit" ?>
|
||||||
<?define UpgradeGuid="E8A4FA54-14B9-4FD1-8E00-7BC46555FDA0" ?>
|
<?define UpgradeGuid="E8A4FA54-14B9-4FD1-8E00-7BC46555FDA0" ?>
|
||||||
<?define QtPath="C:\Qt\Qt$(var.QtVersion)\$(var.QtVersion)\msvc2015_64" ?>
|
|
||||||
<?else ?>
|
<?else ?>
|
||||||
<?define ProgramFilesFolder="ProgramFilesFolder" ?>
|
<?define ProgramFilesFolder="ProgramFilesFolder" ?>
|
||||||
<?define PlatformSimpleName="32-bit" ?>
|
<?define PlatformSimpleName="32-bit" ?>
|
||||||
<?define UpgradeGuid="BE0B9FD8-45E2-4A8E-A0D8-1F774D074A78" ?>
|
<?define UpgradeGuid="BE0B9FD8-45E2-4A8E-A0D8-1F774D074A78" ?>
|
||||||
<?define QtPath="C:\Qt\Qt$(var.QtVersion)\$(var.QtVersion)\msvc2015" ?>
|
|
||||||
<?endif ?>
|
<?endif ?>
|
||||||
|
<?define QtPath="@QT_PATH@" ?>
|
||||||
<?define QtBinPath="$(var.QtPath)\bin" ?>
|
<?define QtBinPath="$(var.QtPath)\bin" ?>
|
||||||
<?define QtPlatformPath="$(var.QtPath)\plugins\platforms" ?>
|
<?define QtPluginsPath="$(var.QtPath)\plugins" ?>
|
||||||
<?define OpenSSLPath="$(var.ExtPath)\openssl\windows\$(var.Platform)" ?>
|
<?define OpenSSLPath="$(var.ExtPath)\openssl\windows\$(var.Platform)" ?>
|
||||||
<?define OpenSSLBinPath="$(var.OpenSSLPath)\bin" ?>
|
<?define OpenSSLBinPath="$(var.OpenSSLPath)\bin" ?>
|
||||||
</Include>
|
</Include>
|
||||||
|
|
|
@ -13,8 +13,10 @@
|
||||||
<Feature Id="ProductFeature" Title="$(var.Name)">
|
<Feature Id="ProductFeature" Title="$(var.Name)">
|
||||||
<ComponentGroupRef Id="ProductComponents"/>
|
<ComponentGroupRef Id="ProductComponents"/>
|
||||||
<ComponentGroupRef Id="OpenSSLComponents"/>
|
<ComponentGroupRef Id="OpenSSLComponents"/>
|
||||||
|
<ComponentGroupRef Id="ProductQtStylesComponents"/>
|
||||||
<ComponentGroupRef Id="ProductQtPluginComponents"/>
|
<ComponentGroupRef Id="ProductQtPluginComponents"/>
|
||||||
<ComponentRef Id="RegistryEntries"/>
|
<ComponentRef Id="RegistryEntries"/>
|
||||||
|
<MergeRef Id="VC_Redist"/>
|
||||||
</Feature>
|
</Feature>
|
||||||
<DirectoryRef Id="TARGETDIR">
|
<DirectoryRef Id="TARGETDIR">
|
||||||
<Component Guid="7CF3564D-1F8E-4D3D-9781-E1EE22D5BD67" Id="RegistryEntries">
|
<Component Guid="7CF3564D-1F8E-4D3D-9781-E1EE22D5BD67" Id="RegistryEntries">
|
||||||
|
@ -36,6 +38,11 @@
|
||||||
<!-- Windows 8 and later only -->
|
<!-- Windows 8 and later only -->
|
||||||
<Condition><![CDATA[Installed OR (VersionNT >= 602)]]></Condition>
|
<Condition><![CDATA[Installed OR (VersionNT >= 602)]]></Condition>
|
||||||
</Component>
|
</Component>
|
||||||
|
<?if $(var.Platform) = x64 ?>
|
||||||
|
<Merge Id="VC_Redist" SourceFile="$(env.ProgramFiles)\Microsoft Visual Studio\2019\BuildTools\VC\Redist\MSVC\14.23.27820\MergeModules\Microsoft_VC142_CRT_x64.msm" DiskId="1" Language="0"/>
|
||||||
|
<?else ?>
|
||||||
|
<Merge Id="VC_Redist" SourceFile="$(env.ProgramFiles)\Microsoft Visual Studio\2019\BuildTools\VC\Redist\MSVC\14.23.27820\MergeModules\Microsoft_VC142_CRT_x86.msm" DiskId="1" Language="0"/>
|
||||||
|
<?endif ?>
|
||||||
</DirectoryRef>
|
</DirectoryRef>
|
||||||
<Icon Id="synergy.ico" SourceFile="$(var.ResPath)/synergy.ico"/>
|
<Icon Id="synergy.ico" SourceFile="$(var.ResPath)/synergy.ico"/>
|
||||||
<WixVariable Id="WixUIBannerBmp" Value="$(var.ResPath)\banner.bmp"/>
|
<WixVariable Id="WixUIBannerBmp" Value="$(var.ResPath)\banner.bmp"/>
|
||||||
|
@ -71,6 +78,7 @@
|
||||||
<Directory Id="INSTALLFOLDER" Name="$(var.Name)">
|
<Directory Id="INSTALLFOLDER" Name="$(var.Name)">
|
||||||
<Directory Id="OpenSSLDir" Name="OpenSSL"/>
|
<Directory Id="OpenSSLDir" Name="OpenSSL"/>
|
||||||
<Directory Id="PlatformsDir" Name="Platforms"/>
|
<Directory Id="PlatformsDir" Name="Platforms"/>
|
||||||
|
<Directory Id="QTStylesDir" Name="styles"/>
|
||||||
</Directory>
|
</Directory>
|
||||||
</Directory>
|
</Directory>
|
||||||
<Directory Id="ProgramMenuFolder"/>
|
<Directory Id="ProgramMenuFolder"/>
|
||||||
|
@ -89,7 +97,6 @@
|
||||||
</File>
|
</File>
|
||||||
<File Source="$(var.BinPath)/synergyc.exe"/>
|
<File Source="$(var.BinPath)/synergyc.exe"/>
|
||||||
<File Source="$(var.BinPath)/syntool.exe"/>
|
<File Source="$(var.BinPath)/syntool.exe"/>
|
||||||
<File Source="$(var.BinPath)/synwinhk.dll"/>
|
|
||||||
<?if $(var.Platform) = x64 ?>
|
<?if $(var.Platform) = x64 ?>
|
||||||
<File Source="$(var.OpenSSLBinPath)/libssl-1_1-x64.dll"/>
|
<File Source="$(var.OpenSSLBinPath)/libssl-1_1-x64.dll"/>
|
||||||
<File Source="$(var.OpenSSLBinPath)/libcrypto-1_1-x64.dll"/>
|
<File Source="$(var.OpenSSLBinPath)/libcrypto-1_1-x64.dll"/>
|
||||||
|
@ -124,12 +131,17 @@
|
||||||
<?endif ?>
|
<?endif ?>
|
||||||
</Component>
|
</Component>
|
||||||
</ComponentGroup>
|
</ComponentGroup>
|
||||||
|
<ComponentGroup Directory="QTStylesDir" Id="ProductQtStylesComponents">
|
||||||
|
<Component Guid="96E0F8D8-64FD-4CE8-94D1-F6EDCBBB4995" Id="Styles">
|
||||||
|
<File Id="qwindowsvistastyle" Source="$(var.QtPluginsPath)\styles\qwindowsvistastyle.dll"/>
|
||||||
|
</Component>
|
||||||
|
</ComponentGroup>
|
||||||
<ComponentGroup Directory="PlatformsDir" Id="ProductQtPluginComponents">
|
<ComponentGroup Directory="PlatformsDir" Id="ProductQtPluginComponents">
|
||||||
<Component Guid="684EFA14-856B-440E-A5E6-E90E04E36B41" Id="QtPlatformPlugin">
|
<Component Guid="684EFA14-856B-440E-A5E6-E90E04E36B41" Id="QtPlatformPlugin">
|
||||||
<?if $(var.Configuration) = "Debug" ?>
|
<?if $(var.Configuration) = "Debug" ?>
|
||||||
<File Source="$(var.QtPlatformPath)\qwindowsd.dll"/>
|
<File Source="$(var.QtPluginsPath)\platforms\qwindowsd.dll"/>
|
||||||
<?else ?>
|
<?else ?>
|
||||||
<File Source="$(var.QtPlatformPath)\qwindows.dll"/>
|
<File Source="$(var.QtPluginsPath)\platforms\qwindows.dll"/>
|
||||||
<?endif ?>
|
<?endif ?>
|
||||||
</Component>
|
</Component>
|
||||||
</ComponentGroup>
|
</ComponentGroup>
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio 14
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
VisualStudioVersion = 14.0.23107.0
|
# Visual Studio Version 16
|
||||||
|
VisualStudioVersion = 16.0.29411.108
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Synergy", "Synergy.wixproj", "{D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}"
|
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "Synergy", "Synergy.wixproj", "{D4BA9F39-6A35-4C8F-9CB2-67FCBE5CAB17}"
|
||||||
EndProject
|
EndProject
|
||||||
|
@ -24,4 +25,7 @@ Global
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {2E0AA1C9-0F14-4FE4-8F18-430484EFBACE}
|
||||||
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|
|
@ -1,31 +1,33 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<ProductVersion>3.10</ProductVersion>
|
<ProductVersion>3.11</ProductVersion>
|
||||||
<ProjectGuid>{d4ba9f39-6a35-4c8f-9cb2-67fcbe5cab17}</ProjectGuid>
|
<ProjectGuid>{d4ba9f39-6a35-4c8f-9cb2-67fcbe5cab17}</ProjectGuid>
|
||||||
<SchemaVersion>2.0</SchemaVersion>
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
<OutputName>Synergy</OutputName>
|
<OutputName>Synergy</OutputName>
|
||||||
<OutputType>Package</OutputType>
|
<OutputType>Package</OutputType>
|
||||||
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' AND '$(MSBuildExtensionsPath32)' != '' ">$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
<WixTargetsPath Condition=" '$(WixTargetsPath)' == '' ">$(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets</WixTargetsPath>
|
<IntermediateOutputPath>wix\obj\$(Configuration)\</IntermediateOutputPath>
|
||||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
</PropertyGroup>
|
||||||
<IntermediateOutputPath>wix\obj\$(Configuration)\</IntermediateOutputPath>
|
<ItemGroup>
|
||||||
</PropertyGroup>
|
<Compile Include="$(SolutionDir)/Product.wxs" />
|
||||||
<ItemGroup>
|
<Content Include="$(SolutionDir)/Include.wxi" />
|
||||||
<WixExtension Include="WixFirewallExtension">
|
|
||||||
<HintPath>$(WixExtDir)\WixFirewallExtension.dll</HintPath>
|
</ItemGroup>
|
||||||
<Name>WixFirewallExtension</Name>
|
<ItemGroup>
|
||||||
</WixExtension>
|
<WixExtension Include="WixUtilExtension">
|
||||||
<WixExtension Include="WixUtilExtension">
|
<HintPath>C:\Program Files (x86)\WiX Toolset v3.11\bin\WixUtilExtension.dll</HintPath>
|
||||||
<HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath>
|
<Name>WixUtilExtension</Name>
|
||||||
<Name>WixUtilExtension</Name>
|
</WixExtension>
|
||||||
</WixExtension>
|
<WixExtension Include="WixUIExtension">
|
||||||
<WixExtension Include="WixUIExtension">
|
<HintPath>C:\Program Files (x86)\WiX Toolset v3.11\bin\WixUIExtension.dll</HintPath>
|
||||||
<HintPath>$(WixExtDir)\WixUIExtension.dll</HintPath>
|
<Name>WixUIExtension</Name>
|
||||||
<Name>WixUIExtension</Name>
|
</WixExtension>
|
||||||
</WixExtension>
|
<WixExtension Include="WixFirewallExtension">
|
||||||
<Compile Include="Product.wxs"/>
|
<HintPath>C:\Program Files (x86)\WiX Toolset v3.11\bin\WixFirewallExtension.dll</HintPath>
|
||||||
<Content Include="Include.wxi"/>
|
<Name>WixFirewallExtension</Name>
|
||||||
</ItemGroup>
|
</WixExtension>
|
||||||
<Import Project="$(WixTargetsPath)"/>
|
</ItemGroup>
|
||||||
|
<Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " />
|
||||||
|
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " />
|
||||||
</Project>
|
</Project>
|
|
@ -52,7 +52,7 @@
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string><p>
|
<string><p>
|
||||||
Keyboard and mouse sharing application. Cross platform and open source.<br /><br />
|
Keyboard and mouse sharing application. Cross platform and open source.<br /><br />
|
||||||
Copyright © 2012-2016 Symless Ltd.<br />
|
Copyright © 2012-2019 Symless Ltd.<br />
|
||||||
Copyright © 2002-2012 Chris Schoeneman, Nick Bolton, Volker Lanz.<br /><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 released under the GNU General Public License (GPLv2).<br /><br />
|
||||||
Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br />
|
Synergy is based on CosmoSynergy by Richard Lee and Adam Feder.<br />
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
const char* Action::m_ActionTypeNames[] =
|
const char* Action::m_ActionTypeNames[] =
|
||||||
{
|
{
|
||||||
"keyDown", "keyUp", "keystroke",
|
"keyDown", "keyUp", "keystroke",
|
||||||
"switchToScreen", "switchInDirection", "lockCursorToScreen",
|
"switchToScreen", "switchInDirection", "lockCursorToScreen", "restartServer",
|
||||||
"mouseDown", "mouseUp", "mousebutton"
|
"mouseDown", "mouseUp", "mousebutton"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -87,6 +87,9 @@ QString Action::text() const
|
||||||
text += m_LockCursorModeNames[m_LockCursorMode];
|
text += m_LockCursorModeNames[m_LockCursorMode];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case restartAllConnections:
|
||||||
|
text += "restart";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
Q_ASSERT(0);
|
Q_ASSERT(0);
|
||||||
break;
|
break;
|
||||||
|
@ -116,6 +119,7 @@ void Action::loadSettings(QSettings& settings)
|
||||||
setLockCursorMode(settings.value("lockCursorToScreen", lockCursorToggle).toInt());
|
setLockCursorMode(settings.value("lockCursorToScreen", lockCursorToggle).toInt());
|
||||||
setActiveOnRelease(settings.value("activeOnRelease", false).toBool());
|
setActiveOnRelease(settings.value("activeOnRelease", false).toBool());
|
||||||
setHaveScreens(settings.value("hasScreens", false).toBool());
|
setHaveScreens(settings.value("hasScreens", false).toBool());
|
||||||
|
setRestartServer(settings.value("restartServer", false).toBool());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Action::saveSettings(QSettings& settings) const
|
void Action::saveSettings(QSettings& settings) const
|
||||||
|
@ -136,6 +140,7 @@ void Action::saveSettings(QSettings& settings) const
|
||||||
settings.setValue("lockCursorToScreen", lockCursorMode());
|
settings.setValue("lockCursorToScreen", lockCursorMode());
|
||||||
settings.setValue("activeOnRelease", activeOnRelease());
|
settings.setValue("activeOnRelease", activeOnRelease());
|
||||||
settings.setValue("hasScreens", haveScreens());
|
settings.setValue("hasScreens", haveScreens());
|
||||||
|
settings.setValue("restartServer", restartServer());
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextStream& operator<<(QTextStream& outStream, const Action& action)
|
QTextStream& operator<<(QTextStream& outStream, const Action& action)
|
||||||
|
|
|
@ -36,9 +36,29 @@ class Action
|
||||||
friend QTextStream& operator<<(QTextStream& outStream, const Action& action);
|
friend QTextStream& operator<<(QTextStream& outStream, const Action& action);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum ActionType { keyDown, keyUp, keystroke, switchToScreen, switchInDirection, lockCursorToScreen, mouseDown, mouseUp, mousebutton };
|
enum ActionType {
|
||||||
enum SwitchDirection { switchLeft, switchRight, switchUp, switchDown };
|
keyDown,
|
||||||
enum LockCursorMode { lockCursorToggle, lockCursonOn, lockCursorOff };
|
keyUp,
|
||||||
|
keystroke,
|
||||||
|
switchToScreen,
|
||||||
|
switchInDirection,
|
||||||
|
lockCursorToScreen,
|
||||||
|
restartAllConnections,
|
||||||
|
mouseDown,
|
||||||
|
mouseUp,
|
||||||
|
mousebutton,
|
||||||
|
};
|
||||||
|
enum SwitchDirection {
|
||||||
|
switchLeft,
|
||||||
|
switchRight,
|
||||||
|
switchUp,
|
||||||
|
switchDown
|
||||||
|
};
|
||||||
|
enum LockCursorMode {
|
||||||
|
lockCursorToggle,
|
||||||
|
lockCursonOn,
|
||||||
|
lockCursorOff
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Action();
|
Action();
|
||||||
|
@ -55,6 +75,7 @@ class Action
|
||||||
int lockCursorMode() const { return m_LockCursorMode; }
|
int lockCursorMode() const { return m_LockCursorMode; }
|
||||||
bool activeOnRelease() const { return m_ActiveOnRelease; }
|
bool activeOnRelease() const { return m_ActiveOnRelease; }
|
||||||
bool haveScreens() const { return m_HasScreens; }
|
bool haveScreens() const { return m_HasScreens; }
|
||||||
|
bool restartServer() const { return m_restartServer; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
KeySequence& keySequence() { return m_KeySequence; }
|
KeySequence& keySequence() { return m_KeySequence; }
|
||||||
|
@ -66,6 +87,7 @@ class Action
|
||||||
void setLockCursorMode(int m) { m_LockCursorMode = m; }
|
void setLockCursorMode(int m) { m_LockCursorMode = m; }
|
||||||
void setActiveOnRelease(bool b) { m_ActiveOnRelease = b; }
|
void setActiveOnRelease(bool b) { m_ActiveOnRelease = b; }
|
||||||
void setHaveScreens(bool b) { m_HasScreens = b; }
|
void setHaveScreens(bool b) { m_HasScreens = b; }
|
||||||
|
void setRestartServer( bool b) { m_restartServer = b; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KeySequence m_KeySequence;
|
KeySequence m_KeySequence;
|
||||||
|
@ -76,6 +98,7 @@ class Action
|
||||||
int m_LockCursorMode;
|
int m_LockCursorMode;
|
||||||
bool m_ActiveOnRelease;
|
bool m_ActiveOnRelease;
|
||||||
bool m_HasScreens;
|
bool m_HasScreens;
|
||||||
|
bool m_restartServer;
|
||||||
|
|
||||||
static const char* m_ActionTypeNames[];
|
static const char* m_ActionTypeNames[];
|
||||||
static const char* m_SwitchDirectionNames[];
|
static const char* m_SwitchDirectionNames[];
|
||||||
|
|
|
@ -39,7 +39,7 @@ ActionDialog::ActionDialog(QWidget* parent, ServerConfig& config, Hotkey& hotkey
|
||||||
|
|
||||||
// work around Qt Designer's lack of a QButtonGroup; we need it to get
|
// work around Qt Designer's lack of a QButtonGroup; we need it to get
|
||||||
// at the button id of the checked radio button
|
// at the button id of the checked radio button
|
||||||
QRadioButton* const typeButtons[] = { m_pRadioPress, m_pRadioRelease, m_pRadioPressAndRelease, m_pRadioSwitchToScreen, m_pRadioSwitchInDirection, m_pRadioLockCursorToScreen };
|
QRadioButton* const typeButtons[] = { m_pRadioPress, m_pRadioRelease, m_pRadioPressAndRelease, m_pRadioSwitchToScreen, m_pRadioSwitchInDirection, m_pRadioLockCursorToScreen , m_pRadioRestartAllConnections};
|
||||||
|
|
||||||
for (unsigned int i = 0; i < sizeof(typeButtons) / sizeof(typeButtons[0]); i++)
|
for (unsigned int i = 0; i < sizeof(typeButtons) / sizeof(typeButtons[0]); i++)
|
||||||
m_pButtonGroupType->addButton(typeButtons[i], i);
|
m_pButtonGroupType->addButton(typeButtons[i], i);
|
||||||
|
@ -91,6 +91,7 @@ void ActionDialog::accept()
|
||||||
m_Action.setSwitchDirection(m_pComboSwitchInDirection->currentIndex());
|
m_Action.setSwitchDirection(m_pComboSwitchInDirection->currentIndex());
|
||||||
m_Action.setLockCursorMode(m_pComboLockCursorToScreen->currentIndex());
|
m_Action.setLockCursorMode(m_pComboLockCursorToScreen->currentIndex());
|
||||||
m_Action.setActiveOnRelease(m_pRadioHotkeyReleased->isChecked());
|
m_Action.setActiveOnRelease(m_pRadioHotkeyReleased->isChecked());
|
||||||
|
m_Action.setRestartServer(m_pRadioRestartAllConnections->isChecked());
|
||||||
|
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,6 +239,17 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="m_pRadioRestartAllConnections">
|
||||||
|
<property name="text">
|
||||||
|
<string>Restart server</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -369,6 +380,22 @@
|
||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>m_pRadioRestartAllConnections</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>m_pKeySequenceWidgetHotkey</receiver>
|
||||||
|
<slot>setDisabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>101</x>
|
||||||
|
<y>353</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>68</x>
|
||||||
|
<y>126</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
<connection>
|
<connection>
|
||||||
<sender>m_pRadioPress</sender>
|
<sender>m_pRadioPress</sender>
|
||||||
<signal>toggled(bool)</signal>
|
<signal>toggled(bool)</signal>
|
||||||
|
@ -561,6 +588,22 @@
|
||||||
</hint>
|
</hint>
|
||||||
</hints>
|
</hints>
|
||||||
</connection>
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>m_pRadioRestartAllConnections</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>m_pGroupBoxScreens</receiver>
|
||||||
|
<slot>setDisabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>48</x>
|
||||||
|
<y>339</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>79</x>
|
||||||
|
<y>234</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
<connection>
|
<connection>
|
||||||
<sender>m_pRadioSwitchToScreen</sender>
|
<sender>m_pRadioSwitchToScreen</sender>
|
||||||
<signal>toggled(bool)</signal>
|
<signal>toggled(bool)</signal>
|
||||||
|
|
|
@ -140,6 +140,8 @@ MainWindow::MainWindow (QSettings& settings, AppConfig& appConfig,
|
||||||
// hide padlock icon
|
// hide padlock icon
|
||||||
secureSocket(false);
|
secureSocket(false);
|
||||||
|
|
||||||
|
sslToggled(appConfig.getCryptoEnabled());
|
||||||
|
|
||||||
connect (this, SIGNAL(windowShown()),
|
connect (this, SIGNAL(windowShown()),
|
||||||
this, SLOT(on_windowShown()), Qt::QueuedConnection);
|
this, SLOT(on_windowShown()), Qt::QueuedConnection);
|
||||||
#ifndef SYNERGY_ENTERPRISE
|
#ifndef SYNERGY_ENTERPRISE
|
||||||
|
@ -1104,12 +1106,6 @@ void MainWindow::setEdition(Edition edition)
|
||||||
#ifndef SYNERGY_ENTERPRISE
|
#ifndef SYNERGY_ENTERPRISE
|
||||||
setWindowTitle(m_LicenseManager->getEditionName (edition));
|
setWindowTitle(m_LicenseManager->getEditionName (edition));
|
||||||
#endif
|
#endif
|
||||||
if (m_AppConfig->getCryptoEnabled()) {
|
|
||||||
m_pSslCertificate = new SslCertificate(this);
|
|
||||||
m_pSslCertificate->generateCertificate();
|
|
||||||
}
|
|
||||||
updateLocalFingerprint();
|
|
||||||
saveSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef SYNERGY_ENTERPRISE
|
#ifndef SYNERGY_ENTERPRISE
|
||||||
|
|
|
@ -25,8 +25,8 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const char kCertificateKeyLength[] = "rsa:1024"; //RSA Bit length (e.g. 1024/2048/4096)
|
static const char kCertificateKeyLength[] = "rsa:2048"; //RSA Bit length (e.g. 1024/2048/4096)
|
||||||
static const char kCertificateHashAlgorithm[] = "-sha1"; //fingerprint hashing algorithm
|
static const char kCertificateHashAlgorithm[] = "-sha256"; //fingerprint hashing algorithm
|
||||||
static const char kCertificateLifetime[] = "365";
|
static const char kCertificateLifetime[] = "365";
|
||||||
static const char kCertificateSubjectInfo[] = "/CN=Synergy";
|
static const char kCertificateSubjectInfo[] = "/CN=Synergy";
|
||||||
static const char kCertificateFilename[] = "Synergy.pem";
|
static const char kCertificateFilename[] = "Synergy.pem";
|
||||||
|
@ -34,8 +34,8 @@ static const char kSslDir[] = "SSL";
|
||||||
static const char kUnixOpenSslCommand[] = "openssl";
|
static const char kUnixOpenSslCommand[] = "openssl";
|
||||||
|
|
||||||
#if defined(Q_OS_WIN)
|
#if defined(Q_OS_WIN)
|
||||||
static const char kWinOpenSslBinary[] = "OpenSSL\\openssl.exe";
|
static const char kWinOpenSslBinary[] = "openssl.exe";
|
||||||
static const char kConfigFile[] = "OpenSSL\\synergy.conf";
|
static const char kConfigFile[] = "synergy.conf";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SslCertificate::SslCertificate(QObject *parent) :
|
SslCertificate::SslCertificate(QObject *parent) :
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
#define VERSION_REGEX "(\\d+\\.\\d+\\.\\d+-[a-z1-9]*)"
|
#define VERSION_REGEX "(\\d+\\.\\d+\\.\\d+-[a-z1-9]*)"
|
||||||
#define VERSION_REGEX_SECTIONED "(\\d+)\\.(\\d+)\\.(\\d+)-([a-z1-9]*)"
|
#define VERSION_REGEX_SECTIONED "(\\d+)\\.(\\d+)\\.(\\d+)-([a-z1-9]*)"
|
||||||
#define VERSION_SEGMENT_COUNT 4
|
#define VERSION_SEGMENT_COUNT 4
|
||||||
#define VERSION_URL "http://version.symless.com/synergy"
|
#define VERSION_URL "https://version.symless.com/synergy"
|
||||||
|
|
||||||
|
|
||||||
VersionChecker::VersionChecker()
|
VersionChecker::VersionChecker()
|
||||||
|
@ -45,7 +45,10 @@ VersionChecker::~VersionChecker()
|
||||||
|
|
||||||
void VersionChecker::checkLatest()
|
void VersionChecker::checkLatest()
|
||||||
{
|
{
|
||||||
m_manager->get(QNetworkRequest(QUrl(VERSION_URL)));
|
auto request = QNetworkRequest(QUrl(VERSION_URL));
|
||||||
|
request.setHeader(QNetworkRequest::UserAgentHeader, QString("Synergy (") + getVersion() + ") " + QSysInfo::prettyProductName());
|
||||||
|
request.setRawHeader("X-Synergy-Version", getVersion().toStdString().c_str() );
|
||||||
|
m_manager->get(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VersionChecker::replyFinished(QNetworkReply* reply)
|
void VersionChecker::replyFinished(QNetworkReply* reply)
|
||||||
|
|
|
@ -26,7 +26,3 @@ add_subdirectory(platform)
|
||||||
add_subdirectory(server)
|
add_subdirectory(server)
|
||||||
add_subdirectory(synergy)
|
add_subdirectory(synergy)
|
||||||
add_subdirectory(shared)
|
add_subdirectory(shared)
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
add_subdirectory(synwinhk)
|
|
||||||
endif()
|
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include <openssl/ssl.h>
|
#include <openssl/ssl.h>
|
||||||
#include <openssl/err.h>
|
#include <openssl/err.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iterator>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
@ -37,15 +39,6 @@
|
||||||
|
|
||||||
#define MAX_ERROR_SIZE 65535
|
#define MAX_ERROR_SIZE 65535
|
||||||
|
|
||||||
//Add the new function names in case older ones are deprecated
|
|
||||||
#if OPENSSL_VERSION_NUMBER > 0x10100000L
|
|
||||||
#define SSL_SERVER_METHOD TLS_server_method
|
|
||||||
#define SSL_CLIENT_METHOD TLS_client_method
|
|
||||||
#else
|
|
||||||
#define SSL_SERVER_METHOD SSLv23_server_method
|
|
||||||
#define SSL_CLIENT_METHOD SSLv23_server_method
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static const float s_retryDelay = 0.01f;
|
static const float s_retryDelay = 0.01f;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -392,16 +385,19 @@ SecureSocket::initContext(bool server)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (server) {
|
if (server) {
|
||||||
method = SSL_SERVER_METHOD();
|
method = SSLv23_server_method();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
method = SSL_CLIENT_METHOD();
|
method = SSLv23_client_method();
|
||||||
}
|
}
|
||||||
|
|
||||||
// create new context from method
|
// create new context from method
|
||||||
SSL_METHOD* m = const_cast<SSL_METHOD*>(method);
|
SSL_METHOD* m = const_cast<SSL_METHOD*>(method);
|
||||||
m_ssl->m_context = SSL_CTX_new(m);
|
m_ssl->m_context = SSL_CTX_new(m);
|
||||||
|
|
||||||
|
//Prevent the usage of of all version prior to TLSv1.2 as they are known to be vulnerable
|
||||||
|
SSL_CTX_set_options(m_ssl->m_context, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1);
|
||||||
|
|
||||||
if (m_ssl->m_context == NULL) {
|
if (m_ssl->m_context == NULL) {
|
||||||
showError();
|
showError();
|
||||||
}
|
}
|
||||||
|
@ -856,9 +852,28 @@ SecureSocket::showSecureConnectInfo()
|
||||||
char msg[kMsgSize];
|
char msg[kMsgSize];
|
||||||
SSL_CIPHER_description(cipher, msg, kMsgSize);
|
SSL_CIPHER_description(cipher, msg, kMsgSize);
|
||||||
LOG((CLOG_DEBUG "openssl cipher: %s", msg));
|
LOG((CLOG_DEBUG "openssl cipher: %s", msg));
|
||||||
|
|
||||||
|
//For some reason SSL_get_version is return mismatching information to SSL_CIPHER_description
|
||||||
|
// so grab the version out the description instead, This seems like a hacky way of doing it.
|
||||||
|
// But when the cipher says "TLSv1.2" but the get_version returns "TLSv1/SSLv3" we it doesn't look right
|
||||||
|
// For some reason macOS hates regex's so stringstream is used
|
||||||
|
|
||||||
LOG((CLOG_INFO "network encryption protocol: %s", SSL_CIPHER_get_version(cipher)));
|
std::istringstream iss(msg);
|
||||||
|
|
||||||
|
//Take the stream input and splits it into a vetor directly
|
||||||
|
const std::vector<std::string> parts{std::istream_iterator<std::string>{iss},
|
||||||
|
std::istream_iterator<std::string>{}};
|
||||||
|
if (parts.size() > 2)
|
||||||
|
{
|
||||||
|
//log the section containing the protocol version
|
||||||
|
LOG((CLOG_INFO "network encryption protocol: %s", parts[1].c_str()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//log the error in spliting then display the whole description rather then nothing
|
||||||
|
LOG((CLOG_ERR "could not split cipher for protocol"));
|
||||||
|
LOG((CLOG_INFO "network encryption protocol: %s", msg));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG((CLOG_ERR "could not get secure socket cipher"));
|
LOG((CLOG_ERR "could not get secure socket cipher"));
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#include "platform/MSWindowsDesks.h"
|
#include "platform/MSWindowsDesks.h"
|
||||||
|
|
||||||
#include "synwinhk/synwinhk.h"
|
#include "platform/synwinhk.h"
|
||||||
#include "platform/MSWindowsScreen.h"
|
#include "platform/MSWindowsScreen.h"
|
||||||
#include "synergy/IScreenSaver.h"
|
#include "synergy/IScreenSaver.h"
|
||||||
#include "synergy/XScreen.h"
|
#include "synergy/XScreen.h"
|
||||||
|
@ -93,7 +93,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
MSWindowsDesks::MSWindowsDesks(
|
MSWindowsDesks::MSWindowsDesks(
|
||||||
bool isPrimary, bool noHooks, HINSTANCE hookLibrary,
|
bool isPrimary, bool noHooks,
|
||||||
const IScreenSaver* screensaver, IEventQueue* events,
|
const IScreenSaver* screensaver, IEventQueue* events,
|
||||||
IJob* updateKeys, bool stopOnDeskSwitch) :
|
IJob* updateKeys, bool stopOnDeskSwitch) :
|
||||||
m_isPrimary(isPrimary),
|
m_isPrimary(isPrimary),
|
||||||
|
@ -114,8 +114,6 @@ MSWindowsDesks::MSWindowsDesks(
|
||||||
m_events(events),
|
m_events(events),
|
||||||
m_stopOnDeskSwitch(stopOnDeskSwitch)
|
m_stopOnDeskSwitch(stopOnDeskSwitch)
|
||||||
{
|
{
|
||||||
if (hookLibrary != NULL)
|
|
||||||
queryHookLibrary(hookLibrary);
|
|
||||||
|
|
||||||
m_cursor = createBlankCursor();
|
m_cursor = createBlankCursor();
|
||||||
m_deskClass = createDeskWindowClass(m_isPrimary);
|
m_deskClass = createDeskWindowClass(m_isPrimary);
|
||||||
|
@ -348,35 +346,6 @@ MSWindowsDesks::sendMessage(UINT msg, WPARAM wParam, LPARAM lParam) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
HCURSOR
|
||||||
MSWindowsDesks::createBlankCursor() const
|
MSWindowsDesks::createBlankCursor() const
|
||||||
{
|
{
|
||||||
|
@ -690,13 +659,13 @@ MSWindowsDesks::deskThread(void* vdesk)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case SYNERGY_MSG_SWITCH:
|
case SYNERGY_MSG_SWITCH:
|
||||||
if (m_isPrimary && !m_noHooks) {
|
if (!m_noHooks) {
|
||||||
m_uninstall();
|
MSWindowsHook::uninstall();
|
||||||
if (m_screensaverNotify) {
|
if (m_screensaverNotify) {
|
||||||
m_uninstallScreensaver();
|
MSWindowsHook::uninstallScreenSaver();
|
||||||
m_installScreensaver();
|
MSWindowsHook::installScreenSaver();
|
||||||
}
|
}
|
||||||
switch (m_install()) {
|
switch (MSWindowsHook::install()) {
|
||||||
case kHOOK_FAILED:
|
case kHOOK_FAILED:
|
||||||
// we won't work on this desk
|
// we won't work on this desk
|
||||||
desk->m_lowLevel = false;
|
desk->m_lowLevel = false;
|
||||||
|
@ -772,10 +741,10 @@ MSWindowsDesks::deskThread(void* vdesk)
|
||||||
case SYNERGY_MSG_SCREENSAVER:
|
case SYNERGY_MSG_SCREENSAVER:
|
||||||
if (!m_noHooks) {
|
if (!m_noHooks) {
|
||||||
if (msg.wParam != 0) {
|
if (msg.wParam != 0) {
|
||||||
m_installScreensaver();
|
MSWindowsHook::installScreenSaver();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_uninstallScreensaver();
|
MSWindowsHook::uninstallScreenSaver();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "synwinhk/synwinhk.h"
|
#include "platform/synwinhk.h"
|
||||||
#include "synergy/key_types.h"
|
#include "synergy/key_types.h"
|
||||||
#include "synergy/mouse_types.h"
|
#include "synergy/mouse_types.h"
|
||||||
#include "synergy/option_types.h"
|
#include "synergy/option_types.h"
|
||||||
|
@ -65,7 +65,7 @@ public:
|
||||||
\p hookLibrary must be a handle to the hook library.
|
\p hookLibrary must be a handle to the hook library.
|
||||||
*/
|
*/
|
||||||
MSWindowsDesks(
|
MSWindowsDesks(
|
||||||
bool isPrimary, bool noHooks, HINSTANCE hookLibrary,
|
bool isPrimary, bool noHooks,
|
||||||
const IScreenSaver* screensaver, IEventQueue* events,
|
const IScreenSaver* screensaver, IEventQueue* events,
|
||||||
IJob* updateKeys, bool stopOnDeskSwitch);
|
IJob* updateKeys, bool stopOnDeskSwitch);
|
||||||
~MSWindowsDesks();
|
~MSWindowsDesks();
|
||||||
|
@ -206,7 +206,6 @@ private:
|
||||||
typedef std::map<String, Desk*> Desks;
|
typedef std::map<String, Desk*> Desks;
|
||||||
|
|
||||||
// initialization and shutdown operations
|
// initialization and shutdown operations
|
||||||
void queryHookLibrary(HINSTANCE hookLibrary);
|
|
||||||
HCURSOR createBlankCursor() const;
|
HCURSOR createBlankCursor() const;
|
||||||
void destroyCursor(HCURSOR cursor) const;
|
void destroyCursor(HCURSOR cursor) const;
|
||||||
ATOM createDeskWindowClass(bool isPrimary) const;
|
ATOM createDeskWindowClass(bool isPrimary) const;
|
||||||
|
@ -283,14 +282,6 @@ private:
|
||||||
CondVar<bool> m_deskReady;
|
CondVar<bool> m_deskReady;
|
||||||
Desks m_desks;
|
Desks m_desks;
|
||||||
|
|
||||||
// hook library stuff
|
|
||||||
InstallFunc m_install;
|
|
||||||
UninstallFunc m_uninstall;
|
|
||||||
InstallScreenSaverFunc
|
|
||||||
m_installScreensaver;
|
|
||||||
UninstallScreenSaverFunc
|
|
||||||
m_uninstallScreensaver;
|
|
||||||
|
|
||||||
// keyboard stuff
|
// keyboard stuff
|
||||||
IJob* m_updateKeys;
|
IJob* m_updateKeys;
|
||||||
HKL m_keyLayout;
|
HKL m_keyLayout;
|
||||||
|
|
|
@ -17,19 +17,35 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "platform/MSWindowsHook.h"
|
#include "platform/MSWindowsHook.h"
|
||||||
|
#include "synergy/protocol_types.h"
|
||||||
#include "synergy/XScreen.h"
|
#include "synergy/XScreen.h"
|
||||||
#include "base/Log.h"
|
#include "base/Log.h"
|
||||||
|
|
||||||
static const char* g_name = "synwinhk";
|
static const char* g_name = "synwinhk";
|
||||||
|
|
||||||
MSWindowsHook::MSWindowsHook() :
|
static DWORD g_processID = 0;
|
||||||
m_initFunc(NULL),
|
static DWORD g_threadID = 0;
|
||||||
m_cleanupFunc(NULL),
|
static HHOOK g_getMessage = NULL;
|
||||||
m_setSidesFunc(NULL),
|
static HHOOK g_keyboardLL = NULL;
|
||||||
m_setZoneFunc(NULL),
|
static HHOOK g_mouseLL = NULL;
|
||||||
m_setModeFunc(NULL),
|
static bool g_screenSaver = false;
|
||||||
m_instance(NULL)
|
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_fakeServerInput = false;
|
||||||
|
static BOOL g_isPrimary = TRUE;
|
||||||
|
|
||||||
|
MSWindowsHook::MSWindowsHook()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,35 +53,18 @@ MSWindowsHook::~MSWindowsHook()
|
||||||
{
|
{
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|
||||||
if (m_instance != NULL) {
|
if (g_processID == GetCurrentProcessId()) {
|
||||||
FreeLibrary(m_instance);
|
uninstall();
|
||||||
|
uninstallScreenSaver();
|
||||||
|
g_processID = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MSWindowsHook::loadLibrary()
|
MSWindowsHook::loadLibrary()
|
||||||
{
|
{
|
||||||
// load library
|
if (g_processID == 0) {
|
||||||
m_instance = LoadLibrary(g_name);
|
g_processID = GetCurrentProcessId();
|
||||||
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
|
// initialize library
|
||||||
|
@ -76,53 +75,703 @@ MSWindowsHook::loadLibrary()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HINSTANCE
|
|
||||||
MSWindowsHook::getInstance() const
|
|
||||||
{
|
|
||||||
return m_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
MSWindowsHook::init(DWORD threadID)
|
MSWindowsHook::init(DWORD threadID)
|
||||||
{
|
{
|
||||||
if (m_initFunc == NULL) {
|
// try to open process that last called init() to see if it's
|
||||||
return NULL;
|
// 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_processID = GetCurrentProcessId();
|
||||||
|
g_threadID = 0;
|
||||||
|
g_getMessage = NULL;
|
||||||
|
g_keyboardLL = NULL;
|
||||||
|
g_mouseLL = NULL;
|
||||||
|
g_screenSaver = false;
|
||||||
}
|
}
|
||||||
return m_initFunc(threadID);
|
|
||||||
|
// 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
|
int
|
||||||
MSWindowsHook::cleanup()
|
MSWindowsHook::cleanup()
|
||||||
{
|
{
|
||||||
if (m_cleanupFunc == NULL) {
|
if (g_processID == GetCurrentProcessId()) {
|
||||||
return NULL;
|
g_threadID = 0;
|
||||||
}
|
}
|
||||||
return m_cleanupFunc();
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MSWindowsHook::setSides(UInt32 sides)
|
MSWindowsHook::setSides(UInt32 sides)
|
||||||
{
|
{
|
||||||
if (m_setSidesFunc == NULL) {
|
g_zoneSides = sides;
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_setSidesFunc(sides);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MSWindowsHook::setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize)
|
MSWindowsHook::setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize)
|
||||||
{
|
{
|
||||||
if (m_setZoneFunc == NULL) {
|
g_zoneSize = jumpZoneSize;
|
||||||
return;
|
g_xScreen = x;
|
||||||
}
|
g_yScreen = y;
|
||||||
m_setZoneFunc(x, y, w, h, jumpZoneSize);
|
g_wScreen = w;
|
||||||
|
g_hScreen = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MSWindowsHook::setMode(EHookMode mode)
|
MSWindowsHook::setMode(EHookMode mode)
|
||||||
{
|
{
|
||||||
if (m_setModeFunc == NULL) {
|
if (mode == g_mode) {
|
||||||
|
// no change
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_setModeFunc(mode);
|
g_mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
WPARAM
|
||||||
|
makeKeyMsg(UINT virtKey, char c, bool noAltGr)
|
||||||
|
{
|
||||||
|
return MAKEWPARAM(MAKEWORD(virtKey & 0xff, (BYTE)c), noAltGr ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
bool
|
||||||
|
keyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
DWORD vkCode = static_cast<DWORD>(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_fakeServerInput = ((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_fakeServerInput) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if !NO_GRAB_KEYBOARD
|
||||||
|
static
|
||||||
|
LRESULT CALLBACK
|
||||||
|
keyboardLLHook(int code, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (code >= 0) {
|
||||||
|
// decode the message
|
||||||
|
KBDLLHOOKSTRUCT* info = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
||||||
|
|
||||||
|
bool const injected = info->flags & LLKHF_INJECTED;
|
||||||
|
if (!g_isPrimary && injected) {
|
||||||
|
return CallNextHookEx (g_keyboardLL, code, wParam, 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
|
||||||
|
bool
|
||||||
|
mouseHookHandler(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
|
||||||
|
LRESULT CALLBACK
|
||||||
|
mouseLLHook(int code, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (code >= 0) {
|
||||||
|
// decode the message
|
||||||
|
MSLLHOOKSTRUCT* info = reinterpret_cast<MSLLHOOKSTRUCT*>(lParam);
|
||||||
|
|
||||||
|
bool const injected = info->flags & LLMHF_INJECTED;
|
||||||
|
if (!g_isPrimary && injected) {
|
||||||
|
return CallNextHookEx(g_mouseLL, code, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
SInt32 x = static_cast<SInt32>(info->pt.x);
|
||||||
|
SInt32 y = static_cast<SInt32>(info->pt.y);
|
||||||
|
SInt32 w = static_cast<SInt16>(HIWORD(info->mouseData));
|
||||||
|
|
||||||
|
// handle the message
|
||||||
|
if (mouseHookHandler(wParam, x, y, w)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallNextHookEx(g_mouseLL, code, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
EHookResult
|
||||||
|
MSWindowsHook::install()
|
||||||
|
{
|
||||||
|
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_fakeServerInput = false;
|
||||||
|
|
||||||
|
// install low-level hooks. we require that they both get installed.
|
||||||
|
g_mouseLL = SetWindowsHookEx(WH_MOUSE_LL,
|
||||||
|
&mouseLLHook,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
#if !NO_GRAB_KEYBOARD
|
||||||
|
g_keyboardLL = SetWindowsHookEx(WH_KEYBOARD_LL,
|
||||||
|
&keyboardLLHook,
|
||||||
|
NULL,
|
||||||
|
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
|
||||||
|
|
||||||
|
// check that we got all the hooks we wanted
|
||||||
|
if ((g_mouseLL == NULL) ||
|
||||||
|
#if !NO_GRAB_KEYBOARD
|
||||||
|
(g_keyboardLL == NULL)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
|
uninstall();
|
||||||
|
return kHOOK_FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_keyboardLL != NULL || g_mouseLL != NULL) {
|
||||||
|
g_hookThread = GetCurrentThreadId();
|
||||||
|
return kHOOK_OKAY_LL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kHOOK_OKAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MSWindowsHook::uninstall()
|
||||||
|
{
|
||||||
|
// 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_getMessage != NULL && !g_screenSaver) {
|
||||||
|
UnhookWindowsHookEx(g_getMessage);
|
||||||
|
g_getMessage = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
LRESULT CALLBACK
|
||||||
|
getMessageHook(int code, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
if (code >= 0) {
|
||||||
|
if (g_screenSaver) {
|
||||||
|
MSG* msg = reinterpret_cast<MSG*>(lParam);
|
||||||
|
if (msg->message == WM_SYSCOMMAND &&
|
||||||
|
msg->wParam == SC_SCREENSAVE) {
|
||||||
|
// broadcast screen saver started message
|
||||||
|
PostThreadMessage(g_threadID,
|
||||||
|
SYNERGY_MSG_SCREEN_SAVER, TRUE, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CallNextHookEx(g_getMessage, code, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MSWindowsHook::installScreenSaver()
|
||||||
|
{
|
||||||
|
// 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,
|
||||||
|
NULL,
|
||||||
|
0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (g_getMessage != NULL) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
MSWindowsHook::uninstallScreenSaver()
|
||||||
|
{
|
||||||
|
// uninstall hook unless the mouse wheel hook is installed
|
||||||
|
if (g_getMessage != NULL) {
|
||||||
|
UnhookWindowsHookEx(g_getMessage);
|
||||||
|
g_getMessage = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// screen saver hook is no longer installed
|
||||||
|
g_screenSaver = false;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "synwinhk/synwinhk.h"
|
#include "platform/synwinhk.h"
|
||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
@ -30,19 +30,23 @@ public:
|
||||||
MSWindowsHook();
|
MSWindowsHook();
|
||||||
virtual ~MSWindowsHook();
|
virtual ~MSWindowsHook();
|
||||||
|
|
||||||
void loadLibrary();
|
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:
|
int init(DWORD threadID);
|
||||||
InitFunc m_initFunc;
|
|
||||||
CleanupFunc m_cleanupFunc;
|
int cleanup();
|
||||||
SetSidesFunc m_setSidesFunc;
|
|
||||||
SetZoneFunc m_setZoneFunc;
|
void setSides(UInt32 sides);
|
||||||
SetModeFunc m_setModeFunc;
|
|
||||||
HINSTANCE m_instance;
|
void setZone(SInt32 x, SInt32 y, SInt32 w, SInt32 h, SInt32 jumpZoneSize);
|
||||||
|
|
||||||
|
void setMode(EHookMode mode);
|
||||||
|
|
||||||
|
static EHookResult install();
|
||||||
|
|
||||||
|
static int uninstall();
|
||||||
|
|
||||||
|
static int installScreenSaver();
|
||||||
|
|
||||||
|
static int uninstallScreenSaver();
|
||||||
};
|
};
|
||||||
|
|
|
@ -139,7 +139,6 @@ MSWindowsScreen::MSWindowsScreen(
|
||||||
m_desks = new MSWindowsDesks(
|
m_desks = new MSWindowsDesks(
|
||||||
m_isPrimary,
|
m_isPrimary,
|
||||||
m_noHooks,
|
m_noHooks,
|
||||||
m_hook.getInstance(),
|
|
||||||
m_screensaver,
|
m_screensaver,
|
||||||
m_events,
|
m_events,
|
||||||
new TMethodJob<MSWindowsScreen>(
|
new TMethodJob<MSWindowsScreen>(
|
||||||
|
@ -329,6 +328,13 @@ MSWindowsScreen::enter()
|
||||||
bool
|
bool
|
||||||
MSWindowsScreen::leave()
|
MSWindowsScreen::leave()
|
||||||
{
|
{
|
||||||
|
POINT pos;
|
||||||
|
if (!getThisCursorPos(&pos))
|
||||||
|
{
|
||||||
|
LOG((CLOG_DEBUG "Unable to leave screen as Windows security has disabled critical functions required to let synergy work"));
|
||||||
|
//unable to get position this means synergy will break if the cursor leaves the screen
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// get keyboard layout of foreground window. we'll use this
|
// get keyboard layout of foreground window. we'll use this
|
||||||
// keyboard layout for translating keys sent to clients.
|
// keyboard layout for translating keys sent to clients.
|
||||||
HWND window = GetForegroundWindow();
|
HWND window = GetForegroundWindow();
|
||||||
|
@ -539,6 +545,60 @@ MSWindowsScreen::getCursorPos(SInt32& x, SInt32& y) const
|
||||||
m_desks->getCursorPos(x, y);
|
m_desks->getCursorPos(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getThisCursorPos and setThisCursorPos will attempt to negotiate with the system
|
||||||
|
* to try get the and set the mouse position, however on the logon screen due to
|
||||||
|
* hooks this process has it may unable to work around the problem. Although these
|
||||||
|
* functions did not fix the issue at hand (#5294) its worth keeping them here anyway.
|
||||||
|
*/
|
||||||
|
bool MSWindowsScreen::getThisCursorPos(LPPOINT pos)
|
||||||
|
{
|
||||||
|
auto result = GetCursorPos(pos);
|
||||||
|
auto error = GetLastError();
|
||||||
|
LOG((CLOG_DEBUG3 "%s Attempt: 1 , status %d, code: %d Pos {%d, %d}", __func__, result, error, pos->x, pos->y));
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
result = GetCursorPos(pos);
|
||||||
|
error = GetLastError();
|
||||||
|
LOG((CLOG_DEBUG3 "%s Attempt: 2, status %d, code: %d Pos {%d, %d}", __func__, result, error, pos->x, pos->y));
|
||||||
|
updateDesktopThread();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MSWindowsScreen::setThisCursorPos(int x, int y)
|
||||||
|
{
|
||||||
|
auto result = SetCursorPos(x, y);
|
||||||
|
auto error = GetLastError();
|
||||||
|
LOG((CLOG_DEBUG3 "%s Attempt: 1, status %d, code: %d", __func__, result, error));
|
||||||
|
if (!result)
|
||||||
|
{
|
||||||
|
result = SetCursorPos(x, y);
|
||||||
|
error = GetLastError();
|
||||||
|
LOG((CLOG_DEBUG3 "%s Attempt: 2, status %d, code: %d", __func__, result, error));
|
||||||
|
updateDesktopThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MSWindowsScreen::updateDesktopThread()
|
||||||
|
{
|
||||||
|
|
||||||
|
LOG((CLOG_DEBUG3 "Failed to set cursor Attempting to switch desktop"));
|
||||||
|
SetLastError(0);
|
||||||
|
HDESK cur_hdesk = OpenInputDesktop(0, true, GENERIC_ALL);
|
||||||
|
|
||||||
|
auto error = GetLastError();
|
||||||
|
LOG((CLOG_DEBUG3 "\tGetting desktop Handle: %p Status code: %d", cur_hdesk, error));
|
||||||
|
|
||||||
|
error = GetLastError();
|
||||||
|
LOG((CLOG_DEBUG3 "\tSetting desktop return: %d Status code: %d", SetThreadDesktop(cur_hdesk), GetLastError()));
|
||||||
|
|
||||||
|
CloseDesktop(cur_hdesk);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MSWindowsScreen::reconfigure(UInt32 activeSides)
|
MSWindowsScreen::reconfigure(UInt32 activeSides)
|
||||||
{
|
{
|
||||||
|
@ -1524,12 +1584,12 @@ MSWindowsScreen::warpCursorNoFlush(SInt32 x, SInt32 y)
|
||||||
|
|
||||||
// warp mouse. hopefully this inserts a mouse motion event
|
// warp mouse. hopefully this inserts a mouse motion event
|
||||||
// between the previous message and the following message.
|
// between the previous message and the following message.
|
||||||
SetCursorPos(x, y);
|
setThisCursorPos(x, y);
|
||||||
|
|
||||||
// check to see if the mouse pos was set correctly
|
// check to see if the mouse pos was set correctly
|
||||||
POINT cursorPos;
|
POINT cursorPos;
|
||||||
GetCursorPos(&cursorPos);
|
getThisCursorPos(&cursorPos);
|
||||||
|
|
||||||
// there is a bug or round error in SetCursorPos and GetCursorPos on
|
// 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.
|
// 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.
|
// since this feature is mainly for client, so only check on client.
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "platform/MSWindowsHook.h"
|
#include "platform/MSWindowsHook.h"
|
||||||
#include "synergy/PlatformScreen.h"
|
#include "synergy/PlatformScreen.h"
|
||||||
#include "synergy/DragInformation.h"
|
#include "synergy/DragInformation.h"
|
||||||
#include "synwinhk/synwinhk.h"
|
#include "platform/synwinhk.h"
|
||||||
#include "mt/CondVar.h"
|
#include "mt/CondVar.h"
|
||||||
#include "mt/Mutex.h"
|
#include "mt/Mutex.h"
|
||||||
#include "base/String.h"
|
#include "base/String.h"
|
||||||
|
@ -75,6 +75,25 @@ public:
|
||||||
SInt32& width, SInt32& height) const;
|
SInt32& width, SInt32& height) const;
|
||||||
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
virtual void getCursorPos(SInt32& x, SInt32& y) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the position of the cursor on the current machine
|
||||||
|
* \param pos the object that the function will use to store the position of the cursor
|
||||||
|
* \return true if the function was successful
|
||||||
|
*/
|
||||||
|
virtual bool getThisCursorPos(LPPOINT pos);
|
||||||
|
/**
|
||||||
|
* \brief Sets the cursor position on the current machine
|
||||||
|
* \param x The x coordinate of the cursor
|
||||||
|
* \param y The Y coordinate of the cursor
|
||||||
|
* \return True is successful
|
||||||
|
*/
|
||||||
|
virtual bool setThisCursorPos(int x, int y);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This function will attempt to switch to the current desktop the mouse is located on
|
||||||
|
*/
|
||||||
|
virtual void updateDesktopThread();
|
||||||
|
|
||||||
// IPrimaryScreen overrides
|
// IPrimaryScreen overrides
|
||||||
virtual void reconfigure(UInt32 activeSides);
|
virtual void reconfigure(UInt32 activeSides);
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||||
|
@ -155,6 +174,10 @@ private: // HACK
|
||||||
// the message should not be dispatched.
|
// the message should not be dispatched.
|
||||||
bool onPreDispatchPrimary(HWND, UINT, WPARAM, LPARAM);
|
bool onPreDispatchPrimary(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
|
||||||
|
// handle secondary message before it gets dispatched. returns true iff
|
||||||
|
// the message should not be dispatched.
|
||||||
|
bool onPreDispatchSecondary(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
|
||||||
// handle message. returns true iff handled and optionally sets
|
// handle message. returns true iff handled and optionally sets
|
||||||
// \c *result (which defaults to 0).
|
// \c *result (which defaults to 0).
|
||||||
bool onEvent(HWND, UINT, WPARAM, LPARAM, LRESULT* result);
|
bool onEvent(HWND, UINT, WPARAM, LPARAM, LRESULT* result);
|
||||||
|
|
|
@ -67,25 +67,4 @@ enum EHookMode {
|
||||||
kHOOK_RELAY_EVENTS
|
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);
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1241,6 +1241,26 @@ Config::parseAction(ConfigReadContext& s,
|
||||||
action = new InputFilter::LockCursorToScreenAction(m_events, mode);
|
action = new InputFilter::LockCursorToScreenAction(m_events, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (name == "restartServer") {
|
||||||
|
if (args.size() > 1) {
|
||||||
|
throw XConfigRead(s, "syntax for action: restartServer([{{restart}}])");
|
||||||
|
}
|
||||||
|
|
||||||
|
InputFilter::RestartServer::Mode mode =
|
||||||
|
InputFilter::RestartServer::restart;
|
||||||
|
|
||||||
|
if (args.size() == 1) {
|
||||||
|
if (args[0] == "restart") {
|
||||||
|
mode = InputFilter::RestartServer::restart;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw XConfigRead(s, "syntax for action: restartServer([{restart}])");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
action = new InputFilter::RestartServer(m_events, mode);
|
||||||
|
}
|
||||||
|
|
||||||
else if (name == "keyboardBroadcast") {
|
else if (name == "keyboardBroadcast") {
|
||||||
if (args.size() > 2) {
|
if (args.size() > 2) {
|
||||||
throw XConfigRead(s, "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])");
|
throw XConfigRead(s, "syntax for action: keyboardBroadcast([{off|on|toggle}[,screens]])");
|
||||||
|
|
|
@ -323,6 +323,40 @@ InputFilter::LockCursorToScreenAction::perform(const Event& event)
|
||||||
Event::kDeliverImmediately));
|
Event::kDeliverImmediately));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
InputFilter::RestartServer::RestartServer(
|
||||||
|
IEventQueue* events, Mode mode) :
|
||||||
|
m_mode(mode),
|
||||||
|
m_events(events)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
InputFilter::RestartServer::Mode
|
||||||
|
InputFilter::RestartServer::getMode() const
|
||||||
|
{
|
||||||
|
return m_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputFilter::Action *InputFilter::RestartServer::clone() const {
|
||||||
|
return new RestartServer(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
String
|
||||||
|
InputFilter::RestartServer::format() const
|
||||||
|
{
|
||||||
|
static const char* s_mode[] = { "restart" };
|
||||||
|
|
||||||
|
return synergy::string::sprintf("restartServer(%s)", s_mode[m_mode]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
InputFilter::RestartServer::perform(const Event& event)
|
||||||
|
{
|
||||||
|
//HACK Super hack we should gracefully exit
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
InputFilter::SwitchToScreenAction::SwitchToScreenAction(
|
InputFilter::SwitchToScreenAction::SwitchToScreenAction(
|
||||||
IEventQueue* events, const String& screen) :
|
IEventQueue* events, const String& screen) :
|
||||||
m_screen(screen),
|
m_screen(screen),
|
||||||
|
@ -1088,3 +1122,4 @@ InputFilter::handleEvent(const Event& event, void*)
|
||||||
// not handled so pass through
|
// not handled so pass through
|
||||||
m_events->addEvent(myEvent);
|
m_events->addEvent(myEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -149,6 +149,24 @@ public:
|
||||||
Mode m_mode;
|
Mode m_mode;
|
||||||
IEventQueue* m_events;
|
IEventQueue* m_events;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RestartServer : public Action {
|
||||||
|
public:
|
||||||
|
enum Mode { restart };
|
||||||
|
|
||||||
|
RestartServer(IEventQueue* events, Mode = restart);
|
||||||
|
|
||||||
|
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
|
// SwitchToScreenAction
|
||||||
class SwitchToScreenAction : public Action {
|
class SwitchToScreenAction : public Action {
|
||||||
|
|
|
@ -545,7 +545,7 @@ KeyMap::mapCommandKey(Keystrokes& keys, KeyID id, SInt32 group,
|
||||||
KeyModifierMask requiredIgnoreShiftMask = item.m_required & ~KeyModifierShift;
|
KeyModifierMask requiredIgnoreShiftMask = item.m_required & ~KeyModifierShift;
|
||||||
if ((item.m_required & desiredShiftMask) == (item.m_sensitive & desiredShiftMask) &&
|
if ((item.m_required & desiredShiftMask) == (item.m_sensitive & desiredShiftMask) &&
|
||||||
((requiredIgnoreShiftMask & desiredMask) == requiredIgnoreShiftMask)) {
|
((requiredIgnoreShiftMask & desiredMask) == requiredIgnoreShiftMask)) {
|
||||||
LOG((CLOG_INFO "found key in group %d", effectiveGroup));
|
LOG((CLOG_DEBUG1 "found key in group %d", effectiveGroup));
|
||||||
keyItem = &item;
|
keyItem = &item;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
# 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 <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
file(GLOB headers "*.h")
|
|
||||||
file(GLOB sources "*.cpp")
|
|
||||||
|
|
||||||
if (SYNERGY_ADD_HEADERS)
|
|
||||||
list(APPEND sources ${headers})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(synwinhk SHARED ${sources})
|
|
||||||
|
|
||||||
if (NOT MSVC_VERSION VERSION_LESS 1900)
|
|
||||||
target_link_libraries(synwinhk libucrt)
|
|
||||||
endif()
|
|
File diff suppressed because it is too large
Load Diff
|
@ -52,7 +52,7 @@ protected:
|
||||||
MSWindowsDesks* newDesks(IEventQueue* eventQueue)
|
MSWindowsDesks* newDesks(IEventQueue* eventQueue)
|
||||||
{
|
{
|
||||||
return new MSWindowsDesks(
|
return new MSWindowsDesks(
|
||||||
true, false, m_hook.getInstance(), m_screensaver, eventQueue,
|
true, false, m_screensaver, eventQueue,
|
||||||
new TMethodJob<MSWindowsKeyStateTests>(
|
new TMethodJob<MSWindowsKeyStateTests>(
|
||||||
this, &MSWindowsKeyStateTests::updateKeysCB), false);
|
this, &MSWindowsKeyStateTests::updateKeysCB), false);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue