diff --git a/.github/actions/spell-check/allow/names.txt b/.github/actions/spell-check/allow/names.txt
index 97520c020f80..76ecf535e08c 100644
--- a/.github/actions/spell-check/allow/names.txt
+++ b/.github/actions/spell-check/allow/names.txt
@@ -1,19 +1,49 @@
ABradley
+Aleks
+Ashish
azchohfi
+Baltazar
+Bao
bdoserror
+Chinh
+Coplen
crutkas
dependabot
Deuchert
+ductdo
edwinzap
+Essey
+Garside
+Gershaft
hallatore
+Harmath
+Hemmerlein
+Huynh
+Jaswal
jefflord
+Kamra
+Karthick
+Krigun
+Luecking
+Mahalingam
mshtang
+Myrvold
naveensrinivasan
nVidia
+Ponten
+Pooja
robmen
+Schoen
skycommand
snickler
sinclairinat
+streamjsonrpc
+tilovell
TheJoeFin
+Triet
Vidia
+WEX
+WWL
yifan
+Yuniardi
+Zoltan
diff --git a/.github/actions/spell-check/excludes.txt b/.github/actions/spell-check/excludes.txt
index d57db991783f..6f2fd548b27b 100644
--- a/.github/actions/spell-check/excludes.txt
+++ b/.github/actions/spell-check/excludes.txt
@@ -81,6 +81,9 @@
^\Qsrc/common/ManagedCommon/ColorFormatHelper.cs\E$
^\Qsrc/modules/colorPicker/ColorPickerUI/Shaders/GridShader.cso\E$
^\Qsrc/modules/MouseUtils/MouseJumpUI/MainForm.resx\E$
+^\Qsrc/modules/MouseWithoutBorders/App/Form/frmAbout.cs\E$
+^\Qsrc/modules/MouseWithoutBorders/App/Properties/AssemblyInfo.cs\E$
+^\Qsrc/modules/MouseWithoutBorders/ModuleInterface/generateSecurityDescriptor.h\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/CorruptJson/Microsoft/PowerToys/settings.json\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/v0.18.2/Microsoft/PowerToys/PowerRename/power-rename-ui-flags\E$
^\Qsrc/settings-ui/Settings.UI.UnitTests/BackwardsCompatibility/TestFiles/v0.19.2/Microsoft/PowerToys/PowerRename/power-rename-ui-flags\E$
@@ -100,6 +103,10 @@
^src/modules/imageresizer/dll/ContextMenuHandler\.rgs$
^src/modules/imageresizer/dll/ImageResizerExt\.rgs$
^src/modules/MouseUtils/MouseJumpUI/NativeMethods/User32/UI/WindowsAndMessaging/User32.SYSTEM_METRICS_INDEX.cs$
+^src/modules/MouseWithoutBorders/App/Form/.*\.resx$
+^src/modules/MouseWithoutBorders/App/Form/.*\.Designer\.cs$
+^src/modules/MouseWithoutBorders/App/Helper/.*\.resx$
+^src/modules/MouseWithoutBorders/App/.*/NativeMethods\.cs$
^src/modules/peek/Peek\.Common/NativeMethods\.txt$
^src/modules/powerrename/testapp/PowerRenameTest\.vcxproj\.filters$
^src/modules/previewpane/PreviewPaneUnitTests/HelperFiles/MarkdownWithHTMLImageTag\.txt$
diff --git a/.github/actions/spell-check/expect.txt b/.github/actions/spell-check/expect.txt
index e5c4b5ef8741..2292d55e1ab5 100644
--- a/.github/actions/spell-check/expect.txt
+++ b/.github/actions/spell-check/expect.txt
@@ -7,6 +7,7 @@ AACD
AAD
AADF
abap
+abcdefghjkmnpqrstuvxyz
ABE
abgr
abi
@@ -24,6 +25,7 @@ ACFC
ACFF
Acl
aclapi
+AClient
AColumn
acrt
activatable
@@ -31,6 +33,7 @@ ACTIVATEAPP
activationaction
ADDUNDORECORD
ADifferent
+adio
administra
ADMINS
adml
@@ -60,7 +63,7 @@ ALLINPUT
ALLOWUNDO
ALLVIEW
ALPHATYPE
-Altdown
+altdown
alwaysontop
amd
AModifier
@@ -94,10 +97,12 @@ appmanifest
APPNAME
appref
apps
+appsettings
appwindow
appwiz
APSTUDIO
AQS
+ARandom
ARCHITEW
arcosh
ARemapped
@@ -153,6 +158,7 @@ BCB
BCCE
BCCEA
bck
+Bcl
BDB
BDBAD
BDCC
@@ -221,6 +227,7 @@ buildtransitive
BUTTONUP
BVal
BValue
+byapp
BYPOSITION
bytearray
CABD
@@ -267,6 +274,7 @@ CFEE
CFFEE
CFFF
cguid
+CHANGECBCHAIN
changecursor
Changemove
chdir
@@ -291,9 +299,11 @@ clickonce
CLIENTEDGE
clientid
clientside
+CLIPBOARDUPDATE
CLIPCHILDREN
CLIPSIBLINGS
Cloneable
+closesocket
clrcall
Cls
CLSCTX
@@ -342,6 +352,7 @@ comsuppw
comsuppwd
comutil
concrt
+CONFIGW
CONFLICTINGMODIFIERKEY
CONFLICTINGMODIFIERSHORTCUT
CONOUT
@@ -458,6 +469,7 @@ debian
debugbreak
DECLAR
declspec
+decryptor
DED
Dedup
DEFAULTBOOTSTRAPPERINSTALLFOLDER
@@ -482,6 +494,8 @@ depersist
deprioritized
depsfileslistspath
deref
+READOBJECTS
+WRITEOBJECTS
DESKTOPABSOLUTEEDITING
DESKTOPABSOLUTEPARSING
desktopshorcutinstalled
@@ -525,6 +539,7 @@ DPolicy
DPSAPI
DQTAT
DQTYPE
+DRAWCLIPBOARD
DRAWFRAME
drawingcolor
dreamsofameaningfullife
@@ -607,8 +622,10 @@ Emoji
ENABLEDELAYEDEXPANSION
enabledisable
ENABLEDPOPUP
+encryptor
endpointvolume
endregion
+ENDSESSION
ENTERSIZEMOVE
ENU
EOAC
@@ -626,6 +643,7 @@ esize
esrp
estructuredtext
etl
+etstat
etw
EUQ
eurochange
@@ -721,6 +739,7 @@ FILEVERSION
Filtergraph
Filterkeyboard
Filterx
+Finalizers
findfast
firefox
FIXEDFILEINFO
@@ -733,6 +752,7 @@ FORCEMINIMIZE
formatetc
FRAMECHANGED
frankychen
+frm
Froml
FROMTOUCH
FSCTL
@@ -762,10 +782,13 @@ GETDPISCALEDSIZE
GETICON
GETMINMAXINFO
GETPROPERTYSTOREFLAGS
+GETSCREENSAVERRUNNING
+GETSECKEY
GETSTATE
GETTEXT
GETTEXTLENGTH
GHND
+Globbing
GMEM
GNumber
google
@@ -799,6 +822,7 @@ Hashtable
hashtag
HASHVAL
hbitmap
+hbm
hbmp
hbr
HBRBACKGROUND
@@ -973,6 +997,7 @@ Interlop
INTRESOURCE
INVALIDARG
invalidoperatioexception
+invalidkey
IPalette
ipc
ipcmanager
@@ -1023,6 +1048,8 @@ jyuwono
KBDLLHOOKSTRUCT
kbm
kdc
+keybd
+KEYBDDATA
KEYBDINPUT
keyboardeventhandlers
keyboardmanager
@@ -1124,6 +1151,7 @@ LPCWSTR
lpdw
lpfn
LPINPUT
+LPQUERY
lpmi
LPMINMAXINFO
LPMONITORINFO
@@ -1138,6 +1166,7 @@ lpt
LPTHREAD
LPTOP
lptpm
+LPTR
LPTSTR
LPVOID
LPW
@@ -1253,6 +1282,7 @@ monitorinfof
Monthand
Moq
MOUSEACTIVATE
+MOUSEDATA
MOUSEEVENTF
MOUSEHWHEEL
MOUSEINPUT
@@ -1283,6 +1313,7 @@ MSIXCA
MSLLHOOKSTRUCT
Mso
msp
+mspaint
msrc
msstore
mst
@@ -1296,8 +1327,12 @@ mvvm
myfile
MYICON
mysql
+mwb
+MWBEx
NAMECHANGE
nameof
+namespaceanddescendants
+nao
NCACTIVATE
ncc
NCCALCSIZE
@@ -1344,6 +1379,7 @@ NLD
NLog
nls
NLSTEXT
+NNN
NOACTIVATE
NOAGGREGATION
NOASYNC
@@ -1507,6 +1543,7 @@ perfmon
pesi
petabyte
peteblois
+pevent
PEXCEPTION
pfn
pfo
@@ -1704,6 +1741,7 @@ remappings
REMAPSUCCESSFUL
REMAPUNSUCCESSFUL
Remotable
+remoteip
Removedir
Removelnk
renamable
@@ -1770,6 +1808,7 @@ rungameid
RUNLEVEL
runsettings
runtimeclass
+runtimeconfig
runtimedepsjsonpath
runtimeobject
runtimepack
@@ -1816,6 +1855,7 @@ sendvirtualinput
Seperate
Seraphima
serverside
+Ses
SETCONTEXT
setcursor
setenv
@@ -1903,6 +1943,7 @@ SMALLICON
smartphone
SMTO
snd
+sni
snwprintf
softline
somil
@@ -2009,6 +2050,7 @@ SYSICONINDEX
SYSKEY
syskeydown
SYSKEYUP
+SYSLIB
SYSMENU
SYSTEMAPPS
systemroot
@@ -2036,6 +2078,7 @@ tchar
tcl
Tcollab
tcs
+tcp
tcscpy
TCustom
tdbuild
@@ -2141,6 +2184,7 @@ unremapped
unsubscribe
unvirtualized
UOffset
+UOI
Updatelayout
UPGRADINGPRODUCTCODE
Uptool
@@ -2285,6 +2329,7 @@ winget
wingetcreate
Winhook
winkey
+winlogon
WINL
winmd
winmm
@@ -2293,7 +2338,9 @@ winres
winrt
winsdk
winsdkver
+Winsock
winspool
+winsta
winternl
WINTHRESHOLD
winui
@@ -2342,12 +2389,16 @@ WResize
writefile
Wrk
wrl
+WSAEADDRINUSE
+WSAEADDRNOTAVAIL
+WSAECONNRESET
wscui
wsf
wsh
wsl
wss
wstr
+wsystem
wsz
wtoi
WTS
@@ -2375,6 +2426,7 @@ XIncrement
XLoc
XNamespace
XOffset
+XPels
XPixel
XResource
xsi
@@ -2388,6 +2440,7 @@ yinle
yinwang
yinyue
YOffset
+YPels
ypescript
YQuantized
YResolution
diff --git a/.github/actions/spell-check/patterns.txt b/.github/actions/spell-check/patterns.txt
index f17c5fb2aa3a..5d9877ade764 100644
--- a/.github/actions/spell-check/patterns.txt
+++ b/.github/actions/spell-check/patterns.txt
@@ -57,6 +57,7 @@ https?://(?:(?:www\.|)youtube\.com|youtu.be)/[-a-zA-Z0-9?&=]*
# msdn
\b(?:download\.visualstudio|docs|msdn|learn)\.microsoft\.com/[-_a-zA-Z0-9()=./]*
+aka\.ms/[a-zA-Z0-9]+
# medium
link\.medium\.com/[a-zA-Z0-9]+
diff --git a/.pipelines/ESRPSigning_core.json b/.pipelines/ESRPSigning_core.json
index 048147cef1e2..9f48c66184f1 100644
--- a/.pipelines/ESRPSigning_core.json
+++ b/.pipelines/ESRPSigning_core.json
@@ -144,6 +144,14 @@
"modules\\MouseUtils\\MouseJumpUI\\PowerToys.MouseJumpUI.dll",
"modules\\MouseUtils\\MouseJumpUI\\PowerToys.MouseJumpUI.exe",
+ "modules\\MouseWithoutBorders\\PowerToys.MouseWithoutBorders.dll",
+ "modules\\MouseWithoutBorders\\PowerToys.MouseWithoutBorders.exe",
+ "modules\\MouseWithoutBorders\\PowerToys.MouseWithoutBordersModuleInterface.dll",
+ "modules\\MouseWithoutBorders\\PowerToys.MouseWithoutBordersService.dll",
+ "modules\\MouseWithoutBorders\\PowerToys.MouseWithoutBordersService.exe",
+ "modules\\MouseWithoutBorders\\PowerToys.MouseWithoutBordersHelper.dll",
+ "modules\\MouseWithoutBorders\\PowerToys.MouseWithoutBordersHelper.exe",
+
"modules\\PowerAccent\\PowerAccent.Core.dll",
"modules\\PowerAccent\\PowerToys.PowerAccent.dll",
"modules\\PowerAccent\\PowerToys.PowerAccent.exe",
@@ -268,9 +276,15 @@
"modules\\launcher\\ScipBe.Common.Office.OneNote.dll",
"modules\\launcher\\Interop.Microsoft.Office.Interop.OneNote.dll",
"modules\\launcher\\hyjiacan.py4n.dll",
+ "modules\\MouseWithoutBorders\\MessagePack.Annotations.dll",
+ "modules\\MouseWithoutBorders\\MessagePack.dll",
+ "modules\\MouseWithoutBorders\\Nerdbank.Streams.dll",
"Settings\\Microsoft.Graphics.Canvas.Interop.dll",
"Settings\\clrcompression.dll",
"Settings\\CommunityToolkit.Labs.WinUI.SettingsControls.dll",
+ "Settings\\MessagePack.Annotations.dll",
+ "Settings\\MessagePack.dll",
+ "Settings\\Nerdbank.Streams.dll",
"ColorCode.Core.dll",
"ColorCode.UWP.dll",
"UnitsNet.dll"
diff --git a/COMMUNITY.md b/COMMUNITY.md
index 8fce8b92f4a4..6f831031c8ad 100644
--- a/COMMUNITY.md
+++ b/COMMUNITY.md
@@ -111,6 +111,41 @@ Find My Mouse is based on Raymond Chen's SuperSonar.
This amazing team helped PowerToys develop PowerToys Run and Keyboard manager as well as update our Settings to v2. @alekhyareddy28, @arjunbalgovind, @jyuwono @laviusmotileng-ms, @ryanbodrug-microsoft, @saahmedm, @somil55, @traies, @udit3333
+## Mouse Without Borders original contributors
+*Project creator: Truong Do (Đỗ Đức Trường)*
+
+Other contributors:
+ * Microsoft Garage: Quinn Hawkins, Michael Low, Joe Coplen, Nino Yuniardi, Gwyneth Marshall, David Andrews, Karen Luecking
+ * Peter Hauge - Visual Studio
+ * Bruce Dawson - Windows Fundamentals
+ * Alan Myrvold - Office Security
+ * Adrian Garside - WEX
+ * Scott Bradner - Surface
+ * Aleks Gershaft - Windows Azure
+ * Chinh Huynh - Windows Azure
+ * Long Nguyen - Data Center
+ * Triet Le - Cloud Engineering
+ * Luke Schoen - Excel
+ * Bao Nguyen - Bing
+ * Ross Nichols - Windows
+ * Ryan Baltazar - Windows
+ * Ed Essey - The Garage
+ * Mario Madden - The Garage
+ * Karthick Mahalingam - ACE
+ * Pooja Kamra - ACE
+ * Justin White - SA
+ * Chris Ransom - SA
+ * Mike Ricks - Red Team
+ * Randy Santossio - Surface
+ * Ashish Sen Jaswal - Device Health
+ * Zoltan Harmath - Security Tools
+ * Luciano Krigun - Security Products
+ * Jo Hemmerlein - Red Team
+ * Chris Johnson - Surface Hub
+ * Loren Ponten - Surface Hub
+ * Paul Schmitt - WWL
+ * And many other Users!
+
## PowerToys core team
- [@crutkas](https://github.com/crutkas/) - Clint Rutkas - Lead
diff --git a/Directory.Packages.props b/Directory.Packages.props
index a75cb8a8693f..e9ce26ecbb3e 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -20,10 +20,15 @@
-
+
+
+
+
+
+
@@ -39,6 +44,7 @@
+
diff --git a/NOTICE.md b/NOTICE.md
index f88a23ac575e..f88a920756eb 100644
--- a/NOTICE.md
+++ b/NOTICE.md
@@ -295,10 +295,15 @@ SOFTWARE.
- Markdig.Signed 0.27.0
- Microsoft.CodeAnalysis.NetAnalyzers 7.0.1
- Microsoft.Data.Sqlite 7.0.0
-- Microsoft.Extensions.Hosting 7.0.0
+- Microsoft.DotNet.UpgradeAssistant.Extensions.Default.Analyzers 0.4.336902
+- Microsoft.Extensions.DependencyInjection 7.0.0
+- Microsoft.Extensions.Hosting 7.0.1
+- Microsoft.Extensions.Hosting.WindowsServices 7.0.0
+- Microsoft.Extensions.Logging 7.0.0
- Microsoft.NET.Test.Sdk 17.4.1
- Microsoft.Toolkit.Uwp.Notifications 7.1.2
- Microsoft.Web.WebView2 1.0.1722.45
+- Microsoft.Windows.Compatibility 7.0.1
- Microsoft.Windows.CsWin32 0.2.46-beta
- Microsoft.Windows.CsWinRT 2.0.2
- Microsoft.Windows.SDK.BuildTools 10.0.22621.755
@@ -312,6 +317,7 @@ SOFTWARE.
- NLog.Extensions.Logging 5.0.4
- NLog.Schema 5.0.4
- ScipBe.Common.Office.OneNote 3.0.1
+- StreamJsonRpc 2.14.24
- StyleCop.Analyzers 1.2.0-beta.435
- System.CommandLine 2.0.0-beta4.22272.1
- System.ComponentModel.Composition 7.0.0
diff --git a/PowerToys.sln b/PowerToys.sln
index 9a0cae23a308..d82533f29707 100644
--- a/PowerToys.sln
+++ b/PowerToys.sln
@@ -493,6 +493,16 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "StlThumbnailProviderCpp", "
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SvgThumbnailProviderCpp", "src\modules\previewpane\SvgThumbnailProviderCpp\SvgThumbnailProviderCpp.vcxproj", "{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MouseWithoutBorders", "MouseWithoutBorders", "{B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MouseWithoutBordersModuleInterface", "src\modules\MouseWithoutBorders\ModuleInterface\MouseWithoutBordersModuleInterface.vcxproj", "{2833C9C6-AB32-4048-A5C7-A70898337B57}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MouseWithoutBorders", "src\modules\MouseWithoutBorders\App\MouseWithoutBorders.csproj", "{50B82783-242F-42D2-BC03-B3430BF01354}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MouseWithoutBordersService", "src\modules\MouseWithoutBorders\App\Service\MouseWithoutBordersService.csproj", "{B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MouseWithoutBordersHelper", "src\modules\MouseWithoutBorders\App\Helper\MouseWithoutBordersHelper.csproj", "{A663E672-B26D-4EC0-BEAB-FE2E424AC46F}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MouseJump", "src\modules\MouseUtils\MouseJump\MouseJump.vcxproj", "{8A08D663-4995-40E3-B42C-3F910625F284}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MouseJumpUI", "src\modules\MouseUtils\MouseJumpUI\MouseJumpUI.csproj", "{D962A009-834F-4EEC-AABB-430DF8F98E39}"
@@ -2081,6 +2091,54 @@ Global
{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|x64.Build.0 = Release|x64
{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|x86.ActiveCfg = Release|x64
{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA}.Release|x86.Build.0 = Release|x64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Debug|ARM64.Build.0 = Debug|ARM64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Debug|x64.ActiveCfg = Debug|x64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Debug|x64.Build.0 = Debug|x64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Debug|x86.ActiveCfg = Debug|x64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Debug|x86.Build.0 = Debug|x64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Release|ARM64.ActiveCfg = Release|ARM64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Release|ARM64.Build.0 = Release|ARM64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Release|x64.ActiveCfg = Release|x64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Release|x64.Build.0 = Release|x64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Release|x86.ActiveCfg = Release|x64
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}.Release|x86.Build.0 = Release|x64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Debug|ARM64.Build.0 = Debug|ARM64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Debug|x64.ActiveCfg = Debug|x64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Debug|x64.Build.0 = Debug|x64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Debug|x86.ActiveCfg = Debug|x64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Debug|x86.Build.0 = Debug|x64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Release|ARM64.ActiveCfg = Release|ARM64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Release|ARM64.Build.0 = Release|ARM64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Release|x64.ActiveCfg = Release|x64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Release|x64.Build.0 = Release|x64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Release|x86.ActiveCfg = Release|x64
+ {50B82783-242F-42D2-BC03-B3430BF01354}.Release|x86.Build.0 = Release|x64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Debug|ARM64.Build.0 = Debug|ARM64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Debug|x64.ActiveCfg = Debug|x64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Debug|x64.Build.0 = Debug|x64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Debug|x86.ActiveCfg = Debug|x64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Debug|x86.Build.0 = Debug|x64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Release|ARM64.ActiveCfg = Release|ARM64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Release|ARM64.Build.0 = Release|ARM64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Release|x64.ActiveCfg = Release|x64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Release|x64.Build.0 = Release|x64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Release|x86.ActiveCfg = Release|x64
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2}.Release|x86.Build.0 = Release|x64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Debug|ARM64.ActiveCfg = Debug|ARM64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Debug|ARM64.Build.0 = Debug|ARM64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Debug|x64.ActiveCfg = Debug|x64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Debug|x64.Build.0 = Debug|x64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Debug|x86.ActiveCfg = Debug|x64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Debug|x86.Build.0 = Debug|x64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Release|ARM64.ActiveCfg = Release|ARM64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Release|ARM64.Build.0 = Release|ARM64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Release|x64.ActiveCfg = Release|x64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Release|x64.Build.0 = Release|x64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Release|x86.ActiveCfg = Release|x64
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F}.Release|x86.Build.0 = Release|x64
{8A08D663-4995-40E3-B42C-3F910625F284}.Debug|ARM64.ActiveCfg = Debug|ARM64
{8A08D663-4995-40E3-B42C-3F910625F284}.Debug|ARM64.Build.0 = Debug|ARM64
{8A08D663-4995-40E3-B42C-3F910625F284}.Debug|x64.ActiveCfg = Debug|x64
@@ -2362,6 +2420,11 @@ Global
{CA5518ED-0458-4B09-8F53-4122B9888655} = {2F305555-C296-497E-AC20-5FA1B237996A}
{D6DCC3AE-18C0-488A-B978-BAA9E3CFF09D} = {2F305555-C296-497E-AC20-5FA1B237996A}
{2BBC9E33-21EC-401C-84DA-BB6590A9B2AA} = {2F305555-C296-497E-AC20-5FA1B237996A}
+ {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
+ {2833C9C6-AB32-4048-A5C7-A70898337B57} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}
+ {50B82783-242F-42D2-BC03-B3430BF01354} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}
+ {B5EB9FE9-37EF-47C3-B8B8-81AD3C2972C2} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}
+ {A663E672-B26D-4EC0-BEAB-FE2E424AC46F} = {B6C42F16-73EB-477E-8B0D-4E6CF6C20AAC}
{8A08D663-4995-40E3-B42C-3F910625F284} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{D962A009-834F-4EEC-AABB-430DF8F98E39} = {322566EF-20DC-43A6-B9F8-616AF942579A}
{D9C5DE64-6849-4278-91AD-9660AECF2876} = {322566EF-20DC-43A6-B9F8-616AF942579A}
diff --git a/README.md b/README.md
index 9691f8fa26e7..1297c247b378 100644
--- a/README.md
+++ b/README.md
@@ -20,10 +20,10 @@ Microsoft PowerToys is a set of utilities for power users to tune and streamline
| [Always on Top](https://aka.ms/PowerToysOverview_AoT) | [PowerToys Awake](https://aka.ms/PowerToysOverview_Awake) | [Color Picker](https://aka.ms/PowerToysOverview_ColorPicker) |
| [FancyZones](https://aka.ms/PowerToysOverview_FancyZones) | [File Explorer Add-ons](https://aka.ms/PowerToysOverview_FileExplorerAddOns) | [File Locksmith](https://aka.ms/PowerToysOverview_FileLocksmith) |
| [Hosts File Editor](https://aka.ms/PowerToysOverview_HostsFileEditor) | [Image Resizer](https://aka.ms/PowerToysOverview_ImageResizer) | [Keyboard Manager](https://aka.ms/PowerToysOverview_KeyboardManager) |
-| [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | [Peek](https://aka.ms/PowerToysOverview_Peek) | [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) |
-| [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) | [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) |
-| [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) | [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) |
-| [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Video Conference Mute](https://aka.ms/PowerToysOverview_VideoConference) |
+| [Mouse utilities](https://aka.ms/PowerToysOverview_MouseUtilities) | [Mouse Without Borders](https://aka.ms/PowerToysOverview_MouseWithoutBorders) | [Peek](https://aka.ms/PowerToysOverview_Peek) |
+| [Paste as Plain Text](https://aka.ms/PowerToysOverview_PastePlain) | [PowerRename](https://aka.ms/PowerToysOverview_PowerRename) | [PowerToys Run](https://aka.ms/PowerToysOverview_PowerToysRun) |
+| [Quick Accent](https://aka.ms/PowerToysOverview_QuickAccent) | [Registry Preview](https://aka.ms/PowerToysOverview_RegistryPreview) | [Screen Ruler](https://aka.ms/PowerToysOverview_ScreenRuler) |
+| [Shortcut Guide](https://aka.ms/PowerToysOverview_ShortcutGuide) | [Text Extractor](https://aka.ms/PowerToysOverview_TextExtractor) | [Video Conference Mute](https://aka.ms/PowerToysOverview_VideoConference) |
## Installing and running Microsoft PowerToys
diff --git a/doc/images/icons/MouseWithoutBorders.png b/doc/images/icons/MouseWithoutBorders.png
new file mode 100644
index 000000000000..a29adf7d1185
Binary files /dev/null and b/doc/images/icons/MouseWithoutBorders.png differ
diff --git a/installer/PowerToysSetup/Common.wxi b/installer/PowerToysSetup/Common.wxi
index ea955b0e3238..4a1c93fc8ea3 100644
--- a/installer/PowerToysSetup/Common.wxi
+++ b/installer/PowerToysSetup/Common.wxi
@@ -14,6 +14,7 @@
+
diff --git a/installer/PowerToysSetup/MouseWithoutBorders.wxs b/installer/PowerToysSetup/MouseWithoutBorders.wxs
new file mode 100644
index 000000000000..930f500f3fbc
--- /dev/null
+++ b/installer/PowerToysSetup/MouseWithoutBorders.wxs
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/installer/PowerToysSetup/PowerToysInstaller.wixproj b/installer/PowerToysSetup/PowerToysInstaller.wixproj
index 0116b31850ea..3bdc3df807ff 100644
--- a/installer/PowerToysSetup/PowerToysInstaller.wixproj
+++ b/installer/PowerToysSetup/PowerToysInstaller.wixproj
@@ -39,6 +39,7 @@ call "..\..\..\publish.cmd" arm64
call move /Y ..\..\..\KeyboardManager.wxs.bk ..\..\..\KeyboardManager.wxs
call move /Y ..\..\..\MeasureTool.wxs.bk ..\..\..\MeasureTool.wxs
call move /Y ..\..\..\MouseUtils.wxs.bk ..\..\..\MouseUtils.wxs
+ call move /Y ..\..\..\MouseWithoutBorders.wxs.bk ..\..\..\MouseWithoutBorders.wxs
call move /Y ..\..\..\Peek.wxs.bk ..\..\..\Peek.wxs
call move /Y ..\..\..\PowerAccent.wxs.bk ..\..\..\PowerAccent.wxs
call move /Y ..\..\..\PowerRename.wxs.bk ..\..\..\PowerRename.wxs
@@ -123,6 +124,7 @@ call "..\..\..\publish.cmd" arm64
+
@@ -131,6 +133,10 @@ call "..\..\..\publish.cmd" arm64
+
+ $(WixExtDir)\WixFirewallExtension.dll
+ WixFirewallExtension
+
$(WixExtDir)\WixUtilExtension.dll
WixUtilExtension
diff --git a/installer/PowerToysSetup/Product.wxs b/installer/PowerToysSetup/Product.wxs
index 1148bd5d5286..c5ea611145ef 100644
--- a/installer/PowerToysSetup/Product.wxs
+++ b/installer/PowerToysSetup/Product.wxs
@@ -76,7 +76,8 @@
-
+
+
@@ -192,7 +193,10 @@
Installed AND (REMOVE="ALL")
-
+
+ Installed AND (REMOVE="ALL")
+
+
@@ -330,7 +334,14 @@
DllEntry="UninstallEmbeddedMSIXCA"
/>
-
+
+
+
+
+
+
@@ -537,7 +552,7 @@
-
+
diff --git a/installer/PowerToysSetup/generateAllFileComponents.ps1 b/installer/PowerToysSetup/generateAllFileComponents.ps1
index eaa920e4c8d2..de5411683145 100644
--- a/installer/PowerToysSetup/generateAllFileComponents.ps1
+++ b/installer/PowerToysSetup/generateAllFileComponents.ps1
@@ -72,6 +72,10 @@ Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListNa
Invoke-Expression -Command "$PSScriptRoot\generateFileList.ps1 -fileDepsJson ""$PSScriptRoot..\..\..\$platform\Release\modules\MouseUtils\MouseJumpUI\PowerToys.MouseJumpUI.deps.json"" -fileListName MouseJumpUIFiles -wxsFilePath $PSScriptRoot\MouseUtils.wxs"
Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListName ""MouseJumpUIFiles"" -wxsFilePath $PSScriptRoot\MouseUtils.wxs -regroot $registryroot"
+#MouseWithoutBorders
+Invoke-Expression -Command "$PSScriptRoot\generateFileList.ps1 -fileDepsJson ""$PSScriptRoot..\..\..\$platform\Release\modules\MouseWithoutBorders\PowerToys.MouseWithoutBorders.deps.json;$PSScriptRoot..\..\..\$platform\Release\modules\MouseWithoutBorders\PowerToys.MouseWithoutBordersHelper.deps.json;$PSScriptRoot..\..\..\$platform\Release\modules\MouseWithoutBorders\PowerToys.MouseWithoutBordersService.deps.json"" -fileListName MouseWithoutBordersFiles -wxsFilePath $PSScriptRoot\MouseWithoutBorders.wxs"
+Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListName ""MouseWithoutBordersFiles"" -wxsFilePath $PSScriptRoot\MouseWithoutBorders.wxs -regroot $registryroot"
+
#MeasureTool
Invoke-Expression -Command "$PSScriptRoot\generateFileList.ps1 -fileDepsJson ""$PSScriptRoot..\..\..\$platform\Release\modules\MeasureTool\PowerToys.MeasureToolUI.deps.json"" -fileListName MeasureToolFiles -wxsFilePath $PSScriptRoot\MeasureTool.wxs -isWinAppSdkProj 1"
Invoke-Expression -Command "$PSScriptRoot\generateFileComponents.ps1 -fileListName ""MeasureToolFiles"" -wxsFilePath $PSScriptRoot\MeasureTool.wxs -regroot $registryroot"
diff --git a/installer/PowerToysSetup/generateFileList.ps1 b/installer/PowerToysSetup/generateFileList.ps1
index 5925ebedb203..a27447ee7498 100644
--- a/installer/PowerToysSetup/generateFileList.ps1
+++ b/installer/PowerToysSetup/generateFileList.ps1
@@ -1,5 +1,6 @@
[CmdletBinding()]
Param(
+ # Can be multiple files separated by ; as long as they're on the same directory
[Parameter(Mandatory = $True, Position = 1)]
[AllowEmptyString()]
[string]$fileDepsJson,
@@ -56,16 +57,22 @@ $dllsToIgnore = @("System.CodeDom.dll", "WindowsBase.dll")
if ($fileDepsJson -eq [string]::Empty) {
$fileDepsRoot = $depsPath
} else {
- $fileDepsRoot = (Get-ChildItem $fileDepsJson).Directory.FullName
- $depsJson = Get-Content $fileDepsJson | ConvertFrom-Json
+ $multipleDepsJson = $fileDepsJson.Split(";")
- $runtimeList = ([array]$depsJson.targets.PSObject.Properties)[-1].Value.PSObject.Properties | Where-Object {
- $_.Name -match "runtimepack.*Runtime"
- };
+ foreach ( $singleDepsJson in $multipleDepsJson )
+ {
- $runtimeList | ForEach-Object {
- $_.Value.PSObject.Properties.Value | ForEach-Object {
- $fileExclusionList += $_.PSObject.Properties.Name
+ $fileDepsRoot = (Get-ChildItem $singleDepsJson).Directory.FullName
+ $depsJson = Get-Content $singleDepsJson | ConvertFrom-Json
+
+ $runtimeList = ([array]$depsJson.targets.PSObject.Properties)[-1].Value.PSObject.Properties | Where-Object {
+ $_.Name -match "runtimepack.*Runtime"
+ };
+
+ $runtimeList | ForEach-Object {
+ $_.Value.PSObject.Properties.Value | ForEach-Object {
+ $fileExclusionList += $_.PSObject.Properties.Name
+ }
}
}
}
diff --git a/installer/PowerToysSetupCustomActions/CustomAction.cpp b/installer/PowerToysSetupCustomActions/CustomAction.cpp
index 8ecd9ce08872..106884e233ae 100644
--- a/installer/PowerToysSetupCustomActions/CustomAction.cpp
+++ b/installer/PowerToysSetupCustomActions/CustomAction.cpp
@@ -62,7 +62,7 @@ UINT __stdcall CheckGPOCA(MSIHANDLE hInstall)
LPWSTR currentScope = nullptr;
hr = WcaGetProperty(L"InstallScope", ¤tScope);
- if(std::wstring{ currentScope } == L"perUser")
+ if (std::wstring{ currentScope } == L"perUser")
{
if (powertoys_gpo::getDisablePerUserInstallationValue() == powertoys_gpo::gpo_rule_configured_enabled)
{
@@ -202,6 +202,69 @@ UINT __stdcall UninstallEmbeddedMSIXCA(MSIHANDLE hInstall)
return WcaFinalize(er);
}
+UINT __stdcall RemoveWindowsServiceByName(std::wstring serviceName)
+{
+ SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
+
+ if (!hSCManager)
+ {
+ return ERROR_INSTALL_FAILURE;
+ }
+
+ SC_HANDLE hService = OpenService(hSCManager, serviceName.c_str(), SERVICE_STOP | DELETE);
+ if (!hService)
+ {
+ CloseServiceHandle(hSCManager);
+ return ERROR_INSTALL_FAILURE;
+ }
+
+ SERVICE_STATUS ss;
+ if (ControlService(hService, SERVICE_CONTROL_STOP, &ss))
+ {
+ Sleep(1000);
+ while (QueryServiceStatus(hService, &ss))
+ {
+ if (ss.dwCurrentState == SERVICE_STOP_PENDING)
+ {
+ Sleep(1000);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ BOOL deleteResult = DeleteService(hService);
+ CloseServiceHandle(hService);
+ CloseServiceHandle(hSCManager);
+
+ if (!deleteResult)
+ {
+ return ERROR_INSTALL_FAILURE;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+
+UINT __stdcall UninstallServicesCA(MSIHANDLE hInstall)
+{
+ HRESULT hr = S_OK;
+ UINT er = ERROR_SUCCESS;
+ hr = WcaInitialize(hInstall, "CreateScheduledTaskCA");
+
+ ExitOnFailure(hr, "Failed to initialize");
+
+ hr = RemoveWindowsServiceByName(L"PowerToys.MWB.Service");
+
+LExit:
+ er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
+ return WcaFinalize(er);
+}
+
+
// Creates a Scheduled Task to run at logon for the current user.
// The path of the executable to run should be passed as the CustomActionData (Value).
// Based on the Task Scheduler Logon Trigger Example:
@@ -269,10 +332,10 @@ UINT __stdcall CreateScheduledTaskCA(MSIHANDLE hInstall)
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
- nullptr,
- CLSCTX_INPROC_SERVER,
- IID_ITaskService,
- reinterpret_cast(&pService));
+ nullptr,
+ CLSCTX_INPROC_SERVER,
+ IID_ITaskService,
+ reinterpret_cast(&pService));
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
// Connect to the task service.
@@ -495,10 +558,10 @@ UINT __stdcall RemoveScheduledTasksCA(MSIHANDLE hInstall)
// ------------------------------------------------------
// Create an instance of the Task Service.
hr = CoCreateInstance(CLSID_TaskScheduler,
- nullptr,
- CLSCTX_INPROC_SERVER,
- IID_ITaskService,
- reinterpret_cast(&pService));
+ nullptr,
+ CLSCTX_INPROC_SERVER,
+ IID_ITaskService,
+ reinterpret_cast(&pService));
ExitOnFailure(hr, "Failed to create an instance of ITaskService: %x", hr);
// Connect to the task service.
@@ -831,11 +894,11 @@ UINT __stdcall CertifyVirtualCameraDriverCA(MSIHANDLE hInstall)
}
if (!CertAddEncodedCertificateToStore(hCertStore,
- X509_ASN_ENCODING,
- reinterpret_cast(pFileContent),
- size,
- CERT_STORE_ADD_ALWAYS,
- nullptr))
+ X509_ASN_ENCODING,
+ reinterpret_cast(pFileContent),
+ size,
+ CERT_STORE_ADD_ALWAYS,
+ nullptr))
{
hr = GetLastError();
ExitOnFailure(hr, "Adding certificate failed", hr);
@@ -1071,6 +1134,7 @@ const std::wstring PTInteropConsumers[] =
L"modules\\Hosts",
L"modules\\Peek",
L"modules\\FileExplorerPreview",
+ L"modules\\MouseWithoutBorders",
L"modules\\MouseUtils\\MouseJumpUI",
L"modules\\RegistryPreview",
};
@@ -1090,12 +1154,12 @@ UINT __stdcall CreatePTInteropHardlinksCA(MSIHANDLE hInstall)
interopFilesSrcDir = installationFolder + L"dll\\Interop\\";
for (auto file : powerToysInteropFiles)
- {
+ {
for (auto consumer : PTInteropConsumers)
{
std::error_code ec;
std::filesystem::create_hard_link((interopFilesSrcDir + file).c_str(), (installationFolder + consumer + L"\\" + file).c_str(), ec);
-
+
if (ec.value() != S_OK)
{
std::wstring errorMessage{ L"Error creating hard link for: " };
@@ -1116,8 +1180,8 @@ UINT __stdcall CreateDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
HRESULT hr = S_OK;
UINT er = ERROR_SUCCESS;
std::wstring installationFolder, dotnetRuntimeFilesSrcDir, colorPickerDir, powerOCRDir, launcherDir, fancyZonesDir,
- imageResizerDir, settingsDir, awakeDir, measureToolDir, powerAccentDir, fileExplorerAddOnsDir, hostsDir, fileLocksmithDir,
- mouseJumpDir, registryPreviewDir, peekDir;
+ imageResizerDir, settingsDir, awakeDir, measureToolDir, powerAccentDir, fileExplorerAddOnsDir, hostsDir, fileLocksmithDir,
+ mouseJumpDir, registryPreviewDir, peekDir, mwbDir;
hr = WcaInitialize(hInstall, "CreateDotnetRuntimeHardlinksCA");
ExitOnFailure(hr, "Failed to initialize");
@@ -1138,6 +1202,7 @@ UINT __stdcall CreateDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
fileExplorerAddOnsDir = installationFolder + L"modules\\FileExplorerPreview\\";
hostsDir = installationFolder + L"modules\\Hosts\\";
fileLocksmithDir = installationFolder + L"modules\\FileLocksmith\\";
+ mwbDir = installationFolder + L"modules\\MouseWithoutBorders\\";
mouseJumpDir = installationFolder + L"modules\\MouseUtils\\MouseJumpUI\\";
registryPreviewDir = installationFolder + L"modules\\RegistryPreview\\";
peekDir = installationFolder + L"modules\\Peek\\";
@@ -1157,6 +1222,7 @@ UINT __stdcall CreateDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fileExplorerAddOnsDir + file).c_str(), ec);
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (hostsDir + file).c_str(), ec);
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fileLocksmithDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (mwbDir + file).c_str(), ec);
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (mouseJumpDir + file).c_str(), ec);
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (registryPreviewDir + file).c_str(), ec);
std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (peekDir + file).c_str(), ec);
@@ -1173,31 +1239,32 @@ UINT __stdcall CreateDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
for (auto file : dotnetRuntimeWPFFiles)
{
- std::error_code ec;
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (awakeDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (colorPickerDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (powerOCRDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (launcherDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fancyZonesDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (imageResizerDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (powerAccentDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fileExplorerAddOnsDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (hostsDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (mouseJumpDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (registryPreviewDir + file).c_str(), ec);
- std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (peekDir + file).c_str(), ec);
-
- if (ec.value() != S_OK)
- {
- std::wstring errorMessage{ L"Error creating hard link for: " };
- errorMessage += file;
- errorMessage += L", error code: " + std::to_wstring(ec.value());
- Logger::error(errorMessage);
- er = ERROR_INSTALL_FAILURE;
- }
+ std::error_code ec;
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (awakeDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (colorPickerDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (powerOCRDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (launcherDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fancyZonesDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (imageResizerDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (powerAccentDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (fileExplorerAddOnsDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (hostsDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (mouseJumpDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (registryPreviewDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (peekDir + file).c_str(), ec);
+ std::filesystem::create_hard_link((dotnetRuntimeFilesSrcDir + file).c_str(), (mwbDir + file).c_str(), ec);
+
+ if (ec.value() != S_OK)
+ {
+ std::wstring errorMessage{ L"Error creating hard link for: " };
+ errorMessage += file;
+ errorMessage += L", error code: " + std::to_wstring(ec.value());
+ Logger::error(errorMessage);
+ er = ERROR_INSTALL_FAILURE;
+ }
}
- LExit:
+LExit:
er = SUCCEEDED(hr) ? ERROR_SUCCESS : ERROR_INSTALL_FAILURE;
return WcaFinalize(er);
}
@@ -1280,7 +1347,7 @@ UINT __stdcall DeleteDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
UINT er = ERROR_SUCCESS;
std::wstring installationFolder, colorPickerDir, powerOCRDir, launcherDir, fancyZonesDir,
imageResizerDir, settingsDir, awakeDir, measureToolDir, powerAccentDir, fileExplorerAddOnsDir,
- hostsDir, fileLocksmithDir, mouseJumpDir, registryPreviewDir, peekDir;
+ hostsDir, fileLocksmithDir, mouseJumpDir, registryPreviewDir, peekDir, mwbDir;
hr = WcaInitialize(hInstall, "DeleteDotnetRuntimeHardlinksCA");
ExitOnFailure(hr, "Failed to initialize");
@@ -1300,6 +1367,7 @@ UINT __stdcall DeleteDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
fileExplorerAddOnsDir = installationFolder + L"modules\\FileExplorerPreview\\";
hostsDir = installationFolder + L"modules\\Hosts\\";
fileLocksmithDir = installationFolder + L"modules\\FileLocksmith\\";
+ mwbDir = installationFolder + L"modules\\MouseWithoutBorders\\";
mouseJumpDir = installationFolder + L"modules\\MouseUtils\\MouseJumpUI\\";
registryPreviewDir = installationFolder + L"modules\\RegistryPreview\\";
peekDir = installationFolder + L"modules\\Peek\\";
@@ -1308,37 +1376,39 @@ UINT __stdcall DeleteDotnetRuntimeHardlinksCA(MSIHANDLE hInstall)
{
for (auto file : dotnetRuntimeFiles)
{
- DeleteFile((colorPickerDir + file).c_str());
- DeleteFile((powerOCRDir + file).c_str());
- DeleteFile((launcherDir + file).c_str());
- DeleteFile((fancyZonesDir + file).c_str());
- DeleteFile((imageResizerDir + file).c_str());
- DeleteFile((settingsDir + file).c_str());
- DeleteFile((awakeDir + file).c_str());
- DeleteFile((measureToolDir + file).c_str());
- DeleteFile((powerAccentDir + file).c_str());
- DeleteFile((fileExplorerAddOnsDir + file).c_str());
- DeleteFile((hostsDir + file).c_str());
- DeleteFile((fileLocksmithDir + file).c_str());
- DeleteFile((mouseJumpDir + file).c_str());
- DeleteFile((registryPreviewDir + file).c_str());
- DeleteFile((peekDir + file).c_str());
+ DeleteFile((colorPickerDir + file).c_str());
+ DeleteFile((powerOCRDir + file).c_str());
+ DeleteFile((launcherDir + file).c_str());
+ DeleteFile((fancyZonesDir + file).c_str());
+ DeleteFile((imageResizerDir + file).c_str());
+ DeleteFile((settingsDir + file).c_str());
+ DeleteFile((awakeDir + file).c_str());
+ DeleteFile((measureToolDir + file).c_str());
+ DeleteFile((powerAccentDir + file).c_str());
+ DeleteFile((fileExplorerAddOnsDir + file).c_str());
+ DeleteFile((hostsDir + file).c_str());
+ DeleteFile((fileLocksmithDir + file).c_str());
+ DeleteFile((mouseJumpDir + file).c_str());
+ DeleteFile((registryPreviewDir + file).c_str());
+ DeleteFile((peekDir + file).c_str());
+ DeleteFile((mwbDir + file).c_str());
}
for (auto file : dotnetRuntimeWPFFiles)
{
- DeleteFile((awakeDir + file).c_str());
- DeleteFile((colorPickerDir + file).c_str());
- DeleteFile((powerOCRDir + file).c_str());
- DeleteFile((launcherDir + file).c_str());
- DeleteFile((fancyZonesDir + file).c_str());
- DeleteFile((imageResizerDir + file).c_str());
- DeleteFile((powerAccentDir + file).c_str());
- DeleteFile((fileExplorerAddOnsDir + file).c_str());
- DeleteFile((hostsDir + file).c_str());
- DeleteFile((mouseJumpDir + file).c_str());
- DeleteFile((registryPreviewDir + file).c_str());
- DeleteFile((peekDir + file).c_str());
+ DeleteFile((awakeDir + file).c_str());
+ DeleteFile((colorPickerDir + file).c_str());
+ DeleteFile((powerOCRDir + file).c_str());
+ DeleteFile((launcherDir + file).c_str());
+ DeleteFile((fancyZonesDir + file).c_str());
+ DeleteFile((imageResizerDir + file).c_str());
+ DeleteFile((powerAccentDir + file).c_str());
+ DeleteFile((fileExplorerAddOnsDir + file).c_str());
+ DeleteFile((hostsDir + file).c_str());
+ DeleteFile((mouseJumpDir + file).c_str());
+ DeleteFile((registryPreviewDir + file).c_str());
+ DeleteFile((peekDir + file).c_str());
+ DeleteFile((mwbDir + file).c_str());
}
}
catch (std::exception e)
@@ -1372,7 +1442,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
}
processes.resize(bytes / sizeof(processes[0]));
- std::array processesToTerminate = {
+ std::array processesToTerminate = {
L"PowerToys.PowerLauncher.exe",
L"PowerToys.Settings.exe",
L"PowerToys.Awake.exe",
@@ -1396,6 +1466,9 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
L"PowerToys.PdfPreviewHandler.exe",
L"PowerToys.SvgPreviewHandler.exe",
L"PowerToys.Peek.UI.exe",
+ L"PowerToys.MouseWithoutBorders.exe"
+ L"PowerToys.MouseWithoutBordersHelper.exe"
+ L"PowerToys.MouseWithoutBordersService.exe"
L"PowerToys.exe",
};
@@ -1462,7 +1535,7 @@ void initSystemLogger()
{
Logger::init("PowerToysMSI", std::wstring{ temp_path } + L"\\PowerToysMSIInstaller", L"");
}
- });
+ });
}
// DllMain - Initialize and cleanup WiX custom action utils.
diff --git a/installer/PowerToysSetupCustomActions/CustomAction.def b/installer/PowerToysSetupCustomActions/CustomAction.def
index 21f254705272..2d7397f4da51 100644
--- a/installer/PowerToysSetupCustomActions/CustomAction.def
+++ b/installer/PowerToysSetupCustomActions/CustomAction.def
@@ -27,4 +27,5 @@ EXPORTS
UnApplyModulesRegistryChangeSetsCA
UninstallVirtualCameraDriverCA
UnRegisterContextMenuPackagesCA
- UninstallEmbeddedMSIXCA
\ No newline at end of file
+ UninstallEmbeddedMSIXCA
+ UninstallServicesCA
\ No newline at end of file
diff --git a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj
index 7e0a583bff40..21f0ca114af5 100644
--- a/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj
+++ b/installer/PowerToysSetupCustomActions/PowerToysSetupCustomActions.vcxproj
@@ -61,6 +61,7 @@
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\KeyboardManager.wxs"" ""$(ProjectDir)..\PowerToysSetup\KeyboardManager.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\MeasureTool.wxs"" ""$(ProjectDir)..\PowerToysSetup\MeasureTool.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\MouseUtils.wxs"" ""$(ProjectDir)..\PowerToysSetup\MouseUtils.wxs.bk""""
+ call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\MouseWithoutBorders.wxs"" ""$(ProjectDir)..\PowerToysSetup\MouseWithoutBorders.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\Peek.wxs"" ""$(ProjectDir)..\PowerToysSetup\Peek.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\PowerAccent.wxs"" ""$(ProjectDir)..\PowerToysSetup\PowerAccent.wxs.bk""""
call cmd /C "copy ""$(ProjectDir)..\PowerToysSetup\PowerRename.wxs"" ""$(ProjectDir)..\PowerToysSetup\PowerRename.wxs.bk""""
diff --git a/src/codeAnalysis/GlobalSuppressions.cs b/src/codeAnalysis/GlobalSuppressions.cs
index 59af74b139ec..f130177ee3e3 100644
--- a/src/codeAnalysis/GlobalSuppressions.cs
+++ b/src/codeAnalysis/GlobalSuppressions.cs
@@ -33,6 +33,7 @@
[assembly: SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Static methods may improve performance but decrease maintainability")]
[assembly: SuppressMessage("Naming", "CA1711:Identifiers should not have incorrect suffix", Justification = "Renaming everything would be a lot of work. It does not do any harm if an EventHandler delegate ends with the suffix EventHandler. Besides this, the Rule causes some false positives.")]
[assembly: SuppressMessage("Performance", "CA1838:Avoid 'StringBuilder' parameters for P/Invokes", Justification = "We are not concerned about the performance impact of marshaling a StringBuilder")]
+[assembly: SuppressMessage("Performance", "CA1852:Seal internal types", Justification = "The assembly is getting a ComVisible set to false already.", Scope="namespaceanddescendants", Target="MouseWithoutBorders")]
// Threading suppressions
[assembly: SuppressMessage("Microsoft.VisualStudio.Threading.Analyzers", "VSTHRD100:Avoid async void methods", Justification = "Event handlers needs async void", Scope = "member", Target = "~M:Microsoft.Templates.UI.Controls.Notification.OnClose")]
@@ -54,3 +55,10 @@
// Code quality
[assembly: SuppressMessage("CodeQuality", "IDE0076:Invalid global 'SuppressMessageAttribute'", Justification = "Affect predefined suppressions.")]
+
+// Dotnet port
+[assembly: SuppressMessage("Design", "CA1069:Enums values should not be duplicated", Justification = "", Scope="namespaceanddescendants", Target="MouseWithoutBorders")]
+[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1401:Fields should be private", Justification = "", Scope="namespaceanddescendants", Target="MouseWithoutBorders")]
+[assembly: SuppressMessage("StyleCop.CSharp.MaintainabilityRules", "SA1402:File may only contain a single type", Justification = "", Scope="namespaceanddescendants", Target="MouseWithoutBorders")]
+[assembly: SuppressMessage("StyleCop.CSharp.NamingRules", "SA1310:Field names should not contain underscore", Justification = "", Scope="namespaceanddescendants", Target="MouseWithoutBorders")]
+[assembly: SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "", Scope="namespaceanddescendants", Target="MouseWithoutBorders")]
diff --git a/src/common/GPOWrapper/GPOWrapper.cpp b/src/common/GPOWrapper/GPOWrapper.cpp
index d2a9af2b2bc4..cb5ac5508929 100644
--- a/src/common/GPOWrapper/GPOWrapper.cpp
+++ b/src/common/GPOWrapper/GPOWrapper.cpp
@@ -124,6 +124,10 @@ namespace winrt::PowerToys::GPOWrapper::implementation
{
return static_cast(powertoys_gpo::getConfiguredVideoConferenceMuteEnabledValue());
}
+ GpoRuleConfigured GPOWrapper::GetConfiguredMouseWithoutBordersEnabledValue()
+ {
+ return static_cast(powertoys_gpo::getConfiguredMouseWithoutBordersEnabledValue());
+ }
GpoRuleConfigured GPOWrapper::GetConfiguredPeekEnabledValue()
{
return static_cast(powertoys_gpo::getConfiguredPeekEnabledValue());
diff --git a/src/common/GPOWrapper/GPOWrapper.h b/src/common/GPOWrapper/GPOWrapper.h
index b0c7c7de4bb4..d9e9896caf8e 100644
--- a/src/common/GPOWrapper/GPOWrapper.h
+++ b/src/common/GPOWrapper/GPOWrapper.h
@@ -15,6 +15,7 @@ namespace winrt::PowerToys::GPOWrapper::implementation
static GpoRuleConfigured GetConfiguredSvgPreviewEnabledValue();
static GpoRuleConfigured GetConfiguredMarkdownPreviewEnabledValue();
static GpoRuleConfigured GetConfiguredMonacoPreviewEnabledValue();
+ static GpoRuleConfigured GetConfiguredMouseWithoutBordersEnabledValue();
static GpoRuleConfigured GetConfiguredPdfPreviewEnabledValue();
static GpoRuleConfigured GetConfiguredGcodePreviewEnabledValue();
static GpoRuleConfigured GetConfiguredSvgThumbnailsEnabledValue();
diff --git a/src/common/GPOWrapper/GPOWrapper.idl b/src/common/GPOWrapper/GPOWrapper.idl
index 689cbb1dfcf2..9bec67ccf1c1 100644
--- a/src/common/GPOWrapper/GPOWrapper.idl
+++ b/src/common/GPOWrapper/GPOWrapper.idl
@@ -32,6 +32,7 @@ namespace PowerToys
static GpoRuleConfigured GetConfiguredMouseHighlighterEnabledValue();
static GpoRuleConfigured GetConfiguredMouseJumpEnabledValue();
static GpoRuleConfigured GetConfiguredMousePointerCrosshairsEnabledValue();
+ static GpoRuleConfigured GetConfiguredMouseWithoutBordersEnabledValue();
static GpoRuleConfigured GetConfiguredPowerRenameEnabledValue();
static GpoRuleConfigured GetConfiguredPowerLauncherEnabledValue();
static GpoRuleConfigured GetConfiguredQuickAccentEnabledValue();
diff --git a/src/common/ManagedCommon/NativeMethods.cs b/src/common/ManagedCommon/NativeMethods.cs
index cd191fe4b494..b7cc0a218155 100644
--- a/src/common/ManagedCommon/NativeMethods.cs
+++ b/src/common/ManagedCommon/NativeMethods.cs
@@ -14,5 +14,17 @@ internal static class NativeMethods
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);
+
+ [DllImport("psapi.dll", SetLastError = true)]
+ internal static extern bool EnumProcesses(int[] processIds, uint arraySizeBytes, out uint bytesCopied);
+
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ internal static extern bool QueryFullProcessImageName(IntPtr hProcess, uint dwFlags, System.Text.StringBuilder lpExeName, ref uint lpdwSize);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ internal static extern bool GetExitCodeProcess(IntPtr hProcess, out uint lpExitCode);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ internal static extern bool CloseHandle(IntPtr hObject);
}
}
diff --git a/src/common/ManagedCommon/RunnerHelper.cs b/src/common/ManagedCommon/RunnerHelper.cs
index de528660f2e3..28223a75b996 100644
--- a/src/common/ManagedCommon/RunnerHelper.cs
+++ b/src/common/ManagedCommon/RunnerHelper.cs
@@ -33,5 +33,59 @@ public static void WaitForPowerToysRunner(int powerToysPID, Action act)
}
});
}
+
+ private static readonly string PowerToysRunnerProcessName = "PowerToys.exe";
+
+ // In case we don't have a permission to open user's processes with a SYNCHRONIZE access right, e.g. LocalSystem processes, we could use GetExitCodeProcess to check the process' exit code periodically.
+ public static void WaitForPowerToysRunnerExitFallback(Action act)
+ {
+ int[] processIds = new int[1024];
+ uint bytesCopied;
+
+ NativeMethods.EnumProcesses(processIds, (uint)processIds.Length * sizeof(uint), out bytesCopied);
+
+ const uint PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
+ var handleAccess = PROCESS_QUERY_LIMITED_INFORMATION;
+
+ IntPtr runnerHandle = IntPtr.Zero;
+ foreach (var processId in processIds)
+ {
+ IntPtr hProcess = NativeMethods.OpenProcess(handleAccess, false, processId);
+ System.Text.StringBuilder name = new System.Text.StringBuilder(1024);
+ uint length = 1024;
+ if (hProcess == IntPtr.Zero || !NativeMethods.QueryFullProcessImageName(hProcess, 0, name, ref length))
+ {
+ continue;
+ }
+
+ if (System.IO.Path.GetFileName(name.ToString()) == PowerToysRunnerProcessName)
+ {
+ runnerHandle = hProcess;
+ break;
+ }
+ }
+
+ if (runnerHandle == IntPtr.Zero)
+ {
+ Logger.LogError("Couldn't determine PowerToys.exe pid");
+ return;
+ }
+
+ Task.Run(() =>
+ {
+ const int STILL_ACTIVE = 0x103;
+ uint exit_status;
+ do
+ {
+ System.Threading.Thread.Sleep(1000);
+ NativeMethods.GetExitCodeProcess(runnerHandle, out exit_status);
+ }
+ while (exit_status == STILL_ACTIVE);
+
+ NativeMethods.CloseHandle(runnerHandle);
+
+ act.Invoke();
+ });
+ }
}
}
diff --git a/src/common/logger/logger_settings.h b/src/common/logger/logger_settings.h
index fb64a11eae9e..eeb727433162 100644
--- a/src/common/logger/logger_settings.h
+++ b/src/common/logger/logger_settings.h
@@ -35,6 +35,8 @@ struct LogSettings
inline const static std::wstring svgThumbLogPath = L"logs\\FileExplorer_localLow\\SvgThumbnailProvider\\svg-thumbnail-provider-log.txt";
inline const static std::string launcherLoggerName = "launcher";
inline const static std::wstring launcherLogPath = L"LogsModuleInterface\\launcher-log.txt";
+ inline const static std::string mouseWithoutBordersLoggerName = "mouseWithoutBorders";
+ inline const static std::wstring mouseWithoutBordersLogPath = L"LogsModuleInterface\\mouseWithoutBorders-log.txt";
inline const static std::wstring awakeLogPath = L"Logs\\awake-log.txt";
inline const static std::wstring powerAccentLogPath = L"quick-accent-log.txt";
inline const static std::string fancyZonesLoggerName = "fancyzones";
diff --git a/src/common/utils/gpo.h b/src/common/utils/gpo.h
index 66d14ff3debd..fa937718fb90 100644
--- a/src/common/utils/gpo.h
+++ b/src/common/utils/gpo.h
@@ -49,6 +49,7 @@ namespace powertoys_gpo {
const std::wstring POLICY_CONFIGURE_ENABLED_PASTE_PLAIN = L"ConfigureEnabledUtilityPastePlain";
const std::wstring POLICY_CONFIGURE_ENABLED_VIDEO_CONFERENCE_MUTE = L"ConfigureEnabledUtilityVideoConferenceMute";
const std::wstring POLICY_CONFIGURE_ENABLED_REGISTRY_PREVIEW = L"ConfigureEnabledUtilityRegistryPreview";
+ const std::wstring POLICY_CONFIGURE_ENABLED_MOUSE_WITHOUT_BORDERS = L"ConfigureEnabledUtilityMouseWithoutBorders";
const std::wstring POLICY_CONFIGURE_ENABLED_PEEK = L"ConfigureEnabledUtilityPeek";
// The registry value names for PowerToys installer and update policies.
@@ -258,6 +259,11 @@ namespace powertoys_gpo {
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_VIDEO_CONFERENCE_MUTE);
}
+ inline gpo_rule_configured_t getConfiguredMouseWithoutBordersEnabledValue()
+ {
+ return getConfiguredValue(POLICY_CONFIGURE_ENABLED_MOUSE_WITHOUT_BORDERS);
+ }
+
inline gpo_rule_configured_t getConfiguredPeekEnabledValue()
{
return getConfiguredValue(POLICY_CONFIGURE_ENABLED_PEEK);
diff --git a/src/common/utils/processApi.h b/src/common/utils/processApi.h
index 9f56ce4fe447..ec44f9338593 100644
--- a/src/common/utils/processApi.h
+++ b/src/common/utils/processApi.h
@@ -22,14 +22,15 @@ inline std::vector getProcessHandlesByName(const std
}
processIds.resize(bytesRequired / sizeof(processIds[0]));
- handleAccess |= PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ;
+ handleAccess |= PROCESS_QUERY_LIMITED_INFORMATION;
for (const DWORD processId : processIds)
{
try
{
wil::unique_process_handle hProcess{ OpenProcess(handleAccess, FALSE, processId) };
wchar_t name[MAX_PATH + 1];
- if (!hProcess || !GetProcessImageFileNameW(hProcess.get(), name, MAX_PATH))
+ DWORD length = MAX_PATH;
+ if (!hProcess || !QueryFullProcessImageNameW(hProcess.get(), 0, name, &length))
{
continue;
}
diff --git a/src/gpo/assets/PowerToys.admx b/src/gpo/assets/PowerToys.admx
index d9bedc91b021..2f45a8ab298f 100644
--- a/src/gpo/assets/PowerToys.admx
+++ b/src/gpo/assets/PowerToys.admx
@@ -231,6 +231,16 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/gpo/assets/en-US/PowerToys.adml b/src/gpo/assets/en-US/PowerToys.adml
index 9882bc0d81f3..e70495cc7151 100644
--- a/src/gpo/assets/en-US/PowerToys.adml
+++ b/src/gpo/assets/en-US/PowerToys.adml
@@ -85,6 +85,7 @@ If this setting is disabled, experimentation is not allowed.
Mouse Highlighter: Configure enabled state
Mouse Jump: Configure enabled state
Mouse Pointer Crosshairs: Configure enabled state
+ Mouse Without Borders: Configure enabled state
Paste as Plain Text: Configure enabled state
Peek: Configure enabled state
Power Rename: Configure enabled state
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs
new file mode 100644
index 000000000000..348c1f149eaa
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.Clipboard.cs
@@ -0,0 +1,1144 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.IO.Compression;
+using System.Linq;
+using System.Net.Sockets;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Microsoft.PowerToys.Telemetry;
+
+//
+// Clipboard related routines.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+using MouseWithoutBorders.Exceptions;
+using SystemClipboard = System.Windows.Forms.Clipboard;
+
+namespace MouseWithoutBorders
+{
+ internal partial class Common
+ {
+ private const uint BIG_CLIPBOARD_DATA_TIMEOUT = 30000;
+ private const uint MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP = 1024 * 1024; // 1MB
+ private const uint MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT = 100 * 1024 * 1024; // 100MB
+ private const int TEXT_HEADER_SIZE = 12;
+ private const int DATA_SIZE = 48;
+ private const string TEXT_TYPE_SEP = "{4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}";
+ private static long lastClipboardEventTime;
+ private static string lastMachineWithClipboardData;
+ private static string lastDragDropFile;
+ private static long clipboardCopiedTime;
+
+ internal static ID LastIDWithClipboardData { get; set; }
+
+ internal static string LastDragDropFile
+ {
+ get => Common.lastDragDropFile;
+ set => Common.lastDragDropFile = value;
+ }
+
+ internal static string LastMachineWithClipboardData
+ {
+ get => Common.lastMachineWithClipboardData;
+ set => Common.lastMachineWithClipboardData = value;
+ }
+
+ internal static long LastClipboardEventTime
+ {
+ get => Common.lastClipboardEventTime;
+ set => Common.lastClipboardEventTime = value;
+ }
+
+ internal static IntPtr NextClipboardViewer { get; set; }
+
+ internal static bool IsClipboardDataImage { get; private set; }
+
+ internal static byte[] LastClipboardData { get; private set; }
+
+ private static object lastClipboardObject = string.Empty;
+
+ internal static bool HasSwitchedMachineSinceLastCopy { get; set; }
+
+ internal static bool CheckClipboardEx(ByteArrayOrString data, bool isFilePath)
+ {
+ LogDebug($"{nameof(CheckClipboardEx)}: ShareClipboard = {Setting.Values.ShareClipboard}, TransferFile = {Setting.Values.TransferFile}, data = {data}.");
+ LogDebug($"{nameof(CheckClipboardEx)}: {nameof(Setting.Values.OneWayClipboardMode)} = {Setting.Values.OneWayClipboardMode}.");
+
+ if (!Setting.Values.ShareClipboard)
+ {
+ return false;
+ }
+
+ if (Common.RunWithNoAdminRight && Setting.Values.OneWayClipboardMode)
+ {
+ return false;
+ }
+
+ if (GetTick() - LastClipboardEventTime < 1000)
+ {
+ LogDebug("GetTick() - lastClipboardEventTime < 1000");
+ LastClipboardEventTime = GetTick();
+ return false;
+ }
+
+ LastClipboardEventTime = GetTick();
+
+ try
+ {
+ IsClipboardDataImage = false;
+ LastClipboardData = null;
+ LastDragDropFile = null;
+ GC.Collect();
+
+ string stringData = null;
+ byte[] byteData = null;
+
+ if (data.IsByteArray)
+ {
+ byteData = data.GetByteArray();
+ }
+ else
+ {
+ stringData = data.GetString();
+ }
+
+ if (stringData != null)
+ {
+ if (!HasSwitchedMachineSinceLastCopy)
+ {
+ if (lastClipboardObject is string lastStringData && lastStringData.Equals(stringData, StringComparison.OrdinalIgnoreCase))
+ {
+ LogDebug("CheckClipboardEx: Same string data.");
+ return false;
+ }
+ }
+
+ HasSwitchedMachineSinceLastCopy = false;
+
+ if (isFilePath)
+ {
+ Common.LogDebug("Clipboard contains FileDropList");
+
+ if (!Setting.Values.TransferFile)
+ {
+ Common.LogDebug("TransferFile option is unchecked.");
+ return false;
+ }
+
+ string filePath = stringData;
+
+ _ = Common.ImpersonateLoggedOnUserAndDoSomething(() =>
+ {
+ if (File.Exists(filePath) || Directory.Exists(filePath))
+ {
+ if (File.Exists(filePath) && new FileInfo(filePath).Length <= MAX_CLIPBOARD_FILE_SIZE_CAN_BE_SENT)
+ {
+ LogDebug("Clipboard contains: " + filePath);
+ LastDragDropFile = filePath;
+ SendClipboardBeat();
+ SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_BIG_CLIPBOARD, -1, ICON_BIG_CLIPBOARD, -1 });
+ }
+ else
+ {
+ if (Directory.Exists(filePath))
+ {
+ LogDebug("Clipboard contains a directory: " + filePath);
+ LastDragDropFile = filePath;
+ SendClipboardBeat();
+ }
+ else
+ {
+ LastDragDropFile = filePath + " - File too big (greater than 100MB), please drag and drop the file instead!";
+ SendClipboardBeat();
+ Log("Clipboard: File too big: " + filePath);
+ }
+
+ SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_ERROR, -1, ICON_ERROR, -1 });
+ }
+ }
+ else
+ {
+ Log("CheckClipboardEx: File not found: " + filePath);
+ }
+ });
+ }
+ else
+ {
+ byte[] texts = Common.GetBytesU(stringData);
+
+ using MemoryStream ms = new();
+ using (DeflateStream s = new(ms, CompressionMode.Compress, true))
+ {
+ s.Write(texts, 0, texts.Length);
+ }
+
+ Common.LogDebug("Plain/Zip = " + texts.Length.ToString(CultureInfo.CurrentCulture) + "/" +
+ ms.Length.ToString(CultureInfo.CurrentCulture));
+
+ LastClipboardData = ms.GetBuffer();
+ }
+ }
+ else if (byteData != null)
+ {
+ if (!HasSwitchedMachineSinceLastCopy)
+ {
+ if (lastClipboardObject is byte[] lastByteData && Enumerable.SequenceEqual(lastByteData, byteData))
+ {
+ LogDebug("CheckClipboardEx: Same byte[] data.");
+ return false;
+ }
+ }
+
+ HasSwitchedMachineSinceLastCopy = false;
+
+ Common.LogDebug("Clipboard contains image");
+ IsClipboardDataImage = true;
+ LastClipboardData = byteData;
+ }
+ else
+ {
+ LogDebug("*** Clipboard contains something else!");
+ return false;
+ }
+
+ lastClipboardObject = data;
+
+ if (LastClipboardData != null && LastClipboardData.Length > 0)
+ {
+ if (LastClipboardData.Length > MAX_CLIPBOARD_DATA_SIZE_CAN_BE_SENT_INSTANTLY_TCP)
+ {
+ SendClipboardBeat();
+ SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_BIG_CLIPBOARD, -1, ICON_BIG_CLIPBOARD, -1 });
+ }
+ else
+ {
+ SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_SMALL_CLIPBOARD, -1, -1, -1 });
+ SendClipboardDataUsingTCP(LastClipboardData, IsClipboardDataImage);
+ }
+
+ return true;
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+
+ return false;
+ }
+
+ private static void SendClipboardDataUsingTCP(byte[] bytes, bool image)
+ {
+ if (Sk == null)
+ {
+ return;
+ }
+
+ new Task(() =>
+ {
+ System.Threading.Thread thread = Thread.CurrentThread;
+ thread.Name = $"{nameof(SendClipboardDataUsingTCP)}.{thread.ManagedThreadId}";
+ Thread.UpdateThreads(thread);
+ int l = bytes.Length;
+ int index = 0;
+ int len;
+ DATA package = new();
+ byte[] buf = new byte[PACKAGE_SIZE_EX];
+ int dataStart = PACKAGE_SIZE_EX - DATA_SIZE;
+
+ while (true)
+ {
+ if ((index + DATA_SIZE) > l)
+ {
+ len = l - index;
+ Array.Clear(buf, 0, PACKAGE_SIZE_EX);
+ }
+ else
+ {
+ len = DATA_SIZE;
+ }
+
+ Array.Copy(bytes, index, buf, dataStart, len);
+ package.Bytes = buf;
+
+ package.Type = image ? PackageType.ClipboardImage : PackageType.ClipboardText;
+ package.Des = ID.ALL;
+ SkSend(package, (uint)MachineID, false);
+
+ index += DATA_SIZE;
+ if (index >= l)
+ {
+ break;
+ }
+ }
+
+ package.Type = PackageType.ClipboardDataEnd;
+ package.Des = ID.ALL;
+ SkSend(package, (uint)MachineID, false);
+ }).Start();
+ }
+
+ internal static void ReceiveClipboardDataUsingTCP(DATA data, bool image, TcpSk tcp)
+ {
+ try
+ {
+ if (Sk == null || RunOnLogonDesktop || RunOnScrSaverDesktop)
+ {
+ return;
+ }
+
+ MemoryStream m = new();
+ int dataStart = PACKAGE_SIZE_EX - DATA_SIZE;
+ m.Write(data.Bytes, dataStart, DATA_SIZE);
+ int unexpectedCount = 0;
+
+ bool done = false;
+ do
+ {
+ data = SocketStuff.TcpReceiveData(tcp, out int err);
+
+ switch (data.Type)
+ {
+ case PackageType.ClipboardImage:
+ case PackageType.ClipboardText:
+ m.Write(data.Bytes, dataStart, DATA_SIZE);
+ break;
+
+ case PackageType.ClipboardDataEnd:
+ done = true;
+ break;
+
+ default:
+ ProcessPackage(data, tcp);
+ if (++unexpectedCount > 100)
+ {
+ Log("ReceiveClipboardDataUsingTCP: unexpectedCount > 100!");
+ done = true;
+ }
+
+ break;
+ }
+ }
+ while (!done);
+
+ LastClipboardEventTime = GetTick();
+
+ if (image)
+ {
+ Image im = Image.FromStream(m);
+ Clipboard.SetImage(im);
+ LastClipboardEventTime = GetTick();
+ }
+ else
+ {
+ Common.SetClipboardData(m.GetBuffer());
+ LastClipboardEventTime = GetTick();
+ }
+
+ m.Dispose();
+
+ SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_SMALL_CLIPBOARD, -1, ICON_SMALL_CLIPBOARD, -1 });
+ }
+ catch (Exception e)
+ {
+ Log("ReceiveClipboardDataUsingTCP: " + e.Message);
+ }
+ }
+
+ private static readonly object ClipboardThreadOldLock = new();
+ private static System.Threading.Thread clipboardThreadOld;
+
+ internal static void GetRemoteClipboard(string postAction)
+ {
+ if (!RunOnLogonDesktop && !RunOnScrSaverDesktop)
+ {
+ if (Common.LastMachineWithClipboardData == null ||
+ Common.LastMachineWithClipboardData.Length < 1)
+ {
+ return;
+ }
+
+ new Task(() =>
+ {
+ System.Threading.Thread thread = Thread.CurrentThread;
+ thread.Name = $"{nameof(ConnectAndGetData)}.{thread.ManagedThreadId}";
+ Thread.UpdateThreads(thread);
+ ConnectAndGetData(postAction);
+ }).Start();
+ }
+ }
+
+ private static Stream m;
+
+ private static void ConnectAndGetData(object postAction)
+ {
+ if (Sk == null)
+ {
+ Log("ConnectAndGetData: Sk == null!");
+ return;
+ }
+
+ string remoteMachine;
+ TcpClient clipboardTcpClient = null;
+ string postAct = (string)postAction;
+
+ LogDebug("ConnectAndGetData.postAction: " + postAct);
+
+ ClipboardPostAction clipboardPostAct = postAct.Contains("mspaint,") ? ClipboardPostAction.Mspaint
+ : postAct.Equals("desktop", StringComparison.OrdinalIgnoreCase) ? ClipboardPostAction.Desktop
+ : ClipboardPostAction.Other;
+
+ try
+ {
+ remoteMachine = postAct.Contains("mspaint,") ? postAct.Split(new char[] { ',' })[1] : Common.LastMachineWithClipboardData;
+
+ remoteMachine = remoteMachine.Trim();
+
+ if (!IsConnectedByAClientSocketTo(remoteMachine))
+ {
+ Log($"No potential inbound connection from {MachineName} to {remoteMachine}, ask for a push back instead.");
+ ID machineId = MachinePool.ResolveID(remoteMachine);
+
+ if (machineId != ID.NONE)
+ {
+ SkSend(
+ new DATA()
+ {
+ Type = PackageType.ClipboardAsk,
+ Des = machineId,
+ MachineName = MachineName,
+ PostAction = clipboardPostAct,
+ },
+ null,
+ false);
+ }
+ else
+ {
+ Log($"Unable to resolve {remoteMachine} to its long IP.");
+ }
+
+ return;
+ }
+
+ ShowToolTip("Connecting to " + remoteMachine, 2000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
+
+ clipboardTcpClient = ConnectToRemoteClipboardSocket(remoteMachine);
+ }
+ catch (ThreadAbortException)
+ {
+ Common.Log("The current thread is being aborted (1).");
+ if (clipboardTcpClient != null && clipboardTcpClient.Connected)
+ {
+ clipboardTcpClient.Client.Close();
+ }
+
+ return;
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_BIG_CLIPBOARD,
+ -1, Common.ICON_BIG_CLIPBOARD, -1,
+ });
+ ShowToolTip(e.Message, 1000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+ return;
+ }
+
+ bool clientPushData = false;
+
+ if (!ShakeHand(ref remoteMachine, clipboardTcpClient.Client, out Stream enStream, out Stream deStream, ref clientPushData, ref clipboardPostAct))
+ {
+ return;
+ }
+
+ ReceiveAndProcessClipboardData(remoteMachine, clipboardTcpClient.Client, enStream, deStream, postAct);
+ }
+
+ internal static void ReceiveAndProcessClipboardData(string remoteMachine, Socket s, Stream enStream, Stream deStream, string postAct)
+ {
+ lock (ClipboardThreadOldLock)
+ {
+ // Do not enable two connections at the same time.
+ if (clipboardThreadOld != null && clipboardThreadOld.ThreadState != System.Threading.ThreadState.AbortRequested
+ && clipboardThreadOld.ThreadState != System.Threading.ThreadState.Aborted && clipboardThreadOld.IsAlive
+ && clipboardThreadOld.ManagedThreadId != Thread.CurrentThread.ManagedThreadId)
+ {
+ if (clipboardThreadOld.Join(3000))
+ {
+ if (m != null)
+ {
+ m.Flush();
+ m.Close();
+ m = null;
+ }
+ }
+ }
+
+ clipboardThreadOld = Thread.CurrentThread;
+ }
+
+ try
+ {
+ byte[] header = new byte[1024];
+ byte[] buf = new byte[NETWORK_STREAM_BUF_SIZE];
+ string fileName = null;
+ string tempFile = "data", savingFolder = string.Empty;
+ Common.ToggleIconsIndex = 0;
+ int rv;
+ long receivedCount = 0;
+
+ if ((rv = deStream.ReadEx(header, 0, header.Length)) < header.Length)
+ {
+ Common.Log("Reading header failed: " + rv.ToString(CultureInfo.CurrentCulture));
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_BIG_CLIPBOARD,
+ -1, -1, -1,
+ });
+ return;
+ }
+
+ fileName = Common.GetStringU(header).Replace("\0", string.Empty);
+ Common.LogDebug("Header: " + fileName);
+ string[] headers = fileName.Split(new char[] { '*' });
+
+ if (headers.Length < 2 || !long.TryParse(headers[0], out long dataSize))
+ {
+ Common.Log(string.Format(
+ CultureInfo.CurrentCulture,
+ "Reading header failed: {0}:{1}",
+ headers.Length,
+ fileName));
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_BIG_CLIPBOARD,
+ -1, -1, -1,
+ });
+ return;
+ }
+
+ fileName = headers[1];
+
+ Common.LogDebug(string.Format(
+ CultureInfo.CurrentCulture,
+ "Receiving {0}:{1} from {2}...",
+ Path.GetFileName(fileName),
+ dataSize,
+ remoteMachine));
+ ShowToolTip(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ "Receiving {0} from {1}...",
+ Path.GetFileName(fileName),
+ remoteMachine),
+ 5000,
+ ToolTipIcon.Info,
+ Setting.Values.ShowClipNetStatus);
+ if (fileName.StartsWith("image", StringComparison.CurrentCultureIgnoreCase) ||
+ fileName.StartsWith("text", StringComparison.CurrentCultureIgnoreCase))
+ {
+ m = new MemoryStream();
+ }
+ else
+ {
+ if (postAct.Equals("desktop", StringComparison.OrdinalIgnoreCase))
+ {
+ _ = ImpersonateLoggedOnUserAndDoSomething(() =>
+ {
+ savingFolder = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\MouseWithoutBorders\\";
+
+ if (!Directory.Exists(savingFolder))
+ {
+ _ = Directory.CreateDirectory(savingFolder);
+ }
+ });
+
+ tempFile = savingFolder + Path.GetFileName(fileName);
+ m = new FileStream(tempFile, FileMode.Create);
+ }
+ else if (postAct.Contains("mspaint"))
+ {
+ tempFile = GetMyStorageDir() + @"ScreenCapture-" +
+ remoteMachine + ".png";
+ m = new FileStream(tempFile, FileMode.Create);
+ }
+ else
+ {
+ tempFile = GetMyStorageDir();
+ tempFile += Path.GetFileName(fileName);
+ m = new FileStream(tempFile, FileMode.Create);
+ }
+
+ Common.Log("==> " + tempFile);
+ }
+
+ ShowToolTip(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ "Receiving {0} from {1}...",
+ Path.GetFileName(fileName),
+ remoteMachine),
+ 5000,
+ ToolTipIcon.Info,
+ Setting.Values.ShowClipNetStatus);
+
+ do
+ {
+ rv = deStream.ReadEx(buf, 0, buf.Length);
+
+ if (rv > 0)
+ {
+ receivedCount += rv;
+
+ if (receivedCount > dataSize)
+ {
+ rv -= (int)(receivedCount - dataSize);
+ }
+
+ m.Write(buf, 0, rv);
+ }
+
+ if (Common.ToggleIcons == null)
+ {
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_SMALL_CLIPBOARD,
+ -1, Common.ICON_SMALL_CLIPBOARD, -1,
+ });
+ }
+
+ string text = string.Format(CultureInfo.CurrentCulture, "{0}KB received: {1}", m.Length / 1024, Path.GetFileName(fileName));
+
+ DoSomethingInUIThread(() =>
+ {
+ MainForm.SetTrayIconText(text);
+ });
+ }
+ while (rv > 0);
+
+ if (m != null && fileName != null)
+ {
+ m.Flush();
+ Common.LogDebug(m.Length.ToString(CultureInfo.CurrentCulture) + " bytes received.");
+ Common.LastClipboardEventTime = Common.GetTick();
+ string toolTipText = null;
+ string sizeText = m.Length >= 1024
+ ? (m.Length / 1024).ToString(CultureInfo.CurrentCulture) + "KB"
+ : m.Length.ToString(CultureInfo.CurrentCulture) + "Bytes";
+
+ PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersClipboardFileTransferEvent());
+
+ if (fileName.StartsWith("image", StringComparison.CurrentCultureIgnoreCase))
+ {
+ Clipboard.SetImage(Image.FromStream(m));
+ toolTipText = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1} from {2} is in Clipboard.",
+ sizeText,
+ "image",
+ remoteMachine);
+ }
+ else if (fileName.StartsWith("text", StringComparison.CurrentCultureIgnoreCase))
+ {
+ byte[] data = (m as MemoryStream).GetBuffer();
+ toolTipText = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1} from {2} is in Clipboard.",
+ sizeText,
+ "text",
+ remoteMachine);
+ Common.SetClipboardData(data);
+ }
+ else if (tempFile != null)
+ {
+ if (postAct.Equals("desktop", StringComparison.OrdinalIgnoreCase))
+ {
+ toolTipText = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1} received from {2}!",
+ sizeText,
+ Path.GetFileName(fileName),
+ remoteMachine);
+
+ _ = ImpersonateLoggedOnUserAndDoSomething(() =>
+ {
+ ProcessStartInfo startInfo = new();
+ startInfo.UseShellExecute = true;
+ startInfo.WorkingDirectory = savingFolder;
+ startInfo.FileName = savingFolder;
+ startInfo.Verb = "open";
+ _ = Process.Start(startInfo);
+ });
+ }
+ else if (postAct.Contains("mspaint"))
+ {
+ m.Close();
+ m = null;
+ OpenImage(tempFile);
+ toolTipText = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1} from {2} is in Mspaint.",
+ sizeText,
+ Path.GetFileName(tempFile),
+ remoteMachine);
+ }
+ else
+ {
+ StringCollection filePaths = new()
+ {
+ tempFile,
+ };
+ Clipboard.SetFileDropList(filePaths);
+ toolTipText = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1} from {2} is in Clipboard.",
+ sizeText,
+ Path.GetFileName(fileName),
+ remoteMachine);
+ }
+ }
+
+ if (!string.IsNullOrWhiteSpace(toolTipText))
+ {
+ Common.ShowToolTip(toolTipText, 5000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
+ }
+
+ DoSomethingInUIThread(() =>
+ {
+ MainForm.UpdateNotifyIcon();
+ });
+
+ m?.Close();
+ m = null;
+ }
+ }
+ catch (ThreadAbortException)
+ {
+ Common.Log("The current thread is being aborted (3).");
+ s.Close();
+
+ if (m != null)
+ {
+ m.Close();
+ m = null;
+ }
+
+ return;
+ }
+ catch (Exception e)
+ {
+ if (e is IOException)
+ {
+ string log = $"{nameof(ReceiveAndProcessClipboardData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Common.Log(log);
+ }
+ else
+ {
+ Common.Log(e);
+ }
+
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_BIG_CLIPBOARD,
+ -1, Common.ICON_BIG_CLIPBOARD, -1,
+ });
+ ShowToolTip(e.Message, 1000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
+
+ if (m != null)
+ {
+ m.Close();
+ m = null;
+ }
+
+ return;
+ }
+
+ s.Close();
+ }
+
+ internal static bool ShakeHand(ref string remoteName, Socket s, out Stream enStream, out Stream deStream, ref bool clientPushData, ref ClipboardPostAction postAction)
+ {
+ const int CLIPBOARD_HANDSHAKE_TIMEOUT = 30;
+ s.ReceiveTimeout = CLIPBOARD_HANDSHAKE_TIMEOUT * 1000;
+ s.NoDelay = true;
+ s.SendBufferSize = s.ReceiveBufferSize = 1024000;
+
+ bool handShaken = false;
+ enStream = deStream = null;
+
+ try
+ {
+ DATA package = new()
+ {
+ Type = clientPushData ? PackageType.ClipboardPush : PackageType.Clipboard,
+ PostAction = postAction,
+ Src = MachineID,
+ MachineName = MachineName,
+ };
+
+ byte[] buf = new byte[PACKAGE_SIZE_EX];
+
+ NetworkStream ns = new(s);
+ enStream = Common.GetEncryptedStream(ns);
+ Common.SendOrReceiveARandomDataBlockPerInitialIV(enStream);
+ LogDebug($"{nameof(ShakeHand)}: Writing header package.");
+ enStream.Write(package.Bytes, 0, PACKAGE_SIZE_EX);
+
+ LogDebug($"{nameof(ShakeHand)}: Sent: clientPush={clientPushData}, postAction={postAction}.");
+
+ deStream = Common.GetDecryptedStream(ns);
+ Common.SendOrReceiveARandomDataBlockPerInitialIV(deStream, false);
+
+ LogDebug($"{nameof(ShakeHand)}: Reading header package.");
+
+ int bytesReceived = deStream.ReadEx(buf, 0, Common.PACKAGE_SIZE_EX);
+ package.Bytes = buf;
+
+ string name = "Unknown";
+
+ if (bytesReceived == Common.PACKAGE_SIZE_EX)
+ {
+ if (package.Type is PackageType.Clipboard or PackageType.ClipboardPush)
+ {
+ name = remoteName = package.MachineName;
+
+ Common.LogDebug($"{nameof(ShakeHand)}: Connection from {name}:{package.Src}");
+
+ if (Common.MachinePool.ResolveID(name) == package.Src && Common.IsConnectedTo(package.Src))
+ {
+ clientPushData = package.Type == PackageType.ClipboardPush;
+ postAction = package.PostAction;
+ handShaken = true;
+ LogDebug($"{nameof(ShakeHand)}: Received: clientPush={clientPushData}, postAction={postAction}.");
+ }
+ else
+ {
+ Common.LogDebug($"{nameof(ShakeHand)}: No active connection to the machine: {name}.");
+ }
+ }
+ else
+ {
+ Common.LogDebug($"{nameof(ShakeHand)}: Unexpected package type: {package.Type}.");
+ }
+ }
+ else
+ {
+ Common.LogDebug($"{nameof(ShakeHand)}: BytesTransferred != PACKAGE_SIZE_EX: {bytesReceived}");
+ }
+
+ if (!handShaken)
+ {
+ string msg = $"Clipboard connection rejected: {name}:{remoteName}/{package.Src}\r\n\r\nMake sure you run the same version in all machines.";
+ Common.Log(msg);
+ Common.ShowToolTip(msg, 3000, ToolTipIcon.Warning);
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE] { Common.ICON_BIG_CLIPBOARD, -1, -1, -1 });
+ }
+ }
+ catch (ThreadAbortException)
+ {
+ Common.Log($"{nameof(ShakeHand)}: The current thread is being aborted.");
+ s.Close();
+ }
+ catch (Exception e)
+ {
+ if (e is IOException)
+ {
+ string log = $"{nameof(ShakeHand)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Common.Log(log);
+ }
+ else
+ {
+ Common.Log(e);
+ }
+
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE]
+ {
+ Common.ICON_BIG_CLIPBOARD,
+ -1, Common.ICON_BIG_CLIPBOARD, -1,
+ });
+ MainForm.UpdateNotifyIcon();
+ ShowToolTip(e.Message + "\r\n\r\nMake sure you run the same version in all machines.", 1000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+
+ if (m != null)
+ {
+ m.Close();
+ m = null;
+ }
+ }
+
+ return handShaken;
+ }
+
+ internal static TcpClient ConnectToRemoteClipboardSocket(string remoteMachine)
+ {
+ TcpClient clipboardTcpClient;
+ clipboardTcpClient = new TcpClient(AddressFamily.InterNetworkV6);
+ clipboardTcpClient.Client.DualMode = true;
+
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ Common.DoSomethingInUIThread(() => Common.MainForm.ChangeIcon(Common.ICON_SMALL_CLIPBOARD));
+
+ System.Net.IPAddress ip = GetConnectedClientSocketIPAddressFor(remoteMachine);
+ Common.LogDebug($"{nameof(ConnectToRemoteClipboardSocket)}Connecting to {remoteMachine}:{ip}:{sk.TcpPort}...");
+
+ if (ip != null)
+ {
+ clipboardTcpClient.Connect(ip, sk.TcpPort);
+ }
+ else
+ {
+ clipboardTcpClient.Connect(remoteMachine, sk.TcpPort);
+ }
+
+ Common.LogDebug($"Connected from {clipboardTcpClient.Client.LocalEndPoint}. Getting data...");
+ return clipboardTcpClient;
+ }
+ else
+ {
+ throw new ExpectedSocketException($"{nameof(ConnectToRemoteClipboardSocket)}: No longer connected.");
+ }
+ }
+
+ internal static void SetClipboardData(byte[] data)
+ {
+ if (data == null || data.Length <= 0)
+ {
+ Common.Log("data is null or empty!");
+ return;
+ }
+
+ if (data.Length > 1024000)
+ {
+ ShowToolTip(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ "Decompressing {0} clipboard data ...",
+ (data.Length / 1024).ToString(CultureInfo.CurrentCulture) + "KB"),
+ 5000,
+ ToolTipIcon.Info,
+ Setting.Values.ShowClipNetStatus);
+ }
+
+ string st = string.Empty;
+
+ using (MemoryStream ms = new(data))
+ {
+ using DeflateStream s = new(ms, CompressionMode.Decompress, true);
+ const int BufferSize = 1024000; // Buffer size should be big enough, this is critical to performance!
+
+ int rv = 0;
+
+ do
+ {
+ byte[] buffer = new byte[BufferSize];
+ rv = s.ReadEx(buffer, 0, BufferSize);
+
+ if (rv > 0)
+ {
+ st += Common.GetStringU(buffer);
+ }
+ else
+ {
+ break;
+ }
+ }
+ while (true);
+ }
+
+ int textTypeCount = 0;
+ string[] texts = st.Split(new string[] { TEXT_TYPE_SEP }, StringSplitOptions.RemoveEmptyEntries);
+ string tmp;
+ DataObject data1 = new();
+
+ foreach (string txt in texts)
+ {
+ if (string.IsNullOrEmpty(txt.Trim(new char[] { '\0' })))
+ {
+ continue;
+ }
+
+ tmp = txt[3..];
+
+ if (txt.StartsWith("RTF", StringComparison.CurrentCultureIgnoreCase))
+ {
+ Common.LogDebug(((double)tmp.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of RTF <-");
+ data1.SetData(DataFormats.Rtf, tmp);
+ }
+ else if (txt.StartsWith("HTM", StringComparison.CurrentCultureIgnoreCase))
+ {
+ Common.LogDebug(((double)tmp.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of HTM <-");
+ data1.SetData(DataFormats.Html, tmp);
+ }
+ else if (txt.StartsWith("TXT", StringComparison.CurrentCultureIgnoreCase))
+ {
+ Common.LogDebug(((double)tmp.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of TXT <-");
+ data1.SetData(DataFormats.UnicodeText, tmp);
+ }
+ else
+ {
+ if (textTypeCount == 0)
+ {
+ Common.LogDebug(((double)txt.Length / 1024).ToString("0.00", CultureInfo.InvariantCulture) + "KB of UNI <-");
+ data1.SetData(DataFormats.UnicodeText, txt);
+ }
+
+ Common.Log("Invalid clipboard format received!");
+ }
+
+ textTypeCount++;
+ }
+
+ if (textTypeCount > 0)
+ {
+ Clipboard.SetDataObject(data1);
+ }
+ }
+ }
+
+ internal static class Clipboard
+ {
+ public static void SetFileDropList(StringCollection filePaths)
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ try
+ {
+ _ = Common.Retry(
+ nameof(SystemClipboard.SetFileDropList),
+ () =>
+ {
+ SystemClipboard.SetFileDropList(filePaths);
+ return true;
+ },
+ (log) => Common.TelemetryLogTrace(
+ log,
+ SeverityLevel.Information),
+ () => Common.LastClipboardEventTime = Common.GetTick());
+ }
+ catch (ExternalException e)
+ {
+ Common.Log(e);
+ }
+ catch (ThreadStateException e)
+ {
+ Common.Log(e);
+ }
+ catch (ArgumentNullException e)
+ {
+ Common.Log(e);
+ }
+ catch (ArgumentException e)
+ {
+ Common.Log(e);
+ }
+ });
+ }
+
+ public static void SetImage(Image image)
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ try
+ {
+ _ = Common.Retry(
+ nameof(SystemClipboard.SetImage),
+ () =>
+ {
+ SystemClipboard.SetImage(image);
+ return true;
+ },
+ (log) => Common.TelemetryLogTrace(log, SeverityLevel.Information),
+ () => Common.LastClipboardEventTime = Common.GetTick());
+ }
+ catch (ExternalException e)
+ {
+ Common.Log(e);
+ }
+ catch (ThreadStateException e)
+ {
+ Common.Log(e);
+ }
+ catch (ArgumentNullException e)
+ {
+ Common.Log(e);
+ }
+ });
+ }
+
+ public static void SetText(string text)
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ try
+ {
+ _ = Common.Retry(
+ nameof(SystemClipboard.SetText),
+ () =>
+ {
+ SystemClipboard.SetText(text);
+ return true;
+ },
+ (log) => Common.TelemetryLogTrace(log, SeverityLevel.Information),
+ () => Common.LastClipboardEventTime = Common.GetTick());
+ }
+ catch (ExternalException e)
+ {
+ Common.Log(e);
+ }
+ catch (ThreadStateException e)
+ {
+ Common.Log(e);
+ }
+ catch (ArgumentNullException e)
+ {
+ Common.Log(e);
+ }
+ });
+ }
+
+ public static void SetDataObject(DataObject dataObject)
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ try
+ {
+ SystemClipboard.SetDataObject(dataObject, true, 10, 200);
+ }
+ catch (ExternalException e)
+ {
+ string dataFormats = string.Join(",", dataObject.GetFormats());
+ Common.Log($"{e.Message}: {dataFormats}");
+ }
+ catch (ThreadStateException e)
+ {
+ Common.Log(e);
+ }
+ catch (ArgumentNullException e)
+ {
+ Common.Log(e);
+ }
+ });
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.DragDrop.cs b/src/modules/MouseWithoutBorders/App/Class/Common.DragDrop.cs
new file mode 100644
index 000000000000..cecfa34f4784
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.DragDrop.cs
@@ -0,0 +1,405 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Threading;
+using System.Windows.Forms;
+using Microsoft.PowerToys.Telemetry;
+
+//
+// Drag/Drop implementation.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+
+namespace MouseWithoutBorders
+{
+ /* Common.DragDrop.cs
+ * Drag&Drop is one complicated implementation of the tool with some tricks.
+ *
+ * SEQUENCE OF EVENTS:
+ * DragDropStep01: MachineX: Remember mouse down state since it could be a start of a dragging
+ * DragDropStep02: MachineY: Send an message to the MachineX to ask it to check if it is
+ * doing drag/drop
+ * DragDropStep03: MachineX: Got explorerDragDrop, send WM_CHECK_EXPLORER_DRAG_DROP to its mainForm
+ * DragDropStep04: MachineX: Show Mouse Without Borders Helper form at mouse cursor to get DragEnter event.
+ * DragDropStepXX: MachineX: Mouse Without Borders Helper: Called by DragEnter, check if dragging a single file,
+ * remember the file (set as its window caption)
+ * DragDropStep05: MachineX: Get the file name from Mouse Without Borders Helper, hide Mouse Without Borders Helper window
+ * DragDropStep06: MachineX: Broadcast a message saying that it has some drag file.
+ * DragDropStep08: MachineY: Got ClipboardDragDrop, isDropping set, get the MachineX name from the package.
+ * DragDropStep09: MachineY: Since isDropping is true, show up the drop form (looks like an icon).
+ * DragDropStep10: MachineY: MouseUp, set isDropping to false, hide the drop "icon" and get data.
+ * DragDropStep11: MachineX: Mouse move back without drop event, cancelling drag/dop
+ * SendClipboardBeatDragDropEnd
+ * DragDropStep12: MachineY: Hide the drop "icon" when received ClipboardDragDropEnd.
+ *
+ * FROM VERSION 1.6.3: Drag/Drop is temporary removed, Drop action cannot be done from a lower integrity app to a higher one.
+ * We have to run a helper process...
+ * http://forums.microsoft.com/MSDN/ShowPost.aspx?PageIndex=1&SiteID=1&PageID=1&PostID=736086
+ *
+ * 2008.10.28: Trying to restore the Drag/Drop feature by adding the drag/drop helper process. Coming in version
+ * 1.6.5
+ * */
+
+ internal partial class Common
+ {
+ private static bool isDragging;
+
+ internal static bool IsDragging
+ {
+ get => Common.isDragging;
+ set => Common.isDragging = value;
+ }
+
+ internal static void DragDropStep01(int wParam)
+ {
+ if (!Setting.Values.TransferFile)
+ {
+ return;
+ }
+
+ if (wParam == WM_LBUTTONDOWN)
+ {
+ MouseDown = true;
+ DragMachine = desMachineID;
+ dropMachineID = ID.NONE;
+ LogDebug("DragDropStep01: MouseDown");
+ }
+ else if (wParam == WM_LBUTTONUP)
+ {
+ MouseDown = false;
+ LogDebug("DragDropStep01: MouseUp");
+ }
+
+ if (wParam == WM_RBUTTONUP && IsDropping)
+ {
+ IsDropping = false;
+ LastIDWithClipboardData = ID.NONE;
+ }
+ }
+
+ internal static void DragDropStep02()
+ {
+ if (desMachineID == MachineID)
+ {
+ LogDebug("DragDropStep02: SendCheckExplorerDragDrop sent to myself");
+ DoSomethingInUIThread(() =>
+ {
+ _ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_CHECK_EXPLORER_DRAG_DROP, (IntPtr)0, (IntPtr)0);
+ });
+ }
+ else
+ {
+ SendCheckExplorerDragDrop();
+ LogDebug("DragDropStep02: SendCheckExplorerDragDrop sent");
+ }
+ }
+
+ internal static void DragDropStep03(DATA package)
+ {
+ if (RunOnLogonDesktop || RunOnScrSaverDesktop)
+ {
+ return;
+ }
+
+ if (package.Des == MachineID || package.Des == ID.ALL)
+ {
+ LogDebug("DragDropStep03: ExplorerDragDrop Received.");
+ dropMachineID = package.Src; // Drop machine is the machine that sent ExplorerDragDrop
+ if (MouseDown || IsDropping)
+ {
+ LogDebug("DragDropStep03: Mouse is down, check if dragging...sending WM_CHECK_EXPLORER_DRAG_DROP to myself...");
+ DoSomethingInUIThread(() =>
+ {
+ _ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_CHECK_EXPLORER_DRAG_DROP, (IntPtr)0, (IntPtr)0);
+ });
+ }
+ }
+ }
+
+ private static int dragDropStep05ExCalledByIpc;
+
+ internal static void DragDropStep04()
+ {
+ if (!IsDropping)
+ {
+ IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT);
+ if (h.ToInt32() > 0)
+ {
+ _ = Interlocked.Exchange(ref dragDropStep05ExCalledByIpc, 0);
+
+ MainForm.Hide();
+ MainFormVisible = false;
+
+ Point p = default;
+
+ // NativeMethods.SetWindowText(h, "");
+ _ = NativeMethods.SetWindowPos(h, NativeMethods.HWND_TOPMOST, 0, 0, 0, 0, NativeMethods.SWP_SHOWWINDOW);
+
+ for (int i = -10; i < 10; i++)
+ {
+ if (dragDropStep05ExCalledByIpc > 0)
+ {
+ LogDebug("DragDropStep04: DragDropStep05ExCalledByIpc.");
+ break;
+ }
+
+ _ = NativeMethods.GetCursorPos(ref p);
+ LogDebug("DragDropStep04: Moving Mouse Without Borders Helper to (" + p.X.ToString(CultureInfo.CurrentCulture) + ", " + p.Y.ToString(CultureInfo.CurrentCulture) + ")");
+ _ = NativeMethods.SetWindowPos(h, NativeMethods.HWND_TOPMOST, p.X - 100 + i, p.Y - 100 + i, 200, 200, 0);
+ _ = NativeMethods.SendMessage(h, 0x000F, IntPtr.Zero, IntPtr.Zero); // WM_PAINT
+ Thread.Sleep(20);
+ Application.DoEvents();
+
+ // if (GetText(h).Length > 1) break;
+ }
+ }
+ else
+ {
+ LogDebug("DragDropStep04: Mouse without Borders Helper not found!");
+ }
+ }
+ else
+ {
+ LogDebug("DragDropStep04: IsDropping == true, skip checking");
+ }
+
+ LogDebug("DragDropStep04: Got WM_CHECK_EXPLORER_DRAG_DROP, done with processing jump to DragDropStep05...");
+ }
+
+ internal static void DragDropStep05Ex(string dragFileName)
+ {
+ LogDebug("DragDropStep05 called.");
+
+ _ = Interlocked.Exchange(ref dragDropStep05ExCalledByIpc, 1);
+
+ if (RunOnLogonDesktop || RunOnScrSaverDesktop)
+ {
+ return;
+ }
+
+ if (!IsDropping)
+ {
+ _ = Common.ImpersonateLoggedOnUserAndDoSomething(() =>
+ {
+ if (!string.IsNullOrEmpty(dragFileName) && (File.Exists(dragFileName) || Directory.Exists(dragFileName)))
+ {
+ Common.LastDragDropFile = dragFileName;
+ /*
+ * possibleDropMachineID is used as desID sent in DragDropStep06();
+ * */
+ if (dropMachineID == ID.NONE)
+ {
+ dropMachineID = newDesMachineID;
+ }
+
+ DragDropStep06();
+ LogDebug("DragDropStep05: File dragging: " + dragFileName);
+ _ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_HIDE_DD_HELPER, (IntPtr)1, (IntPtr)0);
+ }
+ else
+ {
+ LogDebug("DragDropStep05: File not found: [" + dragFileName + "]");
+ _ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_HIDE_DD_HELPER, (IntPtr)0, (IntPtr)0);
+ }
+
+ LogDebug("DragDropStep05: WM_HIDE_DDHelper sent");
+ });
+ }
+ else
+ {
+ LogDebug("DragDropStep05: IsDropping == true, change drop machine...");
+ IsDropping = false;
+ MainFormVisible = true; // WM_HIDE_DRAG_DROP
+ SendDropBegin(); // To dropMachineID set in DragDropStep03
+ }
+
+ MouseDown = false;
+ }
+
+ internal static void DragDropStep06()
+ {
+ IsDragging = true;
+ LogDebug("DragDropStep06: SendClipboardBeatDragDrop");
+ SendClipboardBeatDragDrop();
+ SendDropBegin();
+ }
+
+ internal static void DragDropStep08(DATA package)
+ {
+ GetNameOfMachineWithClipboardData(package);
+ LogDebug("DragDropStep08: ClipboardDragDrop Received. machine with drag file was set");
+ }
+
+ internal static void DragDropStep08_2(DATA package)
+ {
+ if (package.Des == MachineID && !RunOnLogonDesktop && !RunOnScrSaverDesktop)
+ {
+ IsDropping = true;
+ dropMachineID = MachineID;
+ LogDebug("DragDropStep08_2: ClipboardDragDropOperation Received. IsDropping set");
+ }
+ }
+
+ internal static void DragDropStep09(int wParam)
+ {
+ if (wParam == WM_MOUSEMOVE && IsDropping)
+ {
+ // Show/Move form
+ DoSomethingInUIThread(() =>
+ {
+ _ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_SHOW_DRAG_DROP, (IntPtr)0, (IntPtr)0);
+ });
+ }
+ else if (wParam == WM_LBUTTONUP && (IsDropping || IsDragging))
+ {
+ if (IsDropping)
+ {
+ // Hide form, get data
+ DragDropStep10();
+ }
+ else
+ {
+ IsDragging = false;
+ LastIDWithClipboardData = ID.NONE;
+ }
+ }
+ }
+
+ internal static void DragDropStep10()
+ {
+ LogDebug("DragDropStep10: Hide the form and get data...");
+ IsDropping = false;
+ IsDragging = false;
+ LastIDWithClipboardData = ID.NONE;
+
+ DoSomethingInUIThread(() =>
+ {
+ _ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_HIDE_DRAG_DROP, (IntPtr)0, (IntPtr)0);
+ });
+
+ PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersDragAndDropEvent());
+ GetRemoteClipboard("desktop");
+ }
+
+ internal static void DragDropStep11()
+ {
+ LogDebug("DragDropStep11: Mouse drag coming back, canceling drag/drop");
+ SendClipboardBeatDragDropEnd();
+ IsDropping = false;
+ IsDragging = false;
+ DragMachine = (ID)1;
+ LastIDWithClipboardData = ID.NONE;
+ LastDragDropFile = null;
+ MouseDown = false;
+ }
+
+ internal static void DragDropStep12()
+ {
+ LogDebug("DragDropStep12: ClipboardDragDropEnd received");
+ IsDropping = false;
+ LastIDWithClipboardData = ID.NONE;
+
+ DoSomethingInUIThread(() =>
+ {
+ _ = NativeMethods.PostMessage(MainForm.Handle, NativeMethods.WM_HIDE_DRAG_DROP, (IntPtr)0, (IntPtr)0);
+ });
+ }
+
+ internal static void SendCheckExplorerDragDrop()
+ {
+ DATA package = new();
+ package.Type = PackageType.ExplorerDragDrop;
+
+ /*
+ * package.src = newDesMachineID:
+ * sent from the master machine but the src must be the
+ * new des machine since the previous des machine will get this and set
+ * to possibleDropMachineID in DragDropStep3()
+ * */
+ package.Src = newDesMachineID;
+
+ package.Des = desMachineID;
+ package.MachineName = MachineName;
+
+ SkSend(package, null, false);
+ }
+
+ private static void ChangeDropMachine()
+ {
+ // desMachineID = current drop machine
+ // newDesMachineID = new drop machine
+
+ // 1. Cancelling dropping in current drop machine
+ if (dropMachineID == MachineID)
+ {
+ // Drag/Drop coming through me
+ IsDropping = false;
+ }
+ else
+ {
+ // Drag/Drop coming back
+ SendClipboardBeatDragDropEnd();
+ }
+
+ // 2. SendClipboardBeatDragDrop to new drop machine
+ // new drop machine is not me
+ if (newDesMachineID != MachineID)
+ {
+ dropMachineID = newDesMachineID;
+ SendDropBegin();
+ }
+
+ // New drop machine is me
+ else
+ {
+ IsDropping = true;
+ }
+ }
+
+ internal static void SendClipboardBeatDragDrop()
+ {
+ SendPackage(ID.ALL, PackageType.ClipboardDragDrop);
+ }
+
+ internal static void SendDropBegin()
+ {
+ LogDebug("SendDropBegin...");
+ SendPackage(dropMachineID, PackageType.ClipboardDragDropOperation);
+ }
+
+ internal static void SendClipboardBeatDragDropEnd()
+ {
+ if (desMachineID != MachineID)
+ {
+ SendPackage(desMachineID, PackageType.ClipboardDragDropEnd);
+ }
+ }
+
+ private static bool isDropping;
+ private static ID dragMachine;
+
+ internal static ID DragMachine
+ {
+ get => Common.dragMachine;
+ set => Common.dragMachine = value;
+ }
+
+ internal static bool IsDropping
+ {
+ get => Common.isDropping;
+ set => Common.isDropping = value;
+ }
+
+ internal static bool MouseDown { get; set; }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Encryption.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Encryption.cs
new file mode 100644
index 000000000000..7a0562b8452d
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.Encryption.cs
@@ -0,0 +1,242 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Encrypt/decrypt implementation.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System;
+using System.Collections.Concurrent;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Threading.Tasks;
+
+namespace MouseWithoutBorders
+{
+ internal partial class Common
+ {
+ private static SymmetricAlgorithm symAl;
+ private static string myKey;
+ private static uint magicNumber;
+ private static Random ran = new(); // Used for non encryption related functionality.
+ internal const int SymAlBlockSize = 16;
+
+ ///
+ /// This is used for the first encryption block, the following blocks will be combined with the cipher text of the previous block.
+ /// Thus identical blocks in the socket stream would be encrypted to different cipher text blocks.
+ /// The first block is a handshake one containing random data.
+ /// Related Unit Test: TestEncryptDecrypt
+ ///
+ internal static readonly string InitialIV = ulong.MaxValue.ToString(CultureInfo.InvariantCulture);
+
+ internal static Random Ran
+ {
+ get => Common.ran ??= new Random();
+ set => Common.ran = value;
+ }
+
+ internal static uint MagicNumber
+ {
+ get => Common.magicNumber;
+ set => Common.magicNumber = value;
+ }
+
+ internal static string MyKey
+ {
+ get => Common.myKey;
+
+ set
+ {
+ if (Common.myKey != value)
+ {
+ Common.myKey = value;
+ _ = Task.Factory.StartNew(
+ () => Common.GenLegalKey(),
+ System.Threading.CancellationToken.None,
+ TaskCreationOptions.None,
+ TaskScheduler.Default); // Cache the key to improve UX.
+ }
+ }
+ }
+
+ internal static string KeyDisplayedText(string key)
+ {
+ string displayedValue = string.Empty;
+ int i = 0;
+
+ do
+ {
+ int length = Math.Min(4, key.Length - i);
+ displayedValue += string.Concat(key.AsSpan(i, length), " ");
+ i += 4;
+ }
+ while (i < key.Length - 1);
+
+ return displayedValue.Trim();
+ }
+
+ internal static bool GeneratedKey { get; set; }
+
+ internal static bool KeyCorrupted { get; set; }
+
+ internal static void InitEncryption()
+ {
+ try
+ {
+ if (symAl == null)
+ {
+#pragma warning disable SYSLIB0021 // No proper replacement for now
+ symAl = new AesCryptoServiceProvider();
+#pragma warning restore SYSLIB0021
+ symAl.KeySize = 256;
+ symAl.BlockSize = SymAlBlockSize * 8;
+ symAl.Padding = PaddingMode.Zeros;
+ symAl.Mode = CipherMode.CBC;
+ symAl.GenerateIV();
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ }
+
+ private static readonly ConcurrentDictionary LegalKeyDictionary = new(StringComparer.OrdinalIgnoreCase);
+
+ internal static byte[] GenLegalKey()
+ {
+ byte[] rv;
+ string myKey = Common.MyKey;
+
+ if (!LegalKeyDictionary.ContainsKey(myKey))
+ {
+ Rfc2898DeriveBytes key = new(
+ myKey,
+ Common.GetBytesU(InitialIV),
+ 50000,
+ HashAlgorithmName.SHA512);
+ rv = key.GetBytes(32);
+ _ = LegalKeyDictionary.AddOrUpdate(myKey, rv, (k, v) => rv);
+ }
+ else
+ {
+ rv = LegalKeyDictionary[myKey];
+ }
+
+ return rv;
+ }
+
+ private static byte[] GenLegalIV()
+ {
+ string st = InitialIV;
+ int ivLength = symAl.IV.Length;
+ if (st.Length > ivLength)
+ {
+ st = st[..ivLength];
+ }
+ else if (st.Length < ivLength)
+ {
+ st = st.PadRight(ivLength, ' ');
+ }
+
+ return GetBytes(st);
+ }
+
+ internal static Stream GetEncryptedStream(Stream encryptedStream)
+ {
+ ICryptoTransform encryptor;
+ encryptor = symAl.CreateEncryptor(GenLegalKey(), GenLegalIV());
+ return new CryptoStream(encryptedStream, encryptor, CryptoStreamMode.Write);
+ }
+
+ internal static Stream GetDecryptedStream(Stream encryptedStream)
+ {
+ ICryptoTransform decryptor;
+ decryptor = symAl.CreateDecryptor(GenLegalKey(), GenLegalIV());
+ return new CryptoStream(encryptedStream, decryptor, CryptoStreamMode.Read);
+ }
+
+ internal static uint Get24BitHash(string st)
+ {
+ if (string.IsNullOrEmpty(st))
+ {
+ return 0;
+ }
+
+ byte[] bytes = new byte[PACKAGE_SIZE];
+ for (int i = 0; i < PACKAGE_SIZE; i++)
+ {
+ if (i < st.Length)
+ {
+ bytes[i] = (byte)st[i];
+ }
+ }
+
+ var hash = SHA512.Create();
+ byte[] hashValue = hash.ComputeHash(bytes);
+
+ for (int i = 0; i < 50000; i++)
+ {
+ hashValue = hash.ComputeHash(hashValue);
+ }
+
+ Common.LogDebug(string.Format(CultureInfo.CurrentCulture, "magic: {0},{1},{2}", hashValue[0], hashValue[1], hashValue[^1]));
+ hash.Clear();
+ return (uint)((hashValue[0] << 23) + (hashValue[1] << 16) + (hashValue[^1] << 8) + hashValue[2]);
+ }
+
+ internal static string GetDebugInfo(string st)
+ {
+ return string.IsNullOrEmpty(st) ? st : ((byte)(Common.GetBytesU(st).Sum(value => value) % 256)).ToString(CultureInfo.InvariantCulture);
+ }
+
+ internal static string CreateDefaultKey()
+ {
+ return CreateRandomKey();
+ }
+
+ private const int PW_LENGTH = 16;
+
+ public static string CreateRandomKey()
+ {
+ // Not including characters like "'`O0& since they are confusing to users.
+ string[] chars = new[] { "abcdefghjkmnpqrstuvxyz", "ABCDEFGHJKMNPQRSTUVXYZ", "123456789", "~!@#$%^*()_-+=:;<,>.?/\\|[]" };
+ char[][] charactersUsedForKey = chars.Select(charset => Enumerable.Range(0, charset.Length - 1).Select(i => charset[i]).ToArray()).ToArray();
+ byte[] randomData = new byte[1];
+ string key = string.Empty;
+
+ do
+ {
+ foreach (string set in chars)
+ {
+ randomData = RandomNumberGenerator.GetBytes(1);
+ key += set[randomData[0] % set.Length];
+
+ if (key.Length >= PW_LENGTH)
+ {
+ break;
+ }
+ }
+ }
+ while (key.Length < PW_LENGTH);
+
+ return key;
+ }
+
+ internal static bool IsKeyValid(string key, out string error)
+ {
+ error = string.IsNullOrEmpty(key) || key.Length < 16
+ ? "Key must have at least 16 characters in length (spaces are discarded). Key must be auto generated in one of the machines."
+ : null;
+
+ return error == null;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Event.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Event.cs
new file mode 100644
index 000000000000..7674ba2296c2
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.Event.cs
@@ -0,0 +1,272 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing;
+using System.Globalization;
+using System.Threading;
+using System.Threading.Tasks;
+
+//
+// Keyboard/Mouse hook callback implementation.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+using MouseWithoutBorders.Form;
+
+namespace MouseWithoutBorders
+{
+ internal partial class Common
+ {
+ private static readonly DATA KeybdPackage = new();
+ private static readonly DATA MousePackage = new();
+ private static ulong inputEventCount;
+ private static ulong invalidPackageCount;
+ internal static int MOVE_MOUSE_RELATIVE = 100000;
+ internal static int XY_BY_PIXEL = 300000;
+
+ static Common()
+ {
+ }
+
+ internal static ulong InvalidPackageCount
+ {
+ get => Common.invalidPackageCount;
+ set => Common.invalidPackageCount = value;
+ }
+
+ internal static ulong InputEventCount
+ {
+ get => Common.inputEventCount;
+ set => Common.inputEventCount = value;
+ }
+
+ internal static ulong RealInputEventCount
+ {
+ get;
+ set;
+ }
+
+ private static Point actualLastPos;
+ private static int myLastX;
+ private static int myLastY;
+
+ [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Dotnet port with style preservation")]
+ internal static void MouseEvent(MOUSEDATA e, int dx, int dy)
+ {
+ try
+ {
+ PaintCount = 0;
+ bool switchByMouseEnabled = IsSwitchingByMouseEnabled();
+
+ if (switchByMouseEnabled && Sk != null && (DesMachineID == MachineID || !Setting.Values.MoveMouseRelatively) && e.dwFlags == WM_MOUSEMOVE)
+ {
+ Point p = MoveToMyNeighbourIfNeeded(e.X, e.Y, desMachineID);
+
+ if (!p.IsEmpty)
+ {
+ HasSwitchedMachineSinceLastCopy = true;
+
+ Common.LogDebug(string.Format(
+ CultureInfo.CurrentCulture,
+ "***** Host Machine: newDesMachineIdEx set = [{0}]. Mouse is now at ({1},{2})",
+ newDesMachineIdEx,
+ e.X,
+ e.Y));
+
+ myLastX = e.X;
+ myLastY = e.Y;
+
+ PrepareToSwitchToMachine(newDesMachineIdEx, p);
+ }
+ }
+
+ if (desMachineID != MachineID && SwitchLocation.Count <= 0)
+ {
+ MousePackage.Des = desMachineID;
+ MousePackage.Type = PackageType.Mouse;
+ MousePackage.Md.dwFlags = e.dwFlags;
+ MousePackage.Md.WheelDelta = e.WheelDelta;
+
+ // Relative move
+ if (Setting.Values.MoveMouseRelatively && Math.Abs(dx) >= MOVE_MOUSE_RELATIVE && Math.Abs(dy) >= MOVE_MOUSE_RELATIVE)
+ {
+ MousePackage.Md.X = dx;
+ MousePackage.Md.Y = dy;
+ }
+ else
+ {
+ MousePackage.Md.X = (e.X - primaryScreenBounds.Left) * 65535 / screenWidth;
+ MousePackage.Md.Y = (e.Y - primaryScreenBounds.Top) * 65535 / screenHeight;
+ }
+
+ SkSend(MousePackage, null, false);
+
+ if (MousePackage.Md.dwFlags is WM_LBUTTONUP or WM_RBUTTONUP)
+ {
+ Thread.Sleep(10);
+ }
+
+ NativeMethods.GetCursorPos(ref actualLastPos);
+
+ if (actualLastPos != Common.LastPos)
+ {
+ Common.LogDebug($"Mouse cursor has moved unexpectedly: Expected: {Common.LastPos}, actual: {actualLastPos}.");
+ Common.LastPos = actualLastPos;
+ }
+ }
+
+#if SHOW_ON_WINLOGON_EX
+ if (RunOnLogonDesktop && e.dwFlags == WM_RBUTTONUP &&
+ desMachineID == machineID &&
+ e.x > 2 && e.x < 100 && e.y > 2 && e.y < 20)
+ {
+ DoSomethingInUIThread(delegate()
+ {
+ MainForm.HideMenuWhenRunOnLogonDesktop();
+ MainForm.MainMenu.Hide();
+ MainForm.MainMenu.Show(e.x - 5, e.y - 3);
+ });
+ }
+#endif
+ }
+ catch (Exception ex)
+ {
+ Log(ex);
+ }
+ }
+
+ private static bool IsSwitchingByMouseEnabled()
+ {
+ return (EasyMouseOption)Setting.Values.EasyMouse == EasyMouseOption.Enable || InputHook.EasyMouseKeyDown;
+ }
+
+ internal static void PrepareToSwitchToMachine(ID newDesMachineID, Point desMachineXY)
+ {
+ LogDebug($"PrepareToSwitchToMachine: newDesMachineID = {newDesMachineID}, desMachineXY = {desMachineXY}");
+
+ if (((GetTick() - lastJump < 100) && (GetTick() - lastJump > 0)) || desMachineID == ID.ALL)
+ {
+ LogDebug("PrepareToSwitchToMachine: lastJump");
+ return;
+ }
+
+ lastJump = GetTick();
+
+ string newDesMachineName = NameFromID(newDesMachineID);
+
+ if (!IsConnectedTo(newDesMachineID))
+ {// Connection lost, cancel switching
+ LogDebug("No active connection found for " + newDesMachineName);
+
+ // ShowToolTip("No active connection found for [" + newDesMachineName + "]!", 500);
+ }
+ else
+ {
+ Common.newDesMachineID = newDesMachineID;
+ SwitchLocation.X = desMachineXY.X;
+ SwitchLocation.Y = desMachineXY.Y;
+ SwitchLocation.ResetCount();
+ _ = EvSwitch.Set();
+
+ // PostMessage(mainForm.Handle, WM_SWITCH, IntPtr.Zero, IntPtr.Zero);
+ if (newDesMachineID != DragMachine)
+ {
+ if (!IsDragging && !IsDropping)
+ {
+ if (MouseDown && !RunOnLogonDesktop && !RunOnScrSaverDesktop)
+ {
+ DragDropStep02();
+ }
+ }
+ else if (DragMachine != (ID)1)
+ {
+ ChangeDropMachine();
+ }
+ }
+ else
+ {
+ DragDropStep11();
+ }
+
+ // Change des machine
+ if (desMachineID != newDesMachineID)
+ {
+ LogDebug("MouseEvent: Switching to new machine:" + newDesMachineName);
+
+ // Ask current machine to hide the Mouse cursor
+ if (newDesMachineID != ID.ALL && desMachineID != MachineID)
+ {
+ SendPackage(desMachineID, PackageType.HideMouse);
+ }
+
+ DesMachineID = newDesMachineID;
+
+ if (desMachineID == MachineID)
+ {
+ if (GetTick() - clipboardCopiedTime < BIG_CLIPBOARD_DATA_TIMEOUT)
+ {
+ clipboardCopiedTime = 0;
+ Common.GetRemoteClipboard("PrepareToSwitchToMachine");
+ }
+ }
+ else
+ {
+ // Ask the new active machine to get clipboard data (if the data is too big)
+ SendPackage(desMachineID, PackageType.MachineSwitched);
+ }
+
+ _ = Interlocked.Increment(ref switchCount);
+ }
+ }
+ }
+
+ internal static void SaveSwitchCount()
+ {
+ if (SwitchCount > 0)
+ {
+ _ = Task.Run(() =>
+ {
+ Setting.Values.SwitchCount += SwitchCount;
+ _ = Interlocked.Exchange(ref switchCount, 0);
+ });
+ }
+ }
+
+ internal static void KeybdEvent(KEYBDDATA e)
+ {
+ try
+ {
+ PaintCount = 0;
+ if (desMachineID != newDesMachineID)
+ {
+ LogDebug("KeybdEvent: Switching to new machine...");
+ DesMachineID = newDesMachineID;
+ }
+
+ if (desMachineID != MachineID)
+ {
+ KeybdPackage.Des = desMachineID;
+ KeybdPackage.Type = PackageType.Keyboard;
+ KeybdPackage.Kd = e;
+ KeybdPackage.DateTime = GetTick();
+ SkSend(KeybdPackage, null, false);
+ if (KeybdPackage.Kd.dwFlags is WM_KEYUP or WM_SYSKEYUP)
+ {
+ Thread.Sleep(10);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Log(ex);
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs
new file mode 100644
index 000000000000..54affce04baf
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.Helper.cs
@@ -0,0 +1,494 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Security.Principal;
+using System.Windows.Forms;
+
+//
+// Some other helper methods.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using Microsoft.Win32;
+using MouseWithoutBorders.Class;
+using static System.Windows.Forms.Control;
+
+namespace MouseWithoutBorders
+{
+ internal partial class Common
+ {
+ internal const string HELPER_FORM_TEXT = "Mouse without Borders Helper";
+ internal const string HelperProcessName = "PowerToys.MouseWithoutBordersHelper";
+ private static bool signalHelperToExit;
+ private static bool signalWatchDogToExit;
+ internal static long WndProcCounter;
+
+ private static void WatchDogThread()
+ {
+ long oldCounter = WndProcCounter;
+
+ do
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ Thread.Sleep(1000);
+
+ if (signalWatchDogToExit)
+ {
+ break;
+ }
+ }
+
+ while (BlockingUI)
+ {
+ Thread.Sleep(1000);
+ }
+
+ if (WndProcCounter == oldCounter)
+ {
+ Process p = Process.GetCurrentProcess();
+ string procInfo = $"{p.PrivateMemorySize64 / 1024 / 1024}MB, {p.TotalProcessorTime}, {Environment.ProcessorCount}.";
+ string threadStacks = $"{procInfo} {Thread.DumpThreadsStack()}";
+ Common.TelemetryLogTrace(threadStacks, SeverityLevel.Error);
+ break;
+ }
+
+ oldCounter = WndProcCounter;
+ }
+ while (true);
+ }
+
+ private static void HelperThread()
+ {
+ try
+ {
+ while (true)
+ {
+ _ = EvSwitch.WaitOne(); // Switching to another machine?
+
+ if (signalHelperToExit)
+ {
+ break;
+ }
+
+ if (Common.NewDesMachineID != Common.MachineID && Common.NewDesMachineID != ID.ALL)
+ {
+ HideMouseCursor(false);
+ Common.MainFormDotEx(true);
+ }
+ else
+ {
+ if (Common.SwitchLocation.Count > 0)
+ {
+ Common.SwitchLocation.Count--;
+
+ // When we want to move mouse by pixels, we add 300k to x and y (search for XY_BY_PIXEL for other related code).
+ Common.LogDebug($"+++++ Moving mouse to {Common.SwitchLocation.X}, {Common.SwitchLocation.Y}");
+
+ // MaxXY = 65535 so 100k is safe.
+ if (Common.SwitchLocation.X > XY_BY_PIXEL - 100000 || Common.SwitchLocation.Y > XY_BY_PIXEL - 100000)
+ {
+ InputSimulation.MoveMouse(Common.SwitchLocation.X - XY_BY_PIXEL, Common.SwitchLocation.Y - XY_BY_PIXEL);
+ }
+ else
+ {
+ InputSimulation.MoveMouseEx(Common.SwitchLocation.X, Common.SwitchLocation.Y);
+ }
+
+ Common.MainFormDot();
+ }
+ }
+
+ if (Common.NewDesMachineID == Common.MachineID)
+ {
+ ReleaseAllKeys();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+
+ signalHelperToExit = false;
+ LogDebug("^^^Helper Thread exiting...^^^");
+ }
+
+ internal static void MainFormDotEx(bool bCheckTS)
+ {
+ LogDebug("***** MainFormDotEx:");
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ int left = Common.PrimaryScreenBounds.Left + ((Common.PrimaryScreenBounds.Right - Common.PrimaryScreenBounds.Left) / 2) - 1;
+ int top = Setting.Values.HideMouse ? 3 : Common.PrimaryScreenBounds.Top + ((Common.PrimaryScreenBounds.Bottom - Common.PrimaryScreenBounds.Top) / 2);
+
+ Common.MainFormVisible = true;
+
+ if (Setting.Values.HideMouse && Setting.Values.StealFocusWhenSwitchingMachine && Common.SendMessageToHelper(0x407, new IntPtr(left), new IntPtr(top), true) == 0)
+ {
+ try
+ {
+ /* When user just switches to the Logon desktop, user is actually on the "Windows Default Lock Screen" (LockApp).
+ * If a click is sent to this during switch, it actually triggers a desktop switch on the local machine causing a reconnection affecting the machine switch.
+ * We can detect and skip in this case.
+ * */
+ IntPtr foreGroundWindow = NativeMethods.GetForegroundWindow();
+ string foreGroundWindowText = GetText(foreGroundWindow);
+
+ bool mouseClick = true;
+
+ if (foreGroundWindowText.Equals("Windows Default Lock Screen", StringComparison.OrdinalIgnoreCase))
+ {
+ mouseClick = false;
+ }
+
+ // Window title may be localized, check process name:
+ if (mouseClick)
+ {
+ _ = NativeMethods.GetWindowThreadProcessId(foreGroundWindow, out uint pid);
+
+ if (pid > 0)
+ {
+ string foreGroundWindowProcess = Process.GetProcessById((int)pid)?.ProcessName;
+
+ if (foreGroundWindowProcess.Equals("LockApp", StringComparison.OrdinalIgnoreCase))
+ {
+ mouseClick = false;
+ }
+ }
+ }
+
+ if (mouseClick)
+ {
+ InputSimulation.MouseClickDotForm(left + 1, top + 1);
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ }
+ }
+
+ CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue);
+ }
+
+ internal static void MainForm3Pixels()
+ {
+ LogDebug("***** MainFormDotLarge:");
+
+ DoSomethingInUIThread(
+ () =>
+ {
+ MainForm.Left = Common.PrimaryScreenBounds.Left + ((Common.PrimaryScreenBounds.Right - Common.PrimaryScreenBounds.Left) / 2) - 2;
+ MainForm.Top = Setting.Values.HideMouse ? 3 : Common.PrimaryScreenBounds.Top + ((Common.PrimaryScreenBounds.Bottom - Common.PrimaryScreenBounds.Top) / 2) - 1;
+ MainForm.Width = 3;
+ MainForm.Height = 3;
+ MainForm.Opacity = 0.11D;
+ MainForm.TopMost = true;
+
+ if (Setting.Values.HideMouse)
+ {
+ MainForm.BackColor = Color.Black;
+ MainForm.Show();
+ Common.MainFormVisible = true;
+ }
+ else
+ {
+ MainForm.BackColor = Color.White;
+ MainForm.Hide();
+ Common.MainFormVisible = false;
+ }
+ },
+ true);
+
+ CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue);
+ }
+
+ internal static void MainFormDot()
+ {
+ DoSomethingInUIThread(
+ () =>
+ {
+ _ = Common.SendMessageToHelper(0x408, IntPtr.Zero, IntPtr.Zero, false);
+
+ MainForm.Left = Common.PrimaryScreenBounds.Left + ((Common.PrimaryScreenBounds.Right - Common.PrimaryScreenBounds.Left) / 2) - 1;
+ MainForm.Top = Setting.Values.HideMouse ? 3 : Common.PrimaryScreenBounds.Top + ((Common.PrimaryScreenBounds.Bottom - Common.PrimaryScreenBounds.Top) / 2);
+ MainForm.Width = 1;
+ MainForm.Height = 1;
+ MainForm.Opacity = 0.15;
+ MainForm.Hide();
+ Common.MainFormVisible = false;
+ },
+ true);
+
+ CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue);
+ }
+
+ internal static void ToggleIcon()
+ {
+ try
+ {
+ if (toggleIconsIndex < TOGGLE_ICONS_SIZE)
+ {
+ Common.DoSomethingInUIThread(() => Common.MainForm.ChangeIcon(toggleIcons[toggleIconsIndex++]));
+ }
+ else
+ {
+ toggleIconsIndex = 0;
+ toggleIcons = null;
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ }
+
+ internal static void RunDDHelper(bool cleanUp = false)
+ {
+ if (Common.RunOnLogonDesktop || Common.RunOnScrSaverDesktop)
+ {
+ return;
+ }
+
+ if (cleanUp)
+ {
+ try
+ {
+ Process[] ps = Process.GetProcessesByName(HelperProcessName);
+ foreach (Process p in ps)
+ {
+ p.KillProcess();
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ _ = Common.SendMessageToHelper(SharedConst.QUIT_CMD, IntPtr.Zero, IntPtr.Zero);
+ }
+
+ return;
+ }
+
+ if (!Common.IsMyDesktopActive())
+ {
+ return;
+ }
+
+ if (!Common.IpcChannelCreated)
+ {
+ TelemetryLogTrace($"{nameof(Common.IpcChannelCreated)} = {Common.IpcChannelCreated}. {GetStackTrace(new StackTrace())}", SeverityLevel.Warning);
+ return;
+ }
+
+ if (!MainForm.IsDisposed)
+ {
+ MainForm.NotifyIcon.Visible = false;
+ MainForm.NotifyIcon.Visible = Setting.Values.ShowOriginalUI;
+ }
+
+ IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT);
+
+ if (h.ToInt32() <= 0)
+ {
+ _ = Common.CreateProcessInInputDesktopSession(
+ $"\"{Path.GetDirectoryName(Application.ExecutablePath)}\\{HelperProcessName}.exe\"",
+ string.Empty,
+ Common.GetInputDesktop(),
+ 0);
+
+ HasSwitchedMachineSinceLastCopy = true;
+
+ // Common.CreateLowIntegrityProcess("\"" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBordersHelper.exe\"", string.Empty, 0, false, 0);
+ if (Process.GetProcessesByName(HelperProcessName)?.Any() != true)
+ {
+ Log("Unable to start helper process.");
+ Common.ShowToolTip("Error starting Mouse Without Borders Helper, clipboard sharing will not work!", 5000, ToolTipIcon.Error);
+ }
+ else
+ {
+ Log("Helper process started.");
+ }
+ }
+ else
+ {
+ if (Process.GetProcessesByName(HelperProcessName)?.Any() == true)
+ {
+ Log("Helper process found running.");
+ }
+ else
+ {
+ Log("Invalid helper process found running.");
+ Common.ShowToolTip("Error finding Mouse Without Borders Helper, clipboard sharing will not work!", 5000, ToolTipIcon.Error);
+ }
+ }
+ }
+
+ internal static int SendMessageToHelper(int msg, IntPtr wparam, IntPtr lparam, bool wait = true, bool log = true)
+ {
+ int h = NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT);
+ int rv = -1;
+
+ if (h > 0)
+ {
+ rv = wait
+ ? (int)NativeMethods.SendMessage((IntPtr)h, msg, wparam, lparam)
+ : NativeMethods.PostMessage((IntPtr)h, msg, wparam, lparam) ? 1 : 0;
+ }
+
+ if (log)
+ {
+ Common.LogDebug($"SendMessageToHelper: HelperWindow={h}, Return={rv}, msg={msg}, w={wparam.ToInt32()}, l={lparam.ToInt32()}, Post={!wait}");
+ }
+
+ return rv;
+ }
+
+ internal static bool IsWindows8AndUp()
+ {
+ return (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 2)
+ || Environment.OSVersion.Version.Major > 6;
+ }
+
+ internal static string GetMiniLog(IEnumerable optionControls)
+ {
+ string log = string.Empty;
+
+ log += "=============================================================================================================================\r\n";
+ log += $"{Application.ProductName} version {Application.ProductVersion}\r\n";
+
+ log += $"{Setting.Values.Username}/{GetDebugInfo(MyKey)}\r\n";
+ log += $"{MachineName}/{MachineID}/{DesMachineID}\r\n";
+ log += $"Id: {Setting.Values.DeviceId}\r\n";
+ log += $"Matrix: {string.Join(",", MachineMatrix)}\r\n";
+ log += $"McPool: {Setting.Values.MachinePoolString}\r\n";
+
+ log += "\r\nOPTIONS:\r\n";
+
+ foreach (ControlCollection controlCollection in optionControls)
+ {
+ foreach (object c in controlCollection)
+ {
+ if (c is CheckBox checkBox)
+ {
+ log += $"({(checkBox.Checked ? 1 : 0)}) {checkBox.Text}\r\n";
+ continue;
+ }
+
+ if (c is RadioButton radioButton)
+ {
+ log += $"({(radioButton.Checked ? 1 : 0)}) {radioButton.Name}.[{radioButton.Text}]\r\n";
+ continue;
+ }
+
+ if (c is ComboBox comboBox)
+ {
+ log += $"{comboBox.Name} = {comboBox.Text}\r\n";
+ continue;
+ }
+ }
+ }
+
+ log += "\r\n";
+
+ SocketStuff sk = Sk;
+
+ if (sk?.TcpSockets != null)
+ {
+ foreach (TcpSk tcp in sk.TcpSockets)
+ {
+ log += $"{Common.MachineName}{(tcp.IsClient ? "=>" : "<=")}{tcp.MachineName}({tcp.MachineId}):{tcp.Status}\r\n";
+ }
+ }
+
+ log += string.Format(CultureInfo.CurrentCulture, "Helper:{0}\r\n", SendMessageToHelper(0x400, IntPtr.Zero, IntPtr.Zero));
+
+ log += Setting.Values.LastPersonalizeLogonScr + "\r\n";
+ log += "Name2IP =\r\n" + Setting.Values.Name2IP + "\r\n";
+
+ log += "Last 10 trace messages:\r\n";
+
+ log += string.Join(Environment.NewLine, LogCounter.Select(item => $"({item.Value}): {item.Key}").Take(10));
+
+ log += "\r\n=============================================================================================================================";
+
+ return log;
+ }
+
+ internal static bool GetUserName()
+ {
+ if (string.IsNullOrEmpty(Setting.Values.Username) && !Common.RunOnLogonDesktop)
+ {
+ if (Program.User.ToLower(CultureInfo.CurrentCulture).Contains("system"))
+ {
+ _ = Common.ImpersonateLoggedOnUserAndDoSomething(() =>
+ {
+ Setting.Values.Username = WindowsIdentity.GetCurrent(true).Name;
+ });
+ }
+ else
+ {
+ Setting.Values.Username = Program.User;
+ }
+
+ Common.LogDebug("[Username] = " + Setting.Values.Username);
+ }
+
+ return !string.IsNullOrEmpty(Setting.Values.Username);
+ }
+
+ internal static void ShowOneWayModeMessage()
+ {
+ ToggleShowTopMostMessage(
+ @"
+Due to Security Controls, a remote device cannot control a SAW device.
+Please use the keyboard and Mouse from the SAW device.
+(Press Esc to hide this message)
+",
+ string.Empty,
+ 10);
+ }
+
+ internal static void ApplyCADSetting()
+ {
+ try
+ {
+ if (Setting.Values.DisableCAD)
+ {
+ RegistryKey k = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System");
+ if (k != null)
+ {
+ k.SetValue("DisableCAD", 1, RegistryValueKind.DWord);
+ k.Close();
+ }
+ }
+ else
+ {
+ RegistryKey k = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System");
+ if (k != null)
+ {
+ k.SetValue("DisableCAD", 0, RegistryValueKind.DWord);
+ k.Close();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.InitAndCleanup.cs b/src/modules/MouseWithoutBorders/App/Class/Common.InitAndCleanup.cs
new file mode 100644
index 000000000000..a5b91eb4608d
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.InitAndCleanup.cs
@@ -0,0 +1,265 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Globalization;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Security.Cryptography;
+using System.Threading;
+
+//
+// Initialization and clean up.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using Microsoft.Win32;
+using MouseWithoutBorders.Class;
+using MouseWithoutBorders.Form;
+
+namespace MouseWithoutBorders
+{
+ internal partial class Common
+ {
+ private static bool initDone;
+ internal static int REOPEN_WHEN_WSAECONNRESET = -10054;
+ internal static int REOPEN_WHEN_HOTKEY = -10055;
+ internal static int PleaseReopenSocket;
+ internal static bool ReopenSocketDueToReadError;
+
+ internal static DateTime LastResumeSuspendTime { get; set; } = DateTime.UtcNow;
+
+ internal static bool InitDone
+ {
+ get => Common.initDone;
+ set => Common.initDone = value;
+ }
+
+ internal static void UpdateMachineTimeAndID()
+ {
+ Common.MachineName = Common.MachineName.Trim();
+ _ = Common.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
+ }
+
+ private static void InitializeMachinePoolFromSettings()
+ {
+ try
+ {
+ MachineInf[] info = MachinePoolHelpers.LoadMachineInfoFromMachinePoolStringSetting(Setting.Values.MachinePoolString);
+ for (int i = 0; i < info.Length; i++)
+ {
+ info[i].Name = info[i].Name.Trim();
+ }
+
+ Common.MachinePool.Initialize(info);
+ Common.MachinePool.ResetIPAddressesForDeadMachines(true);
+ }
+ catch (Exception ex)
+ {
+ Common.Log(ex);
+ Common.MachinePool.Clear();
+ }
+ }
+
+ internal static void SetupMachineNameAndID()
+ {
+ try
+ {
+ GetMachineName();
+ DesMachineID = NewDesMachineID = MachineID;
+
+ // MessageBox.Show(machineID.ToString(CultureInfo.CurrentCulture)); // For test
+ InitializeMachinePoolFromSettings();
+
+ Common.MachineName = Common.MachineName.Trim();
+ _ = Common.MachinePool.LearnMachine(Common.MachineName);
+ _ = Common.MachinePool.TryUpdateMachineID(Common.MachineName, Common.MachineID, true);
+
+ Common.UpdateMachinePoolStringSetting();
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ }
+
+ internal static void Init()
+ {
+ _ = Common.GetUserName();
+ Common.GeneratedKey = true;
+
+ try
+ {
+ Common.MyKey = Setting.Values.MyKey;
+ int tmp = Setting.Values.MyKeyDaysToExpire;
+ }
+ catch (FormatException e)
+ {
+ Common.KeyCorrupted = true;
+ Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
+ Common.Log(e.Message);
+ }
+ catch (CryptographicException e)
+ {
+ Common.KeyCorrupted = true;
+ Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
+ Common.Log(e.Message);
+ }
+
+ bool dummy = Setting.Values.DrawMouseEx;
+ Is64bitOS = IntPtr.Size == 8;
+ tcpPort = Setting.Values.TcpPort;
+ GetScreenConfig();
+ PackageSent = new PackageMonitor(0);
+ PackageReceived = new PackageMonitor(0);
+ SetupMachineNameAndID();
+ InitEncryption();
+ CreateHelperThreads();
+
+ SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);
+ NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
+ SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
+ PleaseReopenSocket = 9;
+ /* TODO: Telemetry for the matrix? */
+ }
+
+ private static void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
+ {
+ Common.WndProcCounter++;
+
+ if (e.Mode is PowerModes.Resume or PowerModes.Suspend)
+ {
+ Common.TelemetryLogTrace($"{nameof(SystemEvents_PowerModeChanged)}: {e.Mode}", SeverityLevel.Information);
+ LastResumeSuspendTime = DateTime.UtcNow;
+ SwitchToMultipleMode(false, true);
+ }
+ }
+
+ private static void CreateHelperThreads()
+ {
+ // NOTE(@yuyoyuppe): service crashes while trying to obtain this info, disabling.
+ /*
+ Thread watchDogThread = new(new ThreadStart(WatchDogThread), nameof(WatchDogThread));
+ watchDogThread.Priority = ThreadPriority.Highest;
+ watchDogThread.Start();
+ */
+
+ helper = new Thread(new ThreadStart(HelperThread), "Helper Thread");
+ helper.SetApartmentState(ApartmentState.STA);
+ helper.Start();
+ }
+
+ private static void AskHelperThreadsToExit(int waitTime)
+ {
+ signalHelperToExit = true;
+ signalWatchDogToExit = true;
+ _ = EvSwitch.Set();
+
+ int c = 0;
+ if (helper != null && c < waitTime)
+ {
+ while (signalHelperToExit)
+ {
+ Thread.Sleep(1);
+ }
+
+ helper = null;
+ }
+ }
+
+ internal static void Cleanup()
+ {
+ try
+ {
+ SendByeBye();
+
+ // UnhookClipboard();
+ AskHelperThreadsToExit(500);
+ MainForm.NotifyIcon.Visible = false;
+ MainForm.NotifyIcon.Dispose();
+ CloseAllFormsAndHooks();
+
+ DoSomethingInUIThread(() =>
+ {
+ Sk?.Close(true);
+ });
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ }
+
+ private static long lastReleaseAllKeysCall;
+
+ internal static void ReleaseAllKeys()
+ {
+ if (Math.Abs(GetTick() - lastReleaseAllKeysCall) < 2000)
+ {
+ return;
+ }
+
+ lastReleaseAllKeysCall = GetTick();
+
+ KEYBDDATA kd;
+ kd.dwFlags = (int)LLKHF.UP;
+
+ VK[] keys = new VK[]
+ {
+ VK.LSHIFT, VK.LCONTROL, VK.LMENU, VK.LWIN, VK.RSHIFT,
+ VK.RCONTROL, VK.RMENU, VK.RWIN, VK.SHIFT, VK.MENU, VK.CONTROL,
+ };
+
+ LogDebug("***** ReleaseAllKeys has been called! *****:");
+
+ foreach (VK vk in keys)
+ {
+ if ((NativeMethods.GetAsyncKeyState((IntPtr)vk) & 0x8000) != 0)
+ {
+ LogDebug(vk.ToString() + " is down, release it...");
+ Hook?.ResetLastSwitchKeys(); // Sticky key can turn ALL PC mode on (CtrlCtrlCtrl)
+ kd.wVk = (int)vk;
+ InputSimulation.SendKey(kd);
+ Hook?.ResetLastSwitchKeys();
+ }
+ }
+ }
+
+ private static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
+ {
+ LogDebug("NetworkAvailabilityEventArgs.IsAvailable: " + e.IsAvailable.ToString(CultureInfo.InvariantCulture));
+ Common.WndProcCounter++;
+ ScheduleReopenSocketsDueToNetworkChanges(!e.IsAvailable);
+ }
+
+ private static void ScheduleReopenSocketsDueToNetworkChanges(bool closeSockets = true)
+ {
+ if (closeSockets)
+ {
+ // Slept/hibernated machine may still have the sockets' status as Connected:( (unchanged) so it would not re-connect after a timeout when waking up.
+ // Closing the sockets when it is going to sleep/hibernate will trigger the reconnection faster when it wakes up.
+ DoSomethingInUIThread(
+ () =>
+ {
+ SocketStuff s = Sk;
+ Sk = null;
+ s?.Close(false);
+ },
+ true);
+ }
+
+ if (!Common.IsMyDesktopActive())
+ {
+ PleaseReopenSocket = 0;
+ }
+ else if (PleaseReopenSocket != 10)
+ {
+ PleaseReopenSocket = 10;
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Launch.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Launch.cs
new file mode 100644
index 000000000000..02dbfd707b02
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.Launch.cs
@@ -0,0 +1,307 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.Security.Principal;
+
+//
+// Impersonation.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+
+namespace MouseWithoutBorders
+{
+ internal partial class Common
+ {
+ internal static bool RunElevated()
+ {
+ return WindowsIdentity.GetCurrent().Owner.IsWellKnown(WellKnownSidType.BuiltinAdministratorsSid);
+ }
+
+ internal static bool ImpersonateLoggedOnUserAndDoSomething(Action targetFunc)
+ {
+ if (Common.RunWithNoAdminRight)
+ {
+ targetFunc();
+ return true;
+ }
+ else
+ {
+ uint dwSessionId;
+ IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero;
+ try
+ {
+ dwSessionId = (uint)Process.GetCurrentProcess().SessionId;
+ uint rv = NativeMethods.WTSQueryUserToken(dwSessionId, ref hUserToken);
+ LogDebug("WTSQueryUserToken returned " + rv.ToString(CultureInfo.CurrentCulture));
+
+ if (rv == 0)
+ {
+ LogDebug($"WTSQueryUserToken failed with: {Marshal.GetLastWin32Error()}.");
+ return false;
+ }
+
+ if (!NativeMethods.DuplicateToken(hUserToken, (int)NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, ref hUserTokenDup))
+ {
+ TelemetryLogTrace($"DuplicateToken Failed! {GetStackTrace(new StackTrace())}", SeverityLevel.Warning);
+ _ = NativeMethods.CloseHandle(hUserToken);
+ _ = NativeMethods.CloseHandle(hUserTokenDup);
+ return false;
+ }
+
+ if (NativeMethods.ImpersonateLoggedOnUser(hUserTokenDup))
+ {
+ targetFunc();
+ _ = NativeMethods.RevertToSelf();
+ _ = NativeMethods.CloseHandle(hUserToken);
+ _ = NativeMethods.CloseHandle(hUserTokenDup);
+ return true;
+ }
+ else
+ {
+ Log("ImpersonateLoggedOnUser Failed!");
+ _ = NativeMethods.CloseHandle(hUserToken);
+ _ = NativeMethods.CloseHandle(hUserTokenDup);
+ return false;
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ return false;
+ }
+ }
+ }
+
+ [SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.String.ToLower", Justification = "Dotnet port with style preservation")]
+ internal static int CreateProcessInInputDesktopSession(string commandLine, string arg, string desktop, short wShowWindow, bool lowIntegrity = false)
+
+ // As user who runs explorer.exe
+ {
+ if (!Program.User.ToLower(CultureInfo.InvariantCulture).Contains("system"))
+ {
+ ProcessStartInfo s = new(commandLine, arg);
+ s.WindowStyle = wShowWindow != 0 ? ProcessWindowStyle.Normal : ProcessWindowStyle.Hidden;
+ Process p = Process.Start(s);
+
+ return p == null ? 0 : p.Id;
+ }
+
+ string commandLineWithArg = commandLine + " " + arg;
+ int lastError;
+ int dwSessionId;
+ IntPtr hUserToken = IntPtr.Zero, hUserTokenDup = IntPtr.Zero;
+
+ Common.LogDebug("CreateProcessInInputDesktopSession called, launching " + commandLineWithArg + " on " + desktop);
+
+ try
+ {
+ dwSessionId = Process.GetCurrentProcess().SessionId;
+
+ // Get the user token used by DuplicateTokenEx
+ lastError = (int)NativeMethods.WTSQueryUserToken((uint)dwSessionId, ref hUserToken);
+
+ NativeMethods.STARTUPINFO si = default;
+ si.cb = Marshal.SizeOf(si);
+ si.lpDesktop = "winsta0\\" + desktop;
+ si.wShowWindow = wShowWindow;
+
+ NativeMethods.SECURITY_ATTRIBUTES sa = default;
+ sa.Length = Marshal.SizeOf(sa);
+
+ if (!NativeMethods.DuplicateTokenEx(hUserToken, NativeMethods.MAXIMUM_ALLOWED, ref sa, (int)NativeMethods.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)NativeMethods.TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
+ {
+ lastError = Marshal.GetLastWin32Error();
+ Common.Log(string.Format(CultureInfo.CurrentCulture, "DuplicateTokenEx error: {0} Token does not have the privilege.", lastError));
+ _ = NativeMethods.CloseHandle(hUserToken);
+ return 0;
+ }
+
+ if (lowIntegrity)
+ {
+ NativeMethods.TOKEN_MANDATORY_LABEL tIL;
+
+ // Low
+ string sIntegritySid = "S-1-16-4096";
+
+ bool rv = NativeMethods.ConvertStringSidToSid(sIntegritySid, out IntPtr pIntegritySid);
+
+ if (!rv)
+ {
+ Log("ConvertStringSidToSid failed");
+ _ = NativeMethods.CloseHandle(hUserToken);
+ _ = NativeMethods.CloseHandle(hUserTokenDup);
+ return 0;
+ }
+
+ tIL.Label.Attributes = NativeMethods.SE_GROUP_INTEGRITY;
+ tIL.Label.Sid = pIntegritySid;
+
+ rv = NativeMethods.SetTokenInformation(hUserTokenDup, NativeMethods.TOKEN_INFORMATION_CLASS.TokenIntegrityLevel, ref tIL, (uint)Marshal.SizeOf(tIL) + (uint)IntPtr.Size);
+
+ if (!rv)
+ {
+ Log("SetTokenInformation failed");
+ _ = NativeMethods.CloseHandle(hUserToken);
+ _ = NativeMethods.CloseHandle(hUserTokenDup);
+ return 0;
+ }
+ }
+
+ uint dwCreationFlags = NativeMethods.NORMAL_PRIORITY_CLASS | NativeMethods.CREATE_NEW_CONSOLE;
+ IntPtr pEnv = IntPtr.Zero;
+
+ if (NativeMethods.CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true))
+ {
+ dwCreationFlags |= NativeMethods.CREATE_UNICODE_ENVIRONMENT;
+ }
+ else
+ {
+ pEnv = IntPtr.Zero;
+ }
+
+ _ = NativeMethods.CreateProcessAsUser(
+ hUserTokenDup, // client's access token
+ null, // file to execute
+ commandLineWithArg, // command line
+ ref sa, // pointer to process SECURITY_ATTRIBUTES
+ ref sa, // pointer to thread SECURITY_ATTRIBUTES
+ false, // handles are not inheritable
+ (int)dwCreationFlags, // creation flags
+ pEnv, // pointer to new environment block
+ null, // name of current directory
+ ref si, // pointer to STARTUPINFO structure
+ out NativeMethods.PROCESS_INFORMATION pi); // receives information about new process
+
+ // GetLastError should be 0
+ int iResultOfCreateProcessAsUser = Marshal.GetLastWin32Error();
+ LogDebug("CreateProcessAsUser returned " + iResultOfCreateProcessAsUser.ToString(CultureInfo.CurrentCulture));
+
+ // Close handles task
+ _ = NativeMethods.CloseHandle(hUserToken);
+ _ = NativeMethods.CloseHandle(hUserTokenDup);
+
+ return (iResultOfCreateProcessAsUser == 0) ? (int)pi.dwProcessId : 0;
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ return 0;
+ }
+ }
+
+#if CUSTOMIZE_LOGON_SCREEN
+ internal static bool CreateLowIntegrityProcess(string commandLine, string args, int wait, bool killIfTimedOut, long limitedMem, short wShowWindow = 0)
+ {
+ int processId = CreateProcessInInputDesktopSession(commandLine, args, "default", wShowWindow, true);
+
+ if (processId <= 0)
+ {
+ return false;
+ }
+
+ if (wait > 0)
+ {
+ if (limitedMem > 0)
+ {
+ int sec = 0;
+ while (true)
+ {
+ Process p;
+
+ try
+ {
+ if ((p = Process.GetProcessById(processId)) == null)
+ {
+ Log("Process exited!");
+ break;
+ }
+ }
+ catch (ArgumentException)
+ {
+ Log("GetProcessById.ArgumentException");
+ break;
+ }
+
+ if ((!p.HasExited && p.PrivateMemorySize64 > limitedMem) || (++sec > (wait / 1000)))
+ {
+ Log(string.Format(CultureInfo.CurrentCulture, "Process log (mem): {0}, {1}", sec, p.PrivateMemorySize64));
+ return false;
+ }
+
+ Thread.Sleep(1000);
+ }
+ }
+ else
+ {
+ Process p;
+
+ if ((p = Process.GetProcessById(processId)) == null)
+ {
+ Log("Process exited!");
+ }
+ else if (NativeMethods.WaitForSingleObject(p.Handle, wait) != NativeMethods.WAIT_OBJECT_0 && killIfTimedOut)
+ {
+ Log("Process log (time).");
+ TerminateProcessTree(p.Handle, (uint)processId, -1);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ internal static void TerminateProcessTree(IntPtr hProcess, uint processID, int exitCode)
+ {
+ if (processID > 0 && hProcess.ToInt32() > 0)
+ {
+ Process[] processes = Process.GetProcesses();
+ int dwSessionId = Process.GetCurrentProcess().SessionId;
+
+ foreach (Process p in processes)
+ {
+ if (p.SessionId == dwSessionId)
+ {
+ NativeMethods.PROCESS_BASIC_INFORMATION processBasicInformation = default;
+
+ try
+ {
+ if (NativeMethods.NtQueryInformationProcess(p.Handle, 0, ref processBasicInformation, (uint)Marshal.SizeOf(processBasicInformation), out uint bytesWritten) >= 0)
+ {// NT_SUCCESS(...)
+ if (processBasicInformation.InheritedFromUniqueProcessId == processID)
+ {
+ TerminateProcessTree(p.Handle, processBasicInformation.UniqueProcessId, exitCode);
+ }
+ }
+ }
+ catch (InvalidOperationException e)
+ {
+ Log(e);
+ continue;
+ }
+ catch (Win32Exception e)
+ {
+ Log(e);
+ continue;
+ }
+ }
+ }
+
+ _ = NativeMethods.TerminateProcess(hProcess, (IntPtr)exitCode);
+ }
+ }
+#endif
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Log.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Log.cs
new file mode 100644
index 000000000000..4736a74cf6cf
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.Log.cs
@@ -0,0 +1,509 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Windows.Forms;
+
+//
+// Logging.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+using MouseWithoutBorders.Exceptions;
+
+namespace MouseWithoutBorders
+{
+ public class Thread
+ {
+ private static readonly object ThreadsLock = new();
+ private static List threads;
+
+ private readonly System.Threading.Thread thread;
+
+ internal Thread(ThreadStart callback, string name)
+ {
+ UpdateThreads(thread = new System.Threading.Thread(callback) { Name = name });
+ }
+
+ internal Thread(ParameterizedThreadStart callback, string name)
+ {
+ UpdateThreads(thread = new System.Threading.Thread(callback) { Name = name });
+ }
+
+ internal static void UpdateThreads(System.Threading.Thread thread)
+ {
+ lock (ThreadsLock)
+ {
+ bool found = false;
+ List toBeRemovedThreads = new();
+ threads ??= new List();
+
+ foreach (System.Threading.Thread t in threads)
+ {
+ if (!t.IsAlive)
+ {
+ toBeRemovedThreads.Add(t);
+ }
+ else if (t.ManagedThreadId == thread.ManagedThreadId)
+ {
+ found = true;
+ }
+ }
+
+ foreach (System.Threading.Thread t in toBeRemovedThreads)
+ {
+ _ = threads.Remove(t);
+ }
+
+ if (!found)
+ {
+ threads.Add(thread);
+ }
+ }
+ }
+
+ internal static string DumpThreadsStack()
+ {
+ string stack = "\r\nMANAGED THREADS: " + threads.Count.ToString(CultureInfo.InvariantCulture) + "\r\n";
+ stack += Common.GetStackTrace(new StackTrace());
+ return stack;
+ }
+
+ internal static void SuspendAllThreadsBut(int threadId)
+ {
+ lock (ThreadsLock)
+ {
+#pragma warning disable 618 // Temporary
+ threads.Where(t => t.IsAlive && t.ManagedThreadId != threadId).ToList().ForEach(t => t.Suspend());
+#pragma warning restore 618
+ }
+ }
+
+ internal void SetApartmentState(ApartmentState apartmentState)
+ {
+ thread.SetApartmentState(apartmentState);
+ }
+
+ internal void Start()
+ {
+ thread.Start();
+ }
+
+ internal void Start(object parameter)
+ {
+ thread.Start(parameter);
+ }
+
+ internal static void Sleep(int millisecondsTimeout)
+ {
+ System.Threading.Thread.Sleep(millisecondsTimeout);
+ }
+
+ internal static System.Threading.Thread CurrentThread => System.Threading.Thread.CurrentThread;
+
+ internal ThreadPriority Priority
+ {
+ get => thread.Priority;
+ set => thread.Priority = value;
+ }
+
+ internal System.Threading.ThreadState ThreadState => thread.ThreadState;
+ }
+
+ internal partial class Common
+ {
+ private static readonly string[] AllLogs = new string[MAX_LOG];
+ private static readonly object AllLogsLock = new();
+ private static readonly ConcurrentDictionary LogCounter = new();
+ private static readonly int[] RepeatedLogIndexSelection = new[] { 1, 3, 10, 50, 100 };
+ private const int MAX_LOG = 10000;
+ private static int allLogsIndex;
+
+ private const int MaxLogExceptionPerHour = 1000;
+ private static int lastHour;
+ private static int exceptionCount;
+
+ internal static void TelemetryLogTrace(string log, SeverityLevel severityLevel, bool flush = false)
+ {
+ int logCount = LogCounter.AddOrUpdate(log, 1, (key, value) => value + 1);
+ Common.Log(log);
+ }
+
+ internal static void Log(Exception e)
+ {
+ if (e is not KnownException)
+ {
+ string exText = e.ToString();
+
+ Log($"!Exception!: {exText}");
+
+ if (DateTime.UtcNow.Hour != lastHour)
+ {
+ lastHour = DateTime.UtcNow.Hour;
+ exceptionCount = 0;
+ }
+
+ if (exceptionCount < MaxLogExceptionPerHour)
+ {
+ exceptionCount++;
+ }
+ else if (exceptionCount != short.MaxValue)
+ {
+ exceptionCount = short.MaxValue;
+ }
+ }
+ }
+
+ private const string HeaderSENT =
+ "Be{0},Ke{1},Mo{2},He{3},Mx{4},Tx{5},Im{6},By{7},Cl{8},Dr{9},De{10},Ed{11},Ie{12},Ni{13}";
+
+ private const string HeaderRECEIVED =
+ "Be{0},Ke{1},Mo{2},He{3},Mx{4},Tx{5},Im{6},By{7},Cl{8},Dr{9},De{10},Ed{11},In{12},Ni{13},Pc{14}/{15}";
+
+ internal static void LogDebug(string log, bool clearLog = false)
+ {
+#if DEBUG
+ Log(log, clearLog);
+#endif
+ }
+
+ internal static void Log(string log, bool clearLog = false)
+ {
+ log = DateTime.Now.ToString("MM/dd HH:mm:ss.fff", CultureInfo.InvariantCulture) + $"({Thread.CurrentThread.ManagedThreadId})" + log;
+
+ ManagedCommon.Logger.LogInfo(log);
+ lock (AllLogsLock)
+ {
+ if (clearLog)
+ {
+ allLogsIndex = 0;
+ }
+
+ AllLogs[allLogsIndex] = log;
+ allLogsIndex = (allLogsIndex + 1) % MAX_LOG;
+ }
+ }
+
+ internal static void LogDebug(string format, params object[] args)
+ {
+#if DEBUG
+ Log(format, args);
+#endif
+ }
+
+ internal static void Log(string format, params object[] args)
+ {
+ Common.Log(string.Format(CultureInfo.InvariantCulture, format, args));
+ }
+
+ private static PackageMonitor p1;
+ private static PackageMonitor p2;
+
+ [Conditional("DEBUG")]
+ internal static void LogAll()
+ {
+ string log;
+
+ if (!p1.Equals(PackageSent))
+ {
+ log = string.Format(
+ CultureInfo.CurrentCulture,
+ "SENT:" + HeaderSENT,
+ PackageSent.Heartbeat,
+ PackageSent.Keyboard,
+ PackageSent.Mouse,
+ PackageSent.Hello,
+ PackageSent.Matrix,
+ PackageSent.ClipboardText,
+ PackageSent.ClipboardImage,
+ PackageSent.ByeBye,
+ PackageSent.Clipboard,
+ PackageSent.ClipboardDragDrop,
+ PackageSent.ClipboardDragDropEnd,
+ PackageSent.ExplorerDragDrop,
+ inputEventCount,
+ PackageSent.Nil);
+ Log(log);
+ p1 = PackageSent; // Copy data
+ }
+
+ if (!p2.Equals(PackageReceived))
+ {
+ log = string.Format(
+ CultureInfo.CurrentCulture,
+ "RECEIVED:" + HeaderRECEIVED,
+ PackageReceived.Heartbeat,
+ PackageReceived.Keyboard,
+ PackageReceived.Mouse,
+ PackageReceived.Hello,
+ PackageReceived.Matrix,
+ PackageReceived.ClipboardText,
+ PackageReceived.ClipboardImage,
+ PackageReceived.ByeBye,
+ PackageReceived.Clipboard,
+ PackageReceived.ClipboardDragDrop,
+ PackageReceived.ClipboardDragDropEnd,
+ PackageReceived.ExplorerDragDrop,
+ invalidPackageCount,
+ PackageReceived.Nil,
+ processedPackageCount,
+ skippedPackageCount);
+ Log(log);
+ p2 = PackageReceived;
+ }
+ }
+
+ internal static void GenerateLog()
+ {
+ int l = Setting.Values.DumpObjectsLevel;
+ if (l is > 0 and < 10)
+ {
+ Common.DumpObjects(l);
+ }
+ }
+
+ private static List myThreads;
+
+ internal static void DumpObjects(int level)
+ {
+ try
+ {
+ string logFile = Path.Combine(Common.RunWithNoAdminRight ? Path.GetTempPath() : Path.GetDirectoryName(Application.ExecutablePath), "MagicMouse.log");
+
+ StringBuilder sb = new(1000000);
+ string log;
+
+ myThreads = new List();
+
+ foreach (ProcessThread t in Process.GetCurrentProcess().Threads)
+ {
+ myThreads.Add(t);
+ }
+
+ _ = PrivateDump(sb, AllLogs, "[Program logs]\r\n===============\r\n", 0, level, false);
+ _ = PrivateDump(sb, new Common(), "[Other Logs]\r\n===============\r\n", 0, level, false);
+
+ log = string.Format(
+ CultureInfo.CurrentCulture,
+ "{0} {1}\r\n{2}\r\n\r\n{3}",
+ Application.ProductName,
+ Application.ProductVersion,
+ "Private Mem: " + (Process.GetCurrentProcess().PrivateMemorySize64 / 1024).ToString(CultureInfo.CurrentCulture) + "KB",
+ sb.ToString());
+
+ if (!string.IsNullOrEmpty(myKey))
+ {
+ log = log.Replace(MyKey, GetDebugInfo(MyKey));
+ }
+
+ log += Thread.DumpThreadsStack();
+ log += $"\r\nCurrent process session: {Process.GetCurrentProcess().SessionId}, active console session: {NativeMethods.WTSGetActiveConsoleSessionId()}.";
+
+ File.WriteAllText(logFile, log);
+
+ if (RunOnLogonDesktop || RunOnScrSaverDesktop)
+ {
+ _ = MessageBox.Show("Dump file created: " + logFile, Application.ProductName);
+ }
+ else
+ {
+ ShowToolTip("Dump file created: " + logFile + " and placed in the Clipboard.", 10000);
+ Clipboard.SetText(logFile);
+ }
+ }
+ catch (Exception e)
+ {
+ _ = MessageBox.Show(e.Message + "\r\n" + e.StackTrace, Application.ProductName);
+ }
+ }
+
+ private static object GetFieldValue(object obj, string fieldName)
+ {
+ FieldInfo fi;
+ Type t;
+
+ t = obj.GetType();
+ fi = t.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+ return fi?.GetValue(obj);
+ }
+
+ private static bool PrivateDump(StringBuilder sb, object obj, string objName, int level, int maxLevel, bool stop)
+ {
+ Type t;
+ string padStr = string.Empty;
+ string[] strArr;
+ string objString;
+
+ if (obj == null || (maxLevel >= 0 && level >= maxLevel) || obj is Cursor)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < level; i++)
+ {
+ padStr += i < level - 1 ? "-" : padStr += string.Empty;
+ }
+
+ objString = obj.ToString();
+ t = obj.GetType();
+ strArr = new string[7];
+ strArr[0] = padStr;
+ strArr[1] = objName;
+
+ // strArr[2] = " ";
+ // strArr[3] = t.FullName;
+ strArr[4] = " = ";
+ strArr[5] = objName.Equals("myKey", StringComparison.OrdinalIgnoreCase) ? GetDebugInfo(objString)
+ : objName.Equals("lastClipboardObject", StringComparison.OrdinalIgnoreCase) ? string.Empty
+ : objString.Replace("System.Windows.Forms.", string.Empty).Replace("System.Net.Sockets.", string.Empty).Replace("System.Security.Cryptography.", string.Empty).Replace("System.Threading.", string.Empty)
+ .Replace("System.ComponentModel.", string.Empty).Replace("System.Runtime.", string.Empty).Replace("System.Drawing.", string.Empty).Replace("System.Object", "O").Replace("System.Diagnostics.", string.Empty)
+ .Replace("System.Collections.", string.Empty).Replace("System.Drawing.", string.Empty).Replace("System.Int", string.Empty).Replace("System.EventHandler.", string.Empty);
+ strArr[6] = "\r\n";
+ _ = sb.Append(string.Concat(strArr).Replace(Common.BinaryName, "MM"));
+
+ if (stop || t.IsPrimitive)
+ {
+ return false;
+ }
+
+ DumpType(padStr, sb, obj, level, t, maxLevel);
+ return true;
+ }
+
+ private static void DumpType(string initialStr, StringBuilder sb, object obj, int level, System.Type t, int maxLevel)
+ {
+ int i;
+ bool stop;
+ if (t == typeof(System.Delegate))
+ {
+ return;
+ }
+
+ FieldInfo[] fi;
+ string type;
+
+ if (obj is MouseWithoutBorders.PackageType or string or AddressFamily or ID or IPAddress
+ )
+ {
+ return;
+ }
+
+ type = obj.GetType().ToString();
+
+ if (type.EndsWith("type", StringComparison.CurrentCultureIgnoreCase) || type.Contains("Cryptography")
+ || type.EndsWith("AsyncEventBits", StringComparison.CurrentCultureIgnoreCase))
+ {
+ return;
+ }
+
+ stop = obj == null || obj is MouseWithoutBorders.DATA || obj.GetType().BaseType == typeof(ValueType)
+ || obj.GetType().Namespace.Contains("System.Windows");
+ fi = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
+
+ foreach (FieldInfo f in fi)
+ {
+ if (f.GetValue(obj) != AllLogs)
+ {
+ _ = PrivateDump(sb, f.GetValue(obj), f.Name, level + 1, maxLevel, stop);
+ }
+ }
+
+ if (obj is Dictionary>)
+ {
+ Dictionary> d = obj as Dictionary>;
+
+ foreach (string k in d.Keys)
+ {
+ if (d.TryGetValue(k, out List l))
+ {
+ foreach (IPAddress ip in l)
+ {
+ _ = PrivateDump(sb, ip, "[" + k + "]", level + 1, maxLevel, false);
+ }
+ }
+ }
+ }
+
+ if (obj is System.Array)
+ {
+ try
+ {
+ if (obj is MachineInf[])
+ {
+ MachineInf[] os = (MachineInf[])obj;
+
+ for (i = 0; i < os.GetLength(0); i++)
+ {
+ _ = PrivateDump(sb, os[i], "[" + i + "]", level + 1, maxLevel, false);
+ }
+ }
+ else if (obj is int[] || obj is uint[])
+ {
+ int[] os = (int[])obj;
+
+ for (i = 0; i < os.GetLength(0); i++)
+ {
+ _ = PrivateDump(sb, os[i], "[" + i + "]", level + 1, maxLevel, false);
+ }
+ }
+ else if (obj is short[] || obj is ushort[])
+ {
+ short[] os = (short[])obj;
+
+ for (i = 0; i < os.GetLength(0); i++)
+ {
+ _ = PrivateDump(sb, os[i], "[" + i + "]", level + 1, maxLevel, false);
+ }
+ }
+ else if (obj is TcpClient[] || obj is IPAddress[] || obj is TcpSk[] || obj is string[]
+ || obj is TcpServer[]
+ || obj is ProcessThread[] || obj is Thread[])
+ {
+ object[] os = (object[])obj;
+
+ for (i = 0; i < os.GetLength(0); i++)
+ {
+ _ = PrivateDump(sb, os[i], "[" + i + "]", level + 1, maxLevel, false);
+ }
+ }
+ else
+ {
+ _ = PrivateDump(sb, obj.GetType().ToString() + ": N/A", obj.GetType().ToString(), level + 1, maxLevel, false);
+ }
+ }
+ catch (Exception)
+ {
+ }
+ }
+ }
+
+ internal static string GetStackTrace(StackTrace st)
+ {
+ string rv = string.Empty;
+
+ for (int i = 0; i < st.FrameCount; i++)
+ {
+ StackFrame sf = st.GetFrame(i);
+ rv += sf.GetMethod() + " <= ";
+ }
+
+ return rv;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.MachineStuff.cs b/src/modules/MouseWithoutBorders/App/Class/Common.MachineStuff.cs
new file mode 100644
index 000000000000..df3ef5d55d57
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.MachineStuff.cs
@@ -0,0 +1,1130 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Threading;
+using System.Windows.Forms;
+using Microsoft.PowerToys.Telemetry;
+
+//
+// Machine setup/switching implementation.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+
+namespace MouseWithoutBorders
+{
+ internal struct MachineInf
+ {
+ internal string Name;
+ internal ID Id;
+ internal long Time;
+ }
+
+ internal class MyRectangle
+ {
+ internal int Left;
+ internal int Top;
+ internal int Right;
+ internal int Bottom;
+ }
+
+ internal partial class Common
+ {
+ private static readonly object McMatrixLock = new();
+
+ internal const byte MAX_MACHINE = 4;
+ internal const byte MAX_SOCKET = MAX_MACHINE * 2;
+ internal const long HEARTBEAT_TIMEOUT = 1500000; // 30 Mins
+ private const int SKIP_PIXELS = 1;
+ private const int JUMP_PIXELS = 2;
+
+ private static ID desMachineID;
+ internal static string DesMachineName = string.Empty;
+ private static ID newDesMachineID;
+ private static ID newDesMachineIdEx;
+ private static ID dropMachineID;
+
+ private static long lastJump = Common.GetTick();
+ private static MyRectangle desktopBounds = new();
+ private static MyRectangle primaryScreenBounds = new();
+ private static MachinePool _machinePool;
+
+ internal static MachinePool MachinePool
+ {
+ get
+ {
+ _machinePool ??= new MachinePool();
+ return _machinePool;
+ }
+ }
+
+ internal static MyRectangle PrimaryScreenBounds => Common.primaryScreenBounds;
+
+ internal static MouseLocation SwitchLocation = new();
+
+ internal static ID NewDesMachineID
+ {
+ get => Common.newDesMachineID;
+ set => Common.newDesMachineID = value;
+ }
+
+ internal static MyRectangle DesktopBounds => Common.desktopBounds;
+
+#if OLD_VERSION
+ static bool MoveToMyNeighbourIfNeeded(int x, int y)
+ {
+ if (Math.Abs(x) > 10) LastX = x;
+ if (Math.Abs(y) > 10) LastY = y;
+ if (GetTick() - lastJump < 500 || desMachineID == IP.ALL) return false;
+ if (desMachineID == machineID)
+ {
+ if (x < desktopBounds.Left + skipPixels) return MoveLeft(x, y, x - desktopBounds.Left, 0);
+ }
+ else
+ {
+ if (x < primaryScreenBounds.Left + skipPixels)
+ {
+ if (MoveLeft(x, y, x - primaryScreenBounds.Left, 0))
+ {
+ return true;
+ }
+ else
+ {
+ if (desktopBounds.Left < primaryScreenBounds.Left)
+ {
+ RequestedX_Ex = primaryScreenBounds.Left;
+ RequestedY_Ex = y;
+ return true;
+ }
+ }
+ }
+ }
+
+ if (desMachineID == machineID)
+ {
+ if (x > desktopBounds.Right - skipPixels) return MoveRight(x, y, x - desktopBounds.Right, 0);
+ }
+ else
+ {
+ if (x > primaryScreenBounds.Right - skipPixels)
+ {
+ if (MoveRight(x, y, x - primaryScreenBounds.Right, 0))
+ {
+ return true;
+ }
+ else
+ {
+ if (desktopBounds.Right > primaryScreenBounds.Right)
+ {
+ RequestedX_Ex = primaryScreenBounds.Right;
+ RequestedY_Ex = y;
+ return true;
+ }
+ }
+ }
+ }
+
+ if (desMachineID == machineID)
+ {
+ if (y < desktopBounds.Top + skipPixels) return MoveUp(x, y, 0, y - desktopBounds.Top);
+ }
+ else
+ {
+ if (y < primaryScreenBounds.Top + skipPixels)
+ {
+ if (MoveUp(x, y, 0, y - primaryScreenBounds.Top))
+ {
+ return true;
+ }
+ else
+ {
+ if (desktopBounds.Top < primaryScreenBounds.Top)
+ {
+ RequestedX_Ex = x;
+ RequestedY_Ex = primaryScreenBounds.Top;
+ return true;
+ }
+ }
+ }
+ }
+
+ if (desMachineID == machineID)
+ {
+ if (y > desktopBounds.Bottom - skipPixels) return MoveDown(x, y, 0, y - desktopBounds.Bottom);
+ }
+ else
+ {
+ if (y > primaryScreenBounds.Bottom - skipPixels)
+ {
+ if (MoveDown(x, y, 0, y - primaryScreenBounds.Bottom))
+ {
+ return true;
+ }
+ else
+ {
+ if (desktopBounds.Bottom > primaryScreenBounds.Bottom)
+ {
+ RequestedX_Ex = x;
+ RequestedY_Ex = primaryScreenBounds.Bottom;
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+#else
+
+ private static Point ConvertToUniversalValue(Point p, MyRectangle r)
+ {
+ if (!p.IsEmpty)
+ {
+ p.X = (p.X - r.Left) * 65535 / (r.Right - r.Left);
+ p.Y = (p.Y - r.Top) * 65535 / (r.Bottom - r.Top);
+ }
+
+ return p;
+ }
+
+ /* Let's say we have 3 machines A, B, and C. A is the controller machine.
+ * (x, y) is the current Mouse position in pixel.
+ * If Setting.Values.MoveMouseRelatively then (x, y) can be from any machine having the value bounded by desktopBounds (can be negative)
+ * Else (x, y) is from the controller machine which is bounded by ONLY primaryScreenBounds (>=0);
+ *
+ * The return point is from 0 to 65535 which is then mapped to the desktop of the new controlled machine by the SendInput method.
+ * Let's say user is switching from machine B to machine C:
+ * If Setting.Values.MoveMouseRelatively the this method is called by B and the return point is calculated by B and sent back to A, A will use it to move Mouse to the right position when switching to C.
+ * Else this method is called by A and the return point is calculated by A.
+ * */
+
+ internal static Point MoveToMyNeighbourIfNeeded(int x, int y, ID desMachineID)
+ {
+ newDesMachineIdEx = desMachineID;
+
+ if (Math.Abs(x) > 10)
+ {
+ LastX = x;
+ }
+
+ if (Math.Abs(y) > 10)
+ {
+ LastY = y;
+ }
+
+ if ((GetTick() - lastJump < 100) || desMachineID == ID.ALL)
+ {
+ return Point.Empty;
+ }
+
+ if (Setting.Values.BlockMouseAtCorners)
+ {
+ lock (SensitivePoints)
+ {
+ foreach (Point p in SensitivePoints)
+ {
+ if (Math.Abs(p.X - x) < 100 && Math.Abs(p.Y - y) < 100)
+ {
+ return Point.Empty;
+ }
+ }
+ }
+ }
+
+ /* If Mouse is moving in the controller machine and this method is called by the controller machine.
+ * Or if Mouse is moving in the controlled machine and this method is called by the controlled machine and Setting.Values.MoveMouseRelative.
+ * */
+ if (desMachineID == MachineID)
+ {
+ if (x < desktopBounds.Left + SKIP_PIXELS)
+ {
+ return MoveLeft(x, y);
+ }
+ else if (x >= desktopBounds.Right - SKIP_PIXELS)
+ {
+ return MoveRight(x, y);
+ }
+ else if (y < desktopBounds.Top + SKIP_PIXELS)
+ {
+ return MoveUp(x, y);
+ }
+ else if (y >= desktopBounds.Bottom - SKIP_PIXELS)
+ {
+ return MoveDown(x, y);
+ }
+ }
+
+ /* If Mouse is moving in the controlled machine and this method is called by the controller machine and !Setting.Values.MoveMouseRelative.
+ * Mouse location is scaled from the primary screen bound of the controller machine regardless of how many monitors the controlled machine may have.
+ * */
+ else
+ {
+ if (x < primaryScreenBounds.Left + SKIP_PIXELS)
+ {
+ return MoveLeft(x, y);
+ }
+ else if (x >= primaryScreenBounds.Right - SKIP_PIXELS)
+ {
+ return MoveRight(x, y);
+ }
+ else if (y < primaryScreenBounds.Top + SKIP_PIXELS)
+ {
+ return MoveUp(x, y);
+ }
+ else if (y >= primaryScreenBounds.Bottom - SKIP_PIXELS)
+ {
+ return MoveDown(x, y);
+ }
+ }
+
+ return Point.Empty;
+ }
+
+#endif
+
+ [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Dotnet port with style preservation")]
+ private static Point MoveRight(int x, int y)
+ {
+ string[] mc = LiveMachineMatrix;
+ if (mc == null)
+ {
+ return Point.Empty;
+ }
+
+ bool oneRow = Setting.Values.MatrixOneRow;
+
+ string currentMachine = NameFromID(desMachineID);
+ if (currentMachine == null)
+ {
+ return Point.Empty;
+ }
+
+ ID newID;
+ if (oneRow)
+ {
+ bool found = false;
+ for (int i = 0; i < MAX_MACHINE; i++)
+ {
+ if (currentMachine.Trim().Equals(mc[i], StringComparison.OrdinalIgnoreCase))
+ {
+ for (int j = i; j < MAX_MACHINE - 1; j++)
+ {
+ if (mc[j + 1] != null && mc[j + 1].Length > 0)
+ {
+ if ((newID = IdFromName(mc[j + 1])) > 0)
+ {
+ newDesMachineIdEx = newID;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found && Setting.Values.MatrixCircle)
+ {
+ for (int j = 0; j < i; j++)
+ {
+ if (mc[j] != null && mc[j].Length > 0)
+ {
+ if ((newID = IdFromName(mc[j])) > 0)
+ {
+ newDesMachineIdEx = newID;
+ break;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (currentMachine.Trim().Equals(mc[0], StringComparison.OrdinalIgnoreCase) && (mc[1] != null)
+ && (mc[1].Length > 0))
+ {
+ if ((newID = IdFromName(mc[1])) > 0)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (currentMachine.Trim().Equals(mc[2], StringComparison.OrdinalIgnoreCase) && (mc[3] != null)
+ && (mc[3].Length > 0))
+ {
+ if ((newID = IdFromName(mc[3])) > 0)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (Setting.Values.MatrixCircle && currentMachine.Trim().Equals(mc[1], StringComparison.OrdinalIgnoreCase) && (mc[0] != null)
+ && (mc[0].Length > 0))
+ {
+ if ((newID = IdFromName(mc[0])) > 0)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (Setting.Values.MatrixCircle && currentMachine.Trim().Equals(mc[3], StringComparison.OrdinalIgnoreCase) && (mc[2] != null)
+ && (mc[2].Length > 0))
+ {
+ if ((newID = IdFromName(mc[2])) > 0)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ }
+
+ // THIS LOGIC IS THE SAME FOR Move*(int x, int y) METHODS.
+ if (newDesMachineIdEx != desMachineID)
+ {
+ LogDebug("Move Right");
+
+ if (!Setting.Values.MoveMouseRelatively)
+ {
+ if (newDesMachineIdEx == MachineID)
+ {
+ /* Switching back to the controller machine, we need to scale up to the desktopBounds from primaryScreenBounds (sine !Setting.Values.MoveMouseRelatively).
+ * primaryScreenBounds => 65535 => desktopBounds, so that the Mouse position is mapped to the right position when the controller machine has multiple monitors.
+ * */
+ return ConvertToUniversalValue(new Point(primaryScreenBounds.Left + JUMP_PIXELS, y), primaryScreenBounds);
+ }
+ else
+ {
+ if (desMachineID == MachineID)
+ {
+ /* Switching FROM the controller machine, since Mouse was not bounded/locked to the primary screen,
+ * Mouse position can just be mapped from desktopBounds to desktopBounds
+ * desktopBounds => 65535 => desktopBounds.
+ * */
+ return ConvertToUniversalValue(new Point(desktopBounds.Left + JUMP_PIXELS, y), desktopBounds);
+ }
+ else
+ {
+ /* Switching between two machines where non of them is the controller machine.
+ * Since the current Mouse position is "mapped" from the primary monitor of the controller machine,
+ * new Mouse position for the new controlled machine needs to be calculated from this as well.
+ * primaryScreenBounds => 65535 => desktopBounds
+ * */
+ return ConvertToUniversalValue(new Point(primaryScreenBounds.Left + JUMP_PIXELS, y), primaryScreenBounds);
+ }
+ }
+ }
+ else
+ {
+ /* In the case where Mouse is moved relatively, Mouse position is simply mapped from desktopBounds to desktopBounds.
+ * desktopBounds => 65535 => desktopBounds.
+ * */
+ return ConvertToUniversalValue(new Point(desktopBounds.Left + JUMP_PIXELS, y), desktopBounds);
+ }
+ }
+
+ return Point.Empty;
+ }
+
+ [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Dotnet port with style preservation")]
+ private static Point MoveLeft(int x, int y)
+ {
+ string[] mc = LiveMachineMatrix;
+ if (mc == null)
+ {
+ return Point.Empty;
+ }
+
+ bool oneRow = Setting.Values.MatrixOneRow;
+
+ string currentMachine = NameFromID(desMachineID);
+ if (currentMachine == null)
+ {
+ return Point.Empty;
+ }
+
+ ID newID;
+ if (oneRow)
+ {
+ bool found = false;
+ for (int i = MAX_MACHINE - 1; i >= 0; i--)
+ {
+ if (currentMachine.Trim().Equals(mc[i], StringComparison.OrdinalIgnoreCase))
+ {
+ for (int j = i; j > 0; j--)
+ {
+ if (mc[j - 1] != null && mc[j - 1].Length > 0)
+ {
+ if ((newID = IdFromName(mc[j - 1])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found && Setting.Values.MatrixCircle)
+ {
+ for (int j = MAX_MACHINE - 1; j > i; j--)
+ {
+ if (mc[j] != null && mc[j].Length > 0)
+ {
+ if ((newID = IdFromName(mc[j])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ break;
+ }
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (currentMachine.Trim().Equals(mc[1], StringComparison.OrdinalIgnoreCase) && (mc[0] != null)
+ && (mc[0].Length > 0))
+ {
+ if ((newID = IdFromName(mc[0])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (currentMachine.Trim().Equals(mc[3], StringComparison.OrdinalIgnoreCase) && (mc[2] != null)
+ && (mc[2].Length > 0))
+ {
+ if ((newID = IdFromName(mc[2])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (Setting.Values.MatrixCircle && currentMachine.Trim().Equals(mc[0], StringComparison.OrdinalIgnoreCase) && (mc[1] != null)
+ && (mc[1].Length > 0))
+ {
+ if ((newID = IdFromName(mc[1])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (Setting.Values.MatrixCircle && currentMachine.Trim().Equals(mc[2], StringComparison.OrdinalIgnoreCase) && (mc[3] != null)
+ && (mc[3].Length > 0))
+ {
+ if ((newID = IdFromName(mc[3])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ }
+
+ if (newDesMachineIdEx != desMachineID)
+ {
+ LogDebug("Move Left");
+
+ return !Setting.Values.MoveMouseRelatively
+ ? newDesMachineIdEx == MachineID
+ ? ConvertToUniversalValue(new Point(primaryScreenBounds.Right - JUMP_PIXELS, y), primaryScreenBounds)
+ : desMachineID == MachineID
+ ? ConvertToUniversalValue(new Point(desktopBounds.Right - JUMP_PIXELS, y), desktopBounds)
+ : ConvertToUniversalValue(new Point(primaryScreenBounds.Right - JUMP_PIXELS, y), primaryScreenBounds)
+ : ConvertToUniversalValue(new Point(desktopBounds.Right - JUMP_PIXELS, y), desktopBounds);
+ }
+
+ return Point.Empty;
+ }
+
+ private static Point MoveUp(int x, int y)
+ {
+ if (Setting.Values.MatrixOneRow)
+ {
+ return Point.Empty;
+ }
+
+ string[] mc = LiveMachineMatrix;
+ if (mc == null)
+ {
+ return Point.Empty;
+ }
+
+ string currentMachine = NameFromID(desMachineID);
+ if (currentMachine == null)
+ {
+ return Point.Empty;
+ }
+
+ ID newID;
+ if (currentMachine.Trim().Equals(mc[2], StringComparison.OrdinalIgnoreCase) && (mc[0] != null)
+ && (mc[0].Length > 0))
+ {
+ if ((newID = IdFromName(mc[0])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (currentMachine.Trim().Equals(mc[3], StringComparison.OrdinalIgnoreCase) && (mc[1] != null)
+ && (mc[1].Length > 0))
+ {
+ if ((newID = IdFromName(mc[1])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (Setting.Values.MatrixCircle && currentMachine.Trim().Equals(mc[0], StringComparison.OrdinalIgnoreCase) && (mc[2] != null)
+ && (mc[2].Length > 0))
+ {
+ if ((newID = IdFromName(mc[2])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (Setting.Values.MatrixCircle && currentMachine.Trim().Equals(mc[1], StringComparison.OrdinalIgnoreCase) && (mc[3] != null)
+ && (mc[3].Length > 0))
+ {
+ if ((newID = IdFromName(mc[3])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+
+ if (newDesMachineIdEx != desMachineID)
+ {
+ LogDebug("Move Up");
+
+ return !Setting.Values.MoveMouseRelatively
+ ? newDesMachineIdEx == MachineID
+ ? ConvertToUniversalValue(new Point(x, primaryScreenBounds.Bottom - JUMP_PIXELS), primaryScreenBounds)
+ : desMachineID == MachineID
+ ? ConvertToUniversalValue(new Point(x, desktopBounds.Bottom - JUMP_PIXELS), desktopBounds)
+ : ConvertToUniversalValue(new Point(x, primaryScreenBounds.Bottom - JUMP_PIXELS), primaryScreenBounds)
+ : ConvertToUniversalValue(new Point(x, desktopBounds.Bottom - JUMP_PIXELS), desktopBounds);
+ }
+
+ return Point.Empty;
+ }
+
+ private static Point MoveDown(int x, int y)
+ {
+ if (Setting.Values.MatrixOneRow)
+ {
+ return Point.Empty;
+ }
+
+ string[] mc = LiveMachineMatrix;
+ if (mc == null)
+ {
+ return Point.Empty;
+ }
+
+ string currentMachine = NameFromID(desMachineID);
+ if (currentMachine == null)
+ {
+ return Point.Empty;
+ }
+
+ ID newID;
+ if (currentMachine.Trim().Equals(mc[0], StringComparison.OrdinalIgnoreCase) && (mc[2] != null)
+ && (mc[2].Length > 0))
+ {
+ if ((newID = IdFromName(mc[2])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (currentMachine.Trim().Equals(mc[1], StringComparison.OrdinalIgnoreCase) && (mc[3] != null)
+ && (mc[3].Length > 0))
+ {
+ if ((newID = IdFromName(mc[3])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+
+ if (Setting.Values.MatrixCircle && currentMachine.Trim().Equals(mc[2], StringComparison.OrdinalIgnoreCase) && (mc[0] != null)
+ && (mc[0].Length > 0))
+ {
+ if ((newID = IdFromName(mc[0])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+ else if (Setting.Values.MatrixCircle && currentMachine.Trim().Equals(mc[3], StringComparison.OrdinalIgnoreCase) && (mc[1] != null)
+ && (mc[1].Length > 0))
+ {
+ if ((newID = IdFromName(mc[1])) != ID.NONE)
+ {
+ newDesMachineIdEx = newID;
+ }
+ }
+
+ if (newDesMachineIdEx != desMachineID)
+ {
+ LogDebug("Move Down");
+
+ return !Setting.Values.MoveMouseRelatively
+ ? newDesMachineIdEx == MachineID
+ ? ConvertToUniversalValue(new Point(x, primaryScreenBounds.Top + JUMP_PIXELS), primaryScreenBounds)
+ : desMachineID == MachineID
+ ? ConvertToUniversalValue(new Point(x, desktopBounds.Top + JUMP_PIXELS), desktopBounds)
+ : ConvertToUniversalValue(new Point(x, primaryScreenBounds.Top + JUMP_PIXELS), primaryScreenBounds)
+ : ConvertToUniversalValue(new Point(x, desktopBounds.Top + JUMP_PIXELS), desktopBounds);
+ }
+
+ return Point.Empty;
+ }
+
+ internal static bool RemoveDeadMachines(ID ip)
+ {
+ bool rv = false;
+
+ // Here we are removing a dead machine by IP.
+ foreach (MachineInf inf in Common.MachinePool.ListAllMachines())
+ {
+ if (inf.Id == ip)
+ {
+ if (MachinePool.SetMachineDisconnected(inf.Name))
+ {
+ rv = true;
+ }
+
+ LogDebug("<><><><><>>><><><<><><><><><><><><><><>><><><><><><><><><><><" + inf.Name);
+ }
+ }
+
+ return rv;
+ }
+
+ internal static void RemoveDeadMachines()
+ {
+ // list of live/dead machines is now automatically up-to-date
+ // if it changed we need to update the UI.
+ // for now assume it changed.
+ // Common.MachinePool.ResetIPAddressesForDeadMachines();
+ // DoSomethingInUIThread(UpdateMenu);
+ Common.UpdateMachinePoolStringSetting();
+
+ // Make sure MachinePool still holds this machine.
+ if (Common.MachinePool.LearnMachine(MachineName))
+ {
+ _ = Common.MachinePool.TryUpdateMachineID(MachineName, MachineID, false);
+ }
+ }
+
+ private static string AddToMachinePool(DATA package)
+ {
+ // Log("********** AddToMachinePool called: " + package.src.ToString(CultureInfo.InvariantCulture));
+
+ // There should be no duplicates in machine pool.
+ string name = package.MachineName;
+
+ // a few things happening here:
+ // 1) find a matching machine (by name)
+ // 2) update its ID and time
+ // 3) logging
+ // 4) updating some variables - desMachineID/newDesMachineID
+ // 5) return the matched name (trimmed) - only in the event of a match
+ if (Common.MachinePool.TryFindMachineByName(name, out MachineInf machineInfo))
+ {
+ _ = Common.MachinePool.TryUpdateMachineID(machineInfo.Name, machineInfo.Id, true);
+
+ _ = Common.MachinePool.TryUpdateMachineID(machineInfo.Name, package.Src, true);
+
+ if (machineInfo.Name.Equals(DesMachineName, StringComparison.OrdinalIgnoreCase))
+ {
+ LogDebug("AddToMachinePool: Des ID updated: " + DesMachineID.ToString() + "/" + package.Src.ToString());
+ newDesMachineID = desMachineID = package.Src;
+ }
+
+ return machineInfo.Name;
+ }
+ else
+ {
+ if (Common.MachinePool.LearnMachine(name))
+ {
+ _ = Common.MachinePool.TryUpdateMachineID(name, package.Src, true);
+ }
+ else
+ {
+ LogDebug("AddToMachinePool: could not add a new machine: " + name);
+ return "The 5th machine";
+ }
+ }
+
+ // if (machineCount != saved)
+ {
+ // DoSomethingInUIThread(UpdateMenu);
+ Common.UpdateMachinePoolStringSetting();
+ }
+
+ // NOTE(yuyoyuppe): automatically active "bidirectional" control between the machines.
+ string[] st = new string[Common.MAX_MACHINE];
+ Array.Fill(st, string.Empty);
+ var machines = Common.MachinePool.ListAllMachines();
+ for (int i = 0; i < machines.Count; ++i)
+ {
+ if (machines[i].Id != ID.NONE && machines[i].Id != ID.ALL)
+ {
+ st[i] = machines[i].Name;
+ }
+ }
+
+ Common.MachineMatrix = st;
+ Common.ReopenSockets(true);
+ Common.SendMachineMatrix();
+
+ LogDebug("Machine added: " + name + "/" + package.Src.ToString());
+ UpdateClientSockets("AddToMachinePool");
+ return name;
+ }
+
+ internal static void UpdateClientSockets(string logHeader)
+ {
+ LogDebug("UpdateClientSockets: " + logHeader);
+ Sk?.UpdateTCPClients();
+ }
+
+ private static SettingsForm settings;
+
+ internal static SettingsForm Settings
+ {
+ get => Common.settings;
+ set => Common.settings = value;
+ }
+
+ internal static void ShowSetupForm(bool reopenSockets = false)
+ {
+ Common.LogDebug("========== BEGIN THE SETUP EXPERIENCE ==========", true);
+ Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
+ Common.GeneratedKey = true;
+
+ if (Process.GetCurrentProcess().SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
+ {
+ Common.Log("Not physical console session.");
+ _ = MessageBox.Show(
+ "Please run the program in the physical console session.\r\nThe program does not work in a remote desktop or virtual machine session.",
+ Application.ProductName,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Stop);
+ return;
+ }
+
+ if (settings == null)
+ {
+ settings = new SettingsForm();
+ settings.Show();
+ }
+ else
+ {
+ settings.Close();
+ Common.MMSleep(0.3);
+ settings = new SettingsForm();
+ settings.Show();
+ }
+
+ if (reopenSockets)
+ {
+ Common.ReopenSockets(true);
+ }
+ }
+
+ internal static void CloseSetupForm()
+ {
+ if (settings != null)
+ {
+ settings.Close();
+ settings = null;
+ }
+ }
+
+ internal static void ShowMachineMatrix()
+ {
+ if (!Setting.Values.ShowOriginalUI)
+ {
+ return;
+ }
+
+ if (Process.GetCurrentProcess().SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
+ {
+ Common.ShowToolTip(Application.ProductName + " cannot be used in a remote desktop or virtual machine session.", 5000);
+ }
+
+#if NEW_SETTINGS_FORM
+ Common.ShowSetupForm();
+#else
+ if (Setting.Values.FirstRun && !Common.AtLeastOneSocketConnected())
+ {
+ Common.ShowSetupForm();
+ }
+ else
+ {
+ PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersOldUIOpenedEvent());
+
+ if (MatrixForm == null)
+ {
+ MatrixForm = new FrmMatrix();
+ MatrixForm.Show();
+
+ if (MainForm != null)
+ {
+ MainForm.NotifyIcon.Visible = false;
+ MainForm.NotifyIcon.Visible = Setting.Values.ShowOriginalUI;
+ }
+ }
+ else
+ {
+ MatrixForm.WindowState = FormWindowState.Normal;
+ MatrixForm.Activate();
+ }
+ }
+#endif
+ }
+
+ private static string[] mcMatrix;
+
+ internal static string[] MachineMatrix
+ {
+ get
+ {
+ lock (McMatrixLock)
+ {
+ if (mcMatrix == null)
+ {
+ string s = Setting.Values.MachineMatrixString;
+
+ if (!string.IsNullOrEmpty(s))
+ {
+ mcMatrix = s.Split(new char[] { ',' });
+
+ if (mcMatrix == null || mcMatrix.Length != MAX_MACHINE)
+ {
+ mcMatrix = new string[MAX_MACHINE] { string.Empty, string.Empty, string.Empty, string.Empty };
+ }
+ }
+ else
+ {
+ mcMatrix = new string[MAX_MACHINE] { string.Empty, string.Empty, string.Empty, string.Empty };
+ }
+ }
+
+ return mcMatrix;
+ }
+ }
+
+ set
+ {
+ lock (McMatrixLock)
+ {
+ if (value == null)
+ {
+ mcMatrix = null; // Force read from registry next time.
+ return;
+ }
+ else
+ {
+ Setting.Values.MachineMatrixString = string.Join(",", mcMatrix = value);
+ }
+ }
+
+ DoSomethingInUIThread(() =>
+ {
+ MainForm.ChangeIcon(-1);
+ MainForm.UpdateNotifyIcon();
+ });
+ }
+ }
+
+ private static string[] LiveMachineMatrix
+ {
+ get
+ {
+ bool twoRow = !Setting.Values.MatrixOneRow;
+ string[] connectedMachines = twoRow ? MachineMatrix : MachineMatrix.Select(m => IsConnectedTo(IdFromName(m)) ? m : string.Empty).ToArray();
+ LogDebug($"Matrix: {string.Join(",", MachineMatrix)}, Connected: {string.Join(",", connectedMachines)}");
+
+ return connectedMachines;
+ }
+ }
+
+ internal static void UpdateMachinePoolStringSetting()
+ {
+ Setting.Values.MachinePoolString = Common.MachinePool.SerializedAsString();
+ }
+
+ internal static void SendMachineMatrix()
+ {
+ if (MachineMatrix == null)
+ {
+ return;
+ }
+
+ DATA package = new();
+
+ for (int i = 0; i < MachineMatrix.Length; i++)
+ {
+ package.MachineName = MachineMatrix[i];
+
+ package.Type = PackageType.Matrix
+ | (Setting.Values.MatrixCircle ? PackageType.MatrixSwapFlag : 0)
+ | (Setting.Values.MatrixOneRow ? 0 : PackageType.MatrixTwoRowFlag);
+
+ package.Src = (ID)(i + 1);
+ package.Des = ID.ALL;
+
+ SkSend(package, null, false);
+
+ LogDebug($"matrixIncludedMachine sent: [{i + 1}]:[{MachineMatrix[i]}]");
+ }
+ }
+
+ internal static void UpdateMachineMatrix(DATA package)
+ {
+ uint i = (uint)package.Src;
+ string matrixIncludedMachine = package.MachineName;
+
+ if (i is > 0 and <= MAX_MACHINE)
+ {
+ LogDebug($"matrixIncludedMachine: [{i}]:[{matrixIncludedMachine}]");
+
+ MachineMatrix[i - 1] = matrixIncludedMachine;
+
+ if (i == MAX_MACHINE)
+ {
+ Setting.Values.MatrixCircle = (package.Type & PackageType.MatrixSwapFlag) == PackageType.MatrixSwapFlag;
+ Setting.Values.MatrixOneRow = !((package.Type & PackageType.MatrixTwoRowFlag) == PackageType.MatrixTwoRowFlag);
+ MachineMatrix = MachineMatrix; // Save
+
+ Common.ReopenSocketDueToReadError = true;
+
+ UpdateClientSockets("UpdateMachineMatrix");
+
+ Setting.Values.Changed = true;
+ }
+ }
+ else
+ {
+ LogDebug("Invalid machine Matrix package!");
+ }
+ }
+
+ internal static void SwitchToMachine(string name)
+ {
+ ID id = Common.MachinePool.ResolveID(name);
+
+ if (id != ID.NONE)
+ {
+ // Ask current machine to hide the Mouse cursor
+ if (desMachineID != MachineID)
+ {
+ SendPackage(desMachineID, PackageType.HideMouse);
+ }
+
+ NewDesMachineID = DesMachineID = id;
+ SwitchLocation.X = XY_BY_PIXEL + primaryScreenBounds.Left + ((primaryScreenBounds.Right - primaryScreenBounds.Left) / 2);
+ SwitchLocation.Y = XY_BY_PIXEL + primaryScreenBounds.Top + ((primaryScreenBounds.Bottom - primaryScreenBounds.Top) / 2);
+ SwitchLocation.ResetCount();
+ Common.UpdateMultipleModeIconAndMenu();
+ HideMouseCursor(false);
+ _ = EvSwitch.Set();
+ }
+ }
+
+ internal static void SwitchToMultipleMode(bool multipleMode, bool centerScreen)
+ {
+ if (multipleMode)
+ {
+ PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersMultipleModeEvent());
+ NewDesMachineID = DesMachineID = ID.ALL;
+ }
+ else
+ {
+ NewDesMachineID = DesMachineID = MachineID;
+ }
+
+ if (centerScreen)
+ {
+ MoveMouseToCenter();
+ }
+
+ ReleaseAllKeys();
+
+ Common.UpdateMultipleModeIconAndMenu();
+ }
+
+ internal static bool CheckSecondInstance(bool sendMessage = false)
+ {
+ int h;
+
+ if ((h = NativeMethods.FindWindow(null, Setting.Values.MyID)) > 0)
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static EventWaitHandle oneInstanceCheck;
+
+ internal static void AssertOneInstancePerDesktopSession()
+ {
+ string eventName = $"Global\\{Application.ProductName}-{FrmAbout.AssemblyVersion}-{GetMyDesktop()}-{CurrentProcess.SessionId}";
+ oneInstanceCheck = new EventWaitHandle(false, EventResetMode.ManualReset, eventName, out bool created);
+
+ if (!created)
+ {
+ TelemetryLogTrace($"Second instance found: {eventName}.", SeverityLevel.Warning, true);
+ CurrentProcess.KillProcess(true);
+ }
+ }
+
+ internal static ID IdFromName(string name)
+ {
+ return Common.MachinePool.ResolveID(name);
+ }
+
+ internal static string NameFromID(ID id)
+ {
+ foreach (MachineInf inf in Common.MachinePool.TryFindMachineByID(id))
+ {
+ if (!string.IsNullOrEmpty(inf.Name))
+ {
+ return inf.Name;
+ }
+ }
+
+ return null;
+ }
+
+ internal static bool InMachineMatrix(string name)
+ {
+ if (MachineMatrix == null || string.IsNullOrWhiteSpace(name))
+ {
+ return false;
+ }
+
+ foreach (string st in MachineMatrix)
+ {
+ if (!string.IsNullOrWhiteSpace(st) && st.Trim().Equals(name.Trim(), StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ internal static void ClearComputerMatrix()
+ {
+ Common.MachineMatrix = new string[Common.MAX_MACHINE] { Common.MachineName.Trim(), string.Empty, string.Empty, string.Empty };
+ Common.MachinePool.Initialize(new string[] { Common.MachineName });
+ Common.UpdateMachinePoolStringSetting();
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Package.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Package.cs
new file mode 100644
index 000000000000..baaf1c05444a
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.Package.cs
@@ -0,0 +1,262 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Package format/conversion.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+
+// In X64, we are WOW
+[module: SuppressMessage("Microsoft.Portability", "CA1900:ValueTypeFieldsShouldBePortable", Scope = "type", Target = "MouseWithoutBorders.DATA", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders
+{
+ internal enum PackageType// : int
+ {
+ // Search for PACKAGE_TYPE_RELATED before changing these!
+ Invalid = 0xFF,
+
+ Error = 0xFE,
+
+ Hi = 2,
+ Hello = 3,
+ ByeBye = 4,
+
+ Heartbeat = 20,
+ Awake = 21,
+ HideMouse = 50,
+ Heartbeat_ex = 51,
+ Heartbeat_ex_l2 = 52,
+ Heartbeat_ex_l3 = 53,
+
+ Clipboard = 69,
+ ClipboardDragDrop = 70,
+ ClipboardDragDropEnd = 71,
+ ExplorerDragDrop = 72,
+ ClipboardCapture = 73,
+ CaptureScreenCommand = 74,
+ ClipboardDragDropOperation = 75,
+ ClipboardDataEnd = 76,
+ MachineSwitched = 77,
+ ClipboardAsk = 78,
+ ClipboardPush = 79,
+
+ NextMachine = 121,
+ Keyboard = 122,
+ Mouse = 123,
+ ClipboardText = 124,
+ ClipboardImage = 125,
+
+ Handshake = 126,
+ HandshakeAck = 127,
+
+ Matrix = 128,
+ MatrixSwapFlag = 2,
+ MatrixTwoRowFlag = 4,
+ }
+
+ internal struct PackageMonitor
+ {
+ internal ulong Keyboard;
+ internal ulong Mouse;
+ internal ulong Heartbeat;
+ internal ulong ByeBye;
+ internal ulong Hello;
+ internal ulong Matrix;
+ internal ulong ClipboardText;
+ internal ulong ClipboardImage;
+ internal ulong Clipboard;
+ internal ulong ClipboardDragDrop;
+ internal ulong ClipboardDragDropEnd;
+ internal ulong ClipboardAsk;
+ internal ulong ExplorerDragDrop;
+ internal ulong Nil;
+
+ internal PackageMonitor(ulong value)
+ {
+ ClipboardDragDrop = ClipboardDragDropEnd = ExplorerDragDrop =
+ Keyboard = Mouse = Heartbeat = ByeBye = Hello = Clipboard =
+ Matrix = ClipboardImage = ClipboardText = Nil = ClipboardAsk = value;
+ }
+ }
+
+ internal enum ID : uint
+ {
+ NONE = 0,
+ ALL = 255,
+ }
+
+ internal enum ClipboardPostAction : uint
+ {
+ Other = 0,
+ Desktop = 1,
+ Mspaint = 2,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct KEYBDDATA
+ {
+ [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Same name as in winAPI")]
+ internal int wVk;
+ [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Same name as in winAPI")]
+ internal int dwFlags;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MOUSEDATA
+ {
+ internal int X;
+ internal int Y;
+ internal int WheelDelta;
+ [SuppressMessage("StyleCop.CSharp.NamingRules", "SA1307:Accessible fields should begin with upper-case letter", Justification = "Same name as in winAPI")]
+ internal int dwFlags;
+ }
+
+ // The beauty of "union" in C#
+ [StructLayout(LayoutKind.Explicit)]
+ internal class DATA
+ {
+ [FieldOffset(0)]
+ internal PackageType Type; // 4 (first byte = package type, 1 = checksum, 2+3 = magic no.)
+
+ [FieldOffset(sizeof(PackageType))]
+ internal int Id; // 4
+
+ [FieldOffset(sizeof(PackageType) + sizeof(uint))]
+ internal ID Src; // 4
+
+ [FieldOffset(sizeof(PackageType) + (2 * sizeof(uint)))]
+ internal ID Des; // 4
+
+ [FieldOffset(sizeof(PackageType) + (3 * sizeof(uint)))]
+ internal long DateTime;
+
+ [FieldOffset(sizeof(PackageType) + (3 * sizeof(uint)) + sizeof(long))]
+ internal KEYBDDATA Kd;
+
+ [FieldOffset(sizeof(PackageType) + (3 * sizeof(uint)))]
+ internal MOUSEDATA Md;
+
+ [FieldOffset(sizeof(PackageType) + (3 * sizeof(uint)))]
+ internal ID Machine1;
+
+ [FieldOffset(sizeof(PackageType) + (4 * sizeof(uint)))]
+ internal ID Machine2;
+
+ [FieldOffset(sizeof(PackageType) + (5 * sizeof(uint)))]
+ internal ID Machine3;
+
+ [FieldOffset(sizeof(PackageType) + (6 * sizeof(uint)))]
+ internal ID Machine4;
+
+ [FieldOffset(sizeof(PackageType) + (3 * sizeof(uint)))]
+ internal ClipboardPostAction PostAction;
+
+ [FieldOffset(sizeof(PackageType) + (7 * sizeof(uint)))]
+ private long machineNameP1;
+
+ [FieldOffset(sizeof(PackageType) + (7 * sizeof(uint)) + sizeof(long))]
+ private long machineNameP2;
+
+ [FieldOffset(sizeof(PackageType) + (7 * sizeof(uint)) + (2 * sizeof(long)))]
+ private long machineNameP3;
+
+ [FieldOffset(sizeof(PackageType) + (7 * sizeof(uint)) + (3 * sizeof(long)))]
+ private long machineNameP4;
+
+ internal string MachineName
+ {
+ get
+ {
+ string name = Common.GetString(BitConverter.GetBytes(machineNameP1))
+ + Common.GetString(BitConverter.GetBytes(machineNameP2))
+ + Common.GetString(BitConverter.GetBytes(machineNameP3))
+ + Common.GetString(BitConverter.GetBytes(machineNameP4));
+ return name.Trim();
+ }
+
+ set
+ {
+ byte[] machineName = Common.GetBytes(value.PadRight(32, ' '));
+ machineNameP1 = BitConverter.ToInt64(machineName, 0);
+ machineNameP2 = BitConverter.ToInt64(machineName, 8);
+ machineNameP3 = BitConverter.ToInt64(machineName, 16);
+ machineNameP4 = BitConverter.ToInt64(machineName, 24);
+ }
+ }
+
+ public DATA()
+ {
+ }
+
+ public DATA(byte[] initialData)
+ {
+ Bytes = initialData;
+ }
+
+ internal byte[] Bytes
+ {
+ get
+ {
+ byte[] buf = new byte[IsBigPackage ? Common.PACKAGE_SIZE_EX : Common.PACKAGE_SIZE];
+ Array.Copy(StructToBytes(this), buf, IsBigPackage ? Common.PACKAGE_SIZE_EX : Common.PACKAGE_SIZE);
+
+ return buf;
+ }
+
+ set
+ {
+ Debug.Assert(value.Length <= Common.PACKAGE_SIZE_EX, "Length > package size");
+ byte[] buf = new byte[Common.PACKAGE_SIZE_EX];
+ Array.Copy(value, buf, value.Length);
+ BytesToStruct(buf, this);
+ }
+ }
+
+ internal bool IsBigPackage
+ {
+ get => Type == 0
+ ? throw new InvalidOperationException("Package type not set.")
+ : Type switch
+ {
+ PackageType.Hello or PackageType.Awake or PackageType.Heartbeat or PackageType.Heartbeat_ex or PackageType.Handshake or PackageType.HandshakeAck or PackageType.ClipboardPush or PackageType.Clipboard or PackageType.ClipboardAsk or PackageType.ClipboardImage or PackageType.ClipboardText or PackageType.ClipboardDataEnd => true,
+ _ => (Type & PackageType.Matrix) == PackageType.Matrix,
+ };
+ }
+
+ private byte[] StructToBytes(object structObject)
+ {
+ byte[] bytes = new byte[Common.PACKAGE_SIZE_EX];
+ GCHandle bHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
+ Marshal.StructureToPtr(structObject, Marshal.UnsafeAddrOfPinnedArrayElement(bytes, 0), false);
+ bHandle.Free();
+ return bytes;
+ }
+
+ private void BytesToStruct(byte[] value, object structObject)
+ {
+ GCHandle bHandle = GCHandle.Alloc(value, GCHandleType.Pinned);
+ Marshal.PtrToStructure(Marshal.UnsafeAddrOfPinnedArrayElement(value, 0), structObject);
+ bHandle.Free();
+ }
+ }
+
+ internal partial class Common
+ {
+ internal const byte PACKAGE_SIZE = 32;
+ internal const byte PACKAGE_SIZE_EX = 64;
+ internal const byte WP_PACKAGE_SIZE = 6;
+ internal static PackageMonitor PackageSent;
+ internal static PackageMonitor PackageReceived;
+ internal static int PackageID;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Receiver.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Receiver.cs
new file mode 100644
index 000000000000..b4d2af42f437
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.Receiver.cs
@@ -0,0 +1,428 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+//
+// Back-end thread for the socket.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+
+[module: SuppressMessage("Microsoft.Reliability", "CA2002:DoNotLockOnObjectsWithWeakIdentity", Scope = "member", Target = "MouseWithoutBorders.Common.#PreProcess(MouseWithoutBorders.DATA)", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders
+{
+ internal partial class Common
+ {
+ private static readonly uint QUEUE_SIZE = 50;
+ private static readonly int[] RecentProcessedPackageIDs = new int[QUEUE_SIZE];
+ private static int recentProcessedPackageIndex;
+ private static long processedPackageCount;
+ private static long skippedPackageCount;
+
+ internal static long JustGotAKey { get; set; }
+
+ private static bool PreProcess(DATA package)
+ {
+ if (package.Type == PackageType.Invalid)
+ {
+ if ((Common.InvalidPackageCount % 100) == 0)
+ {
+ ShowToolTip("Invalid packages received!", 1000, ToolTipIcon.Warning, false);
+ }
+
+ Common.InvalidPackageCount++;
+ Common.Log("Invalid packages received!");
+ return false;
+ }
+ else if (package.Type == 0)
+ {
+ Common.Log("Got an unknown package!");
+ return false;
+ }
+ else if (package.Type is not PackageType.ClipboardText and not PackageType.ClipboardImage
+
+ // BEGIN: These package types are sent by TcpSend which is single direction.
+ and not PackageType.Handshake and not PackageType.HandshakeAck)
+ {
+ // END
+ lock (RecentProcessedPackageIDs)
+ {
+ for (int i = 0; i < QUEUE_SIZE; i++)
+ {
+ if (RecentProcessedPackageIDs[i] == package.Id)
+ {
+ skippedPackageCount++;
+ return false;
+ }
+ }
+
+ processedPackageCount++;
+ recentProcessedPackageIndex = (int)((recentProcessedPackageIndex + 1) % QUEUE_SIZE);
+ RecentProcessedPackageIDs[recentProcessedPackageIndex] = package.Id;
+ }
+ }
+
+ return true;
+ }
+
+ private static System.Drawing.Point lastXY;
+
+ internal static void ProcessPackage(DATA package, TcpSk tcp)
+ {
+ if (!PreProcess(package))
+ {
+ return;
+ }
+
+ switch (package.Type)
+ {
+ case PackageType.Keyboard:
+ PackageReceived.Keyboard++;
+ if (package.Des == MachineID || package.Des == ID.ALL)
+ {
+ JustGotAKey = GetTick();
+
+ // NOTE(@yuyoyuppe): disabled to drop elevation requirement
+ bool nonElevated = Common.RunWithNoAdminRight && false;
+ if (nonElevated && Setting.Values.OneWayControlMode)
+ {
+ if ((package.Kd.dwFlags & (int)Common.LLKHF.UP) == (int)Common.LLKHF.UP)
+ {
+ Common.ShowOneWayModeMessage();
+ }
+
+ return;
+ }
+
+ InputSimulation.SendKey(package.Kd);
+ }
+
+ break;
+
+ case PackageType.Mouse:
+ PackageReceived.Mouse++;
+
+ if (package.Des == MachineID || package.Des == ID.ALL)
+ {
+ if (desMachineID != MachineID)
+ {
+ NewDesMachineID = DesMachineID = MachineID;
+ }
+
+ // NOTE(@yuyoyuppe): disabled to drop elevation requirement
+ bool nonElevated = Common.RunWithNoAdminRight && false;
+ if (nonElevated && Setting.Values.OneWayControlMode && package.Md.dwFlags != Common.WM_MOUSEMOVE)
+ {
+ if (!IsDropping)
+ {
+ if (package.Md.dwFlags is WM_LBUTTONDOWN or WM_RBUTTONDOWN)
+ {
+ Common.ShowOneWayModeMessage();
+ }
+ }
+ else if (package.Md.dwFlags is WM_LBUTTONUP or WM_RBUTTONUP)
+ {
+ IsDropping = false;
+ }
+
+ return;
+ }
+
+ if (Math.Abs(package.Md.X) >= MOVE_MOUSE_RELATIVE && Math.Abs(package.Md.Y) >= MOVE_MOUSE_RELATIVE)
+ {
+ if (package.Md.dwFlags == Common.WM_MOUSEMOVE)
+ {
+ InputSimulation.MoveMouseRelative(
+ package.Md.X < 0 ? package.Md.X + MOVE_MOUSE_RELATIVE : package.Md.X - MOVE_MOUSE_RELATIVE,
+ package.Md.Y < 0 ? package.Md.Y + MOVE_MOUSE_RELATIVE : package.Md.Y - MOVE_MOUSE_RELATIVE);
+ _ = NativeMethods.GetCursorPos(ref lastXY);
+
+ Point p = MoveToMyNeighbourIfNeeded(lastXY.X, lastXY.Y, MachineID);
+
+ if (!p.IsEmpty)
+ {
+ HasSwitchedMachineSinceLastCopy = true;
+
+ Common.LogDebug(string.Format(
+ CultureInfo.CurrentCulture,
+ "***** Controlled Machine: newDesMachineIdEx set = [{0}]. Mouse is now at ({1},{2})",
+ newDesMachineIdEx,
+ lastXY.X,
+ lastXY.Y));
+
+ SendNextMachine(package.Src, newDesMachineIdEx, p);
+ }
+ }
+ else
+ {
+ _ = NativeMethods.GetCursorPos(ref lastXY);
+ package.Md.X = lastXY.X * 65535 / screenWidth;
+ package.Md.Y = lastXY.Y * 65535 / screenHeight;
+ _ = InputSimulation.SendMouse(package.Md);
+ }
+ }
+ else
+ {
+ _ = InputSimulation.SendMouse(package.Md);
+ _ = NativeMethods.GetCursorPos(ref lastXY);
+ }
+
+ LastX = lastXY.X;
+ LastY = lastXY.Y;
+ CustomCursor.ShowFakeMouseCursor(LastX, LastY);
+ }
+
+ DragDropStep01(package.Md.dwFlags);
+ DragDropStep09(package.Md.dwFlags);
+ break;
+
+ case PackageType.NextMachine:
+ LogDebug("PackageType.NextMachine received!");
+
+ if (IsSwitchingByMouseEnabled())
+ {
+ PrepareToSwitchToMachine((ID)package.Md.WheelDelta, new Point(package.Md.X, package.Md.Y));
+ }
+
+ break;
+
+ case PackageType.ExplorerDragDrop:
+ PackageReceived.ExplorerDragDrop++;
+ DragDropStep03(package);
+ break;
+
+ case PackageType.Heartbeat:
+ case PackageType.Heartbeat_ex:
+ PackageReceived.Heartbeat++;
+
+ Common.GeneratedKey = Common.GeneratedKey || package.Type == PackageType.Heartbeat_ex;
+
+ if (Common.GeneratedKey)
+ {
+ Setting.Values.MyKey = Common.MyKey;
+ SendPackage(ID.ALL, PackageType.Heartbeat_ex_l2);
+ }
+
+ string desMachine = Common.AddToMachinePool(package);
+
+ if (Setting.Values.FirstRun && !string.IsNullOrEmpty(desMachine))
+ {
+ Common.UpdateSetupMachineMatrix(desMachine);
+ Common.UpdateClientSockets("UpdateSetupMachineMatrix");
+ }
+
+ break;
+
+ case PackageType.Heartbeat_ex_l2:
+ Common.GeneratedKey = true;
+ Setting.Values.MyKey = Common.MyKey;
+ SendPackage(ID.ALL, PackageType.Heartbeat_ex_l3);
+
+ break;
+
+ case PackageType.Heartbeat_ex_l3:
+ Common.GeneratedKey = true;
+ Setting.Values.MyKey = Common.MyKey;
+
+ break;
+
+ case PackageType.Awake:
+ PackageReceived.Heartbeat++;
+ _ = Common.AddToMachinePool(package);
+ Common.HumanBeingDetected();
+ break;
+
+ case PackageType.Hello:
+ PackageReceived.Hello++;
+ SendHeartBeat();
+ string newMachine = Common.AddToMachinePool(package);
+ if (Setting.Values.MachineMatrixString == null)
+ {
+ string tip = newMachine + " saying Hello!";
+ tip += "\r\n Right Click to setup your machine Matrix";
+ ShowToolTip(tip);
+ }
+
+ break;
+
+ case PackageType.Hi:
+ PackageReceived.Hello++;
+ break;
+
+ case PackageType.ByeBye:
+ PackageReceived.ByeBye++;
+ ProcessByeByeMessage(package);
+ break;
+
+ case PackageType.Clipboard:
+ PackageReceived.Clipboard++;
+ if (!RunOnLogonDesktop && !RunOnScrSaverDesktop)
+ {
+ clipboardCopiedTime = GetTick();
+ GetNameOfMachineWithClipboardData(package);
+ SignalBigClipboardData();
+ }
+
+ break;
+
+ case PackageType.MachineSwitched:
+ if (GetTick() - clipboardCopiedTime < BIG_CLIPBOARD_DATA_TIMEOUT && (package.Des == MachineID))
+ {
+ clipboardCopiedTime = 0;
+ Common.GetRemoteClipboard("PackageType.MachineSwitched");
+ }
+
+ break;
+
+ case PackageType.ClipboardCapture:
+ PackageReceived.Clipboard++;
+ if (!RunOnLogonDesktop && !RunOnScrSaverDesktop)
+ {
+ if (package.Des == MachineID || package.Des == ID.ALL)
+ {
+ GetNameOfMachineWithClipboardData(package);
+ GetRemoteClipboard("mspaint," + LastMachineWithClipboardData);
+ }
+ }
+
+ break;
+
+ case PackageType.CaptureScreenCommand:
+ PackageReceived.Clipboard++;
+ if (package.Des == MachineID || package.Des == ID.ALL)
+ {
+ Common.SendImage(package.Src, Common.CaptureScreen());
+ }
+
+ break;
+
+ case PackageType.ClipboardAsk:
+ PackageReceived.ClipboardAsk++;
+
+ if (package.Des == MachineID)
+ {
+ _ = Task.Run(() =>
+ {
+ try
+ {
+ System.Threading.Thread thread = Thread.CurrentThread;
+ thread.Name = $"{nameof(PackageType.ClipboardAsk)}.{thread.ManagedThreadId}";
+ Thread.UpdateThreads(thread);
+
+ string remoteMachine = package.MachineName;
+ System.Net.Sockets.TcpClient client = ConnectToRemoteClipboardSocket(remoteMachine);
+ bool clientPushData = true;
+
+ if (ShakeHand(ref remoteMachine, client.Client, out Stream enStream, out Stream deStream, ref clientPushData, ref package.PostAction))
+ {
+ SocketStuff.SendClipboardData(client.Client, enStream);
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ });
+ }
+
+ break;
+
+ case PackageType.ClipboardDragDrop:
+ PackageReceived.ClipboardDragDrop++;
+ DragDropStep08(package);
+ break;
+
+ case PackageType.ClipboardDragDropOperation:
+ PackageReceived.ClipboardDragDrop++;
+ DragDropStep08_2(package);
+ break;
+
+ case PackageType.ClipboardDragDropEnd:
+ PackageReceived.ClipboardDragDropEnd++;
+ DragDropStep12();
+ break;
+
+ case PackageType.ClipboardText:
+ case PackageType.ClipboardImage:
+ clipboardCopiedTime = 0;
+ if (package.Type == PackageType.ClipboardImage)
+ {
+ PackageReceived.ClipboardImage++;
+ }
+ else
+ {
+ PackageReceived.ClipboardText++;
+ }
+
+ if (tcp != null)
+ {
+ Common.ReceiveClipboardDataUsingTCP(
+ package,
+ package.Type == PackageType.ClipboardImage,
+ tcp);
+ }
+
+ break;
+
+ case PackageType.HideMouse:
+ HasSwitchedMachineSinceLastCopy = true;
+ HideMouseCursor(true);
+ MainFormDotEx(false);
+ ReleaseAllKeys();
+ break;
+
+ default:
+ if ((package.Type & PackageType.Matrix) == PackageType.Matrix)
+ {
+ PackageReceived.Matrix++;
+ UpdateMachineMatrix(package);
+ break;
+ }
+ else
+ {
+ // We should never get to this point!
+ Common.Log("Invalid package received!");
+ return;
+ }
+ }
+ }
+
+ private static void GetNameOfMachineWithClipboardData(DATA package)
+ {
+ LastIDWithClipboardData = package.Src;
+ List matchingMachines = Common.MachinePool.TryFindMachineByID(LastIDWithClipboardData);
+ if (matchingMachines.Count >= 1)
+ {
+ LastMachineWithClipboardData = matchingMachines[0].Name.Trim();
+ }
+
+ /*
+ lastMachineWithClipboardData =
+ Common.GetString(BitConverter.GetBytes(package.machineNameHead));
+ lastMachineWithClipboardData +=
+ Common.GetString(BitConverter.GetBytes(package.machineNameTail));
+ lastMachineWithClipboardData = lastMachineWithClipboardData.Trim();
+ * */
+ }
+
+ private static void SignalBigClipboardData()
+ {
+ LogDebug("SignalBigClipboardData");
+ SetToggleIcon(new int[TOGGLE_ICONS_SIZE] { ICON_BIG_CLIPBOARD, -1, ICON_BIG_CLIPBOARD, -1 });
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.Service.cs b/src/modules/MouseWithoutBorders/App/Class/Common.Service.cs
new file mode 100644
index 000000000000..2673d95c48ab
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.Service.cs
@@ -0,0 +1,160 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Linq;
+using System.ServiceProcess;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+//
+// Service control code.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+
+[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.Common.#StartMouseWithoutBordersService()", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders
+{
+ internal partial class Common
+ {
+ private static bool shownErrMessage;
+ private static DateTime lastStartServiceTime = DateTime.UtcNow;
+
+ internal static void StartMouseWithoutBordersService(string desktopToRunMouseWithoutBordersOn = null, string startTag1 = "byapp", string startTag2 = null)
+ {
+ // NOTE(@yuyoyuppe): the new flow assumes we run both mwb processes directly from the svc.
+ if (Common.RunWithNoAdminRight || true)
+ {
+ return;
+ }
+
+ Log($"{nameof(StartMouseWithoutBordersService)}: {GetStackTrace(new StackTrace())}.");
+
+ Task task = Task.Run(() =>
+ {
+ Process[] ps = Process.GetProcessesByName("MouseWithoutBordersSvc");
+
+ if (ps.Any())
+ {
+ if (DateTime.UtcNow - lastStartServiceTime < TimeSpan.FromSeconds(5))
+ {
+ Log($"{nameof(StartMouseWithoutBordersService)}: Aborted.");
+ return;
+ }
+
+ foreach (Process pp in ps)
+ {
+ Common.Log(string.Format(CultureInfo.InvariantCulture, "Killing process MouseWithoutBordersSvc {0}.", pp.Id));
+ pp.KillProcess();
+ }
+ }
+
+ lastStartServiceTime = DateTime.UtcNow;
+ ServiceController service = new("MouseWithoutBordersSvc");
+
+ try
+ {
+ Log("Starting " + service.ServiceName);
+ }
+ catch (Exception)
+ {
+ if (!shownErrMessage)
+ {
+ shownErrMessage = true;
+ _ = MessageBox.Show(
+ Application.ProductName + " is not installed yet, please run Setup.exe first!",
+ Application.ProductName,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Error);
+ }
+
+ return;
+ }
+
+ try
+ {
+ int c = 0;
+
+ while (service.Status != ServiceControllerStatus.Stopped && c++ < 5)
+ {
+ Thread.Sleep(1000);
+ service = new ServiceController("MouseWithoutBordersSvc");
+ }
+
+ if (string.IsNullOrWhiteSpace(desktopToRunMouseWithoutBordersOn))
+ {
+ startTag2 ??= Process.GetCurrentProcess().SessionId.ToString(CultureInfo.InvariantCulture);
+ service.Start(new string[] { startTag1, startTag2 });
+ }
+ else
+ {
+ service.Start(new string[] { desktopToRunMouseWithoutBordersOn });
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+
+ // ERROR_SERVICE_ALREADY_RUNNING
+ if (!(shownErrMessage || ((e?.InnerException as Win32Exception)?.NativeErrorCode == 1056)))
+ {
+ shownErrMessage = true;
+ _ = MessageBox.Show(
+ "Cannot start service " + service.ServiceName + ": " + e.Message,
+ Common.BinaryName,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Error);
+ }
+
+ return;
+ }
+ });
+
+ // Wait for the task while not blocking the UI thread.
+ do
+ {
+ MMSleep(1);
+
+ if (task.IsCanceled || task.IsCompleted || task.IsFaulted)
+ {
+ break;
+ }
+ }
+ while (true);
+ }
+
+ internal static void StartServiceAndSendLogoffSignal()
+ {
+ try
+ {
+ Process[] p = Process.GetProcessesByName("winlogon");
+ Process me = Process.GetCurrentProcess();
+ string myWinlogon = p?.FirstOrDefault(item => item.SessionId == me.SessionId)?.Id.ToString(CultureInfo.InvariantCulture) ?? null;
+
+ if (string.IsNullOrWhiteSpace(myWinlogon))
+ {
+ StartMouseWithoutBordersService(null, "logoff");
+ }
+ else
+ {
+ StartMouseWithoutBordersService(null, "logoff", myWinlogon);
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log($"{nameof(StartServiceAndSendLogoffSignal)}: {e.Message}");
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.ShutdownWithPowerToys.cs b/src/modules/MouseWithoutBorders/App/Class/Common.ShutdownWithPowerToys.cs
new file mode 100644
index 000000000000..b18a6601e133
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.ShutdownWithPowerToys.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using ManagedCommon;
+
+namespace MouseWithoutBorders
+{
+ internal class ShutdownWithPowerToys
+ {
+ public static void WaitForPowerToysRunner()
+ {
+ try
+ {
+ RunnerHelper.WaitForPowerToysRunnerExitFallback(() =>
+ {
+ Common.MainForm.Quit(true, false);
+ });
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.VK.cs b/src/modules/MouseWithoutBorders/App/Class/Common.VK.cs
new file mode 100644
index 000000000000..79aa50c6dcf8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.VK.cs
@@ -0,0 +1,130 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Virtual key constants.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System;
+
+namespace MouseWithoutBorders
+{
+ internal enum VK : ushort
+ {
+ CAPITAL = 0x14,
+ NUMLOCK = 0x90,
+ SHIFT = 0x10,
+ CONTROL = 0x11,
+ MENU = 0x12,
+ ESCAPE = 0x1B,
+ BACK = 0x08,
+ TAB = 0x09,
+ RETURN = 0x0D,
+ PRIOR = 0x21,
+ NEXT = 0x22,
+ END = 0x23,
+ HOME = 0x24,
+ LEFT = 0x25,
+ UP = 0x26,
+ RIGHT = 0x27,
+ DOWN = 0x28,
+ SELECT = 0x29,
+ PRINT = 0x2A,
+ EXECUTE = 0x2B,
+ SNAPSHOT = 0x2C,
+ INSERT = 0x2D,
+ DELETE = 0x2E,
+ HELP = 0x2F,
+ NUMPAD0 = 0x60,
+ NUMPAD1 = 0x61,
+ NUMPAD2 = 0x62,
+ NUMPAD3 = 0x63,
+ NUMPAD4 = 0x64,
+ NUMPAD5 = 0x65,
+ NUMPAD6 = 0x66,
+ NUMPAD7 = 0x67,
+ NUMPAD8 = 0x68,
+ NUMPAD9 = 0x69,
+ MULTIPLY = 0x6A,
+ ADD = 0x6B,
+ SEPARATOR = 0x6C,
+ SUBTRACT = 0x6D,
+ DECIMAL = 0x6E,
+ DIVIDE = 0x6F,
+ F1 = 0x70,
+ F2 = 0x71,
+ F3 = 0x72,
+ F4 = 0x73,
+ F5 = 0x74,
+ F6 = 0x75,
+ F7 = 0x76,
+ F8 = 0x77,
+ F9 = 0x78,
+ F10 = 0x79,
+ F11 = 0x7A,
+ F12 = 0x7B,
+ OEM_1 = 0xBA,
+ OEM_PLUS = 0xBB,
+ OEM_COMMA = 0xBC,
+ OEM_MINUS = 0xBD,
+ OEM_PERIOD = 0xBE,
+ OEM_2 = 0xBF,
+ OEM_3 = 0xC0,
+ MEDIA_NEXT_TRACK = 0xB0,
+ MEDIA_PREV_TRACK = 0xB1,
+ MEDIA_STOP = 0xB2,
+ MEDIA_PLAY_PAUSE = 0xB3,
+ LWIN = 0x5B,
+ RWIN = 0x5C,
+ LSHIFT = 0xA0,
+ RSHIFT = 0xA1,
+ LCONTROL = 0xA2,
+ RCONTROL = 0xA3,
+ LMENU = 0xA4,
+ RMENU = 0xA5,
+ }
+
+ internal partial class Common
+ {
+ internal const ushort KEYEVENTF_KEYDOWN = 0x0001;
+ internal const ushort KEYEVENTF_KEYUP = 0x0002;
+
+ internal const int WH_MOUSE = 7;
+ internal const int WH_KEYBOARD = 2;
+ internal const int WH_MOUSE_LL = 14;
+ internal const int WH_KEYBOARD_LL = 13;
+
+ internal const int WM_MOUSEMOVE = 0x200;
+ internal const int WM_LBUTTONDOWN = 0x201;
+ internal const int WM_RBUTTONDOWN = 0x204;
+ internal const int WM_MBUTTONDOWN = 0x207;
+ internal const int WM_XBUTTONDOWN = 0x20B;
+ internal const int WM_LBUTTONUP = 0x202;
+ internal const int WM_RBUTTONUP = 0x205;
+ internal const int WM_MBUTTONUP = 0x208;
+ internal const int WM_XBUTTONUP = 0x20C;
+ internal const int WM_LBUTTONDBLCLK = 0x203;
+ internal const int WM_RBUTTONDBLCLK = 0x206;
+ internal const int WM_MBUTTONDBLCLK = 0x209;
+ internal const int WM_MOUSEWHEEL = 0x020A;
+
+ internal const int WM_KEYDOWN = 0x100;
+ internal const int WM_KEYUP = 0x101;
+ internal const int WM_SYSKEYDOWN = 0x104;
+ internal const int WM_SYSKEYUP = 0x105;
+
+ [Flags]
+ internal enum LLKHF
+ {
+ EXTENDED = 0x01,
+ INJECTED = 0x10,
+ ALTDOWN = 0x20,
+ UP = 0x80,
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs b/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs
new file mode 100644
index 000000000000..775945cc3400
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.WinAPI.cs
@@ -0,0 +1,360 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Windows.Forms;
+
+//
+// Screen/Desktop helper functions.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+
+namespace MouseWithoutBorders
+{
+ // Desktops, and GetScreenConfig routines
+ internal partial class Common
+ {
+ private static MyRectangle newDesktopBounds;
+ private static MyRectangle newPrimaryScreenBounds;
+ private static string activeDesktop;
+
+ internal static string ActiveDesktop => Common.activeDesktop;
+
+ private static void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
+ {
+ GetScreenConfig();
+ }
+
+ private static readonly List SensitivePoints = new();
+
+ private static bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref NativeMethods.RECT lprcMonitor, IntPtr dwData)
+ {
+ // lprcMonitor is wrong!!! => using GetMonitorInfo(...)
+ // Log(String.Format( CultureInfo.CurrentCulture,"MONITOR: l{0}, t{1}, r{2}, b{3}", lprcMonitor.Left, lprcMonitor.Top, lprcMonitor.Right, lprcMonitor.Bottom));
+ NativeMethods.MonitorInfoEx mi = default;
+ mi.cbSize = Marshal.SizeOf(mi);
+ _ = NativeMethods.GetMonitorInfo(hMonitor, ref mi);
+
+ try
+ {
+ // For logging only
+ _ = NativeMethods.GetDpiForMonitor(hMonitor, 0, out uint dpiX, out uint dpiY);
+ Log(string.Format(CultureInfo.CurrentCulture, "MONITOR: ({0}, {1}, {2}, {3}). DPI: ({4}, {5})", mi.rcMonitor.Left, mi.rcMonitor.Top, mi.rcMonitor.Right, mi.rcMonitor.Bottom, dpiX, dpiY));
+ }
+ catch (DllNotFoundException)
+ {
+ Common.Log("GetDpiForMonitor is unsupported in Windows 7 and lower.");
+ }
+ catch (EntryPointNotFoundException)
+ {
+ Common.Log("GetDpiForMonitor is unsupported in Windows 7 and lower.");
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+
+ if (mi.rcMonitor.Left == 0 && mi.rcMonitor.Top == 0 && mi.rcMonitor.Right != 0 && mi.rcMonitor.Bottom != 0)
+ {
+ // Primary screen
+ _ = Interlocked.Exchange(ref screenWidth, mi.rcMonitor.Right - mi.rcMonitor.Left);
+ _ = Interlocked.Exchange(ref screenHeight, mi.rcMonitor.Bottom - mi.rcMonitor.Top);
+
+ newPrimaryScreenBounds.Left = mi.rcMonitor.Left;
+ newPrimaryScreenBounds.Top = mi.rcMonitor.Top;
+ newPrimaryScreenBounds.Right = mi.rcMonitor.Right;
+ newPrimaryScreenBounds.Bottom = mi.rcMonitor.Bottom;
+ }
+ else
+ {
+ if (mi.rcMonitor.Left < newDesktopBounds.Left)
+ {
+ newDesktopBounds.Left = mi.rcMonitor.Left;
+ }
+
+ if (mi.rcMonitor.Top < newDesktopBounds.Top)
+ {
+ newDesktopBounds.Top = mi.rcMonitor.Top;
+ }
+
+ if (mi.rcMonitor.Right > newDesktopBounds.Right)
+ {
+ newDesktopBounds.Right = mi.rcMonitor.Right;
+ }
+
+ if (mi.rcMonitor.Bottom > newDesktopBounds.Bottom)
+ {
+ newDesktopBounds.Bottom = mi.rcMonitor.Bottom;
+ }
+ }
+
+ lock (SensitivePoints)
+ {
+ SensitivePoints.Add(new Point(mi.rcMonitor.Left, mi.rcMonitor.Top));
+ SensitivePoints.Add(new Point(mi.rcMonitor.Right, mi.rcMonitor.Top));
+ SensitivePoints.Add(new Point(mi.rcMonitor.Right, mi.rcMonitor.Bottom));
+ SensitivePoints.Add(new Point(mi.rcMonitor.Left, mi.rcMonitor.Bottom));
+ }
+
+ return true;
+ }
+
+ internal static void GetScreenConfig()
+ {
+ try
+ {
+ Common.LogDebug("==================== GetScreenConfig started");
+ newDesktopBounds = new MyRectangle();
+ newPrimaryScreenBounds = new MyRectangle();
+ newDesktopBounds.Left = newPrimaryScreenBounds.Left = Screen.PrimaryScreen.Bounds.Left;
+ newDesktopBounds.Top = newPrimaryScreenBounds.Top = Screen.PrimaryScreen.Bounds.Top;
+ newDesktopBounds.Right = newPrimaryScreenBounds.Right = Screen.PrimaryScreen.Bounds.Right;
+ newDesktopBounds.Bottom = newPrimaryScreenBounds.Bottom = Screen.PrimaryScreen.Bounds.Bottom;
+
+ Common.Log(string.Format(
+ CultureInfo.CurrentCulture,
+ "logon = {0} PrimaryScreenBounds = {1},{2},{3},{4} desktopBounds = {5},{6},{7},{8}",
+ Common.RunOnLogonDesktop,
+ Common.newPrimaryScreenBounds.Left,
+ Common.newPrimaryScreenBounds.Top,
+ Common.newPrimaryScreenBounds.Right,
+ Common.newPrimaryScreenBounds.Bottom,
+ Common.newDesktopBounds.Left,
+ Common.newDesktopBounds.Top,
+ Common.newDesktopBounds.Right,
+ Common.newDesktopBounds.Bottom));
+
+#if USE_MANAGED_ROUTINES
+ // Managed routines do not work well when running on secure desktop:(
+ screenWidth = Screen.PrimaryScreen.Bounds.Width;
+ screenHeight = Screen.PrimaryScreen.Bounds.Height;
+ screenCount = Screen.AllScreens.Length;
+ for (int i = 0; i < Screen.AllScreens.Length; i++)
+ {
+ if (Screen.AllScreens[i].Bounds.Left < desktopBounds.Left) desktopBounds.Left = Screen.AllScreens[i].Bounds.Left;
+ if (Screen.AllScreens[i].Bounds.Top < desktopBounds.Top) desktopBounds.Top = Screen.AllScreens[i].Bounds.Top;
+ if (Screen.AllScreens[i].Bounds.Right > desktopBounds.Right) desktopBounds.Right = Screen.AllScreens[i].Bounds.Right;
+ if (Screen.AllScreens[i].Bounds.Bottom > desktopBounds.Bottom) desktopBounds.Bottom = Screen.AllScreens[i].Bounds.Bottom;
+ }
+#else
+ lock (SensitivePoints)
+ {
+ SensitivePoints.Clear();
+ }
+
+ NativeMethods.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnumProc, IntPtr.Zero);
+
+ // 1000 calls to EnumDisplayMonitors cost a dozen of milliseconds
+#endif
+ Interlocked.Exchange(ref desktopBounds, newDesktopBounds);
+ Interlocked.Exchange(ref primaryScreenBounds, newPrimaryScreenBounds);
+
+ Common.Log(string.Format(
+ CultureInfo.CurrentCulture,
+ "logon = {0} PrimaryScreenBounds = {1},{2},{3},{4} desktopBounds = {5},{6},{7},{8}",
+ Common.RunOnLogonDesktop,
+ Common.PrimaryScreenBounds.Left,
+ Common.PrimaryScreenBounds.Top,
+ Common.PrimaryScreenBounds.Right,
+ Common.PrimaryScreenBounds.Bottom,
+ Common.DesktopBounds.Left,
+ Common.DesktopBounds.Top,
+ Common.DesktopBounds.Right,
+ Common.DesktopBounds.Bottom));
+
+ Common.Log("==================== GetScreenConfig ended");
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ }
+
+#if USING_SCREEN_SAVER_ROUTINES
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ private static extern int PostMessage(IntPtr hWnd, int wMsg, int wParam, int lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ private static extern IntPtr OpenDesktop(string hDesktop, int Flags, bool Inherit, UInt32 DesiredAccess);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ private static extern bool CloseDesktop(IntPtr hDesktop);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ private static extern bool EnumDesktopWindows( IntPtr hDesktop, EnumDesktopWindowsProc callback, IntPtr lParam);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ private static extern bool IsWindowVisible(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ private static extern bool SystemParametersInfo(int uAction, int uParam, ref int pvParam, int flags);
+
+ private delegate bool EnumDesktopWindowsProc(IntPtr hDesktop, IntPtr lParam);
+ private const int WM_CLOSE = 16;
+ private const int SPI_GETSCREENSAVERRUNNING = 114;
+
+ internal static bool IsScreenSaverRunning()
+ {
+ int isRunning = 0;
+ SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0,ref isRunning, 0);
+ return (isRunning != 0);
+ }
+
+ internal static void CloseScreenSaver()
+ {
+ IntPtr hDesktop = OpenDesktop("Screen-saver", 0, false, DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
+ if (hDesktop != IntPtr.Zero)
+ {
+ LogDebug("Closing screen saver...");
+ EnumDesktopWindows(hDesktop, new EnumDesktopWindowsProc(CloseScreenSaverFunc), IntPtr.Zero);
+ CloseDesktop(hDesktop);
+ }
+ }
+
+ private static bool CloseScreenSaverFunc(IntPtr hWnd, IntPtr lParam)
+ {
+ if (IsWindowVisible(hWnd))
+ {
+ LogDebug("Posting WM_CLOSE to " + hWnd.ToString(CultureInfo.InvariantCulture));
+ PostMessage(hWnd, WM_CLOSE, 0, 0);
+ }
+ return true;
+ }
+#endif
+
+ internal static string GetMyDesktop()
+ {
+ byte[] arThreadDesktop = new byte[256];
+ IntPtr hD = NativeMethods.GetThreadDesktop(NativeMethods.GetCurrentThreadId());
+ if (hD != IntPtr.Zero)
+ {
+ _ = NativeMethods.GetUserObjectInformation(hD, NativeMethods.UOI_NAME, arThreadDesktop, arThreadDesktop.Length, out _);
+ return GetString(arThreadDesktop).Replace("\0", string.Empty);
+ }
+
+ return string.Empty;
+ }
+
+ internal static string GetInputDesktop()
+ {
+ byte[] arInputDesktop = new byte[256];
+ IntPtr hD = NativeMethods.OpenInputDesktop(0, false, NativeMethods.DESKTOP_READOBJECTS);
+ if (hD != IntPtr.Zero)
+ {
+ _ = NativeMethods.GetUserObjectInformation(hD, NativeMethods.UOI_NAME, arInputDesktop, arInputDesktop.Length, out _);
+ return GetString(arInputDesktop).Replace("\0", string.Empty);
+ }
+
+ return string.Empty;
+ }
+
+ internal static void StartMMService(string desktopToRunMouseWithoutBordersOn)
+ {
+ if (!Common.RunWithNoAdminRight)
+ {
+ LogDebug("*** Starting on active Desktop: " + desktopToRunMouseWithoutBordersOn);
+ StartMouseWithoutBordersService(desktopToRunMouseWithoutBordersOn);
+ }
+ }
+
+ internal static void CheckForDesktopSwitchEvent(bool cleanupIfExit)
+ {
+ try
+ {
+ if (!IsMyDesktopActive() || Common.CurrentProcess.SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
+ {
+ Common.RunDDHelper(true);
+ int waitCount = 20;
+
+ while (NativeMethods.WTSGetActiveConsoleSessionId() == 0xFFFFFFFF && waitCount > 0)
+ {
+ waitCount--;
+ LogDebug("The session is detached/attached.");
+ Thread.Sleep(500);
+ }
+
+ string myDesktop = GetMyDesktop();
+ activeDesktop = GetInputDesktop();
+
+ LogDebug("*** Active Desktop = " + activeDesktop);
+ LogDebug("*** My Desktop = " + myDesktop);
+
+ if (myDesktop.Equals(activeDesktop, StringComparison.OrdinalIgnoreCase))
+ {
+ LogDebug("*** Active Desktop == My Desktop (TS session)");
+ }
+
+ if (!activeDesktop.Equals("winlogon", StringComparison.OrdinalIgnoreCase) &&
+ !activeDesktop.Equals("default", StringComparison.OrdinalIgnoreCase) &&
+ !activeDesktop.Equals("disconnect", StringComparison.OrdinalIgnoreCase))
+ {
+ try
+ {
+ StartMMService(activeDesktop);
+ }
+ catch (Exception e)
+ {
+ Common.Log($"{nameof(CheckForDesktopSwitchEvent)}: {e}");
+ }
+ }
+ else
+ {
+ if (!myDesktop.Equals(activeDesktop, StringComparison.OrdinalIgnoreCase))
+ {
+ Log("*** Active Desktop <> My Desktop");
+ }
+
+ uint sid = NativeMethods.WTSGetActiveConsoleSessionId();
+
+ if (Process.GetProcessesByName(Common.BinaryName).Any(p => (uint)p.SessionId == sid))
+ {
+ Log("Found MouseWithoutBorders on the active session!");
+ }
+ else
+ {
+ Log("MouseWithoutBorders not found on the active session!");
+ StartMMService(null);
+ }
+ }
+
+ if (!myDesktop.Equals("winlogon", StringComparison.OrdinalIgnoreCase) &&
+ !myDesktop.Equals("default", StringComparison.OrdinalIgnoreCase))
+ {
+ LogDebug("*** Desktop inactive, exiting: " + myDesktop);
+ Setting.Values.LastX = JUST_GOT_BACK_FROM_SCREEN_SAVER;
+ if (cleanupIfExit)
+ {
+ Common.Cleanup();
+ }
+
+ Process.GetCurrentProcess().KillProcess();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ }
+
+ private static Point p;
+
+ internal static bool IsMyDesktopActive()
+ {
+ return NativeMethods.GetCursorPos(ref p);
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Common.cs b/src/modules/MouseWithoutBorders/App/Class/Common.cs
new file mode 100644
index 000000000000..ec0fa9e0395f
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Common.cs
@@ -0,0 +1,1555 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading;
+using System.Windows.Forms;
+
+//
+// Most of the helper methods.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+using MouseWithoutBorders.Exceptions;
+
+// Log is enough
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckClipboard()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckForDesktopSwitchEvent(System.Boolean)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SetAsStartupItem(System.Boolean)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#HelperThread()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetMyStorageDir()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#MouseEvent(MouseWithoutBorders.MOUSEDATA)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#KeybdEvent(MouseWithoutBorders.KEYBDDATA)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ImpersonateLoggedOnUserAndDoSomething(System.Threading.ThreadStart)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#StartMouseWithoutBordersService()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#HookClipboard()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReceiveClipboardData(MouseWithoutBorders.DATA,System.Boolean)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReceiverCallback(System.Object)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ConnectAndGetData(System.Object)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckNewVersion()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#StartServiceAndSendLogoffSignal()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetScreenConfig()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CaptureScreen()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#InitEncryption()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ToggleIcon()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetNameAndIPAddresses()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#Cleanup()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Scope = "type", Target = "MouseWithoutBorders.Common", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Scope = "member", Target = "MouseWithoutBorders.Common.#ConnectAndGetData(System.Object)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Scope = "member", Target = "MouseWithoutBorders.Common.#ProcessPackage(MouseWithoutBorders.DATA)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SetOEMBackground(System.Boolean)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#get_Machine_Pool()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SetOEMBackground(System.Boolean,System.String)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#GetNewImageAndSaveTo(System.String,System.String)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateLowIntegrityProcess(System.String,System.String,System.Int32)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#LogAll()", MessageId = "System.String.Format(System.IFormatProvider,System.String,System.Object[])", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#CheckForDesktopSwitchEvent(System.Boolean)", MessageId = "MouseWithoutBorders.NativeMethods.SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#DragDropStep04()", MessageId = "MouseWithoutBorders.NativeMethods.SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateLowIntegrityProcess(System.String,System.String,System.Int32)", MessageId = "MouseWithoutBorders.NativeMethods.WaitForSingleObject(System.IntPtr,System.Int32)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#GetText(System.IntPtr)", MessageId = "MouseWithoutBorders.NativeMethods.GetWindowText(System.IntPtr,System.Text.StringBuilder,System.Int32)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.Common.#ImpersonateLoggedOnUserAndDoSomething(System.Threading.ThreadStart)", MessageId = "MouseWithoutBorders.NativeMethods.WTSQueryUserToken(System.UInt32,System.IntPtr@)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateLowIntegrityProcess(System.String,System.String,System.Int32,System.Boolean,System.Int64)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#CreateProcessInInputDesktopSession(System.String,System.String,System.String,System.Boolean,System.Int16)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#SkSend(MouseWithoutBorders.DATA,System.Boolean,System.Int32)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReceiveClipboardDataUsingTCP(MouseWithoutBorders.DATA,System.Boolean,System.Net.Sockets.Socket)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#UpdateMachineMatrix(MouseWithoutBorders.DATA)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Common.#ReopenSockets(System.Boolean)", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders
+{
+ internal partial class Common
+ {
+ private Common()
+ {
+ }
+
+ private static InputHook hook;
+ private static FrmMatrix matrixForm;
+ private static FrmInputCallback inputCallbackForm;
+ private static FrmAbout aboutForm;
+ private static Thread helper;
+ private static int screenWidth;
+ private static int screenHeight;
+ private static int lastX;
+ private static int lastY;
+
+ private static bool mainFormVisible = true;
+ private static bool runOnLogonDesktop;
+ private static bool runOnScrSaverDesktop;
+
+ private static int[] toggleIcons;
+ private static int toggleIconsIndex;
+ internal const int TOGGLE_ICONS_SIZE = 4;
+ internal const int ICON_ONE = 0;
+ internal const int ICON_ALL = 1;
+ internal const int ICON_SMALL_CLIPBOARD = 2;
+ internal const int ICON_BIG_CLIPBOARD = 3;
+ internal const int ICON_ERROR = 4;
+ internal const int JUST_GOT_BACK_FROM_SCREEN_SAVER = 9999;
+
+ internal const int NETWORK_STREAM_BUF_SIZE = 1024 * 1024;
+ private static readonly EventWaitHandle EvSwitch = new(false, EventResetMode.AutoReset);
+ private static Point lastPos;
+ private static int switchCount;
+ private static long lastReconnectByHotKeyTime;
+ private static int tcpPort;
+ private static bool secondOpenSocketTry;
+ private static string binaryName;
+
+ internal static Process CurrentProcess { get; set; }
+
+ public static string BinaryName
+ {
+ get => Common.binaryName;
+ set => Common.binaryName = value;
+ }
+
+ public static bool SecondOpenSocketTry
+ {
+ get => Common.secondOpenSocketTry;
+ set => Common.secondOpenSocketTry = value;
+ }
+
+ public static long LastReconnectByHotKeyTime
+ {
+ get => Common.lastReconnectByHotKeyTime;
+ set => Common.lastReconnectByHotKeyTime = value;
+ }
+
+ public static int SwitchCount
+ {
+ get => Common.switchCount;
+ set => Common.switchCount = value;
+ }
+
+ public static Point LastPos
+ {
+ get => Common.lastPos;
+ set => Common.lastPos = value;
+ }
+
+ internal static FrmAbout AboutForm
+ {
+ get => Common.aboutForm;
+ set => Common.aboutForm = value;
+ }
+
+ internal static FrmInputCallback InputCallbackForm
+ {
+ get => Common.inputCallbackForm;
+ set => Common.inputCallbackForm = value;
+ }
+
+ public static int PaintCount { get; set; }
+
+ internal static bool RunOnScrSaverDesktop
+ {
+ get => Common.runOnScrSaverDesktop;
+ set => Common.runOnScrSaverDesktop = value;
+ }
+
+ internal static bool RunOnLogonDesktop
+ {
+ get => Common.runOnLogonDesktop;
+ set => Common.runOnLogonDesktop = value;
+ }
+
+ internal static bool RunWithNoAdminRight { get; set; }
+
+ internal static int LastX
+ {
+ get => Common.lastX;
+ set => Common.lastX = value;
+ }
+
+ internal static int LastY
+ {
+ get => Common.lastY;
+ set => Common.lastY = value;
+ }
+
+ internal static int[] ToggleIcons => Common.toggleIcons;
+
+ internal static int ScreenHeight => Common.screenHeight;
+
+ internal static int ScreenWidth => Common.screenWidth;
+
+ internal static bool Is64bitOS
+ {
+ get; private set;
+
+ // set { Common.is64bitOS = value; }
+ }
+
+ internal static int ToggleIconsIndex
+ {
+ // get { return Common.toggleIconsIndex; }
+ set => Common.toggleIconsIndex = value;
+ }
+
+ internal static InputHook Hook
+ {
+ get => Common.hook;
+ set => Common.hook = value;
+ }
+
+ internal static SocketStuff Sk { get; set; }
+
+ internal static FrmScreen MainForm { get; set; }
+
+ internal static FrmMouseCursor MouseCursorForm { get; set; }
+
+ internal static FrmMatrix MatrixForm
+ {
+ get => Common.matrixForm;
+ set => Common.matrixForm = value;
+ }
+
+ internal static ID DesMachineID
+ {
+ get => Common.desMachineID;
+
+ set
+ {
+ Common.desMachineID = value;
+ Common.DesMachineName = Common.NameFromID(Common.desMachineID);
+ }
+ }
+
+ internal static ID MachineID => (ID)Setting.Values.MachineId;
+
+ internal static string MachineName { get; set; }
+
+ internal static bool MainFormVisible
+ {
+ get => Common.mainFormVisible;
+ set => Common.mainFormVisible = value;
+ }
+
+ internal static Mutex SocketMutex { get; set; } // Synchronization between MouseWithoutBorders running in different desktops
+
+ // TODO: For telemetry only, to be removed.
+ private static int socketMutexBalance;
+
+ internal static void ReleaseSocketMutex()
+ {
+ if (SocketMutex != null)
+ {
+ LogDebug("SOCKET MUTEX BEGIN RELEASE.");
+
+ try
+ {
+ _ = Interlocked.Decrement(ref socketMutexBalance);
+ SocketMutex.ReleaseMutex();
+ }
+ catch (ApplicationException e)
+ {
+ // The current thread does not own the mutex, the thread acquired it will own it.
+ TelemetryLogTrace($"{nameof(ReleaseSocketMutex)}: {e.Message}. {Thread.CurrentThread.ManagedThreadId}/{UIThreadID}.", SeverityLevel.Warning);
+ }
+
+ LogDebug("SOCKET MUTEX RELEASED.");
+ }
+ else
+ {
+ LogDebug("SOCKET MUTEX NULL.");
+ }
+ }
+
+ internal static void AcquireSocketMutex()
+ {
+ if (SocketMutex != null)
+ {
+ LogDebug("SOCKET MUTEX BEGIN WAIT.");
+ int waitTimeout = 60000; // TcpListener.Stop may take very long to complete for some reason.
+
+ int socketMutexBalance = int.MinValue;
+
+ bool acquireMutex = ExecuteAndTrace(
+ "Waiting for sockets to close",
+ () =>
+ {
+ socketMutexBalance = Interlocked.Increment(ref Common.socketMutexBalance);
+ _ = SocketMutex.WaitOne(waitTimeout); // The app now requires .Net 4.0. Note: .Net20RTM does not have the one-parameter version of the API.
+ },
+ TimeSpan.FromSeconds(5));
+
+ // Took longer than expected.
+ if (!acquireMutex)
+ {
+ Process[] ps = Process.GetProcessesByName(Common.BinaryName);
+ TelemetryLogTrace($"Balance: {socketMutexBalance}, Active: {IsMyDesktopActive()}, Sid/Console: {Process.GetCurrentProcess().SessionId}/{NativeMethods.WTSGetActiveConsoleSessionId()}, Desktop/Input: {GetMyDesktop()}/{GetInputDesktop()}, count: {ps?.Length}.", SeverityLevel.Warning);
+ }
+
+ LogDebug("SOCKET MUTEX ENDED.");
+ }
+ else
+ {
+ LogDebug("SOCKET MUTEX NULL.");
+ }
+ }
+
+ internal static bool BlockingUI { get; private set; }
+
+ internal static bool ExecuteAndTrace(string actionName, Action action, TimeSpan timeout, bool restart = false)
+ {
+ bool rv = true;
+ LogDebug(actionName);
+ bool done = false;
+
+ BlockingUI = true;
+
+ if (restart)
+ {
+ Common.MainForm.Text = Setting.Values.MyIdEx;
+
+ /* closesocket() rarely gets stuck for some reason inside ntdll!ZwClose ...=>... afd!AfdCleanupCore.
+ * There is no good workaround for it so far, still working with [Winsock 2.0 Discussions] to address the issue.
+ * */
+ new Thread(
+ () =>
+ {
+ for (int i = 0; i < timeout.TotalSeconds; i++)
+ {
+ Thread.Sleep(1000);
+
+ if (done)
+ {
+ return;
+ }
+ }
+
+ TelemetryLogTrace($"[{actionName}] took more than {(long)timeout.TotalSeconds}, restarting the process.", SeverityLevel.Warning, true);
+
+ string desktop = Common.GetMyDesktop();
+ oneInstanceCheck?.Close();
+ _ = Process.Start(Application.ExecutablePath, desktop);
+ LogDebug($"Started on desktop {desktop}");
+
+ Thread.SuspendAllThreadsBut(Thread.CurrentThread.ManagedThreadId);
+
+ Process.GetCurrentProcess().KillProcess(true);
+ },
+ $"{actionName} watchdog").Start();
+ }
+
+ Stopwatch timer = Stopwatch.StartNew();
+
+ try
+ {
+ action();
+ }
+ finally
+ {
+ done = true;
+ BlockingUI = false;
+
+ if (restart)
+ {
+ Common.MainForm.Text = Setting.Values.MyID;
+ }
+
+ timer.Stop();
+
+ if (timer.Elapsed > timeout)
+ {
+ rv = false;
+
+ if (!restart)
+ {
+ TelemetryLogTrace($"[{actionName}] took more than {(long)timeout.TotalSeconds}: {(long)timer.Elapsed.TotalSeconds}.", SeverityLevel.Warning);
+ }
+ }
+ }
+
+ return rv;
+ }
+
+ internal static byte[] GetBytes(string st)
+ {
+ return ASCIIEncoding.ASCII.GetBytes(st);
+ }
+
+ internal static string GetString(byte[] bytes)
+ {
+ return ASCIIEncoding.ASCII.GetString(bytes);
+ }
+
+ internal static byte[] GetBytesU(string st)
+ {
+ return ASCIIEncoding.Unicode.GetBytes(st);
+ }
+
+ internal static string GetStringU(byte[] bytes)
+ {
+ return ASCIIEncoding.Unicode.GetString(bytes);
+ }
+
+ internal static int UIThreadID { get; set; }
+
+ internal static void DoSomethingInUIThread(Action action, bool blocking = false)
+ {
+ InvokeInFormThread(MainForm, UIThreadID, action, blocking);
+ }
+
+ internal static int InputCallbackThreadID { get; set; }
+
+ internal static void DoSomethingInTheInputCallbackThread(Action action, bool blocking = true)
+ {
+ InvokeInFormThread(InputCallbackForm, InputCallbackThreadID, action, blocking);
+ }
+
+ private static void InvokeInFormThread(System.Windows.Forms.Form form, int threadId, Action action, bool blocking)
+ {
+ if (form != null)
+ {
+ int currentThreadId = Thread.CurrentThread.ManagedThreadId;
+
+ if (currentThreadId == threadId)
+ {
+ action();
+ }
+ else
+ {
+ bool done = false;
+
+ try
+ {
+ Action callback = () =>
+ {
+ try
+ {
+ action();
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ finally
+ {
+ done = true;
+ }
+ };
+ _ = form.BeginInvoke(callback);
+ }
+ catch (Exception e)
+ {
+ done = true;
+ Log(e);
+ }
+
+ while (blocking && !done)
+ {
+ Thread.Sleep(16);
+
+ if (currentThreadId == UIThreadID || currentThreadId == InputCallbackThreadID)
+ {
+ Application.DoEvents();
+ }
+ }
+ }
+ }
+ }
+
+ private static readonly object InputSimulationLock = new();
+
+ internal static void DoSomethingInTheInputSimulationThread(ThreadStart target)
+ {
+ /*
+ * For some reason, SendInput may hit deadlock if it is called in the InputHookProc thread.
+ * For now leave it as is in the caller thread which is the socket receiver thread.
+ * */
+
+ // SendInput is thread-safe but few users seem to hit a deadlock occasionally, probably a Windows bug.
+ lock (InputSimulationLock)
+ {
+ target();
+ }
+ }
+
+ internal static void SendPackage(ID des, PackageType packageType)
+ {
+ DATA package = new();
+ package.Type = packageType;
+ package.Des = des;
+ package.MachineName = MachineName;
+
+ SkSend(package, null, false);
+ }
+
+ internal static void SendHeartBeat(bool initial = false)
+ {
+ SendPackage(ID.ALL, initial && Common.GeneratedKey ? PackageType.Heartbeat_ex : PackageType.Heartbeat);
+ }
+
+ private static long lastSendNextMachine;
+
+ internal static void SendNextMachine(ID hostMachine, ID nextMachine, Point requestedXY)
+ {
+ LogDebug($"SendNextMachine: Host machine: {hostMachine}, Next machine: {nextMachine}, Requested XY: {requestedXY}");
+
+ if (GetTick() - lastSendNextMachine < 100)
+ {
+ LogDebug("Machine switching in progress."); // "Move Mouse relatively" mode, slow machine/network, quick/busy hand.
+ return;
+ }
+
+ lastSendNextMachine = GetTick();
+
+ DATA package = new();
+ package.Type = PackageType.NextMachine;
+
+ package.Des = hostMachine;
+
+ package.Md.X = requestedXY.X;
+ package.Md.Y = requestedXY.Y;
+ package.Md.WheelDelta = (int)nextMachine;
+
+ SkSend(package, null, false);
+
+ LogDebug("SendNextMachine done.");
+ }
+
+ private static ulong lastInputEventCount;
+ private static ulong lastRealInputEventCount;
+
+ internal static void SendAwakeBeat()
+ {
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && Common.IsMyDesktopActive() &&
+ Setting.Values.BlockScreenSaver && lastRealInputEventCount != Common.RealInputEventCount)
+ {
+ SendPackage(ID.ALL, PackageType.Awake);
+ }
+ else
+ {
+ SendHeartBeat();
+
+ if (Setting.Values.BlockScreenSaverEx && lastInputEventCount == Common.InputEventCount && Common.DesMachineID == Common.MachineID)
+ {
+ PokeMyself();
+ }
+ }
+
+ lastInputEventCount = Common.InputEventCount;
+ lastRealInputEventCount = Common.RealInputEventCount;
+ }
+
+ private static void HumanBeingDetected()
+ {
+ if (lastInputEventCount == Common.InputEventCount)
+ {
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && Common.IsMyDesktopActive())
+ {
+ PokeMyself();
+ }
+ }
+
+ lastInputEventCount = Common.InputEventCount;
+ }
+
+ private static void PokeMyself()
+ {
+ int x, y = 0;
+
+ for (int i = 0; i < 10; i++)
+ {
+ x = Ran.Next(-9, 10);
+ InputSimulation.MoveMouseRelative(x, y);
+ Thread.Sleep(50);
+ InputSimulation.MoveMouseRelative(-x, -y);
+ Thread.Sleep(50);
+
+ if (lastInputEventCount != Common.InputEventCount)
+ {
+ break;
+ }
+ }
+ }
+
+ internal static void InitLastInputEventCount()
+ {
+ lastInputEventCount = Common.InputEventCount;
+ lastRealInputEventCount = Common.RealInputEventCount;
+ }
+
+ internal static void SendHello()
+ {
+ SendPackage(ID.ALL, PackageType.Hello);
+ }
+
+ /*
+ internal static void SendHi()
+ {
+ SendPackage(IP.ALL, PackageType.hi);
+ }
+ * */
+
+ private static void SendByeBye()
+ {
+ LogDebug($"{nameof(SendByeBye)}");
+ SendPackage(ID.ALL, PackageType.ByeBye);
+ }
+
+ internal static void SendClipboardBeat()
+ {
+ SendPackage(ID.ALL, PackageType.Clipboard);
+ }
+
+ private static void ProcessByeByeMessage(DATA package)
+ {
+ if (package.Src == desMachineID)
+ {
+ SwitchToMachine(MachineName.Trim());
+ }
+
+ _ = RemoveDeadMachines(package.Src);
+ }
+
+ internal static long GetTick() // ms
+ {
+ return DateTime.Now.Ticks / 10000;
+ }
+
+ internal static void SetToggleIcon(int[] toggleIcons)
+ {
+ Common.LogDebug($"{nameof(SetToggleIcon)}: {toggleIcons?.FirstOrDefault()}");
+ Common.toggleIcons = toggleIcons;
+ toggleIconsIndex = 0;
+ }
+
+ internal static string CaptureScreen()
+ {
+ try
+ {
+ string fileName = GetMyStorageDir() + @"ScreenCaptureByMouseWithoutBorders.png";
+ int w = desktopBounds.Right - desktopBounds.Left;
+ int h = desktopBounds.Bottom - desktopBounds.Top;
+ Bitmap bm = new(w, h);
+ Graphics g = Graphics.FromImage(bm);
+ Size s = new(w, h);
+ g.CopyFromScreen(desktopBounds.Left, desktopBounds.Top, 0, 0, s);
+ bm.Save(fileName, ImageFormat.Png);
+ bm.Dispose();
+ return fileName;
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ return null;
+ }
+ }
+
+ internal static void PrepareScreenCapture()
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ if (!MouseDown && Common.SendMessageToHelper(0x401, IntPtr.Zero, IntPtr.Zero) > 0)
+ {
+ Common.MMSleep(0.2);
+ InputSimulation.SendKey(new KEYBDDATA() { wVk = (int)VK.SNAPSHOT });
+ InputSimulation.SendKey(new KEYBDDATA() { dwFlags = (int)Common.LLKHF.UP, wVk = (int)VK.SNAPSHOT });
+
+ Common.LogDebug("PrepareScreenCapture: SNAPSHOT simulated.");
+
+ _ = NativeMethods.MoveWindow(
+ (IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT),
+ Common.DesktopBounds.Left,
+ Common.DesktopBounds.Top,
+ Common.DesktopBounds.Right - Common.DesktopBounds.Left,
+ Common.DesktopBounds.Bottom - Common.DesktopBounds.Top,
+ false);
+
+ _ = Common.SendMessageToHelper(0x406, IntPtr.Zero, IntPtr.Zero, false);
+ }
+ else
+ {
+ Common.Log("PrepareScreenCapture: Validation failed.");
+ }
+ });
+ }
+
+ internal static void OpenImage(string file)
+ {
+ // We want to run mspaint under the user account who ran explorer.exe (who logged in this current input desktop)
+
+ // ImpersonateLoggedOnUserAndDoSomething(delegate()
+ // {
+ // Process.Start("explorer", "\"" + file + "\"");
+ // });
+ _ = CreateProcessInInputDesktopSession(
+ "\"" + Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe") +
+ "\"",
+ "\"" + file + "\"",
+ GetInputDesktop(),
+ 1);
+
+ // CreateNormalIntegrityProcess(Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe") +
+ // " \"" + file + "\"");
+
+ // We don't want to run mspaint as local system account
+ /*
+ ProcessStartInfo s = new ProcessStartInfo(
+ Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe"),
+ "\"" + file + "\"");
+ s.WindowStyle = ProcessWindowStyle.Maximized;
+ Process.Start(s);
+ * */
+ }
+
+ internal static void SendImage(string machine, string file)
+ {
+ LastDragDropFile = file;
+
+ // Send ClipboardCapture
+ if (machine.Equals("All", StringComparison.OrdinalIgnoreCase))
+ {
+ SendPackage(ID.ALL, PackageType.ClipboardCapture);
+ }
+ else
+ {
+ ID id = Common.MachinePool.ResolveID(machine);
+ if (id != ID.NONE)
+ {
+ SendPackage(id, PackageType.ClipboardCapture);
+ }
+ }
+ }
+
+ internal static void SendImage(ID src, string file)
+ {
+ LastDragDropFile = file;
+
+ // Send ClipboardCapture
+ SendPackage(src, PackageType.ClipboardCapture);
+ }
+
+ internal static void ShowToolTip(string tip, int timeOutInMilliseconds = 5000, ToolTipIcon icon = ToolTipIcon.Info, bool showBalloonTip = true)
+ {
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ DoSomethingInUIThread(() =>
+ {
+ if (Setting.Values.FirstRun)
+ {
+ Common.Settings?.ShowTip(icon, tip, timeOutInMilliseconds);
+ }
+
+ Common.MatrixForm?.ShowTip(icon, tip, timeOutInMilliseconds);
+
+ if (showBalloonTip)
+ {
+ if (MainForm != null)
+ {
+ MainForm.ShowToolTip(tip, timeOutInMilliseconds);
+ }
+ else
+ {
+ Log(tip);
+ }
+ }
+ });
+ }
+ }
+
+ private static FrmMessage topMostMessageForm;
+
+ internal static void ToggleShowTopMostMessage(string text, string bigText, int timeOut)
+ {
+ DoSomethingInUIThread(() =>
+ {
+ if (topMostMessageForm == null)
+ {
+ topMostMessageForm = new FrmMessage(text, bigText, timeOut);
+ topMostMessageForm.Show();
+ }
+ else
+ {
+ FrmMessage currentMessageForm = topMostMessageForm;
+ topMostMessageForm = null;
+ currentMessageForm.Close();
+ }
+ });
+ }
+
+ internal static void HideTopMostMessage()
+ {
+ DoSomethingInUIThread(() =>
+ {
+ topMostMessageForm?.Close();
+ });
+ }
+
+ internal static void NullTopMostMessage()
+ {
+ DoSomethingInUIThread(() =>
+ {
+ if (topMostMessageForm != null)
+ {
+ topMostMessageForm = null;
+ }
+ });
+ }
+
+ internal static bool IsTopMostMessageNotNull()
+ {
+ return topMostMessageForm != null;
+ }
+
+ private static bool TestSend(TcpSk t)
+ {
+ ID remoteMachineID;
+
+ if (t.Status == SocketStatus.Connected)
+ {
+ try
+ {
+ DATA package = new();
+ package.Type = PackageType.Hi;
+ package.Des = remoteMachineID = (ID)t.MachineId;
+ package.MachineName = MachineName;
+
+ _ = Sk.TcpSend(t, package);
+ t.EncryptedStream?.Flush();
+
+ return true;
+ }
+ catch (ExpectedSocketException)
+ {
+ t.BackingSocket = null; // To be removed at CloseAnUnusedSocket()
+ }
+ }
+
+ t.Status = SocketStatus.SendError;
+ return false;
+ }
+
+ internal static bool IsConnectedTo(ID remoteMachineID)
+ {
+ bool updateClientSockets = false;
+
+ if (remoteMachineID == MachineID)
+ {
+ return true;
+ }
+
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ if (sk.TcpSockets != null)
+ {
+ foreach (TcpSk t in sk.TcpSockets)
+ {
+ if (t.Status == SocketStatus.Connected && (uint)remoteMachineID == t.MachineId)
+ {
+ if (TestSend(t))
+ {
+ return true;
+ }
+ else
+ {
+ updateClientSockets = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (updateClientSockets)
+ {
+ UpdateClientSockets(nameof(IsConnectedTo));
+ }
+
+ return false;
+ }
+
+#if DEBUG
+ private static long minSendTime = long.MaxValue;
+ private static long avgSendTime;
+ private static long maxSendTime;
+ private static long totalSendCount;
+ private static long totalSendTime;
+#endif
+
+ internal static void SkSend(DATA data, uint? exceptDes, bool includeHandShakingSockets)
+ {
+ bool connected = false;
+
+ SocketStuff sk = Sk;
+
+ if (sk != null)
+ {
+#if DEBUG
+ long startStop = DateTime.Now.Ticks;
+ totalSendCount++;
+#endif
+
+ try
+ {
+ data.Id = Interlocked.Increment(ref PackageID);
+
+ bool updateClientSockets = false;
+
+ lock (sk.TcpSocketsLock)
+ {
+ foreach (TcpSk t in sk.TcpSockets)
+ {
+ if (t != null && t.BackingSocket != null && (t.Status == SocketStatus.Connected || (t.Status == SocketStatus.Handshaking && includeHandShakingSockets)))
+ {
+ if (t.MachineId == (uint)data.Des || (data.Des == ID.ALL && t.MachineId != exceptDes && InMachineMatrix(t.MachineName)))
+ {
+ try
+ {
+ sk.TcpSend(t, data);
+
+ if (data.Des != ID.ALL)
+ {
+ connected = true;
+ }
+ }
+ catch (ExpectedSocketException)
+ {
+ t.BackingSocket = null; // To be removed at CloseAnUnusedSocket()
+ updateClientSockets = true;
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ t.BackingSocket = null; // To be removed at CloseAnUnusedSocket()
+ updateClientSockets = true;
+ }
+ }
+ }
+ }
+ }
+
+ if (!connected && data.Des != ID.ALL)
+ {
+ LogDebug("********** No active connection found for the remote machine! **********" + data.Des.ToString());
+
+ if (data.Des == ID.NONE || RemoveDeadMachines(data.Des))
+ {
+ // SwitchToMachine(MachineName.Trim());
+ NewDesMachineID = DesMachineID = MachineID;
+ SwitchLocation.X = XY_BY_PIXEL + myLastX;
+ SwitchLocation.Y = XY_BY_PIXEL + myLastY;
+ SwitchLocation.ResetCount();
+ EvSwitch.Set();
+ }
+ }
+
+ if (updateClientSockets)
+ {
+ UpdateClientSockets("SkSend");
+ }
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+
+#if DEBUG
+ startStop = DateTime.Now.Ticks - startStop;
+ totalSendTime += startStop;
+ if (startStop < minSendTime)
+ {
+ minSendTime = startStop;
+ }
+
+ if (startStop > maxSendTime)
+ {
+ maxSendTime = startStop;
+ }
+
+ avgSendTime = totalSendTime / totalSendCount;
+#endif
+ }
+ else
+ {
+ PackageSent.Nil++;
+ }
+ }
+
+ internal static void CloseAnUnusedSocket()
+ {
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ if (sk.TcpSockets != null)
+ {
+ TcpSk tobeRemoved = null;
+
+ foreach (TcpSk t in sk.TcpSockets)
+ {
+ if ((t.Status != SocketStatus.Connected && t.BirthTime < GetTick() - SocketStuff.CONNECT_TIMEOUT) || t.BackingSocket == null)
+ {
+ LogDebug("CloseAnUnusedSocket: " + t.MachineName + ":" + t.MachineId + "|" + t.Status.ToString());
+ tobeRemoved = t;
+
+ if (t.BackingSocket != null)
+ {
+ try
+ {
+ t.BackingSocket.Close();
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+ }
+
+ break; // Each time we try to remove one socket only.
+ }
+ }
+
+ if (tobeRemoved != null)
+ {
+ _ = sk.TcpSockets.Remove(tobeRemoved);
+ }
+ }
+ }
+ }
+ }
+
+ internal static bool AtLeastOneSocketConnected()
+ {
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ if (sk.TcpSockets != null)
+ {
+ foreach (TcpSk t in sk.TcpSockets)
+ {
+ if (t.Status == SocketStatus.Connected)
+ {
+ LogDebug("AtLeastOneSocketConnected returning true: " + t.MachineName);
+ return true;
+ }
+ }
+ }
+ }
+ }
+
+ LogDebug("AtLeastOneSocketConnected returning false.");
+ return false;
+ }
+
+ internal static Socket AtLeastOneServerSocketConnected()
+ {
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ if (sk.TcpSockets != null)
+ {
+ foreach (TcpSk t in sk.TcpSockets)
+ {
+ if (!t.IsClient && t.Status == SocketStatus.Connected)
+ {
+ LogDebug("AtLeastOneServerSocketConnected returning true: " + t.MachineName);
+ return t.BackingSocket;
+ }
+ }
+ }
+ }
+ }
+
+ LogDebug("AtLeastOneServerSocketConnected returning false.");
+ return null;
+ }
+
+ internal static TcpSk GetConnectedClientSocket()
+ {
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ return sk.TcpSockets?.FirstOrDefault(item => item.IsClient && item.Status == SocketStatus.Connected);
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ internal static bool AtLeastOneSocketEstablished()
+ {
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ if (sk.TcpSockets != null)
+ {
+ foreach (TcpSk t in sk.TcpSockets)
+ {
+ if (t.BackingSocket != null && t.BackingSocket.Connected)
+ {
+ if (TestSend(t))
+ {
+ LogDebug($"{nameof(AtLeastOneSocketEstablished)} returning true: {t.MachineName}");
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ LogDebug($"{nameof(AtLeastOneSocketEstablished)} returning false.");
+ return false;
+ }
+
+ internal static bool IsConnectedByAClientSocketTo(string machineName)
+ {
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ foreach (TcpSk t in sk.TcpSockets)
+ {
+ if (t != null && t.IsClient && t.Status == SocketStatus.Connected
+ && t.BackingSocket != null && t.MachineName.Equals(machineName, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ internal static IPAddress GetConnectedClientSocketIPAddressFor(string machineName)
+ {
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ return sk.TcpSockets.FirstOrDefault(t => t != null && t.IsClient && t.Status == SocketStatus.Connected
+ && t.Address != null && t.MachineName.Equals(machineName, StringComparison.OrdinalIgnoreCase))
+ ?.Address;
+ }
+ }
+
+ return null;
+ }
+
+ internal static bool IsConnectingByAClientSocketTo(string machineName, IPAddress ip)
+ {
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ foreach (TcpSk t in sk.TcpSockets)
+ {
+ if (t != null && t.IsClient && t.Status == SocketStatus.Connecting
+ && t.BackingSocket != null && t.MachineName.Equals(machineName, StringComparison.OrdinalIgnoreCase)
+ && t.Address.ToString().Equals(ip.ToString(), StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ internal static void UpdateSetupMachineMatrix(string desMachine)
+ {
+ int machineCt = 0;
+
+ foreach (string m in Common.MachineMatrix)
+ {
+ if (!string.IsNullOrEmpty(m.Trim()))
+ {
+ machineCt++;
+ }
+ }
+
+ if (machineCt < 2 && Common.Settings != null && (Common.Settings.GetCurrentPage() is SetupPage1 || Common.Settings.GetCurrentPage() is SetupPage2b))
+ {
+ Common.MachineMatrix = new string[Common.MAX_MACHINE] { Common.MachineName.Trim(), desMachine, string.Empty, string.Empty };
+ Common.LogDebug("UpdateSetupMachineMatrix: " + string.Join(",", Common.MachineMatrix));
+
+ Common.DoSomethingInUIThread(
+ () =>
+ {
+ Common.Settings.SetControlPage(new SetupPage4());
+ },
+ true);
+ }
+ }
+
+ internal static void ReopenSockets(bool byUser)
+ {
+ DoSomethingInUIThread(
+ () =>
+ {
+ try
+ {
+ SocketStuff tmpSk = Sk;
+
+ if (tmpSk != null)
+ {
+ Sk = null; // TODO: This looks redundant.
+ tmpSk.Close(byUser);
+ }
+
+ Sk = new SocketStuff(tcpPort, byUser);
+ }
+ catch (Exception e)
+ {
+ Sk = null;
+ Log(e);
+ }
+
+ if (Sk != null)
+ {
+ if (byUser)
+ {
+ SocketStuff.ClearBadIPs();
+ }
+
+ UpdateClientSockets("ReopenSockets");
+ }
+ },
+ true);
+
+ if (Sk == null)
+ {
+ return;
+ }
+
+ Common.DoSomethingInTheInputCallbackThread(() =>
+ {
+ if (Common.Hook != null)
+ {
+ Common.Hook.Stop();
+ Common.Hook = null;
+ }
+
+ if (byUser)
+ {
+ Common.InputCallbackForm.Close();
+ Common.InputCallbackForm = null;
+ Program.StartInputCallbackThread();
+ }
+ else
+ {
+ Common.InputCallbackForm.InstallKeyboardAndMouseHook();
+ }
+ });
+ }
+
+ private static string GetMyStorageDir()
+ {
+ string st = string.Empty;
+
+ try
+ {
+ if (RunOnLogonDesktop || RunOnScrSaverDesktop)
+ {
+ st = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
+ if (!Directory.Exists(st))
+ {
+ _ = Directory.CreateDirectory(st);
+ }
+
+ st += @"\" + Common.BinaryName;
+ if (!Directory.Exists(st))
+ {
+ _ = Directory.CreateDirectory(st);
+ }
+
+ st += @"\ScreenCaptures\";
+ if (!Directory.Exists(st))
+ {
+ _ = Directory.CreateDirectory(st);
+ }
+ }
+ else
+ {
+ _ = ImpersonateLoggedOnUserAndDoSomething(() =>
+ {
+ st = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\" + Common.BinaryName;
+ if (!Directory.Exists(st))
+ {
+ _ = Directory.CreateDirectory(st);
+ }
+
+ st += @"\ScreenCaptures\";
+ if (!Directory.Exists(st))
+ {
+ _ = Directory.CreateDirectory(st);
+ }
+ });
+ }
+
+ LogDebug("GetMyStorageDir: " + st);
+
+ // Delete old files.
+ foreach (FileInfo fi in new DirectoryInfo(st).GetFiles())
+ {
+ if (fi.CreationTime.AddDays(1) < DateTime.Now)
+ {
+ fi.Delete();
+ }
+ }
+
+ return st;
+ }
+ catch (Exception e)
+ {
+ Log(e);
+
+ if (string.IsNullOrEmpty(st) || !st.Contains(Common.BinaryName))
+ {
+ st = Path.GetTempPath();
+ }
+
+ return st;
+ }
+ }
+
+ internal static void GetMachineName()
+ {
+ string machine_Name = string.Empty;
+
+ try
+ {
+ machine_Name = Dns.GetHostName();
+ LogDebug("GetHostName = " + machine_Name);
+ }
+ catch (Exception e)
+ {
+ Log(e);
+
+ if (string.IsNullOrEmpty(machine_Name))
+ {
+ machine_Name = "RANDOM" + Ran.Next().ToString(CultureInfo.CurrentCulture);
+ }
+ }
+
+ if (machine_Name.Length > 32)
+ {
+ machine_Name = machine_Name[..32];
+ }
+
+ Common.MachineName = machine_Name.Trim();
+
+ LogDebug($"========== {nameof(GetMachineName)} ended!");
+ }
+
+ private static string GetNetworkName(NetworkInterface networkInterface)
+ {
+ return $"{networkInterface.Name} | {networkInterface.Description.Replace(":", "-")}";
+ }
+
+ internal static string GetRemoteStringIP(Socket s, bool throwException = false)
+ {
+ if (s == null)
+ {
+ return string.Empty;
+ }
+
+ string ip;
+
+ try
+ {
+ ip = (s?.RemoteEndPoint as IPEndPoint)?.Address?.ToString();
+
+ if (string.IsNullOrEmpty(ip))
+ {
+ return string.Empty;
+ }
+ }
+ catch (ObjectDisposedException e)
+ {
+ Log($"{nameof(GetRemoteStringIP)}: The socket could have been disposed by other threads, error: {e.Message}");
+
+ if (throwException)
+ {
+ throw;
+ }
+
+ return string.Empty;
+ }
+ catch (SocketException e)
+ {
+ Log($"{nameof(GetRemoteStringIP)}: {e.Message}");
+
+ if (throwException)
+ {
+ throw;
+ }
+
+ return string.Empty;
+ }
+
+ return ip;
+ }
+
+ internal static void CloseAllFormsAndHooks()
+ {
+ if (Hook != null)
+ {
+ Hook.Stop();
+ Hook = null;
+ if (InputCallbackForm != null)
+ {
+ DoSomethingInTheInputCallbackThread(() =>
+ {
+ InputCallbackForm.Close();
+ InputCallbackForm = null;
+ });
+ }
+ }
+
+ if (MainForm != null)
+ {
+ MainForm.Destroy();
+ MainForm = null;
+ }
+
+ if (MatrixForm != null)
+ {
+ MatrixForm.Close();
+ MatrixForm = null;
+ }
+
+ if (AboutForm != null)
+ {
+ AboutForm.Close();
+ AboutForm = null;
+ }
+ }
+
+ internal static void MoveMouseToCenter()
+ {
+ LogDebug("+++++ MoveMouseToCenter");
+ InputSimulation.MoveMouse(
+ Common.PrimaryScreenBounds.Left + ((Common.PrimaryScreenBounds.Right - Common.PrimaryScreenBounds.Left) / 2),
+ Common.PrimaryScreenBounds.Top + ((Common.PrimaryScreenBounds.Bottom - Common.PrimaryScreenBounds.Top) / 2));
+ }
+
+ internal static void HideMouseCursor(bool byHideMouseMessage)
+ {
+ Common.LastPos = new Point(
+ Common.PrimaryScreenBounds.Left + ((Common.PrimaryScreenBounds.Right - Common.PrimaryScreenBounds.Left) / 2),
+ Setting.Values.HideMouse ? 4 : Common.PrimaryScreenBounds.Top + ((Common.PrimaryScreenBounds.Bottom - Common.PrimaryScreenBounds.Top) / 2));
+
+ if ((desMachineID != MachineID && desMachineID != ID.ALL) || byHideMouseMessage)
+ {
+ _ = NativeMethods.SetCursorPos(Common.LastPos.X, Common.LastPos.Y);
+ _ = NativeMethods.GetCursorPos(ref Common.lastPos);
+ LogDebug($"+++++ HideMouseCursor, byHideMouseMessage = {byHideMouseMessage}");
+ }
+
+ CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue);
+ }
+
+ internal static string GetText(IntPtr hWnd)
+ {
+ int length = NativeMethods.GetWindowTextLength(hWnd);
+ StringBuilder sb = new(length + 1);
+ int rv = NativeMethods.GetWindowText(hWnd, sb, sb.Capacity);
+ LogDebug("GetWindowText returned " + rv.ToString(CultureInfo.CurrentCulture));
+ return sb.ToString();
+ }
+
+ public static string GetWindowClassName(IntPtr hWnd)
+ {
+ StringBuilder buffer = new(128);
+ _ = NativeMethods.GetClassName(hWnd, buffer, buffer.Capacity);
+ return buffer.ToString();
+ }
+
+ internal static void MMSleep(double secs)
+ {
+ for (int i = 0; i < secs * 10; i++)
+ {
+ Application.DoEvents();
+ Thread.Sleep(100);
+ }
+ }
+
+ internal static void UpdateMultipleModeIconAndMenu()
+ {
+ MainForm?.UpdateMultipleModeIconAndMenu();
+ }
+
+ internal static void SendOrReceiveARandomDataBlockPerInitialIV(Stream st, bool send = true)
+ {
+ byte[] ranData = new byte[SymAlBlockSize];
+
+ try
+ {
+ if (send)
+ {
+ ranData = RandomNumberGenerator.GetBytes(SymAlBlockSize);
+ st.Write(ranData, 0, ranData.Length);
+ }
+ else
+ {
+ int toRead = ranData.Length;
+ int read = st.ReadEx(ranData, 0, toRead);
+
+ if (read != toRead)
+ {
+ Common.LogDebug("Stream has no more data after reading {0} bytes.", read);
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ string log = $"{nameof(SendOrReceiveARandomDataBlockPerInitialIV)}: Exception {(send ? "writing" : "reading")} to the socket stream: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Common.Log(log);
+
+ if (e.InnerException is not (SocketException or ObjectDisposedException))
+ {
+ throw;
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/CustomCursor.cs b/src/modules/MouseWithoutBorders/App/Class/CustomCursor.cs
new file mode 100644
index 000000000000..d1e56f7f8a04
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/CustomCursor.cs
@@ -0,0 +1,150 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Create a customed cursor.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+
+// Disable the warning to preserve original code
+#pragma warning disable CA1716
+namespace MouseWithoutBorders.Class
+#pragma warning restore CA1716
+{
+ internal struct IconInfo
+ {
+ // Suppress warning to match COM names
+ #pragma warning disable SA1307
+ internal bool fIcon;
+ internal int xHotspot;
+ internal int yHotspot;
+ internal IntPtr hbmMask;
+ internal IntPtr hbmColor;
+ #pragma warning restore SA1307
+ }
+
+ internal class CustomCursor
+ {
+ private CustomCursor()
+ {
+ }
+
+ internal static Cursor CreateCursor(Bitmap bmp, int xHotSpot, int yHotSpot)
+ {
+ IconInfo tmp = default;
+ tmp.xHotspot = xHotSpot;
+ tmp.yHotspot = yHotSpot;
+ tmp.fIcon = false;
+
+ // GetIconInfo(bmp.GetHicon(), ref tmp);
+ tmp.hbmColor = bmp.GetHbitmap();
+ tmp.hbmMask = bmp.GetHbitmap();
+ return new Cursor(NativeMethods.CreateIconIndirect(ref tmp));
+ }
+
+ internal static Cursor CreateDotCursor()
+ {
+ Bitmap bitmap = new(32, 32, PixelFormat.Format24bppRgb);
+ bitmap.MakeTransparent(Color.Black);
+ Graphics g = Graphics.FromImage(bitmap);
+ g.DrawLine(Pens.Gray, 0, 0, 1, 1);
+ Cursor c = CreateCursor(bitmap, 0, 0);
+ bitmap.Dispose();
+ return c;
+ }
+
+ private static int hiding;
+ private static NativeMethods.CURSORINFO ci;
+
+ internal static void ShowFakeMouseCursor(int x, int y)
+ {
+ if (Setting.Values.DrawMouse)
+ {
+ ci.cbSize = Marshal.SizeOf(typeof(NativeMethods.CURSORINFO));
+ _ = NativeMethods.GetCursorInfo(out ci);
+
+ // The cursor is hidden or suppressed.q
+ if (ci.flags != 1)
+ {
+ Common.DoSomethingInTheInputCallbackThread(
+ () =>
+ {
+ Common.MouseCursorForm ??= new FrmMouseCursor();
+
+ try
+ {
+ Common.MouseCursorForm.Text = string.Empty;
+
+ if (x == int.MinValue || y == int.MinValue)
+ {
+ hiding = 3;
+ }
+
+ if (hiding > 0)
+ {
+ hiding--;
+
+ Common.MouseCursorForm.Hide();
+ }
+ else
+ {
+ Common.MouseCursorForm.Left = x + 1;
+ Common.MouseCursorForm.Top = y + 1;
+ Common.MouseCursorForm.Width = Common.MouseCursorForm.Height = 32;
+ Common.MouseCursorForm.TopMost = true;
+ Common.MouseCursorForm.Show();
+ }
+ }
+ catch (NullReferenceException)
+ {
+ Common.Log($"{nameof(Common.MouseCursorForm)} has been set to null by another thread.");
+ Common.MouseCursorForm = new FrmMouseCursor();
+ }
+ catch (ObjectDisposedException)
+ {
+ Common.Log($"{nameof(Common.MouseCursorForm)} has been disposed.");
+ Common.MouseCursorForm = new FrmMouseCursor();
+ }
+ },
+ false);
+
+ return;
+ }
+ }
+
+ Common.DoSomethingInTheInputCallbackThread(
+ () =>
+ {
+ if (Common.MouseCursorForm != null)
+ {
+ try
+ {
+ Common.MouseCursorForm.Close();
+ Common.MouseCursorForm.Dispose();
+ }
+ catch (NullReferenceException)
+ {
+ Common.Log($"{nameof(Common.MouseCursorForm)} has already been set to null by another thread!");
+ }
+ catch (ObjectDisposedException)
+ {
+ Common.Log($"{nameof(Common.MouseCursorForm)} has already been disposed!");
+ }
+
+ Common.MouseCursorForm = null;
+ }
+ },
+ false);
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/EasyMouseOption.cs b/src/modules/MouseWithoutBorders/App/Class/EasyMouseOption.cs
new file mode 100644
index 000000000000..8ce223260a20
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/EasyMouseOption.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace MouseWithoutBorders.Class
+{
+ internal enum EasyMouseOption : int
+ {
+ Disable = 0,
+ Enable = 1,
+ Ctrl = 2,
+ Shift = 3,
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Extensions.cs b/src/modules/MouseWithoutBorders/App/Class/Extensions.cs
new file mode 100644
index 000000000000..e199a5797ccb
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Extensions.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.ComponentModel;
+using System.Diagnostics;
+using System.IO;
+
+namespace MouseWithoutBorders.Class
+{
+ internal static class Extensions
+ {
+ internal static int ReadEx(this Stream st, byte[] buf, int bufIndex, int length)
+ {
+ int bytesReceived = st.Read(buf, bufIndex, length);
+
+ int receivedCount = bytesReceived;
+
+ while (receivedCount != 0 && bytesReceived < length)
+ {
+ bytesReceived += receivedCount = st.Read(buf, bufIndex + bytesReceived, length - bytesReceived);
+ }
+
+ return bytesReceived;
+ }
+
+ internal static void KillProcess(this Process process, bool keepTrying = false)
+ {
+ string processName = process.ProcessName;
+ int processId = process.Id;
+
+ do
+ {
+ try
+ {
+ process.Kill();
+ break;
+ }
+ catch (Win32Exception e)
+ {
+ string log = $"The process {processName} (PID={processId}) could not be terminated, error: {e.Message}";
+ Common.TelemetryLogTrace(log, SeverityLevel.Error);
+ Common.ShowToolTip(log, 5000);
+
+ if (!keepTrying)
+ {
+ Thread.Sleep(1000);
+ break;
+ }
+ }
+ }
+ while (true);
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs b/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs
new file mode 100644
index 000000000000..321cc2f0b196
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/IClipboardHelper.cs
@@ -0,0 +1,636 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.IO.Pipes;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Security.AccessControl;
+using System.Security.Principal;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Microsoft.VisualStudio.Threading;
+using Newtonsoft.Json;
+using StreamJsonRpc;
+
+#if !MM_HELPER
+using MouseWithoutBorders.Class;
+#endif
+using SystemClipboard = System.Windows.Forms.Clipboard;
+
+namespace MouseWithoutBorders
+{
+ [JsonObject(MemberSerialization.OptIn)]
+ public struct ByteArrayOrString
+ {
+ private enum ValueType
+ {
+ ByteArray,
+ String,
+ }
+
+ [JsonProperty]
+ private ValueType _type;
+
+ private byte[] _byteArrayValue;
+ private string _stringValue;
+
+ public ByteArrayOrString(byte[] byteArray)
+ {
+ _type = ValueType.ByteArray;
+ _byteArrayValue = byteArray;
+ _stringValue = null;
+ }
+
+ public ByteArrayOrString(string str)
+ {
+ _type = ValueType.String;
+ _byteArrayValue = null;
+ _stringValue = str;
+ }
+
+ public bool IsByteArray => _type == ValueType.ByteArray;
+
+ public bool IsString => _type == ValueType.String;
+
+ [JsonProperty("byteArray")]
+ public byte[] ByteArray
+ {
+ get => _byteArrayValue;
+ set
+ {
+ _byteArrayValue = value;
+ _type = ValueType.ByteArray;
+ }
+ }
+
+ [JsonProperty("string")]
+ public string TheString
+ {
+ get => _stringValue;
+ set
+ {
+ _stringValue = value;
+ _type = ValueType.String;
+ }
+ }
+
+ public bool ShouldSerializeByteArray() => IsByteArray;
+
+ public bool ShouldSerializeString() => IsString;
+
+ public byte[] GetByteArray()
+ {
+ if (IsByteArray)
+ {
+ return _byteArrayValue;
+ }
+
+ throw new InvalidOperationException("The value is not a byte array.");
+ }
+
+ public string GetString()
+ {
+ if (IsString)
+ {
+ return _stringValue;
+ }
+
+ throw new InvalidOperationException("The value is not a string.");
+ }
+
+ public static implicit operator ByteArrayOrString(byte[] byteArray) => new ByteArrayOrString(byteArray);
+
+ public static implicit operator ByteArrayOrString(string str) => new ByteArrayOrString(str);
+ }
+
+ public interface IClipboardHelper
+ {
+ void SendLog(string log);
+
+ void SendDragFile(string fileName);
+
+ void SendClipboardData(ByteArrayOrString data, bool isFilePath);
+ }
+
+#if !MM_HELPER
+ public class ClipboardHelper : IClipboardHelper
+ {
+ public void SendLog(string log)
+ {
+ Common.LogDebug("FROM HELPER: " + log);
+
+ if (!string.IsNullOrEmpty(log))
+ {
+ if (log.StartsWith("Screen capture ended", StringComparison.InvariantCulture))
+ {
+ /* TODO: Telemetry for screen capture. */
+
+ if (Setting.Values.FirstCtrlShiftS)
+ {
+ Setting.Values.FirstCtrlShiftS = false;
+ Common.ShowToolTip("Selective screen capture has been triggered, you can change the hotkey on the Settings form.", 10000);
+ }
+ }
+ else if (log.StartsWith("Trace:", StringComparison.InvariantCulture))
+ {
+ Common.TelemetryLogTrace(log, SeverityLevel.Information);
+ }
+ }
+ }
+
+ public void SendDragFile(string fileName)
+ {
+ Common.DragDropStep05Ex(fileName);
+ }
+
+ public void SendClipboardData(ByteArrayOrString data, bool isFilePath)
+ {
+ _ = Common.CheckClipboardEx(data, isFilePath);
+ }
+ }
+#endif
+
+ internal sealed class IpcChannel
+ where T : new()
+ {
+ public static T StartIpcServer(string pipeName, CancellationToken cancellationToken)
+ {
+ SecurityIdentifier securityIdentifier = new SecurityIdentifier(
+WellKnownSidType.AuthenticatedUserSid, null);
+
+ PipeSecurity pipeSecurity = new PipeSecurity();
+ pipeSecurity.AddAccessRule(new PipeAccessRule(
+ securityIdentifier,
+ PipeAccessRights.ReadWrite | PipeAccessRights.CreateNewInstance,
+ AccessControlType.Allow));
+
+ _ = Task.Factory.StartNew(
+ async () =>
+ {
+ try
+ {
+ while (!cancellationToken.IsCancellationRequested)
+ {
+ using (var serverChannel = NamedPipeServerStreamAcl.Create(pipeName, PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances, PipeTransmissionMode.Byte, PipeOptions.Asynchronous, 0, 0, pipeSecurity))
+ {
+ await serverChannel.WaitForConnectionAsync();
+ var taskRpc = JsonRpc.Attach(serverChannel, new T());
+ await taskRpc.Completion;
+ }
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ }
+ catch (Exception e)
+ {
+#if MM_HELPER
+ _ = e;
+#else
+ Common.Log(e);
+#endif
+ }
+ },
+ cancellationToken,
+ TaskCreationOptions.None,
+ TaskScheduler.Default);
+
+ return default(T);
+ }
+ }
+
+ internal sealed class IpcHelper
+ {
+ private const string ChannelName = "MouseWithoutBorders";
+ private const string RemoteObjectName = "ClipboardHelper";
+
+#if !MM_HELPER
+ private static void CleanupStream()
+ {
+ if (_serverTaskCancellationSource != null)
+ {
+ _serverTaskCancellationSource.Cancel();
+ _serverTaskCancellationSource.Dispose();
+ _serverTaskCancellationSource = null;
+ }
+ }
+
+ private static CancellationTokenSource _serverTaskCancellationSource;
+
+ internal static void CreateIpcServer(bool cleanup)
+ {
+ try
+ {
+ if (cleanup)
+ {
+ CleanupStream();
+ return;
+ }
+
+ _serverTaskCancellationSource = new CancellationTokenSource();
+ CancellationToken cancellationToken = _serverTaskCancellationSource.Token;
+
+ IpcChannel.StartIpcServer(ChannelName + "/" + RemoteObjectName, cancellationToken);
+ Common.IpcChannelCreated = true;
+ }
+ catch (Exception e)
+ {
+ Common.IpcChannelCreated = false;
+ Common.ShowToolTip("Error setting up clipboard sharing, clipboard sharing will not work!", 5000, ToolTipIcon.Error);
+ Common.Log(e);
+ }
+ }
+#else
+ internal static IClipboardHelper CreateIpcClient()
+ {
+ try
+ {
+ var stream = new NamedPipeClientStream(".", ChannelName + "/" + RemoteObjectName, PipeDirection.InOut, PipeOptions.Asynchronous);
+
+ stream.Connect();
+
+ return JsonRpc.Attach(stream);
+ }
+ catch (Exception e)
+ {
+ Logger.LogEvent(e.Message, EventLogEntryType.Error);
+ }
+
+ return null;
+ }
+#endif
+
+ }
+
+ internal static class Logger
+ {
+#if MM_HELPER
+ private const string EventSourceName = "MouseWithoutBordersHelper";
+#else
+ private const string EventSourceName = "MouseWithoutBorders";
+#endif
+
+ internal static void LogEvent(string message, EventLogEntryType logType = EventLogEntryType.Information)
+ {
+ try
+ {
+ if (!EventLog.SourceExists(EventSourceName))
+ {
+ EventLog.CreateEventSource(EventSourceName, "Application");
+ }
+
+ EventLog.WriteEntry(EventSourceName, message, logType);
+ }
+ catch (Exception e)
+ {
+ Debug.WriteLine(message + ": " + e.Message);
+ }
+ }
+ }
+#if MM_HELPER
+
+ internal static class ClipboardMMHelper
+ {
+ internal static IntPtr NextClipboardViewer = IntPtr.Zero;
+ private static FormHelper helperForm;
+ private static bool addClipboardFormatListenerResult;
+
+ private static void Log(string log)
+ {
+ helperForm.SendLog(log);
+ }
+
+ private static void Log(Exception e)
+ {
+ Log($"Trace: {e}");
+ }
+
+ internal static void HookClipboard(FormHelper f)
+ {
+ helperForm = f;
+
+ try
+ {
+ addClipboardFormatListenerResult = NativeMethods.AddClipboardFormatListener(f.Handle);
+
+ int err = addClipboardFormatListenerResult ? 0 : Marshal.GetLastWin32Error();
+
+ if (err != 0)
+ {
+ Log($"Trace: {nameof(NativeMethods.AddClipboardFormatListener)}: GetLastError = {err}");
+ }
+ }
+ catch (EntryPointNotFoundException e)
+ {
+ Log($"{nameof(NativeMethods.AddClipboardFormatListener)} is unavailable in this version of Windows.");
+ Log(e);
+ }
+ catch (Exception e)
+ {
+ Log(e);
+ }
+
+ // Fallback
+ if (!addClipboardFormatListenerResult)
+ {
+ NextClipboardViewer = NativeMethods.SetClipboardViewer(f.Handle);
+ int err = NextClipboardViewer == IntPtr.Zero ? Marshal.GetLastWin32Error() : 0;
+
+ if (err != 0)
+ {
+ Log($"Trace: {nameof(NativeMethods.SetClipboardViewer)}: GetLastError = {err}");
+ }
+ }
+
+ Log($"Trace: Clipboard monitor method {(addClipboardFormatListenerResult ? nameof(NativeMethods.AddClipboardFormatListener) : NextClipboardViewer != IntPtr.Zero ? nameof(NativeMethods.SetClipboardViewer) : "(none)")} is used.");
+ }
+
+ internal static void UnhookClipboard()
+ {
+ if (addClipboardFormatListenerResult)
+ {
+ addClipboardFormatListenerResult = false;
+ _ = NativeMethods.RemoveClipboardFormatListener(helperForm.Handle);
+ }
+ else
+ {
+ _ = NativeMethods.ChangeClipboardChain(helperForm.Handle, NextClipboardViewer);
+ NextClipboardViewer = IntPtr.Zero;
+ }
+ }
+
+ private static void ReHookClipboard()
+ {
+ UnhookClipboard();
+ HookClipboard(helperForm);
+ }
+
+ internal static bool UpdateNextClipboardViewer(Message m)
+ {
+ if (m.WParam == NextClipboardViewer)
+ {
+ NextClipboardViewer = m.LParam;
+ return true;
+ }
+
+ return false;
+ }
+
+ internal static void PassMessageToTheNextViewer(Message m)
+ {
+ if (NextClipboardViewer != IntPtr.Zero && NextClipboardViewer != helperForm.Handle)
+ {
+ _ = NativeMethods.SendMessage(NextClipboardViewer, m.Msg, m.WParam, m.LParam);
+ }
+ }
+
+ public static bool ContainsFileDropList()
+ {
+ bool rv = false;
+
+ try
+ {
+ rv = Common.Retry(nameof(SystemClipboard.ContainsFileDropList), () => { return SystemClipboard.ContainsFileDropList(); }, (log) => Log(log));
+ }
+ catch (ExternalException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (ThreadStateException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+
+ return rv;
+ }
+
+ public static bool ContainsImage()
+ {
+ bool rv = false;
+
+ try
+ {
+ rv = Common.Retry(nameof(SystemClipboard.ContainsImage), () => { return SystemClipboard.ContainsImage(); }, (log) => Log(log));
+ }
+ catch (ExternalException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (ThreadStateException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+
+ return rv;
+ }
+
+ public static bool ContainsText()
+ {
+ bool rv = false;
+
+ try
+ {
+ rv = Common.Retry(nameof(SystemClipboard.ContainsText), () => { return SystemClipboard.ContainsText(); }, (log) => Log(log));
+ }
+ catch (ExternalException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (ThreadStateException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+
+ return rv;
+ }
+
+ public static StringCollection GetFileDropList()
+ {
+ StringCollection rv = null;
+
+ try
+ {
+ rv = Common.Retry(nameof(SystemClipboard.GetFileDropList), () => { return SystemClipboard.GetFileDropList(); }, (log) => Log(log));
+ }
+ catch (ExternalException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (ThreadStateException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+
+ return rv;
+ }
+
+ public static Image GetImage()
+ {
+ Image rv = null;
+
+ try
+ {
+ rv = Common.Retry(nameof(SystemClipboard.GetImage), () => { return SystemClipboard.GetImage(); }, (log) => Log(log));
+ }
+ catch (ExternalException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (ThreadStateException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+
+ return rv;
+ }
+
+ public static string GetText(TextDataFormat format)
+ {
+ string rv = null;
+
+ try
+ {
+ rv = Common.Retry(nameof(SystemClipboard.GetText), () => { return SystemClipboard.GetText(format); }, (log) => Log(log));
+ }
+ catch (ExternalException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (ThreadStateException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (System.ComponentModel.InvalidEnumArgumentException e)
+ {
+ Log(e);
+ }
+
+ return rv;
+ }
+
+ public static void SetImage(Image image)
+ {
+ try
+ {
+ _ = Common.Retry(
+ nameof(SystemClipboard.SetImage),
+ () =>
+ {
+ SystemClipboard.SetImage(image);
+ return true;
+ },
+ (log) => Log(log));
+ }
+ catch (ExternalException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (ThreadStateException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (ArgumentNullException e)
+ {
+ Log(e);
+ }
+ }
+
+ public static void SetText(string text)
+ {
+ try
+ {
+ _ = Common.Retry(
+ nameof(SystemClipboard.SetText),
+ () =>
+ {
+ SystemClipboard.SetText(text);
+ return true;
+ },
+ (log) => Log(log));
+ }
+ catch (ExternalException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (ThreadStateException e)
+ {
+ Log(e);
+ ReHookClipboard();
+ }
+ catch (ArgumentNullException e)
+ {
+ Log(e);
+ }
+ }
+ }
+
+#endif
+
+ internal sealed class SharedConst
+ {
+ internal const int QUIT_CMD = 0x409;
+ }
+
+ internal sealed partial class Common
+ {
+ internal static bool IpcChannelCreated { get; set; }
+
+ internal static T Retry(string name, Func func, Action log, Action preRetry = null)
+ {
+ int count = 0;
+
+ do
+ {
+ try
+ {
+ T rv = func();
+
+ if (count > 0)
+ {
+ log($"Trace: {name} has been successful after {count} retry.");
+ }
+
+ return rv;
+ }
+ catch (Exception)
+ {
+ count++;
+
+ preRetry?.Invoke();
+
+ if (count > 10)
+ {
+ throw;
+ }
+
+ Application.DoEvents();
+ Thread.Sleep(200);
+ }
+ }
+ while (true);
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/InputHook.cs b/src/modules/MouseWithoutBorders/App/Class/InputHook.cs
new file mode 100644
index 000000000000..ed4fc1d76bde
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/InputHook.cs
@@ -0,0 +1,705 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Keyboard/Mouse hook callbacks, pre-process before calling to routines in Common.Event.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Windows.Forms;
+
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.InputHook.#MouseHookProc(System.Int32,System.Int32,System.IntPtr)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Scope = "member", Target = "MouseWithoutBorders.InputHook.#ProcessKeyEx(System.Int32,System.Int32)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.InputHook.#Start()", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders.Class
+{
+ internal class InputHook
+ {
+ internal delegate void MouseEvHandler(MOUSEDATA e, int dx, int dy);
+
+ internal delegate void KeybdEvHandler(KEYBDDATA e);
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct MouseHookStruct
+ {
+ internal NativeMethods.POINT Pt;
+ internal int Hwnd;
+ internal int WHitTestCode;
+ internal int DwExtraInfo;
+ }
+
+ // http://msdn.microsoft.com/en-us/library/ms644970(VS.85).aspx
+ [StructLayout(LayoutKind.Sequential)]
+ private struct MouseLLHookStruct
+ {
+ internal NativeMethods.POINT Pt;
+ internal int MouseData;
+ internal int Flags;
+ internal int Time;
+ internal int DwExtraInfo;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct KeyboardHookStruct
+ {
+ internal int VkCode;
+ internal int ScanCode;
+ internal int Flags;
+ internal int Time;
+ internal int DwExtraInfo;
+ }
+
+ internal event MouseEvHandler MouseEvent;
+
+ internal event KeybdEvHandler KeyboardEvent;
+
+ private int hMouseHook;
+ private int hKeyboardHook;
+ private static NativeMethods.HookProc mouseHookProcedure;
+ private static NativeMethods.HookProc keyboardHookProcedure;
+
+ private static MouseLLHookStruct mouseHookStruct;
+ private static KeyboardHookStruct keyboardHookStruct;
+ private static MOUSEDATA hookCallbackMouseData;
+ private static KEYBDDATA hookCallbackKeybdData;
+
+ private static bool winDown;
+ private static bool altDown;
+ private static bool shiftDown;
+
+ internal static bool RealData { get; set; } = true;
+
+ internal static int SkipMouseUpCount { get; set; }
+
+ internal static bool SkipMouseUpDown { get; set; }
+
+ internal static bool CtrlDown { get; private set; }
+
+ internal static bool EasyMouseKeyDown { get; set; }
+
+ internal InputHook()
+ {
+ Start();
+ }
+
+ ~InputHook()
+ {
+ Stop();
+ }
+
+ internal void Start()
+ {
+ int le;
+ bool er = false;
+
+ // Install Mouse Hook
+ mouseHookProcedure = new NativeMethods.HookProc(MouseHookProc);
+ hMouseHook = NativeMethods.SetWindowsHookEx(
+ Common.WH_MOUSE_LL,
+ mouseHookProcedure,
+ Marshal.GetHINSTANCE(
+ Assembly.GetExecutingAssembly().GetModules()[0]),
+ 0);
+
+ if (hMouseHook == 0)
+ {
+ le = Marshal.GetLastWin32Error();
+ Common.Log("Error installing Mouse hook: " + le.ToString(CultureInfo.CurrentCulture));
+ er = true;
+ Stop();
+ }
+
+ // Install Keyboard Hook
+ keyboardHookProcedure = new NativeMethods.HookProc(KeyboardHookProc);
+ hKeyboardHook = NativeMethods.SetWindowsHookEx(
+ Common.WH_KEYBOARD_LL,
+ keyboardHookProcedure,
+ Marshal.GetHINSTANCE(
+ Assembly.GetExecutingAssembly().GetModules()[0]),
+ 0);
+ if (hKeyboardHook == 0)
+ {
+ le = Marshal.GetLastWin32Error();
+ Common.Log("Error installing keyboard hook: " + le.ToString(CultureInfo.CurrentCulture));
+ er = true;
+ Stop();
+ }
+
+ if (er)
+ {
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ _ = MessageBox.Show(
+ "Error installing keyboard/Mouse hook!",
+ Application.ProductName,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Error);
+ }
+ }
+ else
+ {
+ Common.InitLastInputEventCount();
+ }
+ }
+
+ internal void Stop()
+ {
+ if (hMouseHook != 0)
+ {
+ int retMouse = NativeMethods.UnhookWindowsHookEx(hMouseHook);
+ hMouseHook = 0;
+ if (retMouse == 0)
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+
+ // throw new Win32Exception(errorCode);
+ Common.Log("Exception uninstalling Mouse hook, error code: " + errorCode.ToString(CultureInfo.CurrentCulture));
+ }
+ }
+
+ if (hKeyboardHook != 0)
+ {
+ int retKeyboard = NativeMethods.UnhookWindowsHookEx(hKeyboardHook);
+ hKeyboardHook = 0;
+ if (retKeyboard == 0)
+ {
+ int errorCode = Marshal.GetLastWin32Error();
+
+ // throw new Win32Exception(errorCode);
+ Common.Log("Exception uninstalling keyboard hook, error code: " + errorCode.ToString(CultureInfo.CurrentCulture));
+ }
+ }
+ }
+
+ // Better performance, compared to Marshal.PtrToStructure.
+ private static MouseLLHookStruct LParamToMouseLLHookStruct(IntPtr lParam)
+ {
+ unsafe
+ {
+ return *(MouseLLHookStruct*)lParam;
+ }
+ }
+
+ private static KeyboardHookStruct LParamToKeyboardHookStruct(IntPtr lParam)
+ {
+ unsafe
+ {
+ return *(KeyboardHookStruct*)lParam;
+ }
+ }
+
+ private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
+ {
+ int rv = 1, dx = 0, dy = 0;
+ bool local = false;
+ Common.InputEventCount++;
+
+ try
+ {
+ if (!RealData)
+ {
+ RealData = true;
+
+ // Common.Log("MouseHookProc: Not real data!");
+ // return rv;
+ rv = NativeMethods.CallNextHookEx(hMouseHook, nCode, wParam, lParam);
+ }
+ else
+ {
+ Common.RealInputEventCount++;
+
+ if (Common.NewDesMachineID == Common.MachineID || Common.NewDesMachineID == ID.ALL)
+ {
+ local = true;
+ if (Common.MainFormVisible && !Common.IsDropping)
+ {
+ Common.MainFormDot();
+ }
+ }
+
+ if (nCode >= 0 && MouseEvent != null)
+ {
+ if (wParam == Common.WM_LBUTTONUP && SkipMouseUpCount > 0)
+ {
+ Common.LogDebug($"{nameof(SkipMouseUpCount)}: {SkipMouseUpCount}.");
+ SkipMouseUpCount--;
+ rv = NativeMethods.CallNextHookEx(hMouseHook, nCode, wParam, lParam);
+ return rv;
+ }
+
+ if ((wParam == Common.WM_LBUTTONUP || wParam == Common.WM_LBUTTONDOWN) && SkipMouseUpDown)
+ {
+ rv = NativeMethods.CallNextHookEx(hMouseHook, nCode, wParam, lParam);
+ return rv;
+ }
+
+ mouseHookStruct = LParamToMouseLLHookStruct(lParam);
+ hookCallbackMouseData.dwFlags = wParam;
+
+ // Use WheelDelta to store XBUTTON1/XBUTTON2 data.
+ hookCallbackMouseData.WheelDelta = (short)((mouseHookStruct.MouseData >> 16) & 0xffff);
+
+ if (local)
+ {
+ hookCallbackMouseData.X = mouseHookStruct.Pt.x;
+ hookCallbackMouseData.Y = mouseHookStruct.Pt.y;
+
+ if (Setting.Values.DrawMouse && Common.MouseCursorForm != null)
+ {
+ CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue);
+ }
+ }
+ else
+ {
+ if (Common.SwitchLocation.Count > 0 && Common.NewDesMachineID != Common.MachineID && Common.NewDesMachineID != ID.ALL)
+ {
+ Common.SwitchLocation.Count--;
+
+ if (Common.SwitchLocation.X > Common.XY_BY_PIXEL - 100000 || Common.SwitchLocation.Y > Common.XY_BY_PIXEL - 100000)
+ {
+ hookCallbackMouseData.X = Common.SwitchLocation.X - Common.XY_BY_PIXEL;
+ hookCallbackMouseData.Y = Common.SwitchLocation.Y - Common.XY_BY_PIXEL;
+ }
+ else
+ {
+ hookCallbackMouseData.X = (Common.SwitchLocation.X * Common.ScreenWidth / 65535) + Common.PrimaryScreenBounds.Left;
+ hookCallbackMouseData.Y = (Common.SwitchLocation.Y * Common.ScreenHeight / 65535) + Common.PrimaryScreenBounds.Top;
+ }
+
+ Common.HideMouseCursor(false);
+ }
+ else
+ {
+ dx = mouseHookStruct.Pt.x - Common.LastPos.X;
+ dy = mouseHookStruct.Pt.y - Common.LastPos.Y;
+
+ hookCallbackMouseData.X += dx;
+ hookCallbackMouseData.Y += dy;
+
+ if (hookCallbackMouseData.X < Common.PrimaryScreenBounds.Left)
+ {
+ hookCallbackMouseData.X = Common.PrimaryScreenBounds.Left - 1;
+ }
+ else if (hookCallbackMouseData.X > Common.PrimaryScreenBounds.Right)
+ {
+ hookCallbackMouseData.X = Common.PrimaryScreenBounds.Right + 1;
+ }
+
+ if (hookCallbackMouseData.Y < Common.PrimaryScreenBounds.Top)
+ {
+ hookCallbackMouseData.Y = Common.PrimaryScreenBounds.Top - 1;
+ }
+ else if (hookCallbackMouseData.Y > Common.PrimaryScreenBounds.Bottom)
+ {
+ hookCallbackMouseData.Y = Common.PrimaryScreenBounds.Bottom + 1;
+ }
+
+ dx += dx < 0 ? -Common.MOVE_MOUSE_RELATIVE : Common.MOVE_MOUSE_RELATIVE;
+ dy += dy < 0 ? -Common.MOVE_MOUSE_RELATIVE : Common.MOVE_MOUSE_RELATIVE;
+ }
+ }
+
+ MouseEvent(hookCallbackMouseData, dx, dy);
+
+ Common.DragDropStep01(wParam);
+ Common.DragDropStep09(wParam);
+ }
+
+ if (local)
+ {
+ rv = NativeMethods.CallNextHookEx(hMouseHook, nCode, wParam, lParam);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ rv = NativeMethods.CallNextHookEx(hMouseHook, nCode, wParam, lParam);
+ }
+
+ return rv;
+ }
+
+ private int KeyboardHookProc(int nCode, int wParam, IntPtr lParam)
+ {
+ Common.InputEventCount++;
+ if (!RealData)
+ {
+ return NativeMethods.CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
+ }
+
+ Common.RealInputEventCount++;
+
+ keyboardHookStruct = LParamToKeyboardHookStruct(lParam);
+ hookCallbackKeybdData.dwFlags = keyboardHookStruct.Flags;
+ hookCallbackKeybdData.wVk = (short)keyboardHookStruct.VkCode;
+
+ if (nCode >= 0 && KeyboardEvent != null)
+ {
+ if (!ProcessKeyEx(keyboardHookStruct.VkCode, keyboardHookStruct.Flags, hookCallbackKeybdData))
+ {
+ return 1;
+ }
+
+ KeyboardEvent(hookCallbackKeybdData);
+ }
+
+ if (Common.DesMachineID == ID.NONE || Common.DesMachineID == ID.ALL || Common.DesMachineID == Common.MachineID)
+ {
+ if (nCode >= 0 && Setting.Values.UseVKMap && Setting.Values.VKMap != null && Setting.Values.VKMap.ContainsKey(hookCallbackKeybdData.wVk) && !CtrlDown)
+ {
+ InputSimulation.SendKey(hookCallbackKeybdData);
+ return 1;
+ }
+ else
+ {
+ return NativeMethods.CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
+ }
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ // Returns false if we do not want to redirect the keystrokes to other machine(s).
+ private int ctrlTouchesDnIndex;
+
+ private int ctrlTouchesUpIndex = 1;
+ private const int CONTROL_TOUCH = 4;
+ private readonly long[] ctrlTouches = new long[CONTROL_TOUCH];
+
+ private bool ProcessKeyEx(int vkCode, int flags, KEYBDDATA hookCallbackKeybdData)
+ {
+ bool allTouched;
+
+ if ((flags & (int)Common.LLKHF.UP) == (int)Common.LLKHF.UP)
+ {
+ EasyMouseKeyDown = false;
+
+ switch ((VK)vkCode)
+ {
+ case VK.LWIN:
+ case VK.RWIN:
+ winDown = false;
+ break;
+
+ case VK.LCONTROL:
+ case VK.RCONTROL:
+ CtrlDown = false;
+
+ if (Setting.Values.HotKeySwitch2AllPC == 1)
+ {
+ ctrlTouches[ctrlTouchesUpIndex] = Common.GetTick();
+ ctrlTouchesUpIndex = ((ctrlTouchesUpIndex % CONTROL_TOUCH) + 2) % CONTROL_TOUCH;
+ }
+
+ break;
+
+ case VK.LMENU:
+ case VK.RMENU:
+ altDown = false;
+ break;
+
+ case VK.LSHIFT:
+ shiftDown = false;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ UpdateEasyMouseKeyDown((VK)vkCode);
+
+ switch ((VK)vkCode)
+ {
+ case VK.LWIN:
+ case VK.RWIN:
+ winDown = true;
+ break;
+
+ case VK.LCONTROL:
+ case VK.RCONTROL:
+ Common.LogDebug("VK.RCONTROL");
+ CtrlDown = true;
+
+ if (Setting.Values.HotKeySwitch2AllPC == 1)
+ {
+ ctrlTouches[ctrlTouchesDnIndex] = Common.GetTick();
+ ctrlTouchesDnIndex = (ctrlTouchesDnIndex + 2) % CONTROL_TOUCH;
+ }
+
+ allTouched = true;
+
+ for (int i = 0; i < CONTROL_TOUCH; i++)
+ {
+ if (ctrlTouches[i] == 0 || Common.GetTick() - ctrlTouches[i] > 400)
+ {
+ allTouched = false;
+ break;
+ }
+ }
+
+ if (allTouched && Common.GetTick() - Common.JustGotAKey > 1000)
+ {
+ ResetLastSwitchKeys();
+ Common.SwitchToMultipleMode(Common.DesMachineID != ID.ALL, true);
+ }
+
+ break;
+
+ case VK.LMENU:
+ case VK.RMENU:
+ altDown = true;
+ break;
+
+ case VK.LSHIFT:
+ shiftDown = true;
+ break;
+
+ case VK.DELETE:
+ if (CtrlDown && altDown)
+ {
+ CtrlDown = altDown = false;
+ KeyboardEvent(hookCallbackKeybdData);
+
+ if (Common.DesMachineID != ID.ALL)
+ {
+ Common.SwitchToMachine(Common.MachineName.Trim());
+ }
+
+ /*
+#if CUSTOMIZE_LOGON_SCREEN
+ Common.DoSomethingInUIThread(delegate()
+ {
+ Common.MainForm.LoadNewLogonBackground();
+ });
+#endif
+* */
+ }
+
+ break;
+
+ case (VK)'L':
+ if (winDown)
+ {
+ winDown = false;
+
+ if (Common.DesMachineID != ID.ALL)
+ {
+ KeyboardEvent(hookCallbackKeybdData);
+ Common.SwitchToMachine(Common.MachineName.Trim());
+ }
+ }
+ else
+ {
+ return ProcessHotKeys(vkCode, hookCallbackKeybdData);
+ }
+
+ break;
+
+ case VK.ESCAPE:
+ if (Common.IsTopMostMessageNotNull())
+ {
+ Common.HideTopMostMessage();
+ }
+
+ break;
+
+ default:
+ Common.LogDebug("X");
+ return ProcessHotKeys(vkCode, hookCallbackKeybdData);
+ }
+ }
+
+ return true;
+ }
+
+ private void UpdateEasyMouseKeyDown(VK vkCode)
+ {
+ EasyMouseOption easyMouseOption = (EasyMouseOption)Setting.Values.EasyMouse;
+
+ EasyMouseKeyDown = (easyMouseOption == EasyMouseOption.Ctrl && (vkCode == VK.LCONTROL || vkCode == VK.RCONTROL))
+ || (easyMouseOption == EasyMouseOption.Shift && (vkCode == VK.LSHIFT || vkCode == VK.RSHIFT));
+ }
+
+ private static long lastHotKeyLockMachine;
+
+ private bool ProcessHotKeys(int vkCode, KEYBDDATA hookCallbackKeybdData)
+ {
+ if (vkCode == Setting.Values.HotKeyCaptureScreen && CtrlDown && shiftDown && !altDown &&
+ (Common.DesMachineID == Common.MachineID || Common.DesMachineID == ID.ALL))
+ {
+ CtrlDown = shiftDown = false;
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ Common.PrepareScreenCapture();
+ return false;
+ }
+ }
+
+ if (CtrlDown && altDown)
+ {
+ if (shiftDown && vkCode == Setting.Values.HotKeyExitMM &&
+ (Common.DesMachineID == Common.MachineID || Common.DesMachineID == ID.ALL))
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ Common.MainForm.NotifyIcon.Visible = false;
+
+ for (int i = 1; i < 10; i++)
+ {
+ Application.DoEvents();
+ Thread.Sleep(20);
+ }
+
+ Common.MainForm.Quit(false, false);
+ });
+ }
+ else if (vkCode == Setting.Values.HotKeySwitchMachine ||
+ vkCode == Setting.Values.HotKeySwitchMachine + 1 ||
+ vkCode == Setting.Values.HotKeySwitchMachine + 2 ||
+ vkCode == Setting.Values.HotKeySwitchMachine + 3)
+ {
+ if (Switch2(vkCode - Setting.Values.HotKeySwitchMachine))
+ {
+ return false;
+ }
+ }
+ else if (vkCode == Setting.Values.HotKeyLockMachine)
+ {
+ if (!Common.RunOnLogonDesktop
+ && !Common.RunOnScrSaverDesktop)
+ {
+ if (Common.GetTick() - lastHotKeyLockMachine < 500)
+ {
+ Common.SwitchToMultipleMode(true, true);
+
+ hookCallbackKeybdData.wVk = (short)VK.LCONTROL;
+ KeyboardEvent(hookCallbackKeybdData);
+ hookCallbackKeybdData.wVk = (short)VK.LMENU;
+ KeyboardEvent(hookCallbackKeybdData);
+ hookCallbackKeybdData.wVk = vkCode;
+ KeyboardEvent(hookCallbackKeybdData);
+
+ hookCallbackKeybdData.dwFlags |= (int)Common.LLKHF.UP;
+
+ hookCallbackKeybdData.wVk = (short)VK.LCONTROL;
+ KeyboardEvent(hookCallbackKeybdData);
+ hookCallbackKeybdData.wVk = (short)VK.LMENU;
+ KeyboardEvent(hookCallbackKeybdData);
+ hookCallbackKeybdData.wVk = vkCode;
+ KeyboardEvent(hookCallbackKeybdData);
+
+ Common.SwitchToMultipleMode(false, true);
+
+ _ = NativeMethods.LockWorkStation();
+ }
+ else
+ {
+ KeyboardEvent(hookCallbackKeybdData);
+ }
+
+ lastHotKeyLockMachine = Common.GetTick();
+
+ return false;
+ }
+ }
+ else if (vkCode == Setting.Values.HotKeyReconnect)
+ {
+ Common.ShowToolTip("Reconnecting...", 2000);
+ Common.LastReconnectByHotKeyTime = Common.GetTick();
+ Common.PleaseReopenSocket = Common.REOPEN_WHEN_HOTKEY;
+ return false;
+ }
+ else if (vkCode == Setting.Values.HotKeySwitch2AllPC)
+ {
+ Common.SwitchToMultipleMode(Common.DesMachineID != ID.ALL, true);
+ return false;
+ }
+ else if (vkCode == Setting.Values.HotKeyToggleEasyMouse)
+ {
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ EasyMouseOption easyMouseOption = (EasyMouseOption)Setting.Values.EasyMouse;
+
+ if (easyMouseOption is EasyMouseOption.Disable or EasyMouseOption.Enable)
+ {
+ Setting.Values.EasyMouse = (int)(easyMouseOption == EasyMouseOption.Disable ? EasyMouseOption.Enable : EasyMouseOption.Disable);
+
+ Common.ShowToolTip($"Easy Mouse has been toggled to [{(EasyMouseOption)Setting.Values.EasyMouse}] by a hotkey. You can change the hotkey in the Settings form.", 5000);
+ return false;
+ }
+ }
+ }
+ else if (shiftDown && Setting.Values.VKMap != null && vkCode == (Setting.Values.VKMap.ContainsKey(0) ? (int)Setting.Values.VKMap[0] : 'K'))
+ {
+ if (Common.DesMachineID == Common.MachineID || Common.DesMachineID == ID.ALL)
+ {
+ Setting.Values.UseVKMap = !Setting.Values.UseVKMap;
+ return Common.DesMachineID == ID.ALL;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private static bool Switch2(int index)
+ {
+ if (Common.MachineMatrix != null && Common.MachineMatrix.Length > index)
+ {
+ string mcName = Common.MachineMatrix[index].Trim();
+ if (!string.IsNullOrEmpty(mcName))
+ {
+ // Common.DoSomethingInUIThread(delegate()
+ {
+ Common.ReleaseAllKeys();
+ }
+
+ // );
+ Common.SwitchToMachine(mcName);
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ Common.ShowToolTip(
+ string.Format(
+ CultureInfo.CurrentCulture,
+ "Control has been switched to {0} by the hotkey Ctrl+Alt+{1}{2}",
+ mcName,
+ Setting.Values.HotKeySwitchMachine == (int)VK.F1 ? "F" : string.Empty,
+ index + 1),
+ 3000);
+ }
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ internal void ResetLastSwitchKeys()
+ {
+ for (int i = 0; i < CONTROL_TOUCH; i++)
+ {
+ ctrlTouches[i] = 0;
+ }
+
+ CtrlDown = winDown = altDown = false;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs b/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs
new file mode 100644
index 000000000000..c3623eda1750
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/InputSimulation.cs
@@ -0,0 +1,467 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Keyboard/Mouse simulation.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Runtime.InteropServices;
+using System.ServiceProcess;
+using System.Threading.Tasks;
+
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.InputSimulation.#keybd_event(System.Byte,System.Byte,System.UInt32,System.Int32)", MessageId = "3", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.InputSimulation.#InputProcessKeyEx(System.Int32,System.Int32,System.Boolean&)", MessageId = "MouseWithoutBorders.NativeMethods.LockWorkStation", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders.Class
+{
+ internal class InputSimulation
+ {
+ private InputSimulation()
+ {
+ }
+
+ private static uint SendInputEx(NativeMethods.INPUT input)
+ {
+ Common.PaintCount = 0;
+
+ uint rv;
+ if (Common.Is64bitOS)
+ {
+ NativeMethods.INPUT64 input64 = default;
+ input64.type = input.type;
+
+ // Keyboard
+ if (input.type == 1)
+ {
+ input64.ki.wVk = input.ki.wVk;
+ input64.ki.wScan = input.ki.wScan;
+ input64.ki.dwFlags = input.ki.dwFlags;
+ input64.ki.time = input.ki.time;
+ input64.ki.dwExtraInfo = input.ki.dwExtraInfo;
+ }
+
+ // Mouse
+ else
+ {
+ input64.mi.dx = input.mi.dx;
+ input64.mi.dy = input.mi.dy;
+ input64.mi.dwFlags = input.mi.dwFlags;
+ input64.mi.mouseData = input.mi.mouseData;
+ input64.mi.time = input.mi.time;
+ input64.mi.dwExtraInfo = input.mi.dwExtraInfo;
+ }
+
+ NativeMethods.INPUT64[] inputs = { input64 };
+
+ // mouse click simulation
+ // TODO: Find alternative API that simulates mouse input more directly
+ rv = NativeMethods.SendInput64(1, inputs, Marshal.SizeOf(input64));
+ }
+ else
+ {
+ NativeMethods.INPUT[] inputs = { input };
+
+ // TODO: Find alternative API that simulates mouse input more directly
+ rv = NativeMethods.SendInput(1, inputs, Marshal.SizeOf(input));
+ }
+
+ return rv;
+ }
+
+ internal static void SendKey(KEYBDDATA kd)
+ {
+ string log = string.Empty;
+ NativeMethods.KEYEVENTF dwFlags = NativeMethods.KEYEVENTF.KEYDOWN;
+ uint scanCode = 0;
+
+ // http://msdn.microsoft.com/en-us/library/ms644967(VS.85).aspx
+ if ((kd.dwFlags & (int)Common.LLKHF.UP) == (int)Common.LLKHF.UP)
+ {
+ dwFlags = NativeMethods.KEYEVENTF.KEYUP;
+ }
+
+ if ((kd.dwFlags & (int)Common.LLKHF.EXTENDED) == (int)Common.LLKHF.EXTENDED)
+ {
+ dwFlags |= NativeMethods.KEYEVENTF.EXTENDEDKEY;
+ }
+
+ scanCode = NativeMethods.MapVirtualKey((uint)kd.wVk, 0);
+
+ InputProcessKeyEx(kd.wVk, kd.dwFlags, out bool eatKey);
+
+ if (Setting.Values.UseVKMap && Setting.Values.VKMap != null && Setting.Values.VKMap.ContainsKey(kd.wVk) && !ctrlDown)
+ {
+ kd.wVk = (int)Setting.Values.VKMap[kd.wVk];
+ }
+
+ if (!eatKey)
+ {
+ InputHook.RealData = false;
+#if !USING_keybd_event
+ // #if USING_SendInput
+ NativeMethods.INPUT structInput;
+ structInput = default;
+ structInput.type = 1;
+ structInput.ki.wScan = (short)scanCode;
+ structInput.ki.time = 0;
+ structInput.ki.wVk = (short)kd.wVk;
+ structInput.ki.dwFlags = (int)dwFlags;
+ structInput.ki.dwExtraInfo = NativeMethods.GetMessageExtraInfo();
+
+ Common.DoSomethingInTheInputSimulationThread(() =>
+ {
+ // key press simulation
+ SendInputEx(structInput);
+ });
+
+#else
+ keybd_event((byte)kd.wVk, (byte)scanCode, (UInt32)dwFlags, 0);
+#endif
+ InputHook.RealData = true;
+ }
+
+ log += "*"; // ((Keys)kd.wVk).ToString(CultureInfo.InvariantCulture);
+ Common.LogDebug(log);
+ }
+
+ // Md.X, Md.Y is from 0 to 65535
+ internal static uint SendMouse(MOUSEDATA md)
+ {
+ uint rv = 0;
+ NativeMethods.INPUT mouse_input = default;
+
+ long w65535 = (Common.DesktopBounds.Right - Common.DesktopBounds.Left) * 65535 / Common.ScreenWidth;
+ long h65535 = (Common.DesktopBounds.Bottom - Common.DesktopBounds.Top) * 65535 / Common.ScreenHeight;
+ long l65535 = Common.DesktopBounds.Left * 65535 / Common.ScreenWidth;
+ long t65535 = Common.DesktopBounds.Top * 65535 / Common.ScreenHeight;
+ mouse_input.type = 0;
+ long dx = (md.X * w65535 / 65535) + l65535;
+ long dy = (md.Y * h65535 / 65535) + t65535;
+ mouse_input.mi.dx = (int)dx;
+ mouse_input.mi.dy = (int)dy;
+ mouse_input.mi.mouseData = md.WheelDelta;
+
+ if (md.dwFlags != Common.WM_MOUSEMOVE)
+ {
+ Common.LogDebug($"InputSimulation.SendMouse: x = {md.X}, y = {md.Y}, WheelDelta = {md.WheelDelta}, dwFlags = {md.dwFlags}.");
+ }
+
+ switch (md.dwFlags)
+ {
+ case Common.WM_MOUSEMOVE:
+ mouse_input.mi.dwFlags |= (int)(NativeMethods.MOUSEEVENTF.MOVE | NativeMethods.MOUSEEVENTF.ABSOLUTE);
+ break;
+ case Common.WM_LBUTTONDOWN:
+ mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.LEFTDOWN;
+ break;
+ case Common.WM_LBUTTONUP:
+ mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.LEFTUP;
+ break;
+ case Common.WM_RBUTTONDOWN:
+ mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.RIGHTDOWN;
+ break;
+ case Common.WM_RBUTTONUP:
+ mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.RIGHTUP;
+ break;
+ case Common.WM_MBUTTONDOWN:
+ mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.MIDDLEDOWN;
+ break;
+ case Common.WM_MBUTTONUP:
+ mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.MIDDLEUP;
+ break;
+ case Common.WM_MOUSEWHEEL:
+ mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.WHEEL;
+ break;
+ case Common.WM_XBUTTONUP:
+ mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.XUP;
+ break;
+ case Common.WM_XBUTTONDOWN:
+ mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.XDOWN;
+ break;
+
+ default:
+ break;
+ }
+
+ Common.DoSomethingInTheInputSimulationThread(() =>
+ {
+ InputHook.RealData = false;
+ rv = SendInputEx(mouse_input);
+ });
+
+ if (Common.MainFormVisible && !Common.IsDropping)
+ {
+ Common.MainFormDot();
+ }
+
+ return rv;
+ }
+
+ internal static void MoveMouseEx(int x, int y)
+ {
+ NativeMethods.INPUT mouse_input = default;
+
+ long w65535 = (Common.DesktopBounds.Right - Common.DesktopBounds.Left) * 65535 / Common.ScreenWidth;
+ long h65535 = (Common.DesktopBounds.Bottom - Common.DesktopBounds.Top) * 65535 / Common.ScreenHeight;
+ long l65535 = Common.DesktopBounds.Left * 65535 / Common.ScreenWidth;
+ long t65535 = Common.DesktopBounds.Top * 65535 / Common.ScreenHeight;
+ mouse_input.type = 0;
+ long dx = (x * w65535 / 65535) + l65535;
+ long dy = (y * h65535 / 65535) + t65535;
+ mouse_input.mi.dx = (int)dx;
+ mouse_input.mi.dy = (int)dy;
+
+ Common.LogDebug($"InputSimulation.MoveMouseEx: x = {x}, y = {y}.");
+
+ mouse_input.mi.dwFlags |= (int)(NativeMethods.MOUSEEVENTF.MOVE | NativeMethods.MOUSEEVENTF.ABSOLUTE);
+
+ Common.DoSomethingInTheInputSimulationThread(() =>
+ {
+ InputHook.RealData = false;
+ SendInputEx(mouse_input);
+ });
+ }
+
+ // x, y is in pixel
+ internal static void MoveMouse(int x, int y)
+ {
+ // Common.Log("Mouse move: " + x.ToString(CultureInfo.CurrentCulture) + "," + y.ToString(CultureInfo.CurrentCulture));
+ NativeMethods.INPUT mouse_input = default;
+ mouse_input.type = 0;
+ mouse_input.mi.dx = x * 65535 / Common.ScreenWidth;
+ mouse_input.mi.dy = y * 65535 / Common.ScreenHeight;
+ mouse_input.mi.mouseData = 0;
+ mouse_input.mi.dwFlags = (int)(NativeMethods.MOUSEEVENTF.MOVE | NativeMethods.MOUSEEVENTF.ABSOLUTE);
+
+ Common.LogDebug($"InputSimulation.MoveMouse: x = {x}, y = {y}.");
+
+ Common.DoSomethingInTheInputSimulationThread(() =>
+ {
+ InputHook.RealData = false;
+ SendInputEx(mouse_input);
+
+ // NativeMethods.SetCursorPos(x, y);
+ });
+ }
+
+ // dx, dy is in pixel, relative
+ internal static void MoveMouseRelative(int dx, int dy)
+ {
+ NativeMethods.INPUT mouse_input = default;
+ mouse_input.type = 0;
+ mouse_input.mi.dx = dx; // *65535 / Common.ScreenWidth;
+ mouse_input.mi.dy = dy; // *65535 / Common.ScreenHeight;
+ mouse_input.mi.mouseData = 0;
+ mouse_input.mi.dwFlags = (int)NativeMethods.MOUSEEVENTF.MOVE;
+
+ Common.LogDebug($"InputSimulation.MoveMouseRelative: x = {dx}, y = {dy}.");
+
+ Common.DoSomethingInTheInputSimulationThread(() =>
+ {
+ InputHook.RealData = false;
+ SendInputEx(mouse_input);
+
+ // NativeMethods.SetCursorPos(x, y);
+ });
+ }
+
+ internal static void MouseUp()
+ {
+ Common.DoSomethingInTheInputSimulationThread(() =>
+ {
+ NativeMethods.INPUT input = default;
+ input.type = 0;
+ input.mi.dx = 0;
+ input.mi.dy = 0;
+ input.mi.mouseData = 0;
+ input.mi.dwFlags = (int)NativeMethods.MOUSEEVENTF.LEFTUP;
+
+ InputHook.SkipMouseUpCount++;
+ _ = SendInputEx(input);
+ Common.LogDebug("MouseUp() called");
+ });
+ }
+
+ internal static void MouseClickDotForm(int x, int y)
+ {
+ _ = Task.Factory.StartNew(
+ () =>
+ {
+ NativeMethods.INPUT input = default;
+ input.type = 0;
+ input.mi.dx = 0;
+ input.mi.dy = 0;
+ input.mi.mouseData = 0;
+
+ InputHook.SkipMouseUpDown = true;
+
+ try
+ {
+ MoveMouse(x, y);
+
+ InputHook.RealData = false;
+ input.mi.dwFlags = (int)NativeMethods.MOUSEEVENTF.LEFTDOWN;
+ _ = SendInputEx(input);
+
+ InputHook.RealData = false;
+ input.mi.dwFlags = (int)NativeMethods.MOUSEEVENTF.LEFTUP;
+ _ = SendInputEx(input);
+
+ Common.LogDebug("MouseClick() called");
+ Thread.Sleep(200);
+ }
+ finally
+ {
+ InputHook.SkipMouseUpDown = false;
+ }
+ },
+ System.Threading.CancellationToken.None,
+ TaskCreationOptions.None,
+ TaskScheduler.Default);
+ }
+
+ private static bool winDown;
+ private static bool ctrlDown;
+ private static bool altDown;
+ private static bool shiftDown;
+
+ private static void InputProcessKeyEx(int vkCode, int flags, out bool eatKey)
+ {
+ eatKey = false;
+
+ if ((flags & (int)Common.LLKHF.UP) == (int)Common.LLKHF.UP)
+ {
+ switch ((VK)vkCode)
+ {
+ case VK.LWIN:
+ case VK.RWIN:
+ winDown = false;
+ break;
+
+ case VK.LCONTROL:
+ case VK.RCONTROL:
+ ctrlDown = false;
+ break;
+
+ case VK.LMENU:
+ case VK.RMENU:
+ altDown = false;
+ break;
+
+ case VK.LSHIFT:
+ case VK.RSHIFT:
+ shiftDown = false;
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ if (vkCode == Setting.Values.HotKeyLockMachine)
+ {
+ if (!Common.RunOnLogonDesktop
+ && !Common.RunOnScrSaverDesktop)
+ {
+ if (ctrlDown && altDown)
+ {
+ ctrlDown = altDown = false;
+ eatKey = true;
+ Common.ReleaseAllKeys();
+ _ = NativeMethods.LockWorkStation();
+ }
+ }
+ }
+ else if (Setting.Values.VKMap != null && vkCode == (Setting.Values.VKMap.ContainsKey(0) ? (int)Setting.Values.VKMap[0] : 'K'))
+ {
+ if (ctrlDown && altDown && shiftDown)
+ {
+ ctrlDown = altDown = shiftDown = false;
+ Setting.Values.UseVKMap = !Setting.Values.UseVKMap;
+ eatKey = true;
+ }
+ }
+ else if (vkCode == Setting.Values.HotKeyCaptureScreen && ctrlDown && shiftDown && !altDown)
+ {
+ ctrlDown = shiftDown = false;
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ Common.PrepareScreenCapture();
+ eatKey = true;
+ }
+ }
+
+ switch ((VK)vkCode)
+ {
+ case VK.LWIN:
+ case VK.RWIN:
+ winDown = true;
+ break;
+
+ case VK.LCONTROL:
+ case VK.RCONTROL:
+ ctrlDown = true;
+ break;
+
+ case VK.LMENU:
+ case VK.RMENU:
+ altDown = true;
+ break;
+
+ case VK.LSHIFT:
+ case VK.RSHIFT:
+ shiftDown = true;
+ break;
+
+ case VK.DELETE:
+ if (ctrlDown && altDown)
+ {
+ ctrlDown = altDown = false;
+ eatKey = true;
+ Common.ReleaseAllKeys();
+ }
+
+ break;
+
+ case (VK)'L':
+ if (winDown)
+ {
+ winDown = false;
+ eatKey = true;
+ Common.ReleaseAllKeys();
+ uint rv = NativeMethods.LockWorkStation();
+ Common.LogDebug("LockWorkStation returned " + rv.ToString(CultureInfo.CurrentCulture));
+ }
+
+ break;
+
+ case VK.END:
+ if (ctrlDown && altDown)
+ {
+ ctrlDown = altDown = false;
+ new ServiceController("MouseWithoutBordersSvc").Start(new string[] { "CAD" });
+ }
+
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ internal static void ResetSystemKeyFlags()
+ {
+ ctrlDown = winDown = altDown = false;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/MachinePool.cs b/src/modules/MouseWithoutBorders/App/Class/MachinePool.cs
new file mode 100644
index 000000000000..51bbd88921e6
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/MachinePool.cs
@@ -0,0 +1,342 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Class created as refactoring by Tim Lovell-Smith (tilovell)
+// 2023- Included in PowerToys.
+//
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+
+namespace MouseWithoutBorders.Class
+{
+ ///
+ /// Holds our current 'last known state of the world' information about Machines the user wants to connect to.
+ /// Keeps track of whether machines are 'alive' or 'disconnected' implicitly via timestamps.
+ /// Only ever knows about Common.MAX_MACHINE machines.
+ ///
+ ///
+ /// Operations in the class are designed to be easily thread-safe.
+ /// There are two factors helping this:
+ ///
+ /// 1) Minimal calls outside of itself.
+ /// This class doesn't call other classes to do any 'interesting' or *potentially locking* work. This helps us avoid deadlock. (Common.GetTick() is safe)
+ ///
+ /// 2) Best-effort semantics. Callers will find that sometimes the thing they wanted to do just won't work,
+ /// due to unfortunate timing - machine not found, too many machines, or whatever.
+ /// e.g.
+ /// - Every update is a 'try' to update.
+ /// - Every find is a 'try' to find.
+ /// etc.
+ ///
+ /// Please write regression tests (unit tests) for bugs before fixing them.
+ ///
+ internal class MachinePool
+ {
+ private readonly object @lock;
+ private readonly List list;
+
+ public MachinePool()
+ {
+ @lock = new object();
+ list = new List();
+ }
+
+ // This will set the timestamp to current time, making the machine 'alive'.
+ internal bool TryUpdateMachineID(string machineName, ID id, bool updateTimeStamp)
+ {
+ bool rv = false;
+
+ lock (@lock)
+ {
+ CheckName(machineName);
+ for (int i = 0; i < list.Count; i++)
+ {
+ if (NamesAreEqual(machineName, list[i].Name))
+ {
+ list[i] =
+
+ // This looks funny - but you have to rebuild the actual struct because List doesn't let you make updates to struct fields.
+ new MachineInf
+ {
+ Name = list[i].Name,
+ Id = id,
+ Time = updateTimeStamp ? Common.GetTick() : list[i].Time,
+ };
+
+ rv = true;
+ }
+ else if (list[i].Id == id)
+ {
+ // Duplicate ID? Reset the old machine's.
+ list[i] = new MachineInf
+ {
+ Name = list[i].Name,
+ Id = ID.NONE,
+ Time = updateTimeStamp ? Common.GetTick() : list[i].Time,
+ };
+ }
+ }
+ }
+
+ return rv;
+ }
+
+ ///
+ /// Set a machine to 'disconnected' state due to Socket/Channel exception (overriding timestamp).
+ /// Returns true if a matching machine name existed (regardless of whether the machine was already connected).
+ ///
+ ///
+ /// Explanation: When two machines are connected and one of them hibernates (or sleeps),
+ /// the socket state of the other machine is still Connected and there would be an
+ /// exception when we try to send the data using the socket.
+ /// In this case we would want to remove the machine and move the Mouse control back to the host machine…
+ ///
+ internal bool SetMachineDisconnected(string machineName)
+ {
+ lock (@lock)
+ {
+ bool foundAndTimedOut = false;
+ CheckName(machineName);
+ for (int i = 0; i < list.Count; i++)
+ {
+ if (NamesAreEqual(machineName, list[i].Name))
+ {
+ list[i] =
+
+ // This looks funny - but you have to rebuild the actual struct because List doesn't let you make updates to struct fields.
+ new MachineInf
+ {
+ Name = list[i].Name,
+ Id = list[i].Id,
+ Time = list[i].Time > Common.GetTick() - Common.HEARTBEAT_TIMEOUT + 10000 ? Common.GetTick() - Common.HEARTBEAT_TIMEOUT + 10000 : list[i].Time,
+ };
+
+ foundAndTimedOut = list[i].Time < Common.GetTick() - Common.HEARTBEAT_TIMEOUT + 10000 - 5000;
+ }
+ }
+
+ return foundAndTimedOut;
+ }
+ }
+
+ // TODO: would probably be cleaner interface as IEnumerable
+ internal List ListAllMachines()
+ {
+ return Where((inf) => true);
+ }
+
+ internal List TryFindMachineByID(ID id)
+ {
+ return id == ID.NONE ? new List() : Where((inf) => inf.Id == id);
+ }
+
+ internal void Clear()
+ {
+ lock (@lock)
+ {
+ list.Clear();
+ }
+ }
+
+ public void Initialize(IEnumerable machineNames)
+ {
+ lock (@lock)
+ {
+ list.Clear();
+
+ foreach (string name in machineNames)
+ {
+ if (string.IsNullOrEmpty(name.Trim()))
+ {
+ continue; // next
+ }
+ else if (list.Count >= 4)
+ {
+ throw new ArgumentException("machineNames.Length > Common.MAX_MACHINE");
+ }
+
+ _ = LearnMachine(name);
+ }
+ }
+ }
+
+ public void Initialize(IEnumerable infos)
+ {
+ lock (@lock)
+ {
+ list.Clear();
+
+ foreach (MachineInf inf in infos)
+ {
+ if (string.IsNullOrEmpty(inf.Name.Trim()))
+ {
+ continue; // next
+ }
+ else if (list.Count >= 4)
+ {
+ throw new ArgumentException("infos.Length > Common.MAX_MACHINE");
+ }
+
+ _ = LearnMachine(inf.Name);
+ _ = TryUpdateMachineID(inf.Name, inf.Id, false);
+ }
+ }
+ }
+
+ // Add a new machine to our set of known machines. Initially it is 'disconnected'.
+ // Fails and return false if the machine pool is already full.
+ public bool LearnMachine(string machineName)
+ {
+ if (machineName == null)
+ {
+ throw new ArgumentNullException(machineName);
+ }
+ else if (string.IsNullOrEmpty(machineName.Trim()))
+ {
+ throw new ArgumentException(machineName);
+ }
+
+ lock (@lock)
+ {
+ CheckName(machineName);
+ for (int i = 0; i < list.Count; i++)
+ {
+ if (NamesAreEqual(list[i].Name, machineName))
+ {
+ return false; // already in list
+ }
+ }
+
+ if (list.Count >= Common.MAX_MACHINE)
+ {
+ int slotFound = -1;
+
+ for (int i = 0; i < list.Count; i++)
+ {
+ if (!Common.InMachineMatrix(list[i].Name))
+ {
+ slotFound = i;
+ break;
+ }
+ }
+
+ if (slotFound >= 0)
+ {
+ list.RemoveAt(slotFound);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ list.Add(new MachineInf { Name = machineName });
+ return true;
+ }
+ }
+
+ internal bool TryFindMachineByName(string machineName, out MachineInf result)
+ {
+ lock (@lock)
+ {
+ CheckName(machineName);
+ for (int i = 0; i < list.Count; i++)
+ {
+ if (NamesAreEqual(list[i].Name, machineName))
+ {
+ result = list[i];
+ return true;
+ }
+ }
+
+ result = default;
+ return false;
+ }
+ }
+
+ internal ID ResolveID(string machineName)
+ {
+ return TryFindMachineByName(machineName, out MachineInf inf) ? inf.Id : ID.NONE;
+ }
+
+ private List Where(Predicate test)
+ {
+ lock (@lock)
+ {
+ List ret = new();
+
+ for (int i = 0; i < list.Count; i++)
+ {
+ if (test(list[i]))
+ {
+ ret.Add(list[i]);
+ }
+ }
+
+ return ret;
+ }
+ }
+
+ internal string SerializedAsString()
+ {
+ lock (@lock)
+ {
+ List machinePool = ListAllMachines();
+ string rv = string.Join(",", machinePool.Select(m => $"{m.Name}:{m.Id}"));
+
+ for (int j = machinePool.Count; j < Common.MAX_MACHINE; j++)
+ {
+ rv += ",:";
+ }
+
+ return rv;
+ }
+ }
+
+ /// When doing unit tests it's nice to be able to fudge with the clock time, adding milliseconds, instead of sleeping.
+ internal static bool IsAlive(MachineInf inf, int clockSkewInMS_forTesting = 0)
+ {
+ return inf.Id != ID.NONE && (Common.GetTick() + clockSkewInMS_forTesting - inf.Time <= Common.HEARTBEAT_TIMEOUT || Common.IsConnectedTo(inf.Id));
+ }
+
+ private static bool NamesAreEqual(string name1, string name2)
+ {
+ return string.Equals(name1, name2, StringComparison.OrdinalIgnoreCase);
+ }
+
+ private static void CheckName(string machineName)
+ {
+ Debug.Assert(machineName != null, "machineName is null");
+ Debug.Assert(machineName.Trim().Length == machineName.Length, "machineName contains spaces");
+ }
+
+ internal void ResetIPAddressesForDeadMachines(bool firstLoaded = false)
+ {
+ lock (@lock)
+ {
+ for (int i = 0; i < list.Count; i++)
+ {
+ if (!string.IsNullOrEmpty(list[i].Name) && list[i].Name.Equals(Common.MachineName, StringComparison.Ordinal))
+ {
+ continue;
+ }
+
+ if ((firstLoaded && !Common.InMachineMatrix(list[i].Name)) || (!firstLoaded && (!Common.InMachineMatrix(list[i].Name) || !IsAlive(list[i]))))
+ {
+ list[i] =
+ new MachineInf
+ {
+ Name = list[i].Name,
+ Id = ID.NONE,
+ Time = list[i].Time,
+ };
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/MachinePoolHelpers.cs b/src/modules/MouseWithoutBorders/App/Class/MachinePoolHelpers.cs
new file mode 100644
index 000000000000..66175d8f552c
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/MachinePoolHelpers.cs
@@ -0,0 +1,40 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace MouseWithoutBorders.Class
+{
+ internal static class MachinePoolHelpers
+ {
+ internal static MachineInf[] LoadMachineInfoFromMachinePoolStringSetting(string s)
+ {
+ if (s == null)
+ {
+ throw new ArgumentNullException(s);
+ }
+
+ string[] st = s.Split(new char[] { ',' });
+
+ if (st.Length < Common.MAX_MACHINE)
+ {
+ throw new ArgumentException("Not enough elements in encoded MachinePool string");
+ }
+
+ MachineInf[] rv = new MachineInf[Common.MAX_MACHINE];
+ for (int i = 0; i < Common.MAX_MACHINE; i++)
+ {
+ string[] mc = st[i].Split(new char[] { ':' });
+ if (mc.Length == 2)
+ {
+ rv[i].Name = mc[0];
+ rv[i].Id = uint.TryParse(mc[1], out uint ip) ? (ID)ip : ID.NONE;
+ rv[i].Time = rv[i].Id == ID.NONE ? Common.GetTick() - Common.HEARTBEAT_TIMEOUT : Common.GetTick();
+ }
+ }
+
+ return rv;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/MouseLocation.cs b/src/modules/MouseWithoutBorders/App/Class/MouseLocation.cs
new file mode 100644
index 000000000000..26635817008e
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/MouseLocation.cs
@@ -0,0 +1,20 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace MouseWithoutBorders.Class
+{
+ internal class MouseLocation
+ {
+ internal int X { get; set; }
+
+ internal int Y { get; set; }
+
+ internal int Count { get; set; }
+
+ internal void ResetCount()
+ {
+ Count = 1;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/MyKnownBitmap.cs b/src/modules/MouseWithoutBorders/App/Class/MyKnownBitmap.cs
new file mode 100644
index 000000000000..0b1bb193ef3f
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/MyKnownBitmap.cs
@@ -0,0 +1,159 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Customed bitmap parser.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Globalization;
+using System.IO;
+using System.Runtime.InteropServices;
+
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.MyKnownBitmap.#FromFile(System.string)", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders.Class
+{
+#if CUSTOMIZE_LOGON_SCREEN
+ internal class MyKnownBitmap
+ {
+ private const int BITMAP_FILE_HEADER_SIZE = 14;
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1, Size = BITMAP_FILE_HEADER_SIZE)]
+ private struct BITMAPFILEHEADER
+ {
+ public ushort BfType;
+ public uint BfSize;
+ public ushort BfReserved1;
+ public ushort BfReserved2;
+ public uint BfOffBits;
+ }
+
+ private const int BITMAP_INFO_HEADER_SIZE = 40;
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ private struct BITMAPINFOHEADER
+ {
+ public uint BiSize;
+ public int BiWidth;
+ public int BiHeight;
+ public ushort BiPlanes;
+ public ushort BiBitCount;
+ public uint BiCompression;
+ public uint BiSizeImage;
+ public int BiXPelsPerMeter;
+ public int BiYPelsPerMeter;
+ public uint BiClrUsed;
+ public uint BiClrImportant;
+ }
+
+ private const long MAX_FILE_SIZE = 10 * 1024 * 1024;
+
+ internal static object FromFile(string bitmapFile)
+ {
+ IntPtr p;
+ byte[] buf;
+
+ try
+ {
+ FileStream f = File.OpenRead(bitmapFile);
+ long fs = f.Length;
+
+ if (fs is < 1024 or > MAX_FILE_SIZE)
+ {
+ f.Close();
+ return string.Format(CultureInfo.CurrentCulture, "File Size exception: {0}", fs);
+ }
+
+ BITMAPFILEHEADER bitmapFileHeader;
+ buf = new byte[BITMAP_FILE_HEADER_SIZE];
+ p = Marshal.AllocHGlobal(BITMAP_FILE_HEADER_SIZE);
+
+ if (buf == null)
+ {
+ f.Close();
+ return "p or buf is null! (1)";
+ }
+
+ _ = f.Read(buf, 0, buf.Length);
+ Marshal.Copy(buf, 0, p, buf.Length);
+ bitmapFileHeader = (BITMAPFILEHEADER)Marshal.PtrToStructure(p, typeof(BITMAPFILEHEADER));
+ Marshal.FreeHGlobal(p);
+
+ BITMAPINFOHEADER bitmapInfoHeader;
+ buf = new byte[BITMAP_INFO_HEADER_SIZE];
+ p = Marshal.AllocHGlobal(BITMAP_INFO_HEADER_SIZE);
+
+ if (buf == null)
+ {
+ f.Close();
+ return "p or buf is null! (2)";
+ }
+
+ _ = f.Read(buf, 0, buf.Length);
+ Marshal.Copy(buf, 0, p, buf.Length);
+ bitmapInfoHeader = (BITMAPINFOHEADER)Marshal.PtrToStructure(p, typeof(BITMAPINFOHEADER));
+ Marshal.FreeHGlobal(p);
+
+ if (bitmapFileHeader.BfType != 0x4D42 || bitmapFileHeader.BfSize != fs || bitmapFileHeader.BfOffBits != BITMAP_FILE_HEADER_SIZE + BITMAP_INFO_HEADER_SIZE ||
+ bitmapInfoHeader.BiBitCount != 24 || bitmapInfoHeader.BiCompression != 0 || bitmapInfoHeader.BiSize != BITMAP_INFO_HEADER_SIZE || bitmapInfoHeader.BiPlanes != 1 ||
+ bitmapInfoHeader.BiWidth <= 0 || bitmapInfoHeader.BiWidth > 4096 ||
+ bitmapInfoHeader.BiHeight <= 0 || bitmapInfoHeader.BiHeight > 4096)
+ {
+ f.Close();
+ return string.Format(
+ CultureInfo.CurrentCulture,
+ "Bitmap Format Exception: {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10}",
+ bitmapFileHeader.BfType,
+ bitmapFileHeader.BfSize,
+ bitmapFileHeader.BfOffBits,
+ bitmapInfoHeader.BiBitCount,
+ bitmapInfoHeader.BiCompression,
+ bitmapInfoHeader.BiSize,
+ bitmapInfoHeader.BiPlanes,
+ bitmapInfoHeader.BiWidth,
+ bitmapInfoHeader.BiWidth,
+ bitmapInfoHeader.BiHeight,
+ bitmapInfoHeader.BiHeight);
+ }
+
+ Bitmap bm = new(bitmapInfoHeader.BiWidth, bitmapInfoHeader.BiHeight, PixelFormat.Format24bppRgb);
+ BitmapData bd = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
+ buf = new byte[bm.Width * bm.Height * 3];
+ _ = f.Read(buf, 0, buf.Length);
+ f.Close();
+ int ws = buf.Length < (bd.Width * bd.Stride) ? buf.Length : bd.Width * bd.Stride;
+
+ // Should never happen
+ if (ws <= 0)
+ {
+ bm.UnlockBits(bd);
+ bm.Dispose();
+ return string.Format(CultureInfo.CurrentCulture, "Something wrong: {0} {1} {2}", buf.Length, bd.Width, bd.Stride);
+ }
+
+ Marshal.Copy(buf, 0, bd.Scan0, ws);
+ bm.UnlockBits(bd);
+ bm.RotateFlip(RotateFlipType.Rotate180FlipX);
+ return bm;
+ }
+ catch (Exception e)
+ {
+ return e.Message + e.StackTrace;
+ }
+ }
+
+ private MyKnownBitmap()
+ {
+ }
+ }
+#endif
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/NativeMethods.cs b/src/modules/MouseWithoutBorders/App/Class/NativeMethods.cs
new file mode 100644
index 000000000000..6bc101f6ca79
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/NativeMethods.cs
@@ -0,0 +1,945 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Windows APIs.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+
+// We are sure we dont have managed resource in KEYBDINPUT, IntPtr just holds a value
+[module: SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable", Scope = "type", Target = "MouseWithoutBorders.NativeMethods+KEYBDINPUT", Justification = "Dotnet port with style preservation")]
+
+// Some other minor issues
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#ConvertStringSidToSid(System.String,System.IntPtr&)", MessageId = "0", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#DrawText(System.IntPtr,System.String,System.Int32,MouseWithoutBorders.NativeMethods+RECT&,System.UInt32)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#SetWindowText(System.IntPtr,System.String)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#FindWindow(System.String,System.String)", MessageId = "0", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#FindWindow(System.String,System.String)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetWindowText(System.IntPtr,System.Text.StringBuilder,System.Int32)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#keybd_event(System.Byte,System.Byte,System.UInt32,System.Int32)", MessageId = "3", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", MessageId = "return", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources", Scope = "member", Target = "MouseWithoutBorders.NativeMethods+KEYBDINPUT.#dwExtraInfo", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Scope = "member", Target = "MouseWithoutBorders.NativeMethods+INPUT64.#type", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#TerminateProcess(System.IntPtr,System.IntPtr)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetClassName(System.IntPtr,System.Text.StringBuilder,System.Int32)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetClassName(System.IntPtr,System.Text.StringBuilder,System.Int32)", MessageId = "return", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetAsyncKeyState(System.IntPtr)", MessageId = "0", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetAsyncKeyState(System.IntPtr)", MessageId = "return", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders.Class
+{
+ internal partial class NativeMethods
+ {
+#if !MM_HELPER
+
+ [DllImport("user32.dll")]
+ internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ internal static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll")]
+ internal static extern IntPtr GetForegroundWindow();
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetForegroundWindow(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ internal static extern IntPtr CreateIconIndirect(ref IconInfo icon);
+
+ [return: MarshalAs(UnmanagedType.Bool)]
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern bool SetProcessDPIAware();
+
+ [DllImport("Shcore.dll", SetLastError = true)]
+ internal static extern int SetProcessDpiAwareness(uint type); // Win 8.1 and up, DPI can be per monitor.
+
+ [DllImport("kernel32.dll")]
+ internal static extern uint WTSGetActiveConsoleSessionId();
+
+#endif
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern bool ChangeWindowMessageFilterEx(IntPtr hWnd, uint msg, int action, IntPtr changeInfo);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool PostMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll", SetLastError = false)]
+ internal static extern IntPtr GetDesktopWindow();
+
+ [DllImport("user32.dll")]
+ internal static extern IntPtr GetWindowDC(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)]
+ internal static extern int DrawText(IntPtr hDC, string lpString, int nCount, ref RECT lpRect, uint uFormat);
+
+ [DllImport("gdi32.dll")]
+ internal static extern uint SetTextColor(IntPtr hdc, int crColor);
+
+ [DllImport("gdi32.dll")]
+ internal static extern uint SetBkColor(IntPtr hdc, int crColor);
+
+ [DllImport("user32.dll")]
+ internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
+
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)]
+ internal static extern IntPtr GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool AddClipboardFormatListener(IntPtr hwnd);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
+
+ /*
+ internal const int SW_MAXIMIZE = 3;
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct WINDOWPLACEMENT
+ {
+ public int length;
+ public int flags;
+ public int showCmd;
+ public System.Drawing.Point ptMinPosition;
+ public System.Drawing.Point ptMaxPosition;
+ public System.Drawing.Rectangle rcNormalPosition;
+
+ public static WINDOWPLACEMENT Default
+ {
+ get
+ {
+ WINDOWPLACEMENT result = new WINDOWPLACEMENT();
+ result.length = Marshal.SizeOf(result);
+ return result;
+ }
+ }
+ }
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool GetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);
+ * */
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
+
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetWindowText(IntPtr hWnd, string lpString);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ internal static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
+ internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool DestroyIcon(IntPtr handle);
+
+ // [DllImport("user32.dll")]
+ // [return: MarshalAs(UnmanagedType.Bool)]
+ // internal static extern bool IsWindowVisible(IntPtr hWnd);
+
+ // [DllImport("user32")]
+ // internal static extern int GetKeyboardState(byte[] pbKeyState);
+
+ // [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
+ // internal static extern short GetKeyState(int vKey);
+ [DllImport("user32")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetCursorPos(int X, int Y);
+
+ [DllImport("user32", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool GetCursorPos(ref Point p);
+
+ [DllImport("advapi32", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
+
+ [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
+
+ [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool DuplicateTokenEx(
+ IntPtr ExistingTokenHandle,
+ uint dwDesiredAccess,
+ ref SECURITY_ATTRIBUTES lpThreadAttributes,
+ int TokenType,
+ int ImpersonationLevel,
+ ref IntPtr DuplicateTokenHandle);
+
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ConvertStringSidToSid(string StringSid, out IntPtr ptrSid);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, ref TOKEN_MANDATORY_LABEL TokenInformation, uint TokenInformationLength);
+
+ // [DllImport("advapi32.dll", SetLastError = true)]
+ // [return: MarshalAs(UnmanagedType.Bool)]
+ // internal static extern bool SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, IntPtr TokenInformation, UInt32 TokenInformationLength);
+ [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Justification = "Dotnet port with style preservation")]
+ [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CreateProcessAsUser(
+ IntPtr hToken,
+ string lpApplicationName,
+ string lpCommandLine,
+ ref SECURITY_ATTRIBUTES lpProcessAttributes,
+ ref SECURITY_ATTRIBUTES lpThreadAttributes,
+ [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
+ int dwCreationFlags,
+ IntPtr lpEnvironment,
+ string lpCurrentDirectory,
+ ref STARTUPINFO lpStartupInfo,
+ out PROCESS_INFORMATION lpProcessInformation);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool EnumDisplayMonitors(
+ IntPtr hdc,
+ IntPtr lprcClip,
+ EnumMonitorsDelegate lpfnEnum,
+ IntPtr dwData);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfoEx lpmi);
+
+ [DllImport("User32.dll", CharSet = CharSet.Unicode)]
+ internal static extern int FindWindow(string ClassName, string WindowName);
+
+ [DllImport("kernel32.dll")]
+ internal static extern uint GetCurrentThreadId();
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern IntPtr GetThreadDesktop(uint dwThreadId);
+
+ [DllImport("user32.dll")]
+ internal static extern short GetAsyncKeyState(IntPtr vKey); // Keys vKey
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct POINT
+ {
+ internal int x;
+ internal int y;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct CURSORINFO
+ {
+ public int cbSize;
+ public int flags;
+ public IntPtr hCursor;
+ public POINT ptScreenPos;
+ }
+
+ [DllImport("user32.dll")]
+ internal static extern bool GetCursorInfo(out CURSORINFO ci);
+
+#if CUSTOMIZE_LOGON_SCREEN
+ [DllImport("kernel32", SetLastError = true)]
+ internal static extern uint WaitForSingleObject(IntPtr handle, int milliseconds);
+
+ internal const uint WAIT_OBJECT_0 = 0x00000000;
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PROCESS_BASIC_INFORMATION
+ {
+ public int ExitStatus;
+ public int PebBaseAddress;
+ public int AffinityMask;
+ public int BasePriority;
+ public uint UniqueProcessId;
+ public uint InheritedFromUniqueProcessId;
+ }
+
+ [DllImport("kernel32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool TerminateProcess(IntPtr hProcess, IntPtr exitCode);
+
+ [DllImport("ntdll.dll")]
+ internal static extern int NtQueryInformationProcess(
+ IntPtr hProcess,
+ int processInformationClass /* 0 */,
+ ref PROCESS_BASIC_INFORMATION processBasicInformation,
+ uint processInformationLength,
+ out uint returnLength);
+#endif
+
+#if USE_GetSecurityDescriptorSacl
+ internal enum SE_OBJECT_TYPE
+ {
+ SE_UNKNOWN_OBJECT_TYPE = 0,
+ SE_FILE_OBJECT,
+ SE_SERVICE,
+ SE_PRINTER,
+ SE_REGISTRY_KEY,
+ SE_LMSHARE,
+ SE_KERNEL_OBJECT,
+ SE_WINDOW_OBJECT,
+ SE_DS_OBJECT,
+ SE_DS_OBJECT_ALL,
+ SE_PROVIDER_DEFINED_OBJECT,
+ SE_WMIGUID_OBJECT,
+ SE_REGISTRY_WOW64_32KEY
+ }
+
+ [Flags]
+ internal enum SECURITY_INFORMATION : uint
+ {
+ LABEL_SECURITY_INFORMATION = 0x00000010
+ }
+
+ [StructLayoutAttribute(LayoutKind.Explicit)]
+ internal struct SECURITY_DESCRIPTOR
+ {
+ [FieldOffset(0)]
+ public byte revision;
+
+ [FieldOffset(1)]
+ public byte size;
+
+ [FieldOffset(2)]
+ public short control;
+
+ [FieldOffset(4)]
+ public IntPtr owner;
+
+ [FieldOffset(8)]
+ public IntPtr group;
+
+ [FieldOffset(12)]
+ public IntPtr sacl;
+
+ [FieldOffset(16)]
+ public IntPtr dacl;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ACL { public byte AclRevision; public byte Sbz1; public int AclSize; public int AceCount; public int Sbz2; }
+
+ [DllImport("advapi32", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string StringSecurityDescriptor,
+ UInt32 StringSDRevision, out SECURITY_DESCRIPTOR SecurityDescriptor, out UInt64 SecurityDescriptorSize);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ internal static extern int GetSecurityDescriptorSacl([MarshalAs(UnmanagedType.Struct)] ref SECURITY_DESCRIPTOR pSecurityDescriptor, int lpbSaclPresent, [MarshalAs(UnmanagedType.Struct)] ref ACL pSacl, int lpbSaclDefaulted);
+
+ [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
+ internal static extern uint SetNamedSecurityInfo(
+ string pObjectName,
+ SE_OBJECT_TYPE ObjectType,
+ SECURITY_INFORMATION SecurityInfo,
+ IntPtr psidOwner,
+ IntPtr psidGroup,
+ IntPtr pDacl,
+ IntPtr pSacl);
+#endif
+
+#if SINGLE_PROCESS
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetThreadDesktop(IntPtr hDesktop);
+#endif
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern IntPtr OpenInputDesktop(uint dwFlags, [MarshalAs(UnmanagedType.Bool)] bool fInherit, uint dwDesiredAccess);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, [Out] byte[] pvInfo, int nLength, out uint lpnLengthNeeded);
+
+ // [DllImport("user32.dll")]
+ // [return: MarshalAs(UnmanagedType.Bool)]
+ // internal static extern bool GetIconInfo(IntPtr hIcon, ref IconInfo pIconInfo);
+
+ // [DllImport("gdi32.dll")]
+ // internal static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);
+ [DllImport("gdi32.dll")]
+ internal static extern uint SetPixel(IntPtr hdc, int X, int Y, uint crColor);
+
+ // internal const int WM_CLOSE = 16;
+ internal const int WM_SHOW_DRAG_DROP = 0x400;
+
+ internal const int WM_HIDE_DRAG_DROP = 0x401;
+ internal const int WM_CHECK_EXPLORER_DRAG_DROP = 0x402;
+ internal const int WM_QUIT = 0x403;
+ internal const int WM_SWITCH = 0x404;
+ internal const int WM_HIDE_DD_HELPER = 0x405;
+ internal const int WM_SHOW_SETTINGS_FORM = 0x406;
+
+ internal static readonly IntPtr HWND_TOPMOST = new(-1);
+
+ // internal static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
+ // internal static readonly IntPtr HWND_TOP = new IntPtr(0);
+ // internal static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
+ internal const uint SWP_NOSIZE = 0x0001;
+
+ internal const uint SWP_NOMOVE = 0x0002;
+ internal const uint SWP_NOZORDER = 0x0004;
+ internal const uint SWP_NOREDRAW = 0x0008;
+ internal const uint SWP_SHOWWINDOW = 0x0040;
+ internal const uint SWP_HIDEWINDOW = 0x0080;
+
+ internal const int UOI_FLAGS = 1;
+ internal const int UOI_NAME = 2;
+ internal const int UOI_TYPE = 3;
+ internal const int UOI_USER_SID = 4;
+ internal const uint DESKTOP_WRITEOBJECTS = 0x0080;
+ internal const uint DESKTOP_READOBJECTS = 0x0001;
+ internal const uint DF_ALLOWOTHERACCOUNTHOOK = 0x0001;
+
+ // internal const UInt32 GENERIC_READ = 0x80000000;
+ internal const uint GENERIC_WRITE = 0x40000000;
+
+ // internal const UInt32 GENERIC_EXECUTE = 0x20000000;
+ internal const uint GENERIC_ALL = 0x10000000;
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ internal struct RECT
+ {
+ internal int Left;
+ internal int Top;
+ internal int Right;
+ internal int Bottom;
+ }
+
+ // size of a device name string
+ internal const int CCHDEVICENAME = 32;
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ internal struct MonitorInfoEx
+ {
+ internal int cbSize;
+ internal RECT rcMonitor;
+ internal RECT rcWork;
+ internal uint dwFlags;
+
+ // [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
+ // internal string szDeviceName;
+ }
+
+ // We are WOW
+ [DllImport(
+ "user32.dll",
+ CharSet = CharSet.Auto,
+ CallingConvention = CallingConvention.StdCall,
+ SetLastError = true)]
+ internal static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
+
+ [DllImport(
+ "user32.dll",
+ CharSet = CharSet.Auto,
+ CallingConvention = CallingConvention.StdCall,
+ SetLastError = true)]
+ internal static extern int UnhookWindowsHookEx(int idHook);
+
+ // In X64, we are running WOW
+ [DllImport(
+ "user32.dll",
+ CharSet = CharSet.Auto,
+ CallingConvention = CallingConvention.StdCall)]
+ internal static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
+
+ // [DllImport("user32")]
+ // internal static extern int ToAscii(int uVirtKey, int uScanCode, byte[] lpbKeyState, byte[] lpwTransKey, int fuState);
+ private enum InputType
+ {
+ INPUT_MOUSE = 0,
+ INPUT_KEYBOARD = 1,
+ INPUT_HARDWARE = 2,
+ }
+
+ [Flags]
+ internal enum MOUSEEVENTF
+ {
+ MOVE = 0x0001,
+ LEFTDOWN = 0x0002,
+ LEFTUP = 0x0004,
+ RIGHTDOWN = 0x0008,
+ RIGHTUP = 0x0010,
+ MIDDLEDOWN = 0x0020,
+ MIDDLEUP = 0x0040,
+ XDOWN = 0x0080,
+ XUP = 0x0100,
+ WHEEL = 0x0800,
+ VIRTUALDESK = 0x4000,
+ ABSOLUTE = 0x8000,
+ }
+
+ [Flags]
+ internal enum KEYEVENTF
+ {
+ KEYDOWN = 0x0000,
+ EXTENDEDKEY = 0x0001,
+ KEYUP = 0x0002,
+ UNICODE = 0x0004,
+ SCANCODE = 0x0008,
+ }
+
+ // http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MOUSEINPUT
+ {
+ internal int dx;
+ internal int dy;
+ internal int mouseData;
+ internal int dwFlags;
+ internal int time;
+ internal IntPtr dwExtraInfo;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct KEYBDINPUT
+ {
+ internal short wVk;
+ internal short wScan;
+ internal int dwFlags;
+ internal int time;
+ internal IntPtr dwExtraInfo;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct HARDWAREINPUT
+ {
+ internal int uMsg;
+ internal short wParamL;
+ internal short wParamH;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct INPUT
+ {
+ [FieldOffset(0)]
+ internal int type;
+
+ [FieldOffset(4)]
+ internal MOUSEINPUT mi;
+
+ [FieldOffset(4)]
+ internal KEYBDINPUT ki;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct INPUT64
+ {
+ [FieldOffset(0)]
+ internal int type;
+
+ [FieldOffset(8)]
+ internal MOUSEINPUT mi;
+
+ [FieldOffset(8)]
+ internal KEYBDINPUT ki;
+ }
+
+ [DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
+ internal static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
+
+ [DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
+ internal static extern uint SendInput64(uint nInputs, INPUT64[] pInputs, int cbSize);
+
+ [DllImport("user32.dll", EntryPoint = "GetMessageExtraInfo", SetLastError = true)]
+ internal static extern IntPtr GetMessageExtraInfo();
+
+ [DllImport("user32.dll", EntryPoint = "LockWorkStation", SetLastError = true)]
+ internal static extern uint LockWorkStation();
+
+ // [DllImport("user32.dll")]
+ // internal static extern void keybd_event(byte bVk, byte bScan, UInt32 dwFlags, int dwExtraInfo);
+ [DllImport("user32.dll")]
+ internal static extern uint MapVirtualKey(uint uCode, uint uMapType);
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct LUID
+ {
+ internal int LowPart;
+ internal int HighPart;
+ }// end struct
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct LUID_AND_ATTRIBUTES
+ {
+ internal LUID Luid;
+ internal int Attributes;
+ }// end struct
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct TOKEN_PRIVILEGES
+ {
+ internal int PrivilegeCount;
+
+ // LUID_AND_ATTRIBUTES
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ internal int[] Privileges;
+ }
+
+ internal const int READ_CONTROL = 0x00020000;
+
+ internal const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
+
+ internal const int STANDARD_RIGHTS_READ = READ_CONTROL;
+ internal const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
+ internal const int STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
+
+ internal const int STANDARD_RIGHTS_ALL = 0x001F0000;
+
+ internal const int SPECIFIC_RIGHTS_ALL = 0x0000FFFF;
+
+ internal const int TOKEN_IMPERSONATE = 0x0004;
+ internal const int TOKEN_QUERY_SOURCE = 0x0010;
+ internal const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
+ internal const int TOKEN_ADJUST_GROUPS = 0x0040;
+ internal const int TOKEN_ADJUST_SESSIONID = 0x0100;
+
+ internal const int TOKEN_ALL_ACCESS_P = STANDARD_RIGHTS_REQUIRED |
+ TOKEN_ASSIGN_PRIMARY |
+ TOKEN_DUPLICATE |
+ TOKEN_IMPERSONATE |
+ TOKEN_QUERY |
+ TOKEN_QUERY_SOURCE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT;
+
+ internal const int TOKEN_ALL_ACCESS = TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID;
+
+ internal const int TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY;
+
+ internal const int TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT;
+
+ internal const int TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE;
+
+ internal const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
+ internal const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
+
+ internal const int IDLE_PRIORITY_CLASS = 0x40;
+ internal const int NORMAL_PRIORITY_CLASS = 0x20;
+ internal const int HIGH_PRIORITY_CLASS = 0x80;
+ internal const int REALTIME_PRIORITY_CLASS = 0x100;
+
+ internal const int CREATE_NEW_CONSOLE = 0x00000010;
+
+ internal const string SE_DEBUG_NAME = "SeDebugPrivilege";
+ internal const string SE_RESTORE_NAME = "SeRestorePrivilege";
+ internal const string SE_BACKUP_NAME = "SeBackupPrivilege";
+
+ internal const int SE_PRIVILEGE_ENABLED = 0x0002;
+
+ internal const int ERROR_NOT_ALL_ASSIGNED = 1300;
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PROCESSENTRY32
+ {
+ internal uint dwSize;
+ internal uint cntUsage;
+ internal uint th32ProcessID;
+ internal IntPtr th32DefaultHeapID;
+ internal uint th32ModuleID;
+ internal uint cntThreads;
+ internal uint th32ParentProcessID;
+ internal int pcPriClassBase;
+ internal uint dwFlags;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ internal string szExeFile;
+ }
+
+ internal const uint TH32CS_SNAPPROCESS = 0x00000002;
+
+ // internal static int INVALID_HANDLE_VALUE = -1;
+ [DllImport("kernel32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CloseHandle(IntPtr hSnapshot);
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SECURITY_ATTRIBUTES
+ {
+ internal int Length;
+ internal IntPtr lpSecurityDescriptor;
+ internal bool bInheritHandle;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PROCESS_INFORMATION
+ {
+ internal IntPtr hProcess;
+ internal IntPtr hThread;
+ internal uint dwProcessId;
+ internal uint dwThreadId;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct STARTUPINFO
+ {
+ internal int cb;
+ internal string lpReserved;
+ internal string lpDesktop;
+ internal string lpTitle;
+ internal uint dwX;
+ internal uint dwY;
+ internal uint dwXSize;
+ internal uint dwYSize;
+ internal uint dwXCountChars;
+ internal uint dwYCountChars;
+ internal uint dwFillAttribute;
+ internal uint dwFlags;
+ internal short wShowWindow;
+ internal short cbReserved2;
+ internal IntPtr lpReserved2;
+ internal IntPtr hStdInput;
+ internal IntPtr hStdOutput;
+ internal IntPtr hStdError;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SID_AND_ATTRIBUTES
+ {
+ internal IntPtr Sid;
+ internal int Attributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct TOKEN_MANDATORY_LABEL
+ {
+ internal SID_AND_ATTRIBUTES Label;
+ }
+
+ internal const int TOKEN_DUPLICATE = 0x0002;
+ internal const int TOKEN_QUERY = 0x0008;
+ internal const int TOKEN_ADJUST_DEFAULT = 0x0080;
+ internal const int TOKEN_ASSIGN_PRIMARY = 0x0001;
+ internal const uint MAXIMUM_ALLOWED = 0x2000000;
+ internal const int SE_GROUP_INTEGRITY = 0x00000020;
+
+ internal enum SECURITY_IMPERSONATION_LEVEL : int
+ {
+ SecurityAnonymous = 0,
+ SecurityIdentification = 1,
+ SecurityImpersonation = 2,
+ SecurityDelegation = 3,
+ }
+
+ internal enum TOKEN_TYPE : int
+ {
+ TokenPrimary = 1,
+ TokenImpersonation = 2,
+ }
+
+ internal enum TOKEN_INFORMATION_CLASS : int
+ {
+ TokenUser = 1,
+ TokenGroups,
+ TokenPrivileges,
+ TokenOwner,
+ TokenPrimaryGroup,
+ TokenDefaultDacl,
+ TokenSource,
+ TokenType,
+ TokenImpersonationLevel,
+ TokenStatistics,
+ TokenRestrictedSids,
+ TokenSessionId,
+ TokenGroupsAndPrivileges,
+ TokenSessionReference,
+ TokenSandBoxInert,
+ TokenAuditPolicy,
+ TokenOrigin,
+ TokenElevationType,
+ TokenLinkedToken,
+ TokenElevation,
+ TokenHasRestrictions,
+ TokenAccessInformation,
+ TokenVirtualizationAllowed,
+ TokenVirtualizationEnabled,
+ TokenIntegrityLevel,
+ TokenUIAccess,
+ TokenMandatoryPolicy,
+ TokenLogonSid,
+ MaxTokenInfoClass,
+ }
+
+ // [DllImport("kernel32.dll")]
+ // internal static extern int Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
+
+ // [DllImport("kernel32.dll")]
+ // internal static extern int Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
+
+ // [DllImport("kernel32.dll", SetLastError = true)]
+ // internal static extern IntPtr CreateToolhelp32Snapshot(UInt32 dwFlags, UInt32 th32ProcessID);
+ [DllImport("Wtsapi32.dll")]
+ internal static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
+
+ [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "1", Justification = "Dotnet port with style preservation")]
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
+
+ // [DllImport("kernel32.dll")]
+ // [return: MarshalAs(UnmanagedType.Bool)]
+ // static extern bool ProcessIdToSessionId(UInt32 dwProcessId, ref UInt32 pSessionId);
+ [DllImport("kernel32.dll")]
+ internal static extern IntPtr OpenProcess(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength);
+
+ [DllImport("userenv.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, [MarshalAs(UnmanagedType.Bool)] bool bInherit);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool RevertToSelf();
+
+ internal delegate bool EnumMonitorsDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData);
+
+ internal delegate int HookProc(int nCode, int wParam, IntPtr lParam);
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ internal class MEMORYSTATUSEX
+ {
+ public uint dwLength;
+ public uint dwMemoryLoad;
+ public ulong ullTotalPhys;
+ public ulong ullAvailPhys;
+ public ulong ullTotalPageFile;
+ public ulong ullAvailPageFile;
+ public ulong ullTotalVirtual;
+ public ulong ullAvailVirtual;
+ public ulong ullAvailExtendedVirtual;
+
+ public MEMORYSTATUSEX()
+ {
+ dwLength = (uint)Marshal.SizeOf(typeof(MEMORYSTATUSEX));
+ }
+ }
+
+ [return: MarshalAs(UnmanagedType.Bool)]
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ internal static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
+
+ /*
+ [DllImport("Netapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
+ internal extern static int NetUserGetInfo([MarshalAs(UnmanagedType.LPWStr)] string ServerName,
+ [MarshalAs(UnmanagedType.LPWStr)] string UserName, int level,out IntPtr BufPtr);
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal struct USER_INFO_10
+ {
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string usri10_name;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string usri10_comment;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string usri10_usr_comment;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string usri10_full_name;
+ }
+
+ [DllImport("Netapi32.dll", SetLastError = true)]
+ internal static extern int NetApiBufferFree(IntPtr Buffer);
+ */
+
+ internal enum EXTENDED_NAME_FORMAT
+ {
+ NameUnknown = 0,
+ NameFullyQualifiedDN = 1,
+ NameSamCompatible = 2,
+ NameDisplay = 3,
+ NameUniqueId = 6,
+ NameCanonical = 7,
+ NameUserPrincipal = 8,
+ NameCanonicalEx = 9,
+ NameServicePrincipal = 10,
+ NameDnsDomain = 12,
+ }
+
+ [DllImport("secur32.dll", CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ internal static extern bool GetUserNameEx(int nameFormat, StringBuilder userName, ref uint userNameSize);
+
+ [DllImport("Shcore.dll", SetLastError = true)]
+ internal static extern int GetDpiForMonitor(IntPtr hMonitor, uint dpiType, out uint dpiX, out uint dpiY);
+
+ private static string GetDNSDomain()
+ {
+ if (Environment.OSVersion.Platform != PlatformID.Win32NT)
+ {
+ return null;
+ }
+
+ StringBuilder userName = new(1024);
+ uint userNameSize = (uint)userName.Capacity;
+
+ if (GetUserNameEx((int)EXTENDED_NAME_FORMAT.NameDnsDomain, userName, ref userNameSize))
+ {
+ string[] nameParts = userName.ToString()
+ .Split('\\');
+ return nameParts.Length != 2 ? null : nameParts[0];
+ }
+
+ return null;
+ }
+
+ ///
+ /// Use this method to figure out if your code is running on a Microsoft computer.
+ ///
+ ///
+ internal static bool IsRunningAtMicrosoft()
+ {
+ string domain = GetDNSDomain();
+
+ return !string.IsNullOrEmpty(domain) && domain.EndsWith("microsoft.com", true, System.Globalization.CultureInfo.CurrentCulture);
+ }
+
+ private NativeMethods()
+ {
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Program.cs b/src/modules/MouseWithoutBorders/App/Class/Program.cs
new file mode 100644
index 000000000000..0ecaff6b241e
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Program.cs
@@ -0,0 +1,402 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Application entry and pre-process/initialization.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing.Printing;
+using System.Globalization;
+using System.IO;
+using System.IO.Pipes;
+using System.Linq;
+using System.Security.Authentication.ExtendedProtection;
+using System.Security.Principal;
+using System.ServiceModel.Channels;
+using System.ServiceProcess;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using System.Xml.Linq;
+using ManagedCommon;
+using Microsoft.PowerToys.Settings.UI.Library.Utilities;
+using Microsoft.PowerToys.Telemetry;
+using Newtonsoft.Json;
+using StreamJsonRpc;
+
+[module: SuppressMessage("Microsoft.MSInternal", "CA904:DeclareTypesInMicrosoftOrSystemNamespace", Scope = "namespace", Target = "MouseWithoutBorders", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1014:MarkAssembliesWithClsCompliant", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", Scope = "member", Target = "MouseWithoutBorders.Program.#Main()", MessageId = "System.String.ToLower", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.Program.#Main()", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders.Class
+{
+ internal static class Program
+ {
+ private static readonly string ServiceName = "PowerToys.MWB.Service";
+
+ private static readonly string ServiceModeArg = "UseService";
+
+ [STAThread]
+ private static void Main()
+ {
+ ManagedCommon.Logger.InitializeLogger("\\MouseWithoutBorders\\Logs");
+ Common.Log(Application.ProductName + " Started!");
+
+ if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
+ {
+ Common.Log("Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.");
+ return;
+ }
+
+ Thread.CurrentThread.Name = Application.ProductName + " main thread";
+ Common.BinaryName = Path.GetFileNameWithoutExtension(Application.ExecutablePath);
+
+ WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
+ SecurityIdentifier currentUserSID = currentUser.User;
+ SecurityIdentifier localSystemSID = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
+
+ bool runningAsSystem = currentUserSID.Equals(localSystemSID);
+ Common.RunWithNoAdminRight = !runningAsSystem;
+ try
+ {
+ string[] args = Environment.GetCommandLineArgs();
+
+ string firstArg = string.Empty;
+ if (args.Length > 1 && args[1] != null)
+ {
+ firstArg = args[1].Trim();
+ }
+
+ User = WindowsIdentity.GetCurrent().Name;
+ Common.LogDebug("*** Started as " + User);
+
+ Common.Log(Environment.CommandLine);
+
+ bool serviceMode = firstArg == ServiceModeArg;
+
+ // If we're started from the .dll module or from the service process, we should
+ // assume the service mode.
+ if (serviceMode || runningAsSystem)
+ {
+ if (!runningAsSystem)
+ {
+ var sc = new ServiceController(ServiceName);
+ sc.Start();
+ return;
+ }
+
+ if (args.Length > 2)
+ {
+ Helper.UserLocalAppDataPath = args[2].Trim();
+ }
+ }
+
+ ShutdownWithPowerToys.WaitForPowerToysRunner();
+
+ if (firstArg != string.Empty)
+ {
+ if (Common.CheckSecondInstance(Common.RunWithNoAdminRight))
+ {
+ Common.Log("*** Second instance, exiting...");
+ return;
+ }
+
+ string myDesktop = Common.GetMyDesktop();
+
+ if (firstArg.Equals("winlogon", StringComparison.OrdinalIgnoreCase))
+ {
+ // Executed by service, running on logon desktop
+ Common.Log("*** Running on " + firstArg + " desktop");
+ Common.RunOnLogonDesktop = true;
+ }
+ else if (args[1].Trim().Equals("default", StringComparison.OrdinalIgnoreCase))
+ {
+ Common.Log("*** Running on " + firstArg + " desktop");
+ }
+ else if (args[1].Equals(myDesktop, StringComparison.OrdinalIgnoreCase))
+ {
+ Common.Log("*** Running on " + myDesktop);
+ if (myDesktop.Equals("Screen-saver", StringComparison.OrdinalIgnoreCase))
+ {
+ Common.RunOnScrSaverDesktop = true;
+ Setting.Values.LastX = Common.JUST_GOT_BACK_FROM_SCREEN_SAVER;
+ }
+ }
+ }
+ else
+ {
+ if (Common.CheckSecondInstance(true))
+ {
+ Common.Log("*** Second instance, exiting...");
+ return;
+ }
+ }
+
+ PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersStartedEvent());
+
+ try
+ {
+ Common.CurrentProcess = Process.GetCurrentProcess();
+ Common.CurrentProcess.PriorityClass = ProcessPriorityClass.RealTime;
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+
+ Common.Log(Environment.OSVersion.ToString());
+
+ // Environment.OSVersion is unreliable from 6.2 and up, so just forcefully call the APIs and log the exception unsupported by Windows:
+ int setProcessDpiAwarenessResult = -1;
+
+ try
+ {
+ setProcessDpiAwarenessResult = NativeMethods.SetProcessDpiAwareness(2);
+ Common.Log(string.Format(CultureInfo.InvariantCulture, "SetProcessDpiAwareness: {0}.", setProcessDpiAwarenessResult));
+ }
+ catch (DllNotFoundException)
+ {
+ Common.Log("SetProcessDpiAwareness is unsupported in Windows 7 and lower.");
+ }
+ catch (EntryPointNotFoundException)
+ {
+ Common.Log("SetProcessDpiAwareness is unsupported in Windows 7 and lower.");
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+
+ try
+ {
+ if (setProcessDpiAwarenessResult != 0)
+ {
+ Common.Log(string.Format(CultureInfo.InvariantCulture, "SetProcessDPIAware: {0}.", NativeMethods.SetProcessDPIAware()));
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+
+ System.Threading.Thread mainUIThread = Thread.CurrentThread;
+ Common.UIThreadID = mainUIThread.ManagedThreadId;
+ Thread.UpdateThreads(mainUIThread);
+
+ StartInputCallbackThread();
+ if (!Common.RunOnLogonDesktop)
+ {
+ StartSettingSyncThread();
+ }
+
+ Application.EnableVisualStyles();
+ _ = Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
+ Application.SetCompatibleTextRenderingDefault(false);
+
+ Common.Init();
+ Common.WndProcCounter++;
+
+ var formScreen = new FrmScreen();
+
+ Application.Run(formScreen);
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ private interface ISettingsSyncHelper
+ {
+ [JsonObject(MemberSerialization.OptIn)]
+ public struct MachineSocketState
+ {
+ // Disable false-positive warning due to IPC
+#pragma warning disable CS0649
+ [JsonProperty]
+ public string Name;
+
+ [JsonProperty]
+ public SocketStatus Status;
+#pragma warning restore CS0649
+ }
+
+ void Shutdown();
+
+ void Reconnect();
+
+ void GenerateNewKey();
+
+ void ConnectToMachine(string machineName, string securityKey);
+
+ Task RequestMachineSocketStateAsync();
+ }
+
+ private sealed class SettingsSyncHelper : ISettingsSyncHelper
+ {
+ public Task RequestMachineSocketStateAsync()
+ {
+ var machineStates = new Dictionary();
+ if (Common.Sk == null || Common.Sk.TcpSockets == null)
+ {
+ return Task.FromResult(Array.Empty());
+ }
+
+ foreach (var client in Common.Sk.TcpSockets
+ .Where(t => t != null && t.IsClient && !string.IsNullOrEmpty(t.MachineName)))
+ {
+ var exists = machineStates.TryGetValue(client.MachineName, out var existingStatus);
+ if (!exists || existingStatus == SocketStatus.NA)
+ {
+ machineStates[client.MachineName] = client.Status;
+ }
+ }
+
+ return Task.FromResult(machineStates.Select((state) => new ISettingsSyncHelper.MachineSocketState { Name = state.Key, Status = state.Value }).ToArray());
+ }
+
+ public void ConnectToMachine(string pcName, string securityKey)
+ {
+ Setting.Values.PauseInstantSaving = true;
+
+ Common.ClearComputerMatrix();
+ Setting.Values.MyKey = securityKey;
+ Common.MyKey = securityKey;
+ Common.MagicNumber = Common.Get24BitHash(Common.MyKey);
+ Common.MachineMatrix = new string[Common.MAX_MACHINE] { pcName.Trim().ToUpper(CultureInfo.CurrentCulture), Common.MachineName.Trim(), string.Empty, string.Empty };
+
+ string[] machines = Common.MachineMatrix;
+ Common.MachinePool.Initialize(machines);
+ Common.UpdateMachinePoolStringSetting();
+
+ SocketStuff.InvalidKeyFound = false;
+ Common.ReopenSocketDueToReadError = true;
+ Common.ReopenSockets(true);
+ Common.SendMachineMatrix();
+
+ Setting.Values.PauseInstantSaving = false;
+ Setting.Values.SaveSettings();
+ }
+
+ public void GenerateNewKey()
+ {
+ Setting.Values.PauseInstantSaving = true;
+
+ Setting.Values.EasyMouse = (int)EasyMouseOption.Enable;
+ Common.ClearComputerMatrix();
+ Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
+ Common.GeneratedKey = true;
+
+ Setting.Values.PauseInstantSaving = false;
+ Setting.Values.SaveSettings();
+
+ Reconnect();
+ }
+
+ public void Reconnect()
+ {
+ SocketStuff.InvalidKeyFound = false;
+ Common.ReopenSocketDueToReadError = true;
+ Common.ReopenSockets(true);
+
+ for (int i = 0; i < 10; i++)
+ {
+ if (Common.AtLeastOneSocketConnected())
+ {
+ Common.MMSleep(0.5);
+ break;
+ }
+
+ Common.MMSleep(0.2);
+ }
+
+ Common.SendMachineMatrix();
+ }
+
+ public void Shutdown()
+ {
+ Process[] ps = Process.GetProcessesByName("PowerToys.MouseWithoutBorders");
+ Process me = Process.GetCurrentProcess();
+
+ foreach (Process p in ps)
+ {
+ if (p.Id != me.Id)
+ {
+ p.Kill();
+ }
+ }
+
+ Common.MainForm.Quit(true, false);
+ }
+ }
+
+ internal static void StartSettingSyncThread()
+ {
+ var serverTaskCancellationSource = new CancellationTokenSource();
+ CancellationToken cancellationToken = serverTaskCancellationSource.Token;
+
+ IpcChannel.StartIpcServer("MouseWithoutBorders/SettingsSync", cancellationToken);
+ }
+
+ internal static void StartInputCallbackThread()
+ {
+ System.Collections.Hashtable dummy = Setting.Values.VKMap; // Reading from registry to memory.
+ Thread inputCallback = new(new ThreadStart(InputCallbackThread), "InputCallback Thread");
+ inputCallback.SetApartmentState(ApartmentState.STA);
+ inputCallback.Priority = ThreadPriority.Highest;
+ inputCallback.Start();
+ }
+
+ private static void InputCallbackThread()
+ {
+ Common.InputCallbackThreadID = Thread.CurrentThread.ManagedThreadId;
+ while (!Common.InitDone)
+ {
+ Thread.Sleep(100);
+ }
+
+ Application.Run(new FrmInputCallback());
+ }
+
+ internal static void StartService()
+ {
+ if (Common.RunWithNoAdminRight)
+ {
+ return;
+ }
+
+ try
+ {
+ // Kill all but me
+ Process me = Process.GetCurrentProcess();
+ Process[] ps = Process.GetProcessesByName(Common.BinaryName);
+ foreach (Process pp in ps)
+ {
+ if (pp.Id != me.Id)
+ {
+ Common.Log(string.Format(CultureInfo.InvariantCulture, "Killing process {0}.", pp.Id));
+ pp.KillProcess();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+
+ Common.StartMouseWithoutBordersService();
+ }
+
+ internal static string User { get; set; }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/Setting.cs b/src/modules/MouseWithoutBorders/App/Class/Setting.cs
new file mode 100644
index 000000000000..808990680a77
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/Setting.cs
@@ -0,0 +1,1039 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.IO;
+using System.IO.Abstractions;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Microsoft.PowerToys.Settings.UI.Library;
+using Microsoft.PowerToys.Settings.UI.Library.Utilities;
+
+//
+// Application settings.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using Microsoft.Win32;
+
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Properties.Setting.Values.#LoadIntSetting(System.String,System.Int32)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Properties.Setting.Values.#SaveSetting(System.String,System.Object)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Properties.Setting.Values.#LoadStringSetting(System.String,System.String)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.Properties.Setting.Values.#SaveSettingQWord(System.String,System.Int64)", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders.Class
+{
+ internal class Settings
+ {
+ internal bool Changed;
+
+ private readonly ISettingsUtils _settingsUtils;
+ private readonly object _loadingSettingsLock = new object();
+ private readonly IFileSystemWatcher _watcher;
+
+ private MouseWithoutBordersProperties _properties;
+ private MouseWithoutBordersSettings _settings;
+
+ // Avoid instantly saving every change to the file when updating properties.
+ public bool PauseInstantSaving { get; set; }
+
+ private void UpdateSettingsFromJson()
+ {
+ try
+ {
+ if (!_settingsUtils.SettingsExists("MouseWithoutBorders"))
+ {
+ var defaultSettings = new MouseWithoutBordersSettings();
+ if (!Common.RunOnLogonDesktop)
+ {
+ defaultSettings.Save(_settingsUtils);
+ }
+ }
+
+ var settings = _settingsUtils.GetSettingsOrDefault("MouseWithoutBorders");
+ if (settings != null)
+ {
+ PauseInstantSaving = true;
+
+ var last_properties = _properties;
+
+ _settings = settings;
+
+ _properties = settings.Properties;
+
+ // Keep track of the need to resend the machine matrix.
+ bool shouldSendMachineMatrix = false;
+
+ // Keep track of the need to save into the settings file.
+ bool shouldSaveNewSettingsValues = false;
+
+ if (last_properties != null)
+ {
+ // Same as in CheckBoxCircle_CheckedChanged
+ if (last_properties.WrapMouse != _settings.Properties.WrapMouse)
+ {
+ shouldSendMachineMatrix = true;
+ }
+
+ // Same as CheckBoxDrawMouse_CheckedChanged
+ if (last_properties.DrawMouseCursor != _settings.Properties.DrawMouseCursor && !_settings.Properties.DrawMouseCursor)
+ {
+ CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue);
+ }
+
+ if (!Enumerable.SequenceEqual(last_properties.MachineMatrixString, _settings.Properties.MachineMatrixString))
+ {
+ _properties.MachineMatrixString = _settings.Properties.MachineMatrixString;
+ Common.MachineMatrix = null; // Forces read next time it's needed.
+ shouldSendMachineMatrix = true;
+ }
+
+ var shouldReopenSockets = false;
+
+ if (Common.MyKey != _properties.SecurityKey.Value)
+ {
+ Common.MyKey = _properties.SecurityKey.Value;
+ shouldReopenSockets = true;
+ }
+
+ if (shouldReopenSockets)
+ {
+ SocketStuff.InvalidKeyFound = false;
+ Common.ReopenSocketDueToReadError = true;
+ Common.ReopenSockets(true);
+ }
+
+ if (shouldSendMachineMatrix)
+ {
+ Common.SendMachineMatrix();
+ shouldSaveNewSettingsValues = true;
+ }
+
+ if (shouldSaveNewSettingsValues)
+ {
+ SaveSettings();
+ }
+ }
+ }
+ }
+ catch (IOException ex)
+ {
+ Logger.LogEvent($"Failed to read settings: {ex.Message}", System.Diagnostics.EventLogEntryType.Error);
+ }
+
+ PauseInstantSaving = false;
+ }
+
+ public void SaveSettings()
+ {
+ if (!Common.RunOnLogonDesktop)
+ {
+ SaveSettingsToJson((MouseWithoutBordersProperties)_properties.Clone());
+ }
+ }
+
+ private void SaveSettingsToJson(MouseWithoutBordersProperties properties_to_save)
+ {
+ _settings.Properties = properties_to_save;
+ _ = Task.Factory.StartNew(
+ () =>
+ {
+ bool saved = false;
+
+ for (int i = 0; i < 5; ++i)
+ {
+ try
+ {
+ lock (_loadingSettingsLock)
+ {
+ _settings.Save(_settingsUtils);
+ }
+
+ saved = true;
+ }
+ catch (IOException ex)
+ {
+ Logger.LogEvent($"Failed to write settings: {ex.Message}", System.Diagnostics.EventLogEntryType.Error);
+ }
+
+ if (saved)
+ {
+ break;
+ }
+ else
+ {
+ Thread.Sleep(500);
+ }
+ }
+ },
+ System.Threading.CancellationToken.None,
+ TaskCreationOptions.None,
+ TaskScheduler.Default);
+ }
+
+ internal Settings()
+ {
+ _settingsUtils = new SettingsUtils();
+
+ _watcher = Helper.GetFileWatcher("MouseWithoutBorders", "settings.json", () =>
+ {
+ try
+ {
+ UpdateSettingsFromJson();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogEvent($"Failed to update settings: {ex.Message}", System.Diagnostics.EventLogEntryType.Error);
+ }
+ });
+
+ UpdateSettingsFromJson();
+ }
+
+ internal string Username { get; set; }
+
+ internal bool IsMyKeyRandom { get; set; }
+
+ internal string MachineMatrixString
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return string.Join(",", _properties.MachineMatrixString);
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.MachineMatrixString = new List(value.Split(","));
+ if (!PauseInstantSaving)
+ {
+ SaveSettings();
+ }
+ }
+ }
+ }
+
+ internal string MachinePoolString
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.MachinePool.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ if (!value.Equals(_properties.MachinePool.Value, StringComparison.OrdinalIgnoreCase))
+ {
+ _properties.MachinePool.Value = value;
+ }
+ }
+ }
+ }
+
+ internal string MyID => Application.ProductName + " Application";
+
+ internal string MyIdEx => Application.ProductName + " Application-Ex";
+
+ internal bool ShareClipboard
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.ShareClipboard;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.ShareClipboard = value;
+ }
+ }
+ }
+
+ internal bool TransferFile
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.TransferFile;
+ }
+ }
+
+ set
+ {
+ _properties.TransferFile = value;
+ }
+ }
+
+ internal bool MatrixOneRow
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.MatrixOneRow;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.MatrixOneRow = true;
+ if (!PauseInstantSaving)
+ {
+ SaveSettings();
+ }
+ }
+ }
+ }
+
+ internal bool MatrixCircle
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.WrapMouse;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.WrapMouse = value;
+ if (!PauseInstantSaving)
+ {
+ SaveSettings();
+ }
+ }
+ }
+ }
+
+ internal int EasyMouse
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.EasyMouse.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.EasyMouse.Value = value;
+ if (!PauseInstantSaving)
+ {
+ // Easy Mouse can be enabled or disabled through a shortcut, so a save is required.
+ SaveSettings();
+ }
+ }
+ }
+ }
+
+ internal bool BlockMouseAtCorners
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.BlockMouseAtScreenCorners;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.BlockMouseAtScreenCorners = value;
+ }
+ }
+ }
+
+ internal string Enc(string st, bool dec, DataProtectionScope protectionScope)
+ {
+ if (st == null || st.Length < 1)
+ {
+ return string.Empty;
+ }
+
+ byte[] ep = Common.GetBytesU(st);
+ byte[] rv, st2;
+
+ if (dec)
+ {
+ st2 = Convert.FromBase64String(st);
+ rv = ProtectedData.Unprotect(st2, ep, protectionScope);
+ return Common.GetStringU(rv);
+ }
+ else
+ {
+ st2 = Common.GetBytesU(st);
+ rv = ProtectedData.Protect(st2, ep, protectionScope);
+ return Convert.ToBase64String(rv);
+ }
+ }
+
+ internal string MyKey
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ if (_properties.SecurityKey.Value.Length != 0)
+ {
+ Common.LogDebug("GETSECKEY: Key was already loaded/set: " + _properties.SecurityKey.Value);
+ return _properties.SecurityKey.Value;
+ }
+ else
+ {
+ string randomKey = Common.CreateDefaultKey();
+ _properties.SecurityKey.Value = randomKey;
+
+ return randomKey;
+ }
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.SecurityKey.Value = value;
+ if (!PauseInstantSaving)
+ {
+ SaveSettings();
+ }
+ }
+ }
+ }
+
+ internal int MyKeyDaysToExpire
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return int.MaxValue; // TODO(@yuyoyuppe): do we still need expiration mechanics now?
+ }
+ }
+ }
+
+ internal bool DisableCAD
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ internal bool HideLogonLogo
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ internal bool HideMouse
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.HideMouseAtScreenEdge;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.HideMouseAtScreenEdge = value;
+ }
+ }
+ }
+
+ internal bool BlockScreenSaver
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.BlockScreenSaverOnOtherMachines;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.BlockScreenSaverOnOtherMachines = value;
+ }
+ }
+ }
+
+ internal bool BlockScreenSaverEx
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.BlockScreenSaverOnOtherMachines;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.BlockScreenSaverOnOtherMachines = value;
+ }
+ }
+ }
+
+ internal bool MoveMouseRelatively
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.MoveMouseRelatively;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.MoveMouseRelatively = value;
+ }
+ }
+ }
+
+ internal string LastPersonalizeLogonScr
+ {
+ get
+ {
+ return string.Empty;
+ }
+ }
+
+ internal uint DesMachineID
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return (uint)_properties.MachineID.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.MachineID.Value = (int)value;
+ }
+ }
+ }
+
+ internal int LastX
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.LastX.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ Common.LastX = value;
+ _properties.LastX.Value = value;
+ }
+ }
+ }
+
+ internal int LastY
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.LastY.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ Common.LastY = value;
+ _properties.LastY.Value = value;
+ }
+ }
+ }
+
+ internal int PackageID
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.PackageID.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.PackageID.Value = value;
+ }
+ }
+ }
+
+ internal bool FirstRun
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.FirstRun;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.FirstRun = value;
+ if (!PauseInstantSaving)
+ {
+ SaveSettings();
+ }
+ }
+ }
+ }
+
+ internal int HotKeySwitchMachine
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.HotKeySwitchMachine.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.HotKeySwitchMachine.Value = value;
+ }
+ }
+ }
+
+ internal int HotKeyToggleEasyMouse
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.HotKeyToggleEasyMouse.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.HotKeyToggleEasyMouse.Value = value;
+ }
+ }
+ }
+
+ internal int HotKeyLockMachine
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.HotKeyLockMachine.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.HotKeyLockMachine.Value = value;
+ }
+ }
+ }
+
+ internal int HotKeyReconnect
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.HotKeyReconnect.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.HotKeyReconnect.Value = value;
+ }
+ }
+ }
+
+ internal int HotKeyCaptureScreen
+ {
+ get
+ {
+ return 0;
+ }
+ }
+
+ internal int HotKeyExitMM
+ {
+ get
+ {
+ return 0;
+ }
+ }
+
+ internal int HotKeySwitch2AllPC
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.HotKeySwitch2AllPC.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.HotKeySwitch2AllPC.Value = value;
+ }
+ }
+ }
+
+ private int switchCount;
+
+ internal int SwitchCount
+ {
+ get
+ {
+ return switchCount;
+ }
+
+ set
+ {
+ switchCount = value;
+ if (!PauseInstantSaving)
+ {
+ SaveSettings();
+ }
+ }
+ }
+
+ internal int DumpObjectsLevel => 6;
+
+ internal int TcpPort => _properties.TCPPort.Value;
+
+ internal bool DrawMouse
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.DrawMouseCursor;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.DrawMouseCursor = value;
+ }
+ }
+ }
+
+ internal bool DrawMouseEx
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.DrawMouseEx;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.DrawMouseEx = value;
+ }
+ }
+ }
+
+ internal bool ReverseLookup
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.ValidateRemoteMachineIP;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.ValidateRemoteMachineIP = value;
+ }
+ }
+ }
+
+ internal bool SameSubNetOnly
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.SameSubnetOnly;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.SameSubnetOnly = value;
+ }
+ }
+ }
+
+ internal string Name2IP
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.Name2IP.Value;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.Name2IP.Value = value;
+ }
+ }
+ }
+
+ internal bool UseVKMap
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.UseVKMap;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.UseVKMap = value;
+ }
+ }
+ }
+
+ internal bool FirstCtrlShiftS
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.FirstCtrlShiftS;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.FirstCtrlShiftS = value;
+ }
+ }
+ }
+
+ internal Hashtable VKMap
+ {
+ get
+ {
+ return new Hashtable();
+ }
+ }
+
+ internal bool StealFocusWhenSwitchingMachine => _properties.StealFocusWhenSwitchingMachine;
+
+ private string deviceId;
+
+ internal string DeviceId
+ {
+ get
+ {
+ string newGuid = Guid.NewGuid().ToString();
+
+ if (deviceId == null || deviceId.Length != newGuid.Length)
+ {
+ string defaultId = newGuid;
+ lock (_loadingSettingsLock)
+ {
+ _properties.DeviceID = defaultId;
+ deviceId = _properties.DeviceID.Value;
+
+ if (deviceId.Equals(defaultId, StringComparison.OrdinalIgnoreCase))
+ {
+ return _properties.DeviceID.Value;
+ }
+ }
+ }
+
+ return deviceId;
+ }
+ }
+
+ private int? machineId;
+
+ internal int MachineId
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ machineId ??= (machineId = _properties.MachineID.Value).Value;
+
+ if (machineId == 0)
+ {
+ _properties.MachineID.Value = Common.Ran.Next();
+ machineId = _properties.MachineID.Value;
+ }
+ }
+
+ return machineId.Value;
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.MachineID.Value = value;
+ }
+ }
+ }
+
+ internal bool OneWayControlMode => false;
+
+ internal bool OneWayClipboardMode => false;
+
+ internal bool ShowClipNetStatus
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.ShowClipboardAndNetworkStatusMessages;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.ShowClipboardAndNetworkStatusMessages = value;
+ }
+ }
+ }
+
+ internal bool ShowOriginalUI
+ {
+ get
+ {
+ lock (_loadingSettingsLock)
+ {
+ return _properties.ShowOriginalUI;
+ }
+ }
+
+ set
+ {
+ lock (_loadingSettingsLock)
+ {
+ _properties.ShowOriginalUI = value;
+ }
+ }
+ }
+
+ internal bool SendErrorLogV2
+ {
+ get
+ {
+ return false;
+ }
+ }
+ }
+
+ public static class Setting
+ {
+ internal static Settings Values = new Settings();
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/SeverityLevel.cs b/src/modules/MouseWithoutBorders/App/Class/SeverityLevel.cs
new file mode 100644
index 000000000000..efae30f7e96e
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/SeverityLevel.cs
@@ -0,0 +1,21 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Logging.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+namespace MouseWithoutBorders.Class
+{
+ internal class SeverityLevel
+ {
+ internal static readonly SeverityLevel Information = new SeverityLevel();
+ internal static readonly SeverityLevel Error = new SeverityLevel();
+ internal static readonly SeverityLevel Warning = new SeverityLevel();
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs b/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs
new file mode 100644
index 000000000000..106ba6941ae2
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/SocketStuff.cs
@@ -0,0 +1,2099 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Net.Sockets;
+using System.Security.Cryptography;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+//
+// Socket code.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Exceptions;
+
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendData(System.Byte[])", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#Close()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#CreateSocket(System.Boolean)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendData(System.Byte[],MouseWithoutBorders.IP)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendData(System.Object)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendFile(System.Net.Sockets.Socket,System.String)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#MainTCPRoutine(System.Net.Sockets.Socket,System.String)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#TCPServerThread(System.Object)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendClipboardData(System.Object)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#StartNewTcpClient(MouseWithoutBorders.MachineInf)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#StartNewTcpServer(System.Net.Sockets.Socket,System.String)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#UpdateTCPClients()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#UpdateTcpSockets(System.Net.Sockets.Socket,MouseWithoutBorders.SocketStatus)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#.ctor(System.Int32,System.Boolean)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.SocketStuff.#SendData(System.Byte[],MouseWithoutBorders.IP,System.Int32)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable", Scope = "type", Target = "MouseWithoutBorders.SocketStuff", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders.Class
+{
+ internal enum SocketStatus : int
+ {
+ NA = 0,
+ Resolving = 1,
+ Connecting = 2,
+ Handshaking = 3,
+ Error = 4,
+ ForceClosed = 5,
+ InvalidKey = 6,
+ Timeout = 7,
+ SendError = 8,
+ Connected = 9,
+ }
+
+ internal class TcpSk : IDisposable
+ {
+ public TcpSk(bool isClient, Socket s, SocketStatus status, string machineName, IPAddress address = null)
+ {
+ IsClient = isClient;
+ BackingSocket = s;
+ Status = status;
+ MachineName = machineName;
+ Address = address;
+ BirthTime = Common.GetTick();
+ }
+
+ public bool IsClient { get; set; }
+
+ public Socket BackingSocket { get; set; }
+
+ public SocketStatus Status { get; set; }
+
+ public string MachineName { get; set; }
+
+ public long BirthTime { get; set; }
+
+ public uint MachineId { get; set; }
+
+ public IPAddress Address { get; set; }
+
+ private Stream encryptedStream;
+ private Stream decryptedStream;
+ private Stream socketStream;
+
+ public Stream EncryptedStream
+ {
+ get
+ {
+ if (encryptedStream == null && BackingSocket.Connected)
+ {
+ encryptedStream = Common.GetEncryptedStream(new NetworkStream(BackingSocket));
+ Common.SendOrReceiveARandomDataBlockPerInitialIV(encryptedStream);
+ }
+
+ return encryptedStream;
+ }
+ }
+
+ public Stream DecryptedStream
+ {
+ get
+ {
+ if (decryptedStream == null && BackingSocket.Connected)
+ {
+ decryptedStream = Common.GetDecryptedStream(new NetworkStream(BackingSocket));
+ Common.SendOrReceiveARandomDataBlockPerInitialIV(decryptedStream, false);
+ }
+
+ return decryptedStream;
+ }
+ }
+
+ public Stream SocketStream
+ {
+ get
+ {
+ if (socketStream == null && BackingSocket.Connected)
+ {
+ socketStream = new NetworkStream(BackingSocket);
+ }
+
+ return socketStream;
+ }
+ }
+
+ public void Dispose()
+ {
+ encryptedStream?.Dispose();
+
+ decryptedStream?.Dispose();
+
+ socketStream?.Dispose();
+ }
+ }
+
+ internal class SocketStuff
+ {
+ private readonly int bASE_PORT;
+ private TcpServer skClipboardServer;
+ private TcpServer skMessageServer;
+ internal object TcpSocketsLock = new();
+ internal static bool InvalidKeyFound;
+ internal static bool InvalidKeyFoundOnClientSocket;
+
+ internal const int CONNECT_TIMEOUT = 60000;
+ private static readonly ConcurrentDictionary FailedAttempt = new();
+
+ internal List TcpSockets
+ {
+ get; private set;
+
+ // set { tcpSockets = value; }
+ }
+
+ internal int TcpPort
+ {
+ get;
+
+ // set { tcpPort = value; }
+ }
+
+ private static bool firstRun;
+ private readonly long connectTimeout;
+ private static int restartCount;
+
+ internal SocketStuff(int port, bool byUser)
+ {
+ Common.LogDebug("SocketStuff started.");
+
+ bASE_PORT = port;
+ Common.Ran = new Random();
+
+ Common.LogDebug("Validating session...");
+
+ if (Common.CurrentProcess.SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
+ {
+ if (Common.DesMachineID != Common.MachineID)
+ {
+ Common.SwitchToMultipleMode(false, true);
+ }
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ Common.MainForm.SetTrayIconText("Not physical console session.");
+ if (byUser)
+ {
+ Common.ShowToolTip("Not physical console session.", 5000);
+ }
+ }
+
+ Common.MMSleep(1);
+ Common.Log("Not physical console session.");
+
+ throw new NotPhysicalConsoleException("Not physical console session.");
+ }
+
+ Common.LogDebug("Creating socket list and mutex...");
+
+ try
+ {
+ lock (TcpSocketsLock)
+ {
+ TcpSockets = new List();
+ }
+
+ bool dummy1 = Setting.Values.MatrixOneRow; // Reading from reg to variable
+ dummy1 = Setting.Values.MatrixCircle;
+
+ if (Setting.Values.IsMyKeyRandom)
+ {
+ Setting.Values.MyKey = Common.MyKey;
+ }
+
+ Common.MagicNumber = Common.Get24BitHash(Common.MyKey);
+ Common.PackageID = Setting.Values.PackageID;
+
+ TcpPort = bASE_PORT;
+
+ if (Common.SocketMutex == null)
+ {
+ firstRun = true;
+ Common.SocketMutex = new Mutex(false, $"Global\\{Application.ProductName}-{FrmAbout.AssemblyVersion}-FF7CDABE-1015-0904-1103-24670FA5D16E");
+ }
+
+ Common.AcquireSocketMutex();
+ }
+ catch (AbandonedMutexException e)
+ {
+ Common.TelemetryLogTrace($"{nameof(SocketStuff)}: {e.Message}", SeverityLevel.Warning);
+ }
+
+ Common.GetScreenConfig();
+
+ if (firstRun && Common.RunOnScrSaverDesktop)
+ {
+ firstRun = false;
+ }
+
+ // JUST_GOT_BACK_FROM_SCREEN_SAVER: For bug: monitor does not turn off after logon screen saver exits
+ else if (!Common.RunOnScrSaverDesktop)
+ {
+ if (Setting.Values.LastX == Common.JUST_GOT_BACK_FROM_SCREEN_SAVER)
+ {
+ Common.NewDesMachineID = Common.DesMachineID = Common.MachineID;
+ }
+ else
+ {
+ // Common.Log("Getting IP: " + Setting.Values.DesMachineID.ToString(CultureInfo.CurrentCulture));
+ Common.LastX = Setting.Values.LastX;
+ Common.LastY = Setting.Values.LastY;
+
+ if (Common.RunOnLogonDesktop && Setting.Values.DesMachineID == (uint)ID.ALL)
+ {
+ Common.SwitchToMultipleMode(true, false);
+ }
+ else
+ {
+ Common.SwitchToMultipleMode(false, false);
+ }
+ }
+ }
+
+ connectTimeout = Common.GetTick() + (CONNECT_TIMEOUT / 2);
+ Exception openSocketErr;
+
+ /*
+ * The machine might be getting a new IP address from its DHCP server
+ * for ex, when a laptop with a wireless connection just wakes up, might take long time:(
+ * */
+
+ Common.GetMachineName(); // IPs might have been changed
+ Common.UpdateMachineTimeAndID();
+
+ Common.LogDebug("Creating sockets...");
+
+ openSocketErr = CreateSocket();
+
+ int sleepSecs = 0, errCode = 0;
+
+ if (openSocketErr != null)
+ {
+ if (openSocketErr is SocketException)
+ {
+ errCode = (openSocketErr as SocketException).ErrorCode;
+
+ switch (errCode)
+ {
+ case 0: // No error.
+ break;
+
+ case 10048: // WSAEADDRINUSE
+ sleepSecs = 10;
+
+ // It is reasonable to give a try on restarting MwB processes in other sessions.
+ if (restartCount++ < 5 && Common.IsMyDesktopActive() && !Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ Common.TelemetryLogTrace("Restarting the service dues to WSAEADDRINUSE.", SeverityLevel.Warning);
+ Program.StartService();
+ Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
+ }
+
+ break;
+
+ case 10049: // WSAEADDRNOTAVAIL
+ sleepSecs = 1;
+ break;
+
+ default:
+ sleepSecs = 5;
+ break;
+ }
+ }
+ else
+ {
+ sleepSecs = 10;
+ }
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ if (byUser)
+ {
+ Common.ShowToolTip(errCode.ToString(CultureInfo.CurrentCulture) + ": " + openSocketErr.Message, 5000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+ }
+ }
+
+ Common.MMSleep(sleepSecs);
+ Common.ReleaseSocketMutex();
+ throw new ExpectedSocketException(openSocketErr.Message);
+ }
+ else
+ {
+ restartCount = 0;
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ IpcHelper.CreateIpcServer(false);
+ }
+
+ Common.MainForm.UpdateNotifyIcon();
+ }
+ }
+
+ internal void Close(bool sentWait)
+ {
+ try
+ {
+ if (!Common.RunOnScrSaverDesktop)
+ {
+ Setting.Values.LastX = Common.LastX;
+ Setting.Values.LastY = Common.LastY;
+ Setting.Values.PackageID = Common.PackageID;
+
+ // Common.Log("Saving IP: " + Setting.Values.DesMachineID.ToString(CultureInfo.CurrentCulture));
+ Setting.Values.DesMachineID = (uint)Common.DesMachineID;
+ }
+
+ _ = Common.ExecuteAndTrace(
+ "Closing sockets",
+ () =>
+ {
+ Common.LogDebug($"Closing socket [{skMessageServer?.Name}].");
+ skMessageServer?.Close(); // The original ones, not the socket instances produced by the accept() method.
+ skMessageServer = null;
+
+ Common.LogDebug($"Closing socket [{skClipboardServer?.Name}].");
+ skClipboardServer?.Close();
+ skClipboardServer = null;
+ try
+ {
+ // If these sockets are failed to be closed then the tool would not function properly, more logs are added for debugging.
+ lock (TcpSocketsLock)
+ {
+ int c = 0;
+
+ if (TcpSockets != null)
+ {
+ Common.LogDebug("********** Closing Sockets: " + TcpSockets.Count.ToString(CultureInfo.InvariantCulture));
+
+ List notClosedSockets = new();
+
+ foreach (TcpSk t in TcpSockets)
+ {
+ if (t != null && t.BackingSocket != null && t.Status != SocketStatus.Resolving)
+ {
+ try
+ {
+ t.MachineName = "$*NotUsed*$";
+ t.Status = t.Status >= 0 ? 0 : t.Status - 1;
+
+ if (sentWait)
+ {
+ t.BackingSocket.Close(1);
+ }
+ else
+ {
+ t.BackingSocket.Close();
+ }
+
+ c++;
+
+ continue;
+ }
+ catch (SocketException e)
+ {
+ string log = $"Socket.Close error: {e.GetType()}/{e.Message}. This is expected when the socket is already closed by remote host.";
+ Common.Log(log);
+ }
+ catch (ObjectDisposedException e)
+ {
+ string log = $"Socket.Close error: {e.GetType()}/{e.Message}. This is expected when the socket is already disposed.";
+ Common.Log(log);
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+
+ // If there was an error closing the socket:
+ if ((int)t.Status > -5)
+ {
+ notClosedSockets.Add(t); // Try to give a few times to close the socket later on.
+ }
+ }
+ }
+
+ TcpSockets = notClosedSockets;
+ }
+
+ Common.LogDebug("********** Sockets Closed: " + c.ToString(CultureInfo.CurrentCulture));
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ },
+ TimeSpan.FromSeconds(3),
+ true);
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ finally
+ {
+ Common.ReleaseSocketMutex();
+ }
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ try
+ {
+ IpcHelper.CreateIpcServer(true);
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+ }
+
+ private Exception CreateSocket()
+ {
+ try
+ {
+ skMessageServer = new TcpServer(TcpPort + 1, new ParameterizedThreadStart(TCPServerThread));
+ skClipboardServer = new TcpServer(TcpPort, new ParameterizedThreadStart(AcceptConnectionAndSendClipboardData));
+ }
+ catch (SocketException e)
+ {
+ Common.Log(e);
+ return e;
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ return e;
+ }
+
+ Common.LogDebug("==================================================");
+ return null;
+ }
+
+ private static int TcpSendData(TcpSk tcp, byte[] bytes)
+ {
+ Stream encryptedStream = tcp.EncryptedStream;
+
+ if (tcp.BackingSocket == null || !tcp.BackingSocket.Connected || encryptedStream == null)
+ {
+ string log = $"{nameof(TcpSendData)}: The socket is no longer connected, it could have been closed by the remote host.";
+ Common.Log(log);
+ throw new ExpectedSocketException(log);
+ }
+
+ bytes[3] = (byte)((Common.MagicNumber >> 24) & 0xFF);
+ bytes[2] = (byte)((Common.MagicNumber >> 16) & 0xFF);
+ bytes[1] = 0;
+ for (int i = 2; i < Common.PACKAGE_SIZE; i++)
+ {
+ bytes[1] = (byte)(bytes[1] + bytes[i]);
+ }
+
+ try
+ {
+ encryptedStream.Write(bytes, 0, bytes.Length);
+ }
+ catch (IOException e)
+ {
+ string log = $"{nameof(TcpSendData)}: Exception writing to the socket: {tcp.MachineName}: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Common.Log(log);
+
+ throw e.InnerException is SocketException se ? new ExpectedSocketException(se) : new ExpectedSocketException(log);
+ }
+
+ return bytes.Length;
+ }
+
+ private static void ProcessReceivedDataEx(byte[] buf)
+ {
+ int magic;
+ byte checksum = 0;
+
+ magic = (buf[3] << 24) + (buf[2] << 16);
+
+ if (magic != (Common.MagicNumber & 0xFFFF0000))
+ {
+ Common.Log("Magic number invalid!");
+ buf[0] = (byte)PackageType.Invalid;
+ }
+
+ for (int i = 2; i < Common.PACKAGE_SIZE; i++)
+ {
+ checksum = (byte)(checksum + buf[i]);
+ }
+
+ if (buf[1] != checksum)
+ {
+ Common.Log("Checksum invalid!");
+ buf[0] = (byte)PackageType.Invalid;
+ }
+
+ buf[3] = buf[2] = buf[1] = 0;
+ }
+
+ internal static DATA TcpReceiveData(TcpSk tcp, out int bytesReceived)
+ {
+ byte[] buf = new byte[Common.PACKAGE_SIZE_EX];
+ Stream decryptedStream = tcp.DecryptedStream;
+
+ if (tcp.BackingSocket == null || !tcp.BackingSocket.Connected || decryptedStream == null)
+ {
+ string log = $"{nameof(TcpReceiveData)}: The socket is no longer connected, it could have been closed by the remote host.";
+ Common.Log(log);
+ throw new ExpectedSocketException(log);
+ }
+
+ DATA package;
+
+ try
+ {
+ bytesReceived = decryptedStream.ReadEx(buf, 0, Common.PACKAGE_SIZE);
+
+ if (bytesReceived != Common.PACKAGE_SIZE)
+ {
+ buf[0] = bytesReceived == 0 ? (byte)PackageType.Error : (byte)PackageType.Invalid;
+ }
+ else
+ {
+ ProcessReceivedDataEx(buf);
+ }
+
+ package = new DATA(buf);
+
+ if (package.IsBigPackage)
+ {
+ bytesReceived = decryptedStream.ReadEx(buf, Common.PACKAGE_SIZE, Common.PACKAGE_SIZE);
+
+ if (bytesReceived != Common.PACKAGE_SIZE)
+ {
+ buf[0] = bytesReceived == 0 ? (byte)PackageType.Error : (byte)PackageType.Invalid;
+ }
+ else
+ {
+ package.Bytes = buf;
+ }
+ }
+ }
+ catch (IOException e)
+ {
+ string log = $"{nameof(TcpReceiveData)}: Exception reading from the socket: {tcp.MachineName}: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Common.Log(log);
+
+ throw e.InnerException is SocketException se ? new ExpectedSocketException(se) : new ExpectedSocketException(log);
+ }
+
+ return package;
+ }
+
+ private static void PreProcessData(PackageType type)
+ {
+ switch (type)
+ {
+ case PackageType.Keyboard:
+ Common.PackageSent.Keyboard++;
+ break;
+
+ case PackageType.Mouse:
+ Common.PackageSent.Mouse++;
+ break;
+
+ case PackageType.Heartbeat:
+ case PackageType.Heartbeat_ex:
+ Common.PackageSent.Heartbeat++;
+ break;
+
+ case PackageType.Hello:
+ Common.PackageSent.Hello++;
+ break;
+
+ case PackageType.ByeBye:
+ Common.PackageSent.ByeBye++;
+ break;
+
+ case PackageType.Matrix:
+ Common.PackageSent.Matrix++;
+ break;
+
+ default:
+ byte subtype = (byte)((uint)type & 0x000000FF);
+ switch (subtype)
+ {
+ case (byte)PackageType.ClipboardText:
+ Common.PackageSent.ClipboardText++;
+ break;
+
+ case (byte)PackageType.ClipboardImage:
+ Common.PackageSent.ClipboardImage++;
+ break;
+
+ default:
+ // Common.Log("Send: Other type (1-17)");
+ break;
+ }
+
+ break;
+ }
+ }
+
+ internal int TcpSend(TcpSk tcp, DATA data)
+ {
+ PreProcessData(data.Type);
+
+ if (data.Src == ID.NONE)
+ {
+ data.Src = Common.MachineID;
+ }
+
+ byte[] dataAsBytes = data.Bytes;
+ int rv = TcpSendData(tcp, dataAsBytes);
+ if (rv < dataAsBytes.Length)
+ {
+ Common.Log("TcpSend error! Length of sent data is unexpected.");
+ UpdateTcpSockets(tcp, SocketStatus.SendError);
+ throw new SocketException((int)SocketStatus.SendError);
+ }
+
+ return rv;
+ }
+
+ private void TCPServerThread(object param)
+ {
+ try
+ {
+ TcpListener server = param as TcpListener;
+ do
+ {
+ Common.LogDebug("TCPServerThread: Waiting for request...");
+ Socket s = server.AcceptSocket();
+
+ _ = Task.Run(() =>
+ {
+ try
+ {
+ AddSocket(s);
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ });
+ }
+ while (true);
+ }
+ catch (InvalidOperationException e)
+ {
+ string log = $"TCPServerThread.AcceptSocket: The server socket could have been closed. {e.Message}";
+ Common.Log(log);
+ }
+ catch (SocketException e)
+ {
+ if (e.ErrorCode == (int)SocketError.Interrupted)
+ {
+ Common.Log("TCPServerThread.AcceptSocket: A blocking socket call was canceled.");
+ }
+ else
+ {
+ Common.Log(e);
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ private static string GetMachineNameFromSocket(Socket socket)
+ {
+ string stringIP = socket.RemoteEndPoint.ToString();
+ string name = null;
+
+ try
+ {
+ // Remote machine has IP changed, update it.
+ name = Dns.GetHostEntry((socket.RemoteEndPoint as IPEndPoint).Address).HostName;
+ }
+ catch (SocketException e)
+ {
+ Common.Log($"{nameof(GetMachineNameFromSocket)}: {e.Message}");
+ return stringIP;
+ }
+
+ // Remove the domain part.
+ if (!string.IsNullOrEmpty(name))
+ {
+ int dotPos = name.IndexOf('.');
+
+ if (dotPos > 0)
+ {
+ Common.LogDebug("Removing domain part from the full machine name: {0}.", name);
+ name = name[..dotPos];
+ }
+ }
+
+ return string.IsNullOrEmpty(name) ? stringIP : name;
+ }
+
+ private void AddSocket(Socket s)
+ {
+ string machineName = GetMachineNameFromSocket(s);
+ Common.Log($"New connection from client: [{machineName}].");
+ TcpSk tcp = AddTcpSocket(false, s, SocketStatus.Connecting, machineName);
+ StartNewTcpServer(tcp, machineName);
+ }
+
+ private void StartNewTcpServer(TcpSk tcp, string machineName)
+ {
+ void ServerThread()
+ {
+ try
+ {
+ // Receiving packages
+ MainTCPRoutine(tcp, machineName, false);
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ Thread t = new(ServerThread, "TCP Server Thread " + tcp.BackingSocket.LocalEndPoint.ToString() + " : " + machineName);
+
+ t.SetApartmentState(ApartmentState.STA);
+ t.Start();
+ }
+
+ internal void UpdateTCPClients()
+ {
+ if (InvalidKeyFound)
+ {
+ return;
+ }
+
+ Common.LogDebug("!!!!! UpdateTCPClients !!!!!");
+
+ try
+ {
+ if (Common.MachineMatrix != null)
+ {
+ Common.LogDebug("MachineMatrix = " + string.Join(", ", Common.MachineMatrix));
+
+ foreach (string st in Common.MachineMatrix)
+ {
+ string machineName = st.Trim();
+ if (!string.IsNullOrEmpty(machineName) &&
+ !machineName.Equals(Common.MachineName.Trim(), StringComparison.OrdinalIgnoreCase))
+ {
+ bool found = false;
+
+ found = Common.IsConnectedByAClientSocketTo(machineName);
+
+ if (found)
+ {
+ Common.LogDebug(machineName + " is already connected! ^^^^^^^^^^^^^^^^^^^^^");
+ continue;
+ }
+
+ StartNewTcpClient(machineName);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ private static readonly Dictionary> BadIPs = new();
+ private static readonly object BadIPsLock = new();
+
+ private static bool IsBadIP(string machineName, IPAddress ip)
+ {
+ lock (BadIPsLock)
+ {
+ return BadIPs.ContainsKey(machineName) && BadIPs.TryGetValue(machineName, out List ips) && ips.Contains(ip);
+ }
+ }
+
+ private static void AddBadIP(string machineName, IPAddress ip)
+ {
+ if (!IsBadIP(machineName, ip))
+ {
+ lock (BadIPsLock)
+ {
+ List ips;
+
+ if (BadIPs.ContainsKey(machineName))
+ {
+ _ = BadIPs.TryGetValue(machineName, out ips);
+ }
+ else
+ {
+ ips = new List();
+ BadIPs.Add(machineName, ips);
+ }
+
+ ips.Add(ip);
+ }
+ }
+ }
+
+ internal static void ClearBadIPs()
+ {
+ lock (BadIPsLock)
+ {
+ if (BadIPs.Count > 0)
+ {
+ BadIPs.Clear();
+ }
+ }
+ }
+
+ internal void StartNewTcpClient(string machineName)
+ {
+ void ClientThread(object obj)
+ {
+ IPHostEntry host;
+ bool useName2IP = false;
+ List validAddresses = new();
+ List validatedAddresses = new();
+ string validAddressesSt = string.Empty;
+
+ // Add a dummy socket to show the status.
+ Socket dummySocket = new(AddressFamily.Unspecified, SocketType.Stream, ProtocolType.Tcp);
+ TcpSk dummyTcp = AddTcpSocket(true, dummySocket, SocketStatus.Resolving, machineName);
+
+ Common.LogDebug("Connecting to: " + machineName);
+
+ if (!string.IsNullOrEmpty(Setting.Values.Name2IP))
+ {
+ string[] name2ip = Setting.Values.Name2IP.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
+ string[] nameNip;
+
+ if (name2ip != null)
+ {
+ foreach (string st in name2ip)
+ {
+ nameNip = st.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
+
+ if (nameNip != null && nameNip.Length >= 2 && nameNip[0].Trim().Equals(machineName, StringComparison.OrdinalIgnoreCase)
+ && IPAddress.TryParse(nameNip[1].Trim(), out IPAddress ip) && !validAddressesSt.Contains("[" + ip.ToString() + "]")
+ )
+ {
+ validatedAddresses.Add(ip);
+ validAddressesSt += "[" + ip.ToString() + "]";
+ }
+ }
+ }
+
+ if (validatedAddresses.Count > 0)
+ {
+ useName2IP = true;
+
+ Common.LogDebug("Using both user-defined Name-to-IP mappings and DNS result for " + machineName);
+
+ Common.ShowToolTip("Using both user-defined Name-to-IP mappings and DNS result for " + machineName, 3000, ToolTipIcon.Info, false);
+
+ if (!CheckForSameSubNet(validatedAddresses, machineName))
+ {
+ return;
+ }
+
+ foreach (IPAddress vip in validatedAddresses)
+ {
+ StartNewTcpClientThread(machineName, vip);
+ }
+
+ validatedAddresses.Clear();
+ }
+ }
+
+ try
+ {
+ host = Dns.GetHostEntry(machineName);
+ }
+ catch (SocketException e)
+ {
+ host = null;
+
+ UpdateTcpSockets(dummyTcp, SocketStatus.Timeout);
+
+ Common.ShowToolTip(e.Message + ": " + machineName, 10000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+
+ Common.Log($"{nameof(StartNewTcpClient)}.{nameof(Dns.GetHostEntry)}: {e.Message}");
+ }
+
+ UpdateTcpSockets(dummyTcp, SocketStatus.NA);
+
+ if (!Common.InMachineMatrix(machineName))
+ {
+ // While Resolving from name to IP, user may have changed the machine name and clicked on Apply.
+ return;
+ }
+
+ if (host != null)
+ {
+ string ipLog = string.Empty;
+
+ foreach (IPAddress ip in host.AddressList)
+ {
+ ipLog += "<" + ip.ToString() + ">";
+
+ if ((ip.AddressFamily == AddressFamily.InterNetwork || ip.AddressFamily == AddressFamily.InterNetworkV6) && !validAddressesSt.Contains("[" + ip.ToString() + "]"))
+ {
+ validAddresses.Add(ip);
+ validAddressesSt += "[" + ip.ToString() + "]";
+ }
+ }
+
+ Common.LogDebug(machineName + ipLog);
+ }
+
+ if (validAddresses.Count > 0)
+ {
+ if (!Setting.Values.ReverseLookup)
+ {
+ validatedAddresses = validAddresses;
+ ClearBadIPs();
+ }
+ else
+ {
+ foreach (IPAddress ip in validAddresses)
+ {
+ if (IsBadIP(machineName, ip))
+ {
+ Common.Log($"Skip bad IP address: {ip}");
+ continue;
+ }
+
+ try
+ {
+ // Reverse lookup to validate the IP Address.
+ string hn = Dns.GetHostEntry(ip).HostName;
+
+ if (hn.StartsWith(machineName, StringComparison.CurrentCultureIgnoreCase) || hn.Equals(ip.ToString(), StringComparison.OrdinalIgnoreCase))
+ {
+ validatedAddresses.Add(ip);
+ }
+ else
+ {
+ Common.Log($"DNS information of machine not matched: {machineName} => {ip} => {hn}.");
+ AddBadIP(machineName, ip);
+ }
+ }
+ catch (SocketException se)
+ {
+ Common.Log($"{nameof(StartNewTcpClient)}: DNS information of machine not matched: {machineName} => {ip} => {se.Message}.");
+ AddBadIP(machineName, ip);
+ }
+ catch (ArgumentException ae)
+ {
+ Common.Log($"{nameof(StartNewTcpClient)}: DNS information of machine not matched: {machineName} => {ip} => {ae.Message}.");
+ AddBadIP(machineName, ip);
+ }
+ }
+ }
+ }
+
+ if (validatedAddresses.Count > 0)
+ {
+ if (!CheckForSameSubNet(validatedAddresses, machineName))
+ {
+ return;
+ }
+
+ foreach (IPAddress ip in validatedAddresses)
+ {
+ StartNewTcpClientThread(machineName, ip);
+ }
+ }
+ else
+ {
+ Common.Log("Cannot resolve IPv4 Addresses of machine: " + machineName);
+
+ if (!useName2IP)
+ {
+ Common.ShowToolTip($"Cannot resolve IP Address of the remote machine: {machineName}.\r\nPlease fix your DNS or use the Mapping option in the Settings form.", 10000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+ }
+ }
+ }
+
+ Thread t = new(
+ ClientThread, "StartNewTcpClient." + machineName);
+
+ t.SetApartmentState(ApartmentState.STA);
+ t.Start();
+ }
+
+ private bool CheckForSameSubNet(List validatedAddresses, string machineName)
+ {
+ if (!Setting.Values.SameSubNetOnly)
+ {
+ return true;
+ }
+
+ // Only support if IPv4 addresses found in both.
+ IEnumerable remoteIPv4Addresses = validatedAddresses.Where(addr => addr?.AddressFamily == AddressFamily.InterNetwork);
+
+ if (!remoteIPv4Addresses.Any())
+ {
+ Common.Log($"No IPv4 resolved from the remote machine: {machineName}.");
+ return true;
+ }
+
+ List localIPv4Addresses = GetMyIPv4Addresses().ToList();
+
+ if (!localIPv4Addresses.Any())
+ {
+ Common.Log($"No IPv4 resolved from the local machine: {Common.MachineName}");
+ return true;
+ }
+
+ foreach (IPAddress remote in remoteIPv4Addresses)
+ {
+ foreach (IPAddress local in localIPv4Addresses)
+ {
+ byte[] myIPAddressBytes = local.GetAddressBytes();
+ byte[] yourIPAddressBytes = remote.GetAddressBytes();
+
+ // Same WAN?
+ if (myIPAddressBytes[0] == yourIPAddressBytes[0] && myIPAddressBytes[1] == yourIPAddressBytes[1])
+ {
+ return true;
+ }
+ }
+ }
+
+ Common.Log($"Skip machine not in the same network: {machineName}.");
+
+ return false;
+ }
+
+ private IEnumerable GetMyIPv4Addresses()
+ {
+ try
+ {
+ IEnumerable ip4addresses = NetworkInterface.GetAllNetworkInterfaces()?
+ .Where(networkInterface =>
+ (networkInterface.NetworkInterfaceType == NetworkInterfaceType.Ethernet || networkInterface.NetworkInterfaceType == NetworkInterfaceType.Wireless80211)
+ && networkInterface.OperationalStatus == OperationalStatus.Up)
+ .SelectMany(ni => ni?.GetIPProperties()?.UnicastAddresses.Select(uni => uni?.Address))
+ .Where(addr => addr?.AddressFamily == AddressFamily.InterNetwork);
+
+ return ip4addresses;
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ return Enumerable.Empty();
+ }
+ }
+
+ private void StartNewTcpClientThread(string machineName, IPAddress ip)
+ {
+ void NewTcpClient()
+ {
+ TcpClient tcpClient = null;
+
+ try
+ {
+ tcpClient = new TcpClient(AddressFamily.InterNetworkV6);
+ tcpClient.Client.DualMode = true;
+
+ if (Common.IsConnectedByAClientSocketTo(machineName))
+ {
+ Common.LogDebug(machineName + " is already connected by another client socket.");
+ return;
+ }
+
+ if (Common.IsConnectingByAClientSocketTo(machineName, ip))
+ {
+ Common.LogDebug($"{machineName}:{ip} is already being connected by another client socket.");
+ return;
+ }
+
+ TcpSk tcp = AddTcpSocket(true, tcpClient.Client, SocketStatus.Connecting, machineName, ip);
+
+ // Update the other server socket's machine name based on this corresponding client socket.
+ UpdateTcpSockets(tcp, SocketStatus.Connecting);
+
+ Common.LogDebug(string.Format(CultureInfo.CurrentCulture, "=====> Connecting to: {0}:{1}", machineName, ip.ToString()));
+
+ long timeoutLeft;
+
+ do
+ {
+ try
+ {
+ tcpClient.Connect(ip, TcpPort + 1);
+ }
+ catch (ObjectDisposedException)
+ {
+ // When user reconnects.
+ Common.LogDebug($"tcpClient.Connect: The socket has already been disposed: {machineName}:{ip}");
+ return;
+ }
+ catch (SocketException e)
+ {
+ timeoutLeft = connectTimeout - Common.GetTick();
+
+ if (timeoutLeft > 0)
+ {
+ Common.LogDebug($"tcpClient.Connect: {timeoutLeft}: {e.Message}");
+ Thread.Sleep(1000);
+ continue;
+ }
+ else
+ {
+ Common.Log($"tcpClient.Connect: Unable to connect after a timeout: {machineName}:{ip} : {e.Message}");
+
+ string message = $"Connection timed out: {machineName}:{ip}";
+
+ Common.ShowToolTip(message, 5000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+
+ UpdateTcpSockets(tcp, SocketStatus.Timeout);
+ return;
+ }
+ }
+
+ break;
+ }
+ while (true);
+
+ Common.LogDebug($"=====> Connected: {tcpClient.Client.LocalEndPoint} => {machineName}: {ip}");
+
+ // Sending/Receiving packages
+ MainTCPRoutine(tcp, machineName, true);
+ }
+ catch (ObjectDisposedException e)
+ {
+ Common.Log($"{nameof(StartNewTcpClientThread)}: The socket could have been closed/disposed due to machine switch: {e.Message}");
+ }
+ catch (SocketException e)
+ {
+ // DHCP error, etc.
+ string localIP = tcpClient?.Client?.LocalEndPoint?.ToString();
+
+ if (localIP != null && (localIP.StartsWith("169.254", StringComparison.InvariantCulture) || localIP.ToString().StartsWith("0.0", StringComparison.InvariantCulture)))
+ {
+ Common.ShowToolTip($"Error: The machine has limited connectivity on [{localIP}].", 5000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+ }
+ else
+ {
+ Common.TelemetryLogTrace($"{nameof(StartNewTcpClientThread)}: Error: {e.Message} on the IP Address: {localIP}", SeverityLevel.Error);
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ Thread t = new(NewTcpClient, "TCP Client Thread " + machineName + " " + ip.ToString());
+
+ t.SetApartmentState(ApartmentState.STA);
+ t.Start();
+ }
+
+ private void FlagReopenSocketIfNeeded(Exception e)
+ {
+ /* SCENARIO: MachineA has MM blocked by firewall but MachineA can connect to MachineB so the tool would work normally (MM is not blocked by firewall in MachineB).
+ * 1. a connection from A to B is working. Mouse/Keyboard is connected to A.
+ * 2. User moves Mouse to B and lock B by Ctrl+Alt+L.
+ * 3. B closes all sockets before switches to logon desktop. The client socket in A gets reset by B (the only connection between A and B).
+ * 4. B is now on the logon desktop and tries to connect to A, connection fails since it is block by firewall in A.
+ * 5. When the client socket gets reset in A, it should retry to connect to B => this is the fix implemented by few lines of code below.
+ * */
+
+ // WSAECONNRESET
+ if (e is ExpectedSocketException se && se.ShouldReconnect)
+ {
+ Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
+ Common.Log($"MainTCPRoutine: {nameof(FlagReopenSocketIfNeeded)}");
+ }
+ }
+
+ private long lastRemoteMachineID;
+
+ private void MainTCPRoutine(TcpSk tcp, string machineName, bool isClient)
+ {
+ int packageCount = 0;
+ DATA d;
+ string remoteMachine = string.Empty;
+ string strIP = string.Empty;
+ ID remoteID = ID.NONE;
+
+ byte[] buf = RandomNumberGenerator.GetBytes(Common.PACKAGE_SIZE_EX);
+ d = new DATA(buf);
+
+ TcpSk currentTcp = tcp;
+ Socket currentSocket = currentTcp.BackingSocket;
+
+ if (currentSocket == null)
+ {
+ Common.LogDebug($"{nameof(MainTCPRoutine)}: The socket could have been closed/disposed by other threads.");
+ return;
+ }
+
+ try
+ {
+ currentSocket.SendBufferSize = Common.PACKAGE_SIZE * 10000;
+ currentSocket.ReceiveBufferSize = Common.PACKAGE_SIZE * 10000;
+ currentSocket.NoDelay = true; // This is very interesting to know:(
+ currentSocket.SendTimeout = 500;
+ d.MachineName = Common.MachineName;
+
+ d.Type = PackageType.Handshake;
+
+ for (int i = 0; i < 10; i++)
+ {
+ _ = TcpSend(currentTcp, d);
+ }
+
+ d.Machine1 = ~d.Machine1;
+ d.Machine2 = ~d.Machine2;
+ d.Machine3 = ~d.Machine3;
+ d.Machine4 = ~d.Machine4;
+
+ UpdateTcpSockets(currentTcp, SocketStatus.Handshaking);
+
+ strIP = Common.GetRemoteStringIP(currentSocket, true);
+ remoteMachine = string.IsNullOrEmpty(machineName) ? GetMachineNameFromSocket(currentSocket) : machineName;
+
+ Common.LogDebug($"MainTCPRoutine: Remote machineName/IP = {remoteMachine}/{strIP}");
+ }
+ catch (ObjectDisposedException e)
+ {
+ Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
+ UpdateTcpSockets(currentTcp, SocketStatus.ForceClosed);
+ currentSocket.Close();
+ Common.Log($"{nameof(MainTCPRoutine)}: The socket could have been closed/disposed by other threads: {e.Message}");
+ }
+ catch (Exception e)
+ {
+ UpdateTcpSockets(currentTcp, SocketStatus.ForceClosed);
+ FlagReopenSocketIfNeeded(e);
+ currentSocket.Close();
+ Common.Log(e);
+ }
+
+ int errCount = 0;
+
+ while (true)
+ {
+ try
+ {
+ DATA package = TcpReceiveData(currentTcp, out int receivedCount);
+ remoteID = package.Src;
+
+ if (package.Type == PackageType.Error)
+ {
+ errCount++;
+
+ string log = $"{nameof(MainTCPRoutine)}.TcpReceive error, invalid package from {remoteMachine}: {receivedCount}";
+ Common.Log(log);
+
+ if (receivedCount > 0)
+ {
+ Common.ShowToolTip($"Invalid package from {remoteMachine}. Ensure the security keys are the same in both machines.", 5000, ToolTipIcon.Warning, false);
+ }
+
+ if (errCount > 5)
+ {
+ Common.MMSleep(1);
+
+ UpdateTcpSockets(currentTcp, SocketStatus.Error);
+ currentSocket.Close();
+
+ /*
+ * Sometimes when the peer machine closes the connection, we do not actually get an exception.
+ * Socket status is still connected and a read on the socket stream returns 0 byte.
+ * In this case, we should give ONE try to reconnect.
+ */
+
+ if (Common.ReopenSocketDueToReadError)
+ {
+ Common.PleaseReopenSocket = Common.REOPEN_WHEN_WSAECONNRESET;
+ Common.ReopenSocketDueToReadError = false;
+ }
+
+ break;
+ }
+ }
+ else
+ {
+ errCount = 0;
+ }
+
+ if (package.Type == PackageType.Handshake)
+ {
+ // Common.Log("Got a Handshake signal!");
+ package.Type = PackageType.HandshakeAck;
+ package.Src = ID.NONE;
+ package.MachineName = Common.MachineName;
+
+ package.Machine1 = ~package.Machine1;
+ package.Machine2 = ~package.Machine2;
+ package.Machine3 = ~package.Machine3;
+ package.Machine4 = ~package.Machine4;
+
+ _ = TcpSend(currentTcp, package);
+ }
+ else
+ {
+ if (packageCount >= 0)
+ {
+ if (++packageCount >= 10)
+ {
+ // Common.ShowToolTip("Invalid Security Key from " + remoteMachine, 5000);
+ Common.Log("More than 10 invalid packages received!");
+
+ package.Type = PackageType.Invalid;
+
+ for (int i = 0; i < 10; i++)
+ {
+ _ = TcpSend(currentTcp, package);
+ }
+
+ Common.MMSleep(2);
+
+ UpdateTcpSockets(currentTcp, SocketStatus.InvalidKey);
+ currentSocket.Close();
+ break;
+ }
+ else if (package.Type == PackageType.HandshakeAck)
+ {
+ if (package.Machine1 == d.Machine1 && package.Machine2 == d.Machine2 &&
+ package.Machine3 == d.Machine3 && package.Machine4 == d.Machine4)
+ {
+ string claimedMachineName = package.MachineName;
+
+ if (!remoteMachine.Equals(claimedMachineName, StringComparison.Ordinal))
+ {
+ Common.LogDebug($"DNS.RemoteMachineName({remoteMachine}) <> Claimed.MachineName({claimedMachineName}), using the claimed machine name.");
+ remoteMachine = claimedMachineName;
+ currentTcp.MachineName = remoteMachine;
+ }
+
+ // Double check to avoid a redundant client socket.
+ if (isClient && Common.IsConnectedByAClientSocketTo(remoteMachine))
+ {
+ Common.LogDebug("=====> Duplicate connected client socket for: " + remoteMachine + ":" + strIP + " is being removed.");
+ UpdateTcpSockets(currentTcp, SocketStatus.ForceClosed);
+ currentSocket.Close();
+ return;
+ }
+
+ if (remoteMachine.Equals(Common.MachineName, StringComparison.OrdinalIgnoreCase))
+ {
+ Common.LogDebug("Connected to/from local socket: " + strIP + (isClient ? "-Client" : "-Server"));
+ UpdateTcpSockets(currentTcp, SocketStatus.NA);
+ Common.MMSleep(1);
+ currentSocket.Close();
+ return;
+ }
+
+ packageCount = -1; // Trusted
+ InvalidKeyFound = false;
+ currentTcp.MachineId = (uint)remoteID;
+ currentTcp.Status = SocketStatus.Connected;
+ UpdateTcpSockets(currentTcp, SocketStatus.Connected);
+ Common.LogDebug("))))))))))))))) Machine got trusted: " + remoteMachine + ":" + strIP + ", Is client: " + isClient);
+
+ if (Math.Abs(Common.GetTick() - Common.LastReconnectByHotKeyTime) < 5000)
+ {
+ Common.ShowToolTip("Connected to " + remoteMachine, 1000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
+ }
+
+ Common.SendHeartBeat(initial: true);
+
+ if (Common.MachinePool.TryFindMachineByName(remoteMachine, out MachineInf machineInfo))
+ {
+ Common.LogDebug("Machine updated: " + remoteMachine + "/" + remoteID.ToString());
+
+ if (machineInfo.Name.Equals(Common.DesMachineName, StringComparison.OrdinalIgnoreCase))
+ {
+ Common.LogDebug("Des ID updated: " + Common.DesMachineID.ToString() +
+ "/" + remoteID.ToString());
+ Common.NewDesMachineID = Common.DesMachineID = remoteID;
+ }
+
+ _ = Common.MachinePool.TryUpdateMachineID(remoteMachine, remoteID, true);
+ Common.UpdateMachinePoolStringSetting();
+ }
+ else
+ {
+ Common.LogDebug("New machine connected: {0}.", remoteMachine);
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ Common.ShowToolTip("Connected to new machine " + remoteMachine, 1000, ToolTipIcon.Info, Setting.Values.ShowClipNetStatus);
+ }
+ }
+
+ if (!isClient)
+ {
+ Common.UpdateClientSockets("MainTCPRoutine");
+ }
+ }
+ else
+ {
+ Common.LogDebug("Invalid ACK from " + remoteMachine);
+ UpdateTcpSockets(currentTcp, SocketStatus.InvalidKey);
+
+ string remoteEP = currentSocket.RemoteEndPoint.ToString();
+
+ if (FailedAttempt.AddOrUpdate(remoteEP, 1, (key, value) => value + 1) > 10)
+ {
+ _ = FailedAttempt.AddOrUpdate(remoteEP, 0, (key, value) => 0);
+
+ _ = MessageBox.Show($"Too many connection attempts from [{remoteEP}]!\r\nRestart the app to retry.", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
+ Common.MainForm.Quit(true, false);
+ }
+
+ currentSocket.Close();
+ break;
+ }
+ }
+ else if (package.Type == PackageType.Mouse)
+ {
+ if (packageCount > 5)
+ {
+ packageCount--;
+ }
+ }
+ else if (package.Type is PackageType.Heartbeat or PackageType.Heartbeat_ex)
+ {
+ if (packageCount > 5)
+ {
+ packageCount--;
+ }
+ }
+ else
+ {
+ if (packageCount > 5)
+ {
+ UpdateTcpSockets(currentTcp, SocketStatus.InvalidKey);
+ }
+ else
+ {
+ Common.Log(string.Format(
+ CultureInfo.CurrentCulture,
+ "Unexpected package, size = {0}, type = {1}",
+ receivedCount,
+ package.Type));
+ }
+ }
+ }
+ else if (receivedCount > 0)
+ {
+ // Add some log when remote machine switches.
+ if (lastRemoteMachineID != (long)remoteID)
+ {
+ _ = Interlocked.Exchange(ref lastRemoteMachineID, (long)remoteID);
+ Common.LogDebug($"MainTCPRoutine: Remote machine = {strIP}/{lastRemoteMachineID}");
+ }
+
+ if (package.Type == PackageType.HandshakeAck)
+ {
+ Common.LogDebug("Skipping the rest of the Handshake packages.");
+ }
+ else
+ {
+ Common.ProcessPackage(package, currentTcp);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ UpdateTcpSockets(currentTcp, SocketStatus.Error);
+ FlagReopenSocketIfNeeded(e);
+ currentSocket.Close();
+ Common.Log(e);
+ break;
+ }
+ }
+
+ if (remoteID != ID.NONE)
+ {
+ _ = Common.RemoveDeadMachines(remoteID);
+ }
+ }
+
+ private static void AcceptConnectionAndSendClipboardData(object param)
+ {
+ TcpListener server = param as TcpListener;
+
+ do
+ {
+ Common.LogDebug("SendClipboardData: Waiting for request...");
+ Socket s = null;
+
+ try
+ {
+ s = server.AcceptSocket();
+ }
+ catch (InvalidOperationException e)
+ {
+ Common.Log($"The clipboard socket could have been closed. {e.Message}");
+ break;
+ }
+ catch (SocketException e)
+ {
+ if (e.ErrorCode == (int)SocketError.Interrupted)
+ {
+ Common.Log("server.AcceptSocket: A blocking socket call was canceled.");
+ continue;
+ }
+ else
+ {
+ Common.Log(e);
+ break;
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ break;
+ }
+
+ if (s != null)
+ {
+ try
+ {
+ new Task(() =>
+ {
+ System.Threading.Thread thread = Thread.CurrentThread;
+ thread.Name = $"{nameof(SendOrReceiveClipboardData)}.{thread.ManagedThreadId}";
+ Thread.UpdateThreads(thread);
+ SendOrReceiveClipboardData(s);
+ }).Start();
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+ }
+ while (true);
+ }
+
+ internal static void SendOrReceiveClipboardData(Socket s)
+ {
+ try
+ {
+ string remoteEndPoint = s.RemoteEndPoint.ToString();
+ Common.LogDebug("SendClipboardData: Request accepted: " + s.LocalEndPoint.ToString() + "/" + remoteEndPoint);
+ Common.IsDropping = false;
+ Common.IsDragging = false;
+ Common.DragMachine = (ID)1;
+
+ bool clientPushData = true;
+ ClipboardPostAction postAction = ClipboardPostAction.Other;
+ bool handShaken = Common.ShakeHand(ref remoteEndPoint, s, out Stream enStream, out Stream deStream, ref clientPushData, ref postAction);
+
+ if (!handShaken)
+ {
+ s.Close();
+ return;
+ }
+ else
+ {
+ Common.LogDebug($"{nameof(SendOrReceiveClipboardData)}: Clipboard connection accepted: " + remoteEndPoint);
+ Common.SetToggleIcon(new int[Common.TOGGLE_ICONS_SIZE] { Common.ICON_SMALL_CLIPBOARD, -1, -1, -1 });
+ }
+
+ if (clientPushData)
+ {
+ Common.ReceiveAndProcessClipboardData(remoteEndPoint, s, enStream, deStream, $"{postAction}");
+ }
+ else
+ {
+ SendClipboardData(s, enStream);
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ internal static void SendClipboardData(Socket s, Stream ecStream)
+ {
+ if (Common.RunWithNoAdminRight && Setting.Values.OneWayClipboardMode)
+ {
+ s?.Close();
+ return;
+ }
+
+ const int CLOSE_TIMEOUT = 10;
+ byte[] header = new byte[1024];
+ string headerString = string.Empty;
+ if (Common.LastDragDropFile != null)
+ {
+ string fileName = null;
+
+ if (!Common.ImpersonateLoggedOnUserAndDoSomething(() =>
+ {
+ if (!File.Exists(Common.LastDragDropFile))
+ {
+ headerString = Directory.Exists(Common.LastDragDropFile)
+ ? $"{0}*{Common.LastDragDropFile} - Folder is not supported, zip it first!"
+ : Common.LastDragDropFile.Contains("- File too big")
+ ? $"{0}*{Common.LastDragDropFile}"
+ : $"{0}*{Common.LastDragDropFile} not found!";
+ }
+ else
+ {
+ fileName = Common.LastDragDropFile;
+ headerString = $"{new FileInfo(fileName).Length}*{fileName}";
+ }
+ }))
+ {
+ s?.Close();
+ return;
+ }
+
+ Common.GetBytesU(headerString).CopyTo(header, 0);
+
+ try
+ {
+ ecStream.Write(header, 0, header.Length);
+
+ if (!string.IsNullOrEmpty(fileName))
+ {
+ if (SendFile(s, ecStream, fileName))
+ {
+ s.Close(CLOSE_TIMEOUT);
+ }
+ }
+ else
+ {
+ s.Close(CLOSE_TIMEOUT);
+ }
+ }
+ catch (IOException e)
+ {
+ string log = $"{nameof(SendClipboardData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Common.Log(log);
+ }
+ catch (SocketException e)
+ {
+ string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the connection is closed by the remote host.";
+ Common.Log(log);
+ }
+ catch (ObjectDisposedException e)
+ {
+ string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the socket is disposed by a machine switch for ex..";
+ Common.Log(log);
+ }
+ }
+ else if (!Common.IsClipboardDataImage && Common.LastClipboardData != null)
+ {
+ try
+ {
+ byte[] data = Common.LastClipboardData;
+
+ headerString = $"{data.Length}*{"text"}";
+ Common.GetBytesU(headerString).CopyTo(header, 0);
+
+ if (data != null)
+ {
+ ecStream.Write(header, 0, header.Length);
+ _ = SendData(s, ecStream, data);
+ Common.LogDebug("Text sent: " + data.Length.ToString(CultureInfo.CurrentCulture));
+ }
+
+ s.Close(CLOSE_TIMEOUT);
+ }
+ catch (IOException e)
+ {
+ string log = $"{nameof(SendClipboardData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Common.Log(log);
+ }
+ catch (SocketException e)
+ {
+ string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the connection is closed by the remote host.";
+ Common.Log(log);
+ }
+ catch (ObjectDisposedException e)
+ {
+ string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the socket is disposed by a machine switch for ex..";
+ Common.Log(log);
+ }
+ }
+ else if (Common.LastClipboardData != null && Common.LastClipboardData.Length > 0)
+ {
+ byte[] data = Common.LastClipboardData;
+
+ headerString = $"{data.Length}*{"image"}";
+ Common.GetBytesU(headerString).CopyTo(header, 0);
+ try
+ {
+ ecStream.Write(header, 0, header.Length);
+ _ = SendData(s, ecStream, data);
+ Common.LogDebug("Image sent: " + data.Length.ToString(CultureInfo.CurrentCulture));
+ s.Close(CLOSE_TIMEOUT);
+ }
+ catch (IOException e)
+ {
+ string log = $"{nameof(SendClipboardData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Common.Log(log);
+ }
+ catch (SocketException e)
+ {
+ string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the connection is closed by the remote host.";
+ Common.Log(log);
+ }
+ catch (ObjectDisposedException e)
+ {
+ string log = $"{nameof(SendClipboardData)}: {e.GetType()}/{e.Message}. This is expected when the socket is disposed by a machine switch for ex..";
+ Common.Log(log);
+ }
+ }
+ else
+ {
+ Common.Log("No data available in clipboard or LastDragDropFile!");
+ s.Close();
+ }
+ }
+
+ private static bool SendFileEx(Socket s, Stream ecStream, string fileName)
+ {
+ try
+ {
+ using (FileStream f = File.OpenRead(fileName))
+ {
+ byte[] buf = new byte[Common.NETWORK_STREAM_BUF_SIZE];
+ int rv, sentCount = 0;
+
+ do
+ {
+ if ((rv = f.Read(buf, 0, Common.NETWORK_STREAM_BUF_SIZE)) > 0)
+ {
+ ecStream.Write(buf, 0, rv);
+ sentCount += rv;
+ }
+ }
+ while (rv > 0);
+
+ if ((rv = Common.PACKAGE_SIZE - (sentCount % Common.PACKAGE_SIZE)) > 0)
+ {
+ Array.Clear(buf, 0, buf.Length);
+ ecStream.Write(buf, 0, rv);
+ }
+
+ ecStream.Flush();
+
+ Common.LogDebug("File sent: " + fileName);
+ }
+
+ return true;
+ }
+ catch (Exception e)
+ {
+ if (e is IOException)
+ {
+ string log = $"{nameof(SendFileEx)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Common.Log(log);
+ }
+ else
+ {
+ Common.Log(e);
+ }
+
+ Common.ShowToolTip(e.Message, 1000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+ s.Close();
+ }
+
+ return false;
+ }
+
+ private static bool SendFile(Socket s, Stream ecStream, string fileName)
+ {
+ bool r = false;
+
+ if (Common.RunOnLogonDesktop || Common.RunOnScrSaverDesktop)
+ {
+ if (fileName.StartsWith(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles) + @"\" + Common.BinaryName + @"\ScreenCaptures\", StringComparison.CurrentCultureIgnoreCase))
+ {
+ r = SendFileEx(s, ecStream, fileName);
+ }
+ }
+ else
+ {
+ _ = Common.ImpersonateLoggedOnUserAndDoSomething(() => { r = SendFileEx(s, ecStream, fileName); });
+ }
+
+ return r;
+ }
+
+ private static bool SendData(Socket s, Stream ecStream, byte[] data)
+ {
+ bool r = false;
+
+ try
+ {
+ using MemoryStream f = new(data);
+ byte[] buf = new byte[Common.NETWORK_STREAM_BUF_SIZE];
+ int rv, sentCount = 0;
+
+ do
+ {
+ if ((rv = f.Read(buf, 0, Common.NETWORK_STREAM_BUF_SIZE)) > 0)
+ {
+ ecStream.Write(buf, 0, rv);
+ sentCount += rv;
+ }
+ }
+ while (rv > 0);
+
+ if ((rv = sentCount % Common.PACKAGE_SIZE) > 0)
+ {
+ Array.Clear(buf, 0, buf.Length);
+ ecStream.Write(buf, 0, rv);
+ }
+
+ ecStream.Flush();
+ Common.LogDebug("Data sent: " + data.Length.ToString(CultureInfo.InvariantCulture));
+ r = true;
+ }
+ catch (Exception e)
+ {
+ if (e is IOException)
+ {
+ string log = $"{nameof(SendData)}: Exception accessing the socket: {e.InnerException?.GetType()}/{e.Message}. (This is expected when the remote machine closes the connection during desktop switch or reconnection.)";
+ Common.Log(log);
+ }
+ else
+ {
+ Common.Log(e);
+ }
+
+ Common.ShowToolTip(e.Message, 1000, ToolTipIcon.Warning, Setting.Values.ShowClipNetStatus);
+ ecStream.Close();
+ s.Close();
+ }
+
+ return r;
+ }
+
+ private TcpSk AddTcpSocket(bool isClient, Socket s, SocketStatus status, string machineName)
+ {
+ Common.CloseAnUnusedSocket();
+ TcpSk tcp = new(isClient, s, status, machineName);
+
+ lock (TcpSocketsLock)
+ {
+#if ENABLE_LEGACY_DOS_PROTECTION
+ PreventDoS(TcpSockets);
+#endif
+ TcpSockets.Add(tcp);
+ }
+
+ return tcp;
+ }
+
+ private TcpSk AddTcpSocket(bool isClient, Socket s, SocketStatus status, string machineName, IPAddress ip)
+ {
+ Common.CloseAnUnusedSocket();
+ TcpSk tcp = new(isClient, s, status, machineName, ip);
+
+ lock (TcpSocketsLock)
+ {
+#if ENABLE_LEGACY_DOS_PROTECTION
+ PreventDoS(TcpSockets);
+#endif
+ TcpSockets.Add(tcp);
+ }
+
+ return tcp;
+ }
+
+ private void UpdateTcpSockets(TcpSk tcp, SocketStatus status)
+ {
+ if (status == SocketStatus.InvalidKey)
+ {
+ InvalidKeyFound = true;
+ }
+
+ InvalidKeyFoundOnClientSocket = tcp.IsClient && InvalidKeyFound;
+
+ try
+ {
+ lock (TcpSocketsLock)
+ {
+ if (TcpSockets != null)
+ {
+ if (status == SocketStatus.Connected && tcp.IsClient)
+ {
+ List tobeRemovedSockets = TcpSockets;
+
+ if (tcp.MachineId == Setting.Values.MachineId)
+ {
+ tcp = null;
+ Setting.Values.MachineId = Common.Ran.Next();
+ Common.UpdateMachineTimeAndID();
+ Common.PleaseReopenSocket = Common.REOPEN_WHEN_HOTKEY;
+
+ Common.TelemetryLogTrace("MachineID conflict.", SeverityLevel.Information);
+ }
+ else
+ {
+ // Keep the first connected one.
+ tobeRemovedSockets = TcpSockets.Where(item => item.IsClient && !ReferenceEquals(item, tcp) && item.MachineName.Equals(tcp.MachineName, StringComparison.OrdinalIgnoreCase)).ToList();
+ }
+
+ foreach (TcpSk t in tobeRemovedSockets)
+ {
+ t.Status = SocketStatus.ForceClosed;
+ Common.LogDebug($"Closing duplicated socket {t.MachineName}: {t.Address}");
+ }
+ }
+
+ List toBeRemoved = new();
+
+ foreach (TcpSk t in TcpSockets)
+ {
+ if (t.Status is SocketStatus.Error or
+ SocketStatus.ForceClosed or
+
+ // SocketStatus.InvalidKey or
+ SocketStatus.NA or
+ SocketStatus.Timeout or
+ SocketStatus.SendError)
+ {
+ try
+ {
+ if (t.BackingSocket != null)
+ {
+ t.MachineName = "$*NotUsed*$";
+ t.Status = t.Status >= 0 ? 0 : t.Status - 1; // If error closing, the socket will be closed again at SocketStuff.Close().
+ t.BackingSocket.Close();
+ }
+
+ toBeRemoved.Add(t);
+ }
+ catch (SocketException e)
+ {
+ string log = $"{nameof(UpdateTcpSockets)}: {e.GetType()}/{e.Message}. This is expected when the connection is closed by the remote host.";
+ Common.Log(log);
+ }
+ catch (ObjectDisposedException e)
+ {
+ string log = $"{nameof(UpdateTcpSockets)}: {e.GetType()}/{e.Message}. This is expected when the socket is disposed by a machine switch for ex..";
+ Common.Log(log);
+ }
+ }
+ }
+
+ if (tcp != null)
+ {
+ tcp.Status = status;
+
+ if (status == SocketStatus.Connected)
+ {
+ // Update the socket's machine name based on its corresponding client/server socket.
+ foreach (TcpSk t in TcpSockets)
+ {
+ if (t.MachineId == tcp.MachineId && t.IsClient != tcp.IsClient)
+ {
+ if ((string.IsNullOrEmpty(tcp.MachineName) || tcp.MachineName.Contains('.') || tcp.MachineName.Contains(':'))
+ && !(string.IsNullOrEmpty(t.MachineName) || t.MachineName.Contains('.') || t.MachineName.Contains(':')))
+ {
+ tcp.MachineName = t.MachineName;
+ }
+ else if ((string.IsNullOrEmpty(t.MachineName) || t.MachineName.Contains('.') || t.MachineName.Contains(':'))
+ && !(string.IsNullOrEmpty(tcp.MachineName) || tcp.MachineName.Contains('.') || tcp.MachineName.Contains(':')))
+ {
+ t.MachineName = tcp.MachineName;
+ }
+ }
+ }
+
+ if (string.IsNullOrEmpty(tcp.MachineName) || tcp.MachineName.Contains('.') || tcp.MachineName.Contains(':'))
+ {
+ tcp.MachineName = Common.NameFromID((ID)tcp.MachineId);
+ }
+
+ if (string.IsNullOrEmpty(tcp.MachineName) || tcp.MachineName.Contains('.') || tcp.MachineName.Contains(':'))
+ {
+ tcp.MachineName = Common.GetRemoteStringIP(tcp.BackingSocket);
+ }
+ }
+ }
+ else
+ {
+ Common.Log("UpdateTcpSockets.Exception: Socket not found!");
+ }
+
+ foreach (TcpSk t in toBeRemoved)
+ {
+ _ = TcpSockets.Remove(t);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ private void PreventDoS(List sockets)
+ {
+ if (sockets.Count > 100)
+ {
+ TcpSk tcp;
+
+ try
+ {
+ string msg = Application.ProductName + " has been terminated, too many connections.";
+
+ for (int i = 0; i < 10; i++)
+ {
+ tcp = sockets[i * 10];
+
+ if (tcp != null)
+ {
+ msg += $"\r\n{Common.MachineName}{(tcp.IsClient ? "=>" : "<=")}{tcp.MachineName}:{tcp.Status}";
+ }
+ }
+
+ _ = Common.CreateLowIntegrityProcess(
+ "\"" + Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBordersHelper.exe\"",
+ "InternalError" + " \"" + msg + "\"",
+ 0,
+ false,
+ 0,
+ (short)ProcessWindowStyle.Hidden);
+ }
+ finally
+ {
+ Common.MainForm.Quit(true, false);
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Class/TcpServer.cs b/src/modules/MouseWithoutBorders/App/Class/TcpServer.cs
new file mode 100644
index 000000000000..6e5478d71b96
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Class/TcpServer.cs
@@ -0,0 +1,176 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Globalization;
+using System.Linq;
+using System.Net.Sockets;
+using System.Threading;
+using System.Threading.Tasks;
+
+//
+// TCP Server implementation.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Exceptions;
+
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.TcpServer.#Close()", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders.Class
+{
+ internal class TcpServer
+ {
+ private readonly TcpListener server;
+
+ internal string Name { get; private set; }
+
+ internal TcpServer(int port, ParameterizedThreadStart job)
+ {
+ Common.Log($"TCP listening on port: {port}");
+ Name = port.ToString(CultureInfo.CurrentCulture);
+ server = TcpListener.Create(port);
+ StartServer(job);
+ }
+
+ private void StartServer(ParameterizedThreadStart job)
+ {
+ int tryCount = 6;
+
+ do
+ {
+ try
+ {
+ server.Start();
+ break;
+ }
+ catch (SocketException e)
+ {
+ // DHCP error, etc.
+ if (server.LocalEndpoint.ToString().StartsWith("169.254", StringComparison.InvariantCulture) || server.LocalEndpoint.ToString().StartsWith("0.0", StringComparison.InvariantCulture))
+ {
+ throw new ExpectedSocketException($"Error: The machine has limited connectivity on [{server.LocalEndpoint}]!");
+ }
+
+ if (e.ErrorCode == 10048 /*WSAEADDRINUSE*/)
+ {
+ if (--tryCount >= 0)
+ {
+ Thread.Sleep(500);
+ continue;
+ }
+
+ if (!Common.IsMyDesktopActive())
+ {
+ // We can just throw the SocketException but to avoid a redundant log entry:
+ throw new ExpectedSocketException($"{nameof(StartServer)}: The desktop is no longer active.");
+ }
+ else
+ {
+ LogError($"WSAEADDRINUSE: {server.LocalEndpoint}: {e.Message}");
+ throw;
+ }
+ }
+ else
+ {
+ Common.TelemetryLogTrace($"Error listening on: {server.LocalEndpoint}: {e.ErrorCode}/{e.Message}", SeverityLevel.Error);
+ throw;
+ }
+ }
+ }
+ while (true);
+
+ Thread t = new(job, Name = "Tcp Server: " + job.Method.Name + " " + server.LocalEndpoint.ToString());
+ t.SetApartmentState(ApartmentState.STA);
+ t.Start(server);
+ }
+
+ internal void Close()
+ {
+ try
+ {
+ server?.Stop();
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ private static bool logged;
+
+ private void LogError(string log)
+ {
+ if (!logged)
+ {
+ logged = true;
+
+ _ = Task.Factory.StartNew(
+ () =>
+ {
+ try
+ {
+ using Process proc = new();
+ ProcessStartInfo startInfo = new()
+ {
+ FileName = Environment.ExpandEnvironmentVariables(@"%windir%\System32\netstat.exe"),
+ Arguments = "-nao",
+ WindowStyle = ProcessWindowStyle.Hidden,
+ UseShellExecute = false,
+ RedirectStandardError = true,
+ RedirectStandardInput = true,
+ RedirectStandardOutput = true,
+ };
+
+ proc.StartInfo = startInfo;
+ _ = proc.Start();
+
+ string status = proc.StandardOutput.ReadToEnd() + Environment.NewLine;
+
+ if (proc.ExitCode == 0)
+ {
+ System.Collections.Generic.IEnumerable portLog = status.Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)
+ .Where(line => line.Contains("LISTENING") && (line.Contains(":15100 ") || line.Contains(":15101 ")));
+
+ foreach (string portLogLine in portLog)
+ {
+ int pid = 0;
+ Process process = null;
+
+ try
+ {
+ // Assuming the format of netstat's output is fixed.
+ pid = int.Parse(portLogLine.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries).Last(), CultureInfo.CurrentCulture);
+ process = Process.GetProcessById(pid);
+ }
+ catch (Exception)
+ {
+ /* TODO: There was some telemetry here. Log instead? */
+ }
+
+ /* TODO: There was some telemetry here. Log instead? */
+ }
+ }
+ else
+ {
+ /* TODO: There was some telemetry here. Log instead? */
+ }
+ }
+ catch (Exception)
+ {
+ /* TODO: There was some telemetry here. Log instead? */
+ }
+ },
+ System.Threading.CancellationToken.None,
+ TaskCreationOptions.None,
+ TaskScheduler.Default);
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/ColorBorderField.Designer.cs b/src/modules/MouseWithoutBorders/App/Control/ColorBorderField.Designer.cs
new file mode 100644
index 000000000000..bb7cb6ba2a7a
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/ColorBorderField.Designer.cs
@@ -0,0 +1,60 @@
+namespace MouseWithoutBorders
+{
+ partial class ColorBorderField
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.InnerField = new System.Windows.Forms.TextBox();
+ this.SuspendLayout();
+ //
+ // InnerField
+ //
+ this.InnerField.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.InnerField.Location = new System.Drawing.Point(3, 3);
+ this.InnerField.Name = "InnerField";
+ this.InnerField.Size = new System.Drawing.Size(100, 13);
+ this.InnerField.TabIndex = 0;
+ this.InnerField.WordWrap = false;
+ //
+ // ColorBorderField
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.Controls.Add(this.InnerField);
+ this.Margin = new System.Windows.Forms.Padding(0);
+ this.Name = "ColorBorderField";
+ this.Size = new System.Drawing.Size(134, 36);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.TextBox InnerField;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/ColorBorderField.cs b/src/modules/MouseWithoutBorders/App/Control/ColorBorderField.cs
new file mode 100644
index 000000000000..f7fd54e16f50
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/ColorBorderField.cs
@@ -0,0 +1,123 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ public partial class ColorBorderField : UserControl
+ {
+ [Category("Property Changed")]
+ [Description("The text property of the field has changed")]
+ public event EventHandler FieldTextChanged;
+
+ private int _borderSize;
+
+ [Category("Appearance")]
+ [Description("The thickness of the border around the field")]
+ public int BorderSize
+ {
+ get => _borderSize;
+ set
+ {
+ _borderSize = value;
+ UpdateFieldSize();
+ }
+ }
+
+ private Color _borderColor;
+
+ [Category("Appearance")]
+ [Description("The color of the border around the field")]
+ public Color BorderColor
+ {
+ get => _borderColor;
+ set
+ {
+ _borderColor = value;
+ UpdateBorderColor();
+ }
+ }
+
+ private Color _focusColor;
+
+ [Category("Appearance")]
+ [Description("The color of the border around the field when it has focus")]
+ public Color FocusColor
+ {
+ get => _focusColor;
+ set
+ {
+ _focusColor = value;
+ UpdateBorderColor();
+ }
+ }
+
+ [Category("Behavior")]
+ [Description("The maximum number of characters that can be typed in the field")]
+ public int MaximumLength
+ {
+ get => InnerField.MaxLength;
+ set => InnerField.MaxLength = value;
+ }
+
+ public override string Text
+ {
+ get => InnerField.Text;
+ set => InnerField.Text = value;
+ }
+
+ public ColorBorderField()
+ {
+ InitializeComponent();
+ InnerField.GotFocus += InnerFieldGotFocus;
+ InnerField.LostFocus += InnerFieldLostFocus;
+ InnerField.TextChanged += InnerFieldTextChanged;
+ UpdateBorderColor();
+ }
+
+ protected override void OnResize(EventArgs e)
+ {
+ base.OnResize(e);
+ UpdateFieldSize();
+ }
+
+ protected override void OnGotFocus(EventArgs e)
+ {
+ base.OnGotFocus(e);
+ _ = InnerField.Focus();
+ }
+
+ private void InnerFieldGotFocus(object sender, EventArgs e)
+ {
+ BackColor = FocusColor;
+ }
+
+ private void InnerFieldLostFocus(object sender, EventArgs e)
+ {
+ BackColor = BorderColor;
+ }
+
+ private void InnerFieldTextChanged(object sender, EventArgs e)
+ {
+ FieldTextChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ private void UpdateFieldSize()
+ {
+ InnerField.Left = BorderSize;
+ InnerField.Top = BorderSize;
+ InnerField.Width = Width - (BorderSize * 2);
+ Height = InnerField.Height + (BorderSize * 2);
+ }
+
+ private void UpdateBorderColor()
+ {
+ BackColor = Focused ? FocusColor : BorderColor;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/ColorBorderField.resx b/src/modules/MouseWithoutBorders/App/Control/ColorBorderField.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/ColorBorderField.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Control/ImageButton.Designer.cs b/src/modules/MouseWithoutBorders/App/Control/ImageButton.Designer.cs
new file mode 100644
index 000000000000..ff7681ce57cf
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/ImageButton.Designer.cs
@@ -0,0 +1,44 @@
+namespace MouseWithoutBorders
+{
+ partial class ImageButton
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.SuspendLayout();
+ //
+ // ImageButton
+ //
+ this.Name = "ImageButton";
+ this.Size = new System.Drawing.Size(80, 78);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/ImageButton.cs b/src/modules/MouseWithoutBorders/App/Control/ImageButton.cs
new file mode 100644
index 000000000000..da191ab3c0ed
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/ImageButton.cs
@@ -0,0 +1,146 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ public partial class ImageButton : PictureBox
+ {
+ public ImageButton()
+ {
+ InitializeComponent();
+ UpdateEnabledState();
+ }
+
+ [Category("Appearance")]
+ [Description("Image to show when Mouse is pressed on button")]
+ public Image DownImage { get; set; }
+
+ private Image _normalImage;
+
+ [Category("Appearance")]
+ [Description("Image to show when button is in normal state")]
+ public Image NormalImage
+ {
+ get => _normalImage;
+ set
+ {
+ _normalImage = value;
+ UpdateEnabledState();
+ }
+ }
+
+ [Category("Appearance")]
+ [Description("Image to show when Mouse hovers over button")]
+ public Image HoverImage { get; set; }
+
+ [Category("Appearance")]
+ [Description("Image to show when button is disabled")]
+ public Image DisabledImage { get; set; }
+
+ private bool _hovering;
+ private bool _buttonDown;
+
+ protected override void OnVisibleChanged(EventArgs e)
+ {
+ UpdateEnabledState();
+ base.OnVisibleChanged(e);
+ }
+
+ protected override void OnEnabledChanged(EventArgs e)
+ {
+ UpdateEnabledState();
+ base.OnEnabledChanged(e);
+ }
+
+ protected override void OnLoadCompleted(AsyncCompletedEventArgs e)
+ {
+ UpdateEnabledState();
+ base.OnLoadCompleted(e);
+ }
+
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ _hovering = true;
+ if (Enabled)
+ {
+ if (_buttonDown)
+ {
+ if (DownImage != null && Image != DownImage)
+ {
+ Image = DownImage;
+ }
+ }
+ else
+ {
+ Image = HoverImage ?? NormalImage;
+ }
+ }
+
+ base.OnMouseMove(e);
+ }
+
+ protected override void OnMouseDown(MouseEventArgs e)
+ {
+ _buttonDown = true;
+ if (Enabled)
+ {
+ _ = Focus();
+ if (DownImage != null)
+ {
+ Image = DownImage;
+ }
+ }
+
+ base.OnMouseDown(e);
+ }
+
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ _buttonDown = false;
+ if (Enabled)
+ {
+ if (_hovering)
+ {
+ if (HoverImage != null)
+ {
+ Image = HoverImage;
+ }
+ }
+ else
+ {
+ Image = NormalImage;
+ }
+ }
+
+ base.OnMouseUp(e);
+ }
+
+ protected override void OnMouseLeave(EventArgs e)
+ {
+ _hovering = false;
+ UpdateEnabledState();
+ base.OnMouseLeave(e);
+ }
+
+ private void UpdateEnabledState()
+ {
+ if (Enabled)
+ {
+ Image = _hovering && HoverImage != null ? HoverImage : NormalImage;
+ }
+ else
+ {
+ if (DisabledImage != null)
+ {
+ Image = DisabledImage;
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/ImageButton.resx b/src/modules/MouseWithoutBorders/App/Control/ImageButton.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/ImageButton.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Control/ImageRadioButton.Designer.cs b/src/modules/MouseWithoutBorders/App/Control/ImageRadioButton.Designer.cs
new file mode 100644
index 000000000000..eb2bba86d8aa
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/ImageRadioButton.Designer.cs
@@ -0,0 +1,44 @@
+namespace MouseWithoutBorders
+{
+ partial class ImageRadioButton
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.SuspendLayout();
+ //
+ // ImageCheckButton
+ //
+ this.Name = "ImageCheckButton";
+ this.Size = new System.Drawing.Size(105, 34);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/ImageRadioButton.cs b/src/modules/MouseWithoutBorders/App/Control/ImageRadioButton.cs
new file mode 100644
index 000000000000..fb1f715e36b3
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/ImageRadioButton.cs
@@ -0,0 +1,91 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.ComponentModel;
+using System.Drawing;
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ public partial class ImageRadioButton : RadioButton
+ {
+ private Image CheckImage => Checked ? CheckedImage : UncheckedImage;
+
+ private Point _imageLocation;
+
+ [Category("Appearance")]
+ [Description("The bounding rectangle of the check image in local co-ordinates")]
+ public Point ImageLocation
+ {
+ get => _imageLocation;
+ set
+ {
+ _imageLocation = value;
+ Refresh();
+ }
+ }
+
+ private Point _textLocation;
+
+ public Point TextLocation
+ {
+ get => _textLocation;
+ set
+ {
+ _textLocation = value;
+ Refresh();
+ }
+ }
+
+ public ImageRadioButton()
+ {
+ InitializeComponent();
+ }
+
+ private Image _checkedImage;
+
+ [Category("Appearance")]
+ [Description("Image to show when Mouse is pressed on button")]
+ public Image CheckedImage
+ {
+ get => _checkedImage;
+ set
+ {
+ _checkedImage = value;
+ Refresh();
+ }
+ }
+
+ private Image _uncheckedImage;
+
+ [Category("Appearance")]
+ [Description("Image to show when button is in normal state")]
+ public Image UncheckedImage
+ {
+ get => _uncheckedImage;
+ set
+ {
+ _uncheckedImage = value;
+ Refresh();
+ }
+ }
+
+ protected override void OnPaint(PaintEventArgs pevent)
+ {
+ if (CheckImage == null)
+ {
+ base.OnPaint(pevent);
+ }
+ else
+ {
+ OnPaintBackground(pevent);
+ pevent.Graphics.DrawImage(CheckImage, ImageLocation.X, ImageLocation.Y, CheckImage.Width, CheckImage.Height);
+ if (!string.IsNullOrEmpty(Text))
+ {
+ pevent.Graphics.DrawString(Text, Font, Brushes.White, TextLocation);
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/ImageRadioButton.resx b/src/modules/MouseWithoutBorders/App/Control/ImageRadioButton.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/ImageRadioButton.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Control/Machine.cs b/src/modules/MouseWithoutBorders/App/Control/Machine.cs
new file mode 100644
index 000000000000..e0925ea3129e
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/Machine.cs
@@ -0,0 +1,207 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Windows.Forms;
+
+//
+// User control, used in the Matrix form.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+using MouseWithoutBorders.Properties;
+
+namespace MouseWithoutBorders
+{
+ internal partial class Machine : UserControl
+ {
+ // private int ip;
+ // private Point mouseDownPos;
+ private SocketStatus statusClient;
+
+ private SocketStatus statusServer;
+ private bool localhost;
+
+ internal Machine()
+ {
+ InitializeComponent();
+ Visible = false;
+ MachineEnabled = false;
+ }
+
+ internal string MachineName
+ {
+ get => textBoxName.Text;
+ set => textBoxName.Text = value;
+ }
+
+ internal bool MachineEnabled
+ {
+ get => checkBoxEnabled.Checked;
+ set
+ {
+ checkBoxEnabled.Checked = value;
+ Editable = value;
+ pictureBoxLogo.Image = value ? Resources.MachineEnabled : (System.Drawing.Image)Resources.MachineDisabled;
+ OnEnabledChanged(EventArgs.Empty); // Borrow this event since we do not use it for any other purpose:) (we can create one but l...:))
+ }
+ }
+
+ internal bool Editable
+ {
+ set => textBoxName.Enabled = value;
+
+ // get { return textBoxName.Enabled; }
+ }
+
+ internal bool CheckAble
+ {
+ set
+ {
+ if (!value)
+ {
+ checkBoxEnabled.Checked = true;
+ Editable = false;
+ }
+
+ checkBoxEnabled.Enabled = value;
+ }
+ }
+
+ internal bool LocalHost
+ {
+ // get { return localhost; }
+ set
+ {
+ localhost = value;
+ if (localhost)
+ {
+ labelStatusClient.Text = "local machine";
+ labelStatusServer.Text = "...";
+ CheckAble = false;
+ }
+ else
+ {
+ labelStatusClient.Text = "...";
+ labelStatusServer.Text = "...";
+ CheckAble = true;
+ }
+ }
+ }
+
+ private void PictureBoxLogo_MouseDown(object sender, MouseEventArgs e)
+ {
+ // mouseDownPos = e.Location;
+ OnMouseDown(e);
+ }
+
+ /*
+ internal Point MouseDownPos
+ {
+ get { return mouseDownPos; }
+ }
+ */
+
+ private void CheckBoxEnabled_CheckedChanged(object sender, EventArgs e)
+ {
+ MachineEnabled = checkBoxEnabled.Checked;
+ }
+
+ private static string StatusString(SocketStatus status)
+ {
+ string rv = string.Empty;
+
+ switch (status)
+ {
+ case SocketStatus.Resolving:
+ rv = "Resolving";
+ break;
+
+ case SocketStatus.Connected:
+ rv = "Connected";
+ break;
+
+ case SocketStatus.Connecting:
+ rv = "Connecting";
+ break;
+
+ case SocketStatus.Error:
+ rv = "Error";
+ break;
+
+ case SocketStatus.ForceClosed:
+ rv = "Closed";
+ break;
+
+ case SocketStatus.Handshaking:
+ rv = "Handshaking";
+ break;
+
+ case SocketStatus.SendError:
+ rv = "Send error";
+ break;
+
+ case SocketStatus.InvalidKey:
+ rv = "KeysNotMatched";
+ break;
+
+ case SocketStatus.Timeout:
+ rv = "Timed out";
+ break;
+
+ case SocketStatus.NA:
+ rv = "...";
+ break;
+
+ default:
+ break;
+ }
+
+ return rv;
+ }
+
+ internal SocketStatus StatusClient
+ {
+ get => statusClient;
+
+ set
+ {
+ statusClient = value;
+ if (statusClient is SocketStatus.Connected or
+ SocketStatus.Handshaking)
+ {
+ Editable = false;
+ }
+
+ labelStatusClient.Text = StatusString(statusClient) + " -->";
+ }
+ }
+
+ internal SocketStatus StatusServer
+ {
+ get => statusServer;
+
+ set
+ {
+ statusServer = value;
+ if (statusServer is SocketStatus.Connected or
+ SocketStatus.Handshaking)
+ {
+ Editable = false;
+ }
+
+ labelStatusServer.Text = StatusString(statusServer) + " <--";
+ }
+ }
+
+ private void PictureBoxLogo_Paint(object sender, PaintEventArgs e)
+ {
+ // e.Graphics.DrawString("(Draggable)", this.Font, Brushes.WhiteSmoke, 20, 15);
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/Machine.designer.cs b/src/modules/MouseWithoutBorders/App/Control/Machine.designer.cs
new file mode 100644
index 000000000000..291b48800794
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/Machine.designer.cs
@@ -0,0 +1,125 @@
+namespace MouseWithoutBorders
+{
+ partial class Machine
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ this.labelStatusServer = new System.Windows.Forms.Label();
+ this.textBoxName = new System.Windows.Forms.TextBox();
+ this.checkBoxEnabled = new System.Windows.Forms.CheckBox();
+ this.pictureBoxLogo = new System.Windows.Forms.PictureBox();
+ this.labelStatusClient = new System.Windows.Forms.Label();
+ this.toolTipHelp = new System.Windows.Forms.ToolTip(this.components);
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBoxLogo)).BeginInit();
+ this.SuspendLayout();
+ //
+ // labelStatusServer
+ //
+ this.labelStatusServer.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.labelStatusServer.Location = new System.Drawing.Point(0, 90);
+ this.labelStatusServer.Name = "labelStatusServer";
+ this.labelStatusServer.Size = new System.Drawing.Size(106, 16);
+ this.labelStatusServer.TabIndex = 0;
+ this.labelStatusServer.Text = "...";
+ this.labelStatusServer.TextAlign = System.Drawing.ContentAlignment.TopCenter;
+ //
+ // textBoxName
+ //
+ this.textBoxName.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.textBoxName.Location = new System.Drawing.Point(0, 54);
+ this.textBoxName.Name = "textBoxName";
+ this.textBoxName.Size = new System.Drawing.Size(106, 20);
+ this.textBoxName.TabIndex = 1;
+ this.textBoxName.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
+ //
+ // checkBoxEnabled
+ //
+ this.checkBoxEnabled.AutoSize = true;
+ this.checkBoxEnabled.Checked = true;
+ this.checkBoxEnabled.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.checkBoxEnabled.Location = new System.Drawing.Point(91, 40);
+ this.checkBoxEnabled.Name = "checkBoxEnabled";
+ this.checkBoxEnabled.Size = new System.Drawing.Size(15, 14);
+ this.checkBoxEnabled.TabIndex = 3;
+ this.checkBoxEnabled.UseVisualStyleBackColor = true;
+ this.checkBoxEnabled.CheckedChanged += new System.EventHandler(this.CheckBoxEnabled_CheckedChanged);
+ //
+ // pictureBoxLogo
+ //
+ this.pictureBoxLogo.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.pictureBoxLogo.ErrorImage = null;
+ this.pictureBoxLogo.InitialImage = null;
+ this.pictureBoxLogo.Location = new System.Drawing.Point(0, 0);
+ this.pictureBoxLogo.Name = "pictureBoxLogo";
+ this.pictureBoxLogo.Size = new System.Drawing.Size(106, 54);
+ this.pictureBoxLogo.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+ this.pictureBoxLogo.TabIndex = 2;
+ this.pictureBoxLogo.TabStop = false;
+ this.toolTipHelp.SetToolTip(this.pictureBoxLogo, "Drag to match machine physical layout. Check the checkbox to enter machine name.");
+ this.pictureBoxLogo.Paint += new System.Windows.Forms.PaintEventHandler(this.PictureBoxLogo_Paint);
+ this.pictureBoxLogo.MouseDown += new System.Windows.Forms.MouseEventHandler(this.PictureBoxLogo_MouseDown);
+ //
+ // labelStatusClient
+ //
+ this.labelStatusClient.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.labelStatusClient.Location = new System.Drawing.Point(0, 74);
+ this.labelStatusClient.Name = "labelStatusClient";
+ this.labelStatusClient.Size = new System.Drawing.Size(106, 16);
+ this.labelStatusClient.TabIndex = 4;
+ this.labelStatusClient.Text = "...";
+ this.labelStatusClient.TextAlign = System.Drawing.ContentAlignment.TopCenter;
+ //
+ // Machine
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.Transparent;
+ this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
+ this.Controls.Add(this.checkBoxEnabled);
+ this.Controls.Add(this.pictureBoxLogo);
+ this.Controls.Add(this.textBoxName);
+ this.Controls.Add(this.labelStatusClient);
+ this.Controls.Add(this.labelStatusServer);
+ this.Name = "Machine";
+ this.Size = new System.Drawing.Size(106, 106);
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBoxLogo)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label labelStatusServer;
+ private System.Windows.Forms.TextBox textBoxName;
+ private System.Windows.Forms.PictureBox pictureBoxLogo;
+ private System.Windows.Forms.CheckBox checkBoxEnabled;
+ private System.Windows.Forms.Label labelStatusClient;
+ private System.Windows.Forms.ToolTip toolTipHelp;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/Machine.resx b/src/modules/MouseWithoutBorders/App/Control/Machine.resx
new file mode 100644
index 000000000000..5faded8d2464
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/Machine.resx
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+ True
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Control/Machine2.Designer.cs b/src/modules/MouseWithoutBorders/App/Control/Machine2.Designer.cs
new file mode 100644
index 000000000000..cad1a55b5e93
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/Machine2.Designer.cs
@@ -0,0 +1,168 @@
+namespace MouseWithoutBorders
+{
+ partial class Machine2
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.StatusLabel = new System.Windows.Forms.Label();
+ this.NameLabel = new System.Windows.Forms.Label();
+ this.SelectedPanel = new System.Windows.Forms.Panel();
+ this.ComputerPictureBox = new System.Windows.Forms.PictureBox();
+ this.RemoveButton = new MouseWithoutBorders.ImageButton();
+ this.OnButton = new MouseWithoutBorders.ImageButton();
+ this.OffButton = new MouseWithoutBorders.ImageButton();
+ ((System.ComponentModel.ISupportInitialize)(this.ComputerPictureBox)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.RemoveButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.OnButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.OffButton)).BeginInit();
+ this.SuspendLayout();
+ //
+ // StatusLabel
+ //
+ this.StatusLabel.BackColor = System.Drawing.Color.Transparent;
+ this.StatusLabel.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.StatusLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(49)))), ((int)(((byte)(159)))), ((int)(((byte)(217)))));
+ this.StatusLabel.Location = new System.Drawing.Point(3, 30);
+ this.StatusLabel.Name = "StatusLabel";
+ this.StatusLabel.Size = new System.Drawing.Size(112, 39);
+ this.StatusLabel.TabIndex = 2;
+ this.StatusLabel.Text = "This Computer";
+ this.StatusLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // NameLabel
+ //
+ this.NameLabel.BackColor = System.Drawing.Color.Transparent;
+ this.NameLabel.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.NameLabel.ForeColor = System.Drawing.Color.White;
+ this.NameLabel.Location = new System.Drawing.Point(6, 96);
+ this.NameLabel.Name = "NameLabel";
+ this.NameLabel.Size = new System.Drawing.Size(109, 17);
+ this.NameLabel.TabIndex = 1;
+ this.NameLabel.Text = "label1";
+ this.NameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // SelectedPanel
+ //
+ this.SelectedPanel.Location = new System.Drawing.Point(101, 225);
+ this.SelectedPanel.Name = "SelectedPanel";
+ this.SelectedPanel.Size = new System.Drawing.Size(200, 100);
+ this.SelectedPanel.TabIndex = 8;
+ //
+ // ComputerPictureBox
+ //
+ this.ComputerPictureBox.Image = global::MouseWithoutBorders.Properties.Resources.computer_connected;
+ this.ComputerPictureBox.Location = new System.Drawing.Point(5, 5);
+ this.ComputerPictureBox.Name = "ComputerPictureBox";
+ this.ComputerPictureBox.Padding = new System.Windows.Forms.Padding(0, 10, 0, 0);
+ this.ComputerPictureBox.Size = new System.Drawing.Size(109, 78);
+ this.ComputerPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+ this.ComputerPictureBox.TabIndex = 0;
+ this.ComputerPictureBox.TabStop = false;
+ //
+ // RemoveButton
+ //
+ this.RemoveButton.DisabledImage = null;
+ this.RemoveButton.DownImage = global::MouseWithoutBorders.Properties.Resources.red_close_button_click;
+ this.RemoveButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.red_close_button_hover;
+ this.RemoveButton.Image = global::MouseWithoutBorders.Properties.Resources.red_close_button_normal;
+ this.RemoveButton.Location = new System.Drawing.Point(224, 15);
+ this.RemoveButton.Name = "RemoveButton";
+ this.RemoveButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.red_close_button_normal;
+ this.RemoveButton.Size = new System.Drawing.Size(12, 12);
+ this.RemoveButton.TabIndex = 5;
+ this.RemoveButton.TabStop = false;
+ this.RemoveButton.Click += new System.EventHandler(this.RemoveButtonClick);
+ //
+ // OnButton
+ //
+ this.OnButton.BackColor = System.Drawing.Color.Transparent;
+ this.OnButton.DisabledImage = null;
+ this.OnButton.DownImage = global::MouseWithoutBorders.Properties.Resources.switch_on_click;
+ this.OnButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.switch_on_hover;
+ this.OnButton.Image = global::MouseWithoutBorders.Properties.Resources.switch_on_normal;
+ this.OnButton.Location = new System.Drawing.Point(277, 20);
+ this.OnButton.Name = "OnButton";
+ this.OnButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.switch_on_normal;
+ this.OnButton.Size = new System.Drawing.Size(30, 15);
+ this.OnButton.TabIndex = 3;
+ this.OnButton.TabStop = false;
+ this.OnButton.Click += new System.EventHandler(this.OnButtonClick);
+ //
+ // OffButton
+ //
+ this.OffButton.BackColor = System.Drawing.Color.Transparent;
+ this.OffButton.DisabledImage = null;
+ this.OffButton.DownImage = global::MouseWithoutBorders.Properties.Resources.switch_off_click;
+ this.OffButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.switch_off_hover;
+ this.OffButton.Image = global::MouseWithoutBorders.Properties.Resources.switch_off_normal;
+ this.OffButton.Location = new System.Drawing.Point(241, 42);
+ this.OffButton.Name = "OffButton";
+ this.OffButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.switch_off_normal;
+ this.OffButton.Size = new System.Drawing.Size(30, 15);
+ this.OffButton.TabIndex = 4;
+ this.OffButton.TabStop = false;
+ this.OffButton.Click += new System.EventHandler(this.OffButtonClick);
+ //
+ // Machine2
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.BackColor = System.Drawing.Color.Transparent;
+ this.Controls.Add(this.RemoveButton);
+ this.Controls.Add(this.OnButton);
+ this.Controls.Add(this.OffButton);
+ this.Controls.Add(this.StatusLabel);
+ this.Controls.Add(this.NameLabel);
+ this.Controls.Add(this.ComputerPictureBox);
+ this.Controls.Add(this.SelectedPanel);
+ this.DoubleBuffered = true;
+ this.Margin = new System.Windows.Forms.Padding(0);
+ this.Size = new System.Drawing.Size(471, 432);
+ ((System.ComponentModel.ISupportInitialize)(this.ComputerPictureBox)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.RemoveButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.OnButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.OffButton)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.PictureBox ComputerPictureBox;
+ private System.Windows.Forms.Label StatusLabel;
+ private ImageButton OffButton;
+ private ImageButton OnButton;
+ private ImageButton RemoveButton;
+ private System.Windows.Forms.Label NameLabel;
+ private System.Windows.Forms.Panel SelectedPanel;
+
+
+
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/Machine2.resx b/src/modules/MouseWithoutBorders/App/Control/Machine2.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/Machine2.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Control/MachineMatrix.Designer.cs b/src/modules/MouseWithoutBorders/App/Control/MachineMatrix.Designer.cs
new file mode 100644
index 000000000000..859ecce4ad7d
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/MachineMatrix.Designer.cs
@@ -0,0 +1,99 @@
+namespace MouseWithoutBorders
+{
+ partial class MachineMatrix
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.SingleRowRadioButton = new MouseWithoutBorders.ImageRadioButton();
+ this.TwoRowsRadioButton = new MouseWithoutBorders.ImageRadioButton();
+ this.panel1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // panel1
+ //
+ this.panel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
+ this.panel1.Controls.Add(this.SingleRowRadioButton);
+ this.panel1.Controls.Add(this.TwoRowsRadioButton);
+ this.panel1.Location = new System.Drawing.Point(0, 7);
+ this.panel1.Margin = new System.Windows.Forms.Padding(0);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(51, 56);
+ this.panel1.TabIndex = 6;
+ //
+ // SingleRowRadioButton
+ //
+ this.SingleRowRadioButton.Checked = true;
+ this.SingleRowRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Resources.one_row_button_checked;
+ this.SingleRowRadioButton.ImageLocation = new System.Drawing.Point(0, 0);
+ this.SingleRowRadioButton.Location = new System.Drawing.Point(0, 0);
+ this.SingleRowRadioButton.Margin = new System.Windows.Forms.Padding(0);
+ this.SingleRowRadioButton.Name = "SingleRowRadioButton";
+ this.SingleRowRadioButton.Size = new System.Drawing.Size(51, 24);
+ this.SingleRowRadioButton.TabIndex = 4;
+ this.SingleRowRadioButton.TabStop = true;
+ this.SingleRowRadioButton.TextLocation = new System.Drawing.Point(0, 0);
+ this.SingleRowRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.one_row_button_unchecked;
+ this.SingleRowRadioButton.UseVisualStyleBackColor = true;
+ this.SingleRowRadioButton.CheckedChanged += new System.EventHandler(this.SingleRowRadioButtonCheckedChanged);
+ //
+ // TwoRowsRadioButton
+ //
+ this.TwoRowsRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Resources.two_row_button_checked;
+ this.TwoRowsRadioButton.ImageLocation = new System.Drawing.Point(0, 0);
+ this.TwoRowsRadioButton.Location = new System.Drawing.Point(0, 27);
+ this.TwoRowsRadioButton.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
+ this.TwoRowsRadioButton.Name = "TwoRowsRadioButton";
+ this.TwoRowsRadioButton.Size = new System.Drawing.Size(27, 24);
+ this.TwoRowsRadioButton.TabIndex = 5;
+ this.TwoRowsRadioButton.TextLocation = new System.Drawing.Point(0, 0);
+ this.TwoRowsRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.two_row_button_unchecked;
+ this.TwoRowsRadioButton.UseVisualStyleBackColor = true;
+ this.TwoRowsRadioButton.CheckedChanged += new System.EventHandler(this.TwoRowsRadioButtonCheckedChanged);
+ //
+ // MachineMatrix
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.Maroon;
+ this.Controls.Add(this.panel1);
+ this.DoubleBuffered = true;
+ this.Name = "MachineMatrix";
+ this.Size = new System.Drawing.Size(360, 175);
+ this.panel1.ResumeLayout(false);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private ImageRadioButton SingleRowRadioButton;
+ private ImageRadioButton TwoRowsRadioButton;
+ private System.Windows.Forms.Panel panel1;
+
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Control/MachineMatrix.resx b/src/modules/MouseWithoutBorders/App/Control/MachineMatrix.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Control/MachineMatrix.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Exceptions/ExpectedSocketException.cs b/src/modules/MouseWithoutBorders/App/Exceptions/ExpectedSocketException.cs
new file mode 100644
index 000000000000..9ae57286218d
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Exceptions/ExpectedSocketException.cs
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Net.Sockets;
+
+namespace MouseWithoutBorders.Exceptions
+{
+ internal class ExpectedSocketException : KnownException
+ {
+ internal bool ShouldReconnect { get; set; }
+
+ internal ExpectedSocketException(string message)
+ : base(message)
+ {
+ }
+
+ internal ExpectedSocketException(SocketException se)
+ : base(se.Message)
+ {
+ ShouldReconnect = se.ErrorCode == 10054;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Exceptions/KnownException.cs b/src/modules/MouseWithoutBorders/App/Exceptions/KnownException.cs
new file mode 100644
index 000000000000..ad15584a80c8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Exceptions/KnownException.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace MouseWithoutBorders.Exceptions
+{
+ internal class KnownException : Exception
+ {
+ internal KnownException(string message)
+ : base(message)
+ {
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Exceptions/NotPhysicalConsoleException.cs b/src/modules/MouseWithoutBorders/App/Exceptions/NotPhysicalConsoleException.cs
new file mode 100644
index 000000000000..a1a86089870f
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Exceptions/NotPhysicalConsoleException.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace MouseWithoutBorders.Exceptions
+{
+ internal class NotPhysicalConsoleException : KnownException
+ {
+ internal NotPhysicalConsoleException(string message)
+ : base(message)
+ {
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/PageEventArgs.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/PageEventArgs.cs
new file mode 100644
index 000000000000..0e3e785c6cd4
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/PageEventArgs.cs
@@ -0,0 +1,18 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace MouseWithoutBorders.Form.Settings
+{
+ public class PageEventArgs : EventArgs
+ {
+ public SettingsFormPage Page { get; private set; }
+
+ public PageEventArgs(SettingsFormPage page)
+ {
+ Page = page;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsForm.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsForm.Designer.cs
new file mode 100644
index 000000000000..7a43058dba40
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsForm.Designer.cs
@@ -0,0 +1,95 @@
+namespace MouseWithoutBorders
+{
+ partial class SettingsForm
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(SettingsForm));
+ this.closeWindowButton = new MouseWithoutBorders.ImageButton();
+ this.contentPanel = new System.Windows.Forms.Panel();
+ this.toolTipManual = new System.Windows.Forms.ToolTip(this.components);
+ ((System.ComponentModel.ISupportInitialize)(this.closeWindowButton)).BeginInit();
+ this.SuspendLayout();
+ //
+ // closeWindowButton
+ //
+ this.closeWindowButton.BackColor = System.Drawing.Color.Transparent;
+ this.closeWindowButton.DisabledImage = null;
+ this.closeWindowButton.DownImage = global::MouseWithoutBorders.Properties.Resources.close_window_click;
+ this.closeWindowButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.close_window_hover;
+ this.closeWindowButton.Location = new System.Drawing.Point(454, 6);
+ this.closeWindowButton.Name = "closeWindowButton";
+ this.closeWindowButton.NormalImage = null;
+ this.closeWindowButton.Size = new System.Drawing.Size(16, 16);
+ this.closeWindowButton.TabIndex = 1;
+ this.closeWindowButton.TabStop = false;
+ this.closeWindowButton.Click += new System.EventHandler(this.CloseWindowButtonClick);
+ //
+ // contentPanel
+ //
+ this.contentPanel.BackColor = System.Drawing.Color.Transparent;
+ this.contentPanel.Location = new System.Drawing.Point(12, 26);
+ this.contentPanel.Name = "contentPanel";
+ this.contentPanel.Size = new System.Drawing.Size(453, 438);
+ this.contentPanel.TabIndex = 2;
+ this.contentPanel.Visible = false;
+ //
+ // toolTipManual
+ //
+ this.toolTipManual.ToolTipTitle = "Microsoft® Visual Studio® 2010";
+ //
+ // SettingsForm
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackgroundImage = global::MouseWithoutBorders.Properties.Resources.dialog_background;
+ this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
+ this.ClientSize = new System.Drawing.Size(477, 476);
+ this.Controls.Add(this.closeWindowButton);
+ this.Controls.Add(this.contentPanel);
+ this.DoubleBuffered = true;
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.Name = "SettingsForm";
+ this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "frmSettings";
+ this.TopMost = true;
+ this.TransparencyKey = System.Drawing.Color.Magenta;
+ ((System.ComponentModel.ISupportInitialize)(this.closeWindowButton)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private ImageButton closeWindowButton;
+ private System.Windows.Forms.Panel contentPanel;
+ private System.Windows.Forms.ToolTip toolTipManual;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsForm.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsForm.cs
new file mode 100644
index 000000000000..f6cf932811f8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsForm.cs
@@ -0,0 +1,140 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using MouseWithoutBorders.Form.Settings;
+
+namespace MouseWithoutBorders
+{
+ public partial class SettingsForm : System.Windows.Forms.Form
+ {
+ private bool _movingWindows;
+ private Point _moveWindowOffset;
+ private SettingsFormPage _currentPage;
+
+ public SettingsForm()
+ {
+ InitializeComponent();
+
+ toolTipManual.ToolTipTitle = Application.ProductName;
+ Text = Application.ProductName;
+
+ Common.LogDebug("FIRST RUN, SHOWING THE FIRST SETUP PAGE.");
+
+ Common.LogDebug($"{nameof(Common.RunWithNoAdminRight)} = {Common.RunWithNoAdminRight}");
+
+ if (Common.RunWithNoAdminRight)
+ {
+ SetControlPage(new SetupPage2aa());
+ }
+ else
+ {
+ SetControlPage(new SetupPage1());
+ }
+ }
+
+ protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
+ {
+ Common.Settings = null;
+
+ if (_currentPage != null)
+ {
+ Common.LogDebug(_currentPage.Name + " closing.");
+ _currentPage.OnPageClosing();
+ }
+
+ base.OnClosing(e);
+ }
+
+ internal SettingsFormPage GetCurrentPage()
+ {
+ return _currentPage;
+ }
+
+ internal void SetControlPage(SettingsFormPage page)
+ {
+ SuspendLayout();
+ if (_currentPage != null)
+ {
+ _currentPage.NextPage -= PageNextPage;
+ _currentPage.OnPageClosing();
+ Controls.Remove(_currentPage);
+ }
+
+ if (page != null)
+ {
+ Common.LogDebug("GOING TO NEXT PAGE: " + page.Name);
+ page.BackColor = Color.Transparent;
+ page.NextPage += PageNextPage;
+ page.Location = contentPanel.Location;
+ page.Visible = true;
+ Controls.Add(page);
+ }
+
+ _currentPage = page;
+ ResumeLayout(true);
+ if (page == null)
+ {
+ Close();
+ }
+ }
+
+ private void PageNextPage(object sender, PageEventArgs e)
+ {
+ SetControlPage(e.Page);
+ }
+
+ protected override void OnMouseDown(MouseEventArgs e)
+ {
+ _movingWindows = true;
+ _moveWindowOffset = new Point(e.X, e.Y);
+ base.OnMouseDown(e);
+ }
+
+ protected override void OnMouseMove(MouseEventArgs e)
+ {
+ if (_movingWindows)
+ {
+ Point newLocation = Location;
+ newLocation.X += e.X - _moveWindowOffset.X;
+ newLocation.Y += e.Y - _moveWindowOffset.Y;
+ Location = newLocation;
+ }
+
+ base.OnMouseMove(e);
+ }
+
+ protected override void OnMouseUp(MouseEventArgs e)
+ {
+ if (_movingWindows)
+ {
+ _movingWindows = false;
+ }
+
+ base.OnMouseUp(e);
+ }
+
+ private void CloseWindowButtonClick(object sender, EventArgs e)
+ {
+ Close();
+ }
+
+ private string lastMessage = string.Empty;
+
+ internal void ShowTip(ToolTipIcon icon, string msg, int durationInMilliseconds)
+ {
+ int x = 0;
+ string text = msg + $"\r\n {(lastMessage.Equals(msg, StringComparison.OrdinalIgnoreCase) ? string.Empty : $"\r\nPrevious message/error: {lastMessage}")} ";
+ lastMessage = msg;
+ int y = (-text.Split(new string[] { "\r\n" }, StringSplitOptions.None).Length * 15) - 30;
+
+ toolTipManual.Hide(this);
+
+ toolTipManual.ToolTipIcon = icon;
+ toolTipManual.Show(text, this, x, y, durationInMilliseconds);
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsForm.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsForm.resx
new file mode 100644
index 000000000000..6d4959b7c34b
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsForm.resx
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+
+
+ AAABAAIAICAAAAAAGACoDAAAJgAAABAQAAAAABgAaAMAAM4MAAAoAAAAIAAAAEAAAAABABgAAAAAAAAM
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32FIv3Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32EYv3Eo32AAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32BIf3GJD2Eov3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAEo32CYn3GZD2DIf4Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ QZv0FI72GpH2FIv3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32Con3HJH2FI72QJv0
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANJb1FI72GZD2Ho/2Eo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAEo32Eo32G5H2FI72NJb1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAPpr0Fo72GZD2Don3Eo32AAAAAAAAAAAAAAAAAAAAAAAAEo32BIj3HJH2
+ Fo72Ppr0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpn0
+ Fo/2GZD2II/2Eo32AAAAAAAAAAAAAAAAEo32E432HJH2Fo/2Opn0AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIo/2HJH2GZD2Foz3Eo32AAAAAAAAEo32
+ Cor3HJH2HJH2Io/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUZ7zA4f3Con3Con3Con3Con3
+ Con3Con3Con3DYv3HJH2HpL2HZH2GZD2GIz2Eo32Eo32C4v3HJH2HpL2HpL2HJH2DYv3Con3Con3Con3
+ Con3Con3Con3Con3AIX4Eo32WqLzD432Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2F4/2HZH2HpL2HpL2HZH2
+ EY32O5j0Npf0FI72HZH2HpL2HpL2HJH2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2C4v3Eo32frPvSaPy
+ TqTyTqTyTqTyTqTyTqTyTqTyT6XyV6jxIJH2HZH2HpL2Eo32Opv0AAAAAAAALJT2FY/2HpL2HJH2K5T1
+ V6nxT6TyTqTyTqTyTqTyTqTyTqTyTqTyRqHzEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2
+ GY72HZH2Eo32OJr0AAAAAAAAAAAAAAAAKZP1FY/2G5H2I5H2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2Ho/2GpH2Eo32PZz0AAAAAAAAAAAAAAAAAAAA
+ AAAAL5b1FY/2GJD2KJT2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAHZH2G472GZD2E432Npn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKJL1Fo/2Fo/2J5P2Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2HpD2GJD2FI72MZj1AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAJZL2Fo/2Fo/2KpT1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAHZH2FIv3GZD2E472MZf1AAAAAAAABAQEBAQEAAAAAAAAAAAAAAAABAQEBAQEAAAAAAAA
+ JZL2Fo/2Fo/2H4/3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32H5D2Doz2M5j0AAAA
+ AAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAJpL1D4z2J5T1Eo32AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32NJj1AAAAAAAAAAAABAQE//jwBAQEBAQEAAAAAAAABAQE
+ //jwBAQEBAQEAAAAAAAAAAAAMJb1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQE
+ AAAAAAAAAAAAAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////////////////////////v//f/x/
+ /j/4P/wf/B/4P/4P8H//B+D//4PB///Bg/8AAAAAAAAAAAABgAD/g8H//wfg//4P8H/8H/g/+DPMH/hh
+ hh/84Yc//+GH///zz/////////////////////////////////8oAAAAEAAAACAAAAABABgAAAAAAAAD
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32GJD2Eo32AAAAAAAAAAAAAAAAAAAA
+ AAAACYn3DIf4AAAAAAAAAAAAAAAAAAAAAAAANJb1GZD2Eo32AAAAAAAAAAAAAAAAEo32FI72AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAOpn0GZD2Eo32AAAAAAAAE432Fo/2AAAAAAAAAAAAAAAAAAAAA4f3Con3
+ Con3Con3DYv3HpL2GZD2Eo32C4v3HpL2HJH2Con3Con3Con3Con3Eo32SaPyTqTyTqTyTqTyV6jxHZH2
+ Eo32AAAALJT2HpL2K5T1T6TyTqTyTqTyTqTyEo32AAAAAAAAAAAAAAAAHo/2Eo32AAAAAAAAAAAAL5b1
+ GJD2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAHpD2FI72AAAAAAAAAAAAAAAAAAAAJZL2Fo/2Eo32AAAA
+ AAAAAAAAAAAAAAAAEo32Doz2AAAABAQEBAQEAAAABAQEBAQEAAAAJpL1J5T1AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAABAQEBAQEAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA//8AAP//AAD//wAA7/8AAMfnAADjzwAA8Z8AAAAAAAABAAAA848AAOfHAADJJwAA+T8AAP//
+ AAD//wAA//8AAA==
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsFormPage.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsFormPage.Designer.cs
new file mode 100644
index 000000000000..1a033b69dfe3
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsFormPage.Designer.cs
@@ -0,0 +1,87 @@
+namespace MouseWithoutBorders
+{
+ partial class SettingsFormPage
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.buttonSkip = new System.Windows.Forms.Button();
+ this.BackButton = new MouseWithoutBorders.ImageButton();
+ ((System.ComponentModel.ISupportInitialize)(this.BackButton)).BeginInit();
+ this.SuspendLayout();
+ //
+ // buttonSkip
+ //
+ this.buttonSkip.FlatAppearance.BorderSize = 0;
+ this.buttonSkip.FlatAppearance.MouseDownBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(192)))), ((int)(((byte)(128)))));
+ this.buttonSkip.FlatAppearance.MouseOverBackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(128)))), ((int)(((byte)(0)))));
+ this.buttonSkip.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.buttonSkip.ForeColor = System.Drawing.Color.White;
+ this.buttonSkip.Location = new System.Drawing.Point(0, 36);
+ this.buttonSkip.Name = "buttonSkip";
+ this.buttonSkip.Size = new System.Drawing.Size(40, 23);
+ this.buttonSkip.TabIndex = 1;
+ this.buttonSkip.Text = "&Skip";
+ this.buttonSkip.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ this.buttonSkip.UseVisualStyleBackColor = true;
+ this.buttonSkip.Click += new System.EventHandler(this.ButtonSkip_Click);
+ //
+ // BackButton
+ //
+ this.BackButton.DisabledImage = null;
+ this.BackButton.DownImage = global::MouseWithoutBorders.Properties.Resources.back_button_click;
+ this.BackButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.back_button_hover;
+ this.BackButton.Image = global::MouseWithoutBorders.Properties.Resources.back_button_normal;
+ this.BackButton.Location = new System.Drawing.Point(6, 6);
+ this.BackButton.Name = "BackButton";
+ this.BackButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.back_button_normal;
+ this.BackButton.Size = new System.Drawing.Size(24, 24);
+ this.BackButton.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+ this.BackButton.TabIndex = 0;
+ this.BackButton.TabStop = false;
+ this.BackButton.Visible = false;
+ this.BackButton.Click += new System.EventHandler(this.BackButton_Click);
+ //
+ // SettingsFormPage
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DeepSkyBlue;
+ this.Controls.Add(this.buttonSkip);
+ this.Controls.Add(this.BackButton);
+ this.Name = "SettingsFormPage";
+ this.Size = new System.Drawing.Size(396, 345);
+ ((System.ComponentModel.ISupportInitialize)(this.BackButton)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private ImageButton BackButton;
+ private System.Windows.Forms.Button buttonSkip;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsFormPage.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsFormPage.cs
new file mode 100644
index 000000000000..099f53c86f13
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsFormPage.cs
@@ -0,0 +1,66 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Windows.Forms;
+using MouseWithoutBorders.Class;
+using MouseWithoutBorders.Form.Settings;
+
+namespace MouseWithoutBorders
+{
+ public partial class SettingsFormPage : UserControl
+ {
+ public event EventHandler NextPage;
+
+ protected bool BackButtonVisible
+ {
+ get => BackButton.Visible;
+ set => BackButton.Visible = value;
+ }
+
+ public SettingsFormPage()
+ {
+ InitializeComponent();
+ }
+
+ public virtual void OnPageClosing()
+ {
+ }
+
+ protected void SendNextPage(SettingsFormPage page)
+ {
+ NextPage?.Invoke(this, new PageEventArgs(page));
+ }
+
+ protected virtual SettingsFormPage CreateBackPage()
+ {
+ return null;
+ }
+
+ protected string GetSecureKey()
+ {
+ return Common.MyKey;
+ }
+
+ private void BackButton_Click(object sender, EventArgs e)
+ {
+ SendNextPage(CreateBackPage());
+ }
+
+ private void ButtonSkip_Click(object sender, EventArgs e)
+ {
+ if (MessageBox.Show(
+ "It is strongly recommended that you complete the setup first! Are you sure you want to skip these steps?",
+ Application.ProductName,
+ MessageBoxButtons.YesNo,
+ MessageBoxIcon.Warning,
+ MessageBoxDefaultButton.Button2) == DialogResult.Yes)
+ {
+ Setting.Values.FirstRun = false;
+ Common.CloseSetupForm();
+ Common.ShowMachineMatrix();
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsFormPage.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsFormPage.resx
new file mode 100644
index 000000000000..1af7de150c99
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsFormPage.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage.Designer.cs
new file mode 100644
index 000000000000..7363f062ee07
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage.Designer.cs
@@ -0,0 +1,136 @@
+namespace MouseWithoutBorders
+{
+ partial class SettingsPage
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.label1 = new System.Windows.Forms.Label();
+ this.panel2 = new System.Windows.Forms.Panel();
+ this.DoneButton = new MouseWithoutBorders.ImageButton();
+ this.CloseButton = new MouseWithoutBorders.ImageButton();
+ ((System.ComponentModel.ISupportInitialize)(this.DoneButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.CloseButton)).BeginInit();
+ this.SuspendLayout();
+ //
+ // panel1
+ //
+ this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel1.BackColor = System.Drawing.Color.White;
+ this.panel1.Location = new System.Drawing.Point(41, 343);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(370, 1);
+ this.panel1.TabIndex = 1;
+ //
+ // label1
+ //
+ this.label1.Font = new System.Drawing.Font(DefaultFont.Name, 30F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.ForeColor = System.Drawing.Color.White;
+ this.label1.Location = new System.Drawing.Point(61, 35);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(330, 52);
+ this.label1.TabIndex = 2;
+ this.label1.Text = "Settings";
+ this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // panel2
+ //
+ this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel2.BackColor = System.Drawing.Color.White;
+ this.panel2.Location = new System.Drawing.Point(41, 99);
+ this.panel2.Name = "panel2";
+ this.panel2.Size = new System.Drawing.Size(370, 1);
+ this.panel2.TabIndex = 2;
+ //
+ // DoneButton
+ //
+ this.DoneButton.BackColor = System.Drawing.Color.Transparent;
+ this.DoneButton.DisabledImage = null;
+ this.DoneButton.DownImage = global::MouseWithoutBorders.Properties.Resources.done_button_click;
+ this.DoneButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.done_button_hover;
+ this.DoneButton.Image = global::MouseWithoutBorders.Properties.Resources.done_button_normal;
+ this.DoneButton.InitialImage = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
+ this.DoneButton.Location = new System.Drawing.Point(199, 366);
+ this.DoneButton.Name = "DoneButton";
+ this.DoneButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.done_button_normal;
+ this.DoneButton.Size = new System.Drawing.Size(55, 55);
+ this.DoneButton.TabIndex = 8;
+ this.DoneButton.TabStop = false;
+ this.DoneButton.Visible = false;
+ this.DoneButton.Click += new System.EventHandler(this.DoneButtonClick);
+ //
+ // CloseButton
+ //
+ this.CloseButton.BackColor = System.Drawing.Color.Transparent;
+ this.CloseButton.DisabledImage = null;
+ this.CloseButton.DownImage = global::MouseWithoutBorders.Properties.Resources.close_button_click;
+ this.CloseButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.close_button_hover;
+ this.CloseButton.Image = global::MouseWithoutBorders.Properties.Resources.close_button_normal;
+ this.CloseButton.InitialImage = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
+ this.CloseButton.Location = new System.Drawing.Point(199, 366);
+ this.CloseButton.Name = "CloseButton";
+ this.CloseButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.close_button_normal;
+ this.CloseButton.Size = new System.Drawing.Size(55, 55);
+ this.CloseButton.TabIndex = 7;
+ this.CloseButton.TabStop = false;
+ this.CloseButton.Click += new System.EventHandler(this.CloseButtonClick);
+ //
+ // SettingsPage
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.panel2);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.DoneButton);
+ this.Controls.Add(this.CloseButton);
+ this.DoubleBuffered = true;
+ this.Name = "SettingsPage";
+ this.Size = new System.Drawing.Size(453, 438);
+ this.Controls.SetChildIndex(this.CloseButton, 0);
+ this.Controls.SetChildIndex(this.DoneButton, 0);
+ this.Controls.SetChildIndex(this.panel1, 0);
+ this.Controls.SetChildIndex(this.label1, 0);
+ this.Controls.SetChildIndex(this.panel2, 0);
+ ((System.ComponentModel.ISupportInitialize)(this.DoneButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.CloseButton)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Panel panel1;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Panel panel2;
+ private ImageButton CloseButton;
+ private ImageButton DoneButton;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage1.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage1.Designer.cs
new file mode 100644
index 000000000000..05f9920cd6ed
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage1.Designer.cs
@@ -0,0 +1,154 @@
+namespace MouseWithoutBorders
+{
+ partial class SettingsPage1
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label2 = new System.Windows.Forms.Label();
+ this.AddComputerButton = new MouseWithoutBorders.ImageButton();
+ this.KeyboardShortcutsButton = new MouseWithoutBorders.ImageButton();
+ this.AdvancedOptionsButton = new MouseWithoutBorders.ImageButton();
+ this.LinkComputerButton = new MouseWithoutBorders.ImageButton();
+ this.MachineMatrix = new MouseWithoutBorders.MachineMatrix();
+ ((System.ComponentModel.ISupportInitialize)(this.AddComputerButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.KeyboardShortcutsButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.AdvancedOptionsButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.LinkComputerButton)).BeginInit();
+ this.SuspendLayout();
+ //
+ // label2
+ //
+ this.label2.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label2.ForeColor = System.Drawing.Color.White;
+ this.label2.Location = new System.Drawing.Point(47, 106);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(310, 20);
+ this.label2.TabIndex = 4;
+ this.label2.Text = "DRAG COMPUTERS TO MATCH THEIR PHYSICAL LAYOUT";
+ //
+ // AddComputerButton
+ //
+ this.AddComputerButton.DisabledImage = null;
+ this.AddComputerButton.DownImage = global::MouseWithoutBorders.Properties.Resources.computer_button_click;
+ this.AddComputerButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.computer_button_hover;
+ this.AddComputerButton.Image = global::MouseWithoutBorders.Properties.Resources.computer_button_normal;
+ this.AddComputerButton.Location = new System.Drawing.Point(50, 317);
+ this.AddComputerButton.Name = "AddComputerButton";
+ this.AddComputerButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.computer_button_normal;
+ this.AddComputerButton.Size = new System.Drawing.Size(74, 23);
+ this.AddComputerButton.TabIndex = 9;
+ this.AddComputerButton.TabStop = false;
+ this.AddComputerButton.Click += new System.EventHandler(this.AddComputerButtonClick);
+ //
+ // KeyboardShortcutsButton
+ //
+ this.KeyboardShortcutsButton.DisabledImage = null;
+ this.KeyboardShortcutsButton.DownImage = global::MouseWithoutBorders.Properties.Resources.keyboard_button_click;
+ this.KeyboardShortcutsButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.keyboard_button_hover;
+ this.KeyboardShortcutsButton.Image = global::MouseWithoutBorders.Properties.Resources.keyboard_button_normal;
+ this.KeyboardShortcutsButton.Location = new System.Drawing.Point(327, 317);
+ this.KeyboardShortcutsButton.Name = "KeyboardShortcutsButton";
+ this.KeyboardShortcutsButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.keyboard_button_normal;
+ this.KeyboardShortcutsButton.Size = new System.Drawing.Size(84, 23);
+ this.KeyboardShortcutsButton.TabIndex = 11;
+ this.KeyboardShortcutsButton.TabStop = false;
+ this.KeyboardShortcutsButton.Click += new System.EventHandler(this.KeyboardShortcutsButtonClick);
+ //
+ // AdvancedOptionsButton
+ //
+ this.AdvancedOptionsButton.DisabledImage = null;
+ this.AdvancedOptionsButton.DownImage = global::MouseWithoutBorders.Properties.Resources.advanced_button_click;
+ this.AdvancedOptionsButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.advanced_button_hover;
+ this.AdvancedOptionsButton.Image = global::MouseWithoutBorders.Properties.Resources.advanced_button_normal;
+ this.AdvancedOptionsButton.Location = new System.Drawing.Point(244, 317);
+ this.AdvancedOptionsButton.Name = "AdvancedOptionsButton";
+ this.AdvancedOptionsButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.advanced_button_normal;
+ this.AdvancedOptionsButton.Size = new System.Drawing.Size(74, 23);
+ this.AdvancedOptionsButton.TabIndex = 12;
+ this.AdvancedOptionsButton.TabStop = false;
+ this.AdvancedOptionsButton.Click += new System.EventHandler(this.AdvancedOptionsButtonClick);
+ //
+ // LinkComputerButton
+ //
+ this.LinkComputerButton.DisabledImage = null;
+ this.LinkComputerButton.DownImage = global::MouseWithoutBorders.Properties.Resources.small_link_button_click;
+ this.LinkComputerButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.small_link_button_hover;
+ this.LinkComputerButton.Image = global::MouseWithoutBorders.Properties.Resources.small_link_button_normal;
+ this.LinkComputerButton.Location = new System.Drawing.Point(133, 317);
+ this.LinkComputerButton.Name = "LinkComputerButton";
+ this.LinkComputerButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.small_link_button_normal;
+ this.LinkComputerButton.Size = new System.Drawing.Size(74, 23);
+ this.LinkComputerButton.TabIndex = 13;
+ this.LinkComputerButton.TabStop = false;
+ this.LinkComputerButton.Click += new System.EventHandler(this.LinkComputersButtonClick);
+ //
+ // machineMatrix1
+ //
+ this.MachineMatrix.BackColor = System.Drawing.Color.Transparent;
+ this.MachineMatrix.Location = new System.Drawing.Point(50, 121);
+ this.MachineMatrix.Name = "MachineMatrix";
+ this.MachineMatrix.Size = new System.Drawing.Size(360, 195);
+ this.MachineMatrix.TabIndex = 14;
+ this.MachineMatrix.TwoRows = false;
+ //
+ // SettingsPage1
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.MachineMatrix);
+ this.Controls.Add(this.LinkComputerButton);
+ this.Controls.Add(this.AdvancedOptionsButton);
+ this.Controls.Add(this.KeyboardShortcutsButton);
+ this.Controls.Add(this.AddComputerButton);
+ this.Controls.Add(this.label2);
+ this.Name = "SettingsPage1";
+ this.Controls.SetChildIndex(this.label2, 0);
+ this.Controls.SetChildIndex(this.AddComputerButton, 0);
+ this.Controls.SetChildIndex(this.KeyboardShortcutsButton, 0);
+ this.Controls.SetChildIndex(this.AdvancedOptionsButton, 0);
+ this.Controls.SetChildIndex(this.LinkComputerButton, 0);
+ this.Controls.SetChildIndex(this.MachineMatrix, 0);
+ ((System.ComponentModel.ISupportInitialize)(this.AddComputerButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.KeyboardShortcutsButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.AdvancedOptionsButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.LinkComputerButton)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label2;
+ private ImageButton AddComputerButton;
+ private ImageButton KeyboardShortcutsButton;
+ private ImageButton AdvancedOptionsButton;
+ private ImageButton LinkComputerButton;
+ private MachineMatrix MachineMatrix;
+
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage1.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage1.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage1.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage2.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage2.Designer.cs
new file mode 100644
index 000000000000..84111991d4ae
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage2.Designer.cs
@@ -0,0 +1,123 @@
+namespace MouseWithoutBorders
+{
+ partial class SettingsPage2
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label2 = new System.Windows.Forms.Label();
+ this.label4 = new System.Windows.Forms.Label();
+ this.MachineNameLabel = new System.Windows.Forms.Label();
+ this.label6 = new System.Windows.Forms.Label();
+ this.SecurityKeyLabel = new System.Windows.Forms.Label();
+ this.SuspendLayout();
+ //
+ // label2
+ //
+ this.label2.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label2.ForeColor = System.Drawing.Color.White;
+ this.label2.Location = new System.Drawing.Point(47, 112);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(310, 75);
+ this.label2.TabIndex = 9;
+ this.label2.Text = "You know the drill! Just keep this window open or write down the information below, then head over to your" +
+ " other computer and install Mouse w/o Borders. You can finish the setup and conf" +
+ "iguration over there.";
+ //
+ // label4
+ //
+ this.label4.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.label4.Location = new System.Drawing.Point(73, 267);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(310, 15);
+ this.label4.TabIndex = 13;
+ this.label4.Text = "THIS COMPUTER\'S NAME";
+ this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // MachineNameLabel
+ //
+ this.MachineNameLabel.Font = new System.Drawing.Font(DefaultFont.Name, 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.MachineNameLabel.ForeColor = System.Drawing.Color.White;
+ this.MachineNameLabel.Location = new System.Drawing.Point(50, 279);
+ this.MachineNameLabel.Name = "MachineNameLabel";
+ this.MachineNameLabel.Size = new System.Drawing.Size(340, 61);
+ this.MachineNameLabel.TabIndex = 12;
+ this.MachineNameLabel.Text = "Alan - Desktop";
+ this.MachineNameLabel.TextAlign = System.Drawing.ContentAlignment.TopCenter;
+ //
+ // label6
+ //
+ this.label6.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label6.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.label6.Location = new System.Drawing.Point(73, 208);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(310, 15);
+ this.label6.TabIndex = 11;
+ this.label6.Text = "SECURITY CODE";
+ this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // SecurityKeyLabel
+ //
+ this.SecurityKeyLabel.Font = new System.Drawing.Font(DefaultFont.Name, 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.SecurityKeyLabel.ForeColor = System.Drawing.Color.White;
+ this.SecurityKeyLabel.Location = new System.Drawing.Point(70, 216);
+ this.SecurityKeyLabel.Name = "SecurityKeyLabel";
+ this.SecurityKeyLabel.Size = new System.Drawing.Size(310, 40);
+ this.SecurityKeyLabel.TabIndex = 10;
+ this.SecurityKeyLabel.Text = "SX1q04Wr";
+ this.SecurityKeyLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // SettingsPage2
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.MachineNameLabel);
+ this.Controls.Add(this.label6);
+ this.Controls.Add(this.SecurityKeyLabel);
+ this.Controls.Add(this.label2);
+ this.Name = "SettingsPage2";
+ this.Controls.SetChildIndex(this.label2, 0);
+ this.Controls.SetChildIndex(this.SecurityKeyLabel, 0);
+ this.Controls.SetChildIndex(this.label6, 0);
+ this.Controls.SetChildIndex(this.MachineNameLabel, 0);
+ this.Controls.SetChildIndex(this.label4, 0);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Label MachineNameLabel;
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.Label SecurityKeyLabel;
+
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage2.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage2.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage2.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage3.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage3.Designer.cs
new file mode 100644
index 000000000000..522012f388ee
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage3.Designer.cs
@@ -0,0 +1,233 @@
+namespace MouseWithoutBorders
+{
+ partial class SettingsPage3
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label6 = new System.Windows.Forms.Label();
+ this.EditLink = new System.Windows.Forms.LinkLabel();
+ this.ShareClipboardCheckbox = new MouseWithoutBorders.ImageCheckButton();
+ this.HideOnLoginCheckbox = new MouseWithoutBorders.ImageCheckButton();
+ this.EnableEasyMouseCheckbox = new MouseWithoutBorders.ImageCheckButton();
+ this.WrapMouseCheckbox = new MouseWithoutBorders.ImageCheckButton();
+ this.DisableCADCheckbox = new MouseWithoutBorders.ImageCheckButton();
+ this.BlockScreenSaverCheckbox = new MouseWithoutBorders.ImageCheckButton();
+ this.label3 = new System.Windows.Forms.Label();
+ this.SecurityCodeLabel = new System.Windows.Forms.Label();
+ this.SuspendLayout();
+ //
+ // label6
+ //
+ this.label6.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label6.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.label6.Location = new System.Drawing.Point(51, 119);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(350, 15);
+ this.label6.TabIndex = 12;
+ this.label6.Tag = " ";
+ this.label6.Text = "ADVANCED OPTIONS";
+ this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // EditLink
+ //
+ this.EditLink.AutoSize = true;
+ this.EditLink.LinkColor = System.Drawing.Color.White;
+ this.EditLink.Location = new System.Drawing.Point(202, 146);
+ this.EditLink.Name = "EditLink";
+ this.EditLink.Size = new System.Drawing.Size(104, 13);
+ this.EditLink.TabIndex = 15;
+ this.EditLink.TabStop = true;
+ this.EditLink.Text = "Generate New Code";
+ this.EditLink.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.EditLink_LinkClicked);
+ //
+ // ShareClipboardCheckbox
+ //
+ this.ShareClipboardCheckbox.AutoSize = true;
+ this.ShareClipboardCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
+ this.ShareClipboardCheckbox.DisabledImage = null;
+ this.ShareClipboardCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F);
+ this.ShareClipboardCheckbox.Location = new System.Drawing.Point(54, 188);
+ this.ShareClipboardCheckbox.MixedImage = null;
+ this.ShareClipboardCheckbox.Name = "ShareClipboardCheckbox";
+ this.ShareClipboardCheckbox.Size = new System.Drawing.Size(128, 34);
+ this.ShareClipboardCheckbox.TabIndex = 16;
+ this.ShareClipboardCheckbox.Text = "Share Clipboard (Text \r\nand Image)";
+ this.ShareClipboardCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
+ this.ShareClipboardCheckbox.UseVisualStyleBackColor = true;
+ this.ShareClipboardCheckbox.CheckedChanged += new System.EventHandler(this.ShareClipboardCheckbox_CheckedChanged);
+ //
+ // HideOnLoginCheckbox
+ //
+ this.HideOnLoginCheckbox.AutoSize = true;
+ this.HideOnLoginCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
+ this.HideOnLoginCheckbox.DisabledImage = null;
+ this.HideOnLoginCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F);
+ this.HideOnLoginCheckbox.Location = new System.Drawing.Point(54, 238);
+ this.HideOnLoginCheckbox.MixedImage = null;
+ this.HideOnLoginCheckbox.Name = "HideOnLoginCheckbox";
+ this.HideOnLoginCheckbox.Size = new System.Drawing.Size(143, 34);
+ this.HideOnLoginCheckbox.TabIndex = 17;
+ this.HideOnLoginCheckbox.Text = "Hide Mouse w/o Borders \r\non the Login Desktop";
+ this.HideOnLoginCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
+ this.HideOnLoginCheckbox.UseVisualStyleBackColor = true;
+ this.HideOnLoginCheckbox.CheckedChanged += new System.EventHandler(this.HideOnLoginCheckbox_CheckedChanged);
+ //
+ // EnableEasyMouseCheckbox
+ //
+ this.EnableEasyMouseCheckbox.AutoSize = true;
+ this.EnableEasyMouseCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
+ this.EnableEasyMouseCheckbox.DisabledImage = null;
+ this.EnableEasyMouseCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F);
+ this.EnableEasyMouseCheckbox.Location = new System.Drawing.Point(54, 288);
+ this.EnableEasyMouseCheckbox.MixedImage = null;
+ this.EnableEasyMouseCheckbox.Name = "EnableEasyMouseCheckbox";
+ this.EnableEasyMouseCheckbox.Size = new System.Drawing.Size(114, 19);
+ this.EnableEasyMouseCheckbox.TabIndex = 18;
+ this.EnableEasyMouseCheckbox.Text = "Enable Easy Mouse";
+ this.EnableEasyMouseCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
+ this.EnableEasyMouseCheckbox.UseVisualStyleBackColor = true;
+ this.EnableEasyMouseCheckbox.CheckedChanged += new System.EventHandler(this.EnableEasyMouseCheckbox_CheckedChanged);
+ //
+ // WrapMouseCheckbox
+ //
+ this.WrapMouseCheckbox.AutoSize = true;
+ this.WrapMouseCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
+ this.WrapMouseCheckbox.DisabledImage = null;
+ this.WrapMouseCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.WrapMouseCheckbox.Location = new System.Drawing.Point(238, 288);
+ this.WrapMouseCheckbox.MixedImage = null;
+ this.WrapMouseCheckbox.Name = "WrapMouseCheckbox";
+ this.WrapMouseCheckbox.Size = new System.Drawing.Size(85, 19);
+ this.WrapMouseCheckbox.TabIndex = 19;
+ this.WrapMouseCheckbox.Text = "Wrap Mouse";
+ this.WrapMouseCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
+ this.WrapMouseCheckbox.UseVisualStyleBackColor = true;
+ this.WrapMouseCheckbox.CheckedChanged += new System.EventHandler(this.WrapMouseCheckbox_CheckedChanged);
+ //
+ // DisableCADCheckbox
+ //
+ this.DisableCADCheckbox.AutoSize = true;
+ this.DisableCADCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
+ this.DisableCADCheckbox.DisabledImage = null;
+ this.DisableCADCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F);
+ this.DisableCADCheckbox.Location = new System.Drawing.Point(238, 188);
+ this.DisableCADCheckbox.MixedImage = null;
+ this.DisableCADCheckbox.Name = "DisableCADCheckbox";
+ this.DisableCADCheckbox.Size = new System.Drawing.Size(154, 34);
+ this.DisableCADCheckbox.TabIndex = 20;
+ this.DisableCADCheckbox.Text = "Disable Ctrl+Alt+Del on the \r\nLogin Screen";
+ this.DisableCADCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
+ this.DisableCADCheckbox.UseVisualStyleBackColor = true;
+ this.DisableCADCheckbox.CheckedChanged += new System.EventHandler(this.DisableCADCheckbox_CheckedChanged);
+ //
+ // BlockScreenSaverCheckbox
+ //
+ this.BlockScreenSaverCheckbox.AutoSize = true;
+ this.BlockScreenSaverCheckbox.CheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_checked;
+ this.BlockScreenSaverCheckbox.DisabledImage = null;
+ this.BlockScreenSaverCheckbox.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F);
+ this.BlockScreenSaverCheckbox.Location = new System.Drawing.Point(238, 238);
+ this.BlockScreenSaverCheckbox.MixedImage = null;
+ this.BlockScreenSaverCheckbox.Name = "BlockScreenSaverCheckbox";
+ this.BlockScreenSaverCheckbox.Size = new System.Drawing.Size(158, 34);
+ this.BlockScreenSaverCheckbox.TabIndex = 21;
+ this.BlockScreenSaverCheckbox.Text = "Block Screen Saver on Other\r\nMachines";
+ this.BlockScreenSaverCheckbox.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.checkbox_unchecked;
+ this.BlockScreenSaverCheckbox.UseVisualStyleBackColor = true;
+ this.BlockScreenSaverCheckbox.CheckedChanged += new System.EventHandler(this.BlockScreenSaverCheckbox_CheckedChanged);
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.BackColor = System.Drawing.Color.Transparent;
+ this.label3.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label3.ForeColor = System.Drawing.Color.White;
+ this.label3.Location = new System.Drawing.Point(51, 144);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(79, 16);
+ this.label3.TabIndex = 13;
+ this.label3.Text = "Security Code:";
+ //
+ // SecurityCodeLabel
+ //
+ this.SecurityCodeLabel.AutoSize = true;
+ this.SecurityCodeLabel.BackColor = System.Drawing.Color.Transparent;
+ this.SecurityCodeLabel.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.SecurityCodeLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.SecurityCodeLabel.Location = new System.Drawing.Point(134, 144);
+ this.SecurityCodeLabel.Name = "SecurityCodeLabel";
+ this.SecurityCodeLabel.Size = new System.Drawing.Size(67, 16);
+ this.SecurityCodeLabel.TabIndex = 14;
+ this.SecurityCodeLabel.Text = "SX1q04Wr";
+ //
+ // SettingsPage3
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.BlockScreenSaverCheckbox);
+ this.Controls.Add(this.DisableCADCheckbox);
+ this.Controls.Add(this.WrapMouseCheckbox);
+ this.Controls.Add(this.EnableEasyMouseCheckbox);
+ this.Controls.Add(this.HideOnLoginCheckbox);
+ this.Controls.Add(this.ShareClipboardCheckbox);
+ this.Controls.Add(this.EditLink);
+ this.Controls.Add(this.SecurityCodeLabel);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.label6);
+ this.Name = "SettingsPage3";
+ this.Controls.SetChildIndex(this.label6, 0);
+ this.Controls.SetChildIndex(this.label3, 0);
+ this.Controls.SetChildIndex(this.SecurityCodeLabel, 0);
+ this.Controls.SetChildIndex(this.EditLink, 0);
+ this.Controls.SetChildIndex(this.ShareClipboardCheckbox, 0);
+ this.Controls.SetChildIndex(this.HideOnLoginCheckbox, 0);
+ this.Controls.SetChildIndex(this.EnableEasyMouseCheckbox, 0);
+ this.Controls.SetChildIndex(this.WrapMouseCheckbox, 0);
+ this.Controls.SetChildIndex(this.DisableCADCheckbox, 0);
+ this.Controls.SetChildIndex(this.BlockScreenSaverCheckbox, 0);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.LinkLabel EditLink;
+ private ImageCheckButton ShareClipboardCheckbox;
+ private ImageCheckButton HideOnLoginCheckbox;
+ private ImageCheckButton EnableEasyMouseCheckbox;
+ private ImageCheckButton WrapMouseCheckbox;
+ private ImageCheckButton DisableCADCheckbox;
+ private ImageCheckButton BlockScreenSaverCheckbox;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.Label SecurityCodeLabel;
+
+
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage3.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage3.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage3.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage4.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage4.Designer.cs
new file mode 100644
index 000000000000..045f1f53f44b
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage4.Designer.cs
@@ -0,0 +1,697 @@
+namespace MouseWithoutBorders
+{
+ partial class SettingsPage4
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label6 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.label3 = new System.Windows.Forms.Label();
+ this.label4 = new System.Windows.Forms.Label();
+ this.label5 = new System.Windows.Forms.Label();
+ this.label7 = new System.Windows.Forms.Label();
+ this.label8 = new System.Windows.Forms.Label();
+ this.label9 = new System.Windows.Forms.Label();
+ this.label10 = new System.Windows.Forms.Label();
+ this.label11 = new System.Windows.Forms.Label();
+ this.label12 = new System.Windows.Forms.Label();
+ this.label13 = new System.Windows.Forms.Label();
+ this.AllPcLabel = new System.Windows.Forms.Label();
+ this.DisabledRadioButton = new MouseWithoutBorders.ImageRadioButton();
+ this.NumbersRadioButton = new MouseWithoutBorders.ImageRadioButton();
+ this.FKeysRadioButton = new MouseWithoutBorders.ImageRadioButton();
+ this.ShowSettingsComboBox = new System.Windows.Forms.ComboBox();
+ this.LockComboBox = new System.Windows.Forms.ComboBox();
+ this.ReconnectComboBox = new System.Windows.Forms.ComboBox();
+ this.ExitComboBox = new System.Windows.Forms.ComboBox();
+ this.AllPcComboBox = new System.Windows.Forms.ComboBox();
+ this.panel3 = new System.Windows.Forms.Panel();
+ this.panel3.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // label6
+ //
+ this.label6.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label6.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.label6.Location = new System.Drawing.Point(51, 119);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(310, 15);
+ this.label6.TabIndex = 12;
+ this.label6.Tag = " ";
+ this.label6.Text = "KEYBOARD SHORTCUTS";
+ this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.BackColor = System.Drawing.Color.Transparent;
+ this.label2.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label2.ForeColor = System.Drawing.Color.White;
+ this.label2.Location = new System.Drawing.Point(51, 147);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(134, 16);
+ this.label2.TabIndex = 14;
+ this.label2.Text = "Switch between machines";
+ //
+ // label3
+ //
+ this.label3.AutoSize = true;
+ this.label3.BackColor = System.Drawing.Color.Transparent;
+ this.label3.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label3.ForeColor = System.Drawing.Color.White;
+ this.label3.Location = new System.Drawing.Point(51, 215);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(78, 16);
+ this.label3.TabIndex = 15;
+ this.label3.Text = "Show Settings";
+ //
+ // label4
+ //
+ this.label4.AutoSize = true;
+ this.label4.BackColor = System.Drawing.Color.Transparent;
+ this.label4.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label4.ForeColor = System.Drawing.Color.White;
+ this.label4.Location = new System.Drawing.Point(51, 239);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(147, 16);
+ this.label4.TabIndex = 16;
+ this.label4.Text = "Lock the controlled machine";
+ //
+ // label5
+ //
+ this.label5.AutoSize = true;
+ this.label5.BackColor = System.Drawing.Color.Transparent;
+ this.label5.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label5.ForeColor = System.Drawing.Color.White;
+ this.label5.Location = new System.Drawing.Point(51, 263);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(153, 16);
+ this.label5.TabIndex = 17;
+ this.label5.Text = "Reconnect to other machines";
+ //
+ // label7
+ //
+ this.label7.AutoSize = true;
+ this.label7.BackColor = System.Drawing.Color.Transparent;
+ this.label7.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label7.ForeColor = System.Drawing.Color.White;
+ this.label7.Location = new System.Drawing.Point(51, 287);
+ this.label7.Name = "label7";
+ this.label7.Size = new System.Drawing.Size(127, 16);
+ this.label7.TabIndex = 18;
+ this.label7.Text = "Exit Mouse w/o Borders";
+ //
+ // label8
+ //
+ this.label8.AutoSize = true;
+ this.label8.BackColor = System.Drawing.Color.Transparent;
+ this.label8.Font = new System.Drawing.Font(DefaultFont.Name, 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label8.ForeColor = System.Drawing.Color.White;
+ this.label8.Location = new System.Drawing.Point(51, 311);
+ this.label8.Name = "label8";
+ this.label8.Size = new System.Drawing.Size(131, 16);
+ this.label8.TabIndex = 19;
+ this.label8.Text = "Switch to ALL PC mode";
+ //
+ // label9
+ //
+ this.label9.AutoSize = true;
+ this.label9.BackColor = System.Drawing.Color.Transparent;
+ this.label9.Font = new System.Drawing.Font(DefaultFont.Name, 9F);
+ this.label9.ForeColor = System.Drawing.Color.White;
+ this.label9.Location = new System.Drawing.Point(238, 147);
+ this.label9.Name = "label9";
+ this.label9.Size = new System.Drawing.Size(66, 16);
+ this.label9.TabIndex = 20;
+ this.label9.Text = "Ctrl + Alt +";
+ //
+ // label10
+ //
+ this.label10.AutoSize = true;
+ this.label10.BackColor = System.Drawing.Color.Transparent;
+ this.label10.Font = new System.Drawing.Font(DefaultFont.Name, 9F);
+ this.label10.ForeColor = System.Drawing.Color.White;
+ this.label10.Location = new System.Drawing.Point(238, 215);
+ this.label10.Name = "label10";
+ this.label10.Size = new System.Drawing.Size(66, 16);
+ this.label10.TabIndex = 21;
+ this.label10.Text = "Ctrl + Alt +";
+ //
+ // label11
+ //
+ this.label11.AutoSize = true;
+ this.label11.BackColor = System.Drawing.Color.Transparent;
+ this.label11.Font = new System.Drawing.Font(DefaultFont.Name, 9F);
+ this.label11.ForeColor = System.Drawing.Color.White;
+ this.label11.Location = new System.Drawing.Point(238, 239);
+ this.label11.Name = "label11";
+ this.label11.Size = new System.Drawing.Size(66, 16);
+ this.label11.TabIndex = 22;
+ this.label11.Text = "Ctrl + Alt +";
+ //
+ // label12
+ //
+ this.label12.AutoSize = true;
+ this.label12.BackColor = System.Drawing.Color.Transparent;
+ this.label12.Font = new System.Drawing.Font(DefaultFont.Name, 9F);
+ this.label12.ForeColor = System.Drawing.Color.White;
+ this.label12.Location = new System.Drawing.Point(238, 263);
+ this.label12.Name = "label12";
+ this.label12.Size = new System.Drawing.Size(66, 16);
+ this.label12.TabIndex = 23;
+ this.label12.Text = "Ctrl + Alt +";
+ //
+ // label13
+ //
+ this.label13.AutoSize = true;
+ this.label13.BackColor = System.Drawing.Color.Transparent;
+ this.label13.Font = new System.Drawing.Font(DefaultFont.Name, 9F);
+ this.label13.ForeColor = System.Drawing.Color.White;
+ this.label13.Location = new System.Drawing.Point(200, 287);
+ this.label13.Name = "label13";
+ this.label13.Size = new System.Drawing.Size(104, 16);
+ this.label13.TabIndex = 24;
+ this.label13.Text = "Ctrl + Alt + Shift +";
+ //
+ // AllPcLabel
+ //
+ this.AllPcLabel.AutoSize = true;
+ this.AllPcLabel.BackColor = System.Drawing.Color.Transparent;
+ this.AllPcLabel.Font = new System.Drawing.Font(DefaultFont.Name, 9F);
+ this.AllPcLabel.ForeColor = System.Drawing.Color.White;
+ this.AllPcLabel.Location = new System.Drawing.Point(238, 311);
+ this.AllPcLabel.Name = "AllPcLabel";
+ this.AllPcLabel.Size = new System.Drawing.Size(66, 16);
+ this.AllPcLabel.TabIndex = 25;
+ this.AllPcLabel.Text = "Ctrl + Alt +";
+ //
+ // DisabledRadioButton
+ //
+ this.DisabledRadioButton.AutoSize = true;
+ this.DisabledRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_checked;
+ this.DisabledRadioButton.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.DisabledRadioButton.ForeColor = System.Drawing.Color.White;
+ this.DisabledRadioButton.ImageLocation = new System.Drawing.Point(0, 3);
+ this.DisabledRadioButton.Location = new System.Drawing.Point(4, 39);
+ this.DisabledRadioButton.Name = "DisabledRadioButton";
+ this.DisabledRadioButton.Size = new System.Drawing.Size(67, 19);
+ this.DisabledRadioButton.TabIndex = 2;
+ this.DisabledRadioButton.Text = "Disabled";
+ this.DisabledRadioButton.TextLocation = new System.Drawing.Point(14, 0);
+ this.DisabledRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_unchecked;
+ this.DisabledRadioButton.UseVisualStyleBackColor = true;
+ this.DisabledRadioButton.CheckedChanged += new System.EventHandler(this.DisabledRadioButton_CheckedChanged);
+ //
+ // NumbersRadioButton
+ //
+ this.NumbersRadioButton.AutoSize = true;
+ this.NumbersRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_checked;
+ this.NumbersRadioButton.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.NumbersRadioButton.ForeColor = System.Drawing.Color.White;
+ this.NumbersRadioButton.ImageLocation = new System.Drawing.Point(0, 3);
+ this.NumbersRadioButton.Location = new System.Drawing.Point(4, 21);
+ this.NumbersRadioButton.Name = "NumbersRadioButton";
+ this.NumbersRadioButton.Size = new System.Drawing.Size(64, 19);
+ this.NumbersRadioButton.TabIndex = 1;
+ this.NumbersRadioButton.Text = "1, 2, 3, 4";
+ this.NumbersRadioButton.TextLocation = new System.Drawing.Point(14, 0);
+ this.NumbersRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_unchecked;
+ this.NumbersRadioButton.UseVisualStyleBackColor = true;
+ this.NumbersRadioButton.CheckedChanged += new System.EventHandler(this.NumbersRadioButton_CheckedChanged);
+ //
+ // FKeysRadioButton
+ //
+ this.FKeysRadioButton.AutoSize = true;
+ this.FKeysRadioButton.CheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_checked;
+ this.FKeysRadioButton.Font = new System.Drawing.Font(DefaultFont.Name, 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.FKeysRadioButton.ForeColor = System.Drawing.Color.White;
+ this.FKeysRadioButton.ImageLocation = new System.Drawing.Point(0, 3);
+ this.FKeysRadioButton.Location = new System.Drawing.Point(4, 4);
+ this.FKeysRadioButton.Name = "FKeysRadioButton";
+ this.FKeysRadioButton.Size = new System.Drawing.Size(84, 19);
+ this.FKeysRadioButton.TabIndex = 0;
+ this.FKeysRadioButton.Text = "F1, F2, F3, F4";
+ this.FKeysRadioButton.TextLocation = new System.Drawing.Point(14, 0);
+ this.FKeysRadioButton.UncheckedImage = global::MouseWithoutBorders.Properties.Resources.radio_button_unchecked;
+ this.FKeysRadioButton.UseVisualStyleBackColor = true;
+ this.FKeysRadioButton.CheckedChanged += new System.EventHandler(this.FKeysRadioButton_CheckedChanged);
+ //
+ // ShowSettingsComboBox
+ //
+ this.ShowSettingsComboBox.AutoCompleteCustomSource.AddRange(new string[] {
+ "Disabled",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z"});
+ this.ShowSettingsComboBox.DisplayMember = "M";
+ this.ShowSettingsComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.ShowSettingsComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
+ this.ShowSettingsComboBox.FormattingEnabled = true;
+ this.ShowSettingsComboBox.Items.AddRange(new object[] {
+ "Disabled",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z"});
+ this.ShowSettingsComboBox.Location = new System.Drawing.Point(310, 214);
+ this.ShowSettingsComboBox.MaxDropDownItems = 27;
+ this.ShowSettingsComboBox.Name = "ShowSettingsComboBox";
+ this.ShowSettingsComboBox.Size = new System.Drawing.Size(88, 21);
+ this.ShowSettingsComboBox.TabIndex = 27;
+ this.ShowSettingsComboBox.SelectedIndexChanged += new System.EventHandler(this.ShowSettingsComboBox_SelectedIndexChanged);
+ //
+ // LockComboBox
+ //
+ this.LockComboBox.AutoCompleteCustomSource.AddRange(new string[] {
+ "Disabled",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z"});
+ this.LockComboBox.DisplayMember = "M";
+ this.LockComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.LockComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.LockComboBox.FormattingEnabled = true;
+ this.LockComboBox.Items.AddRange(new object[] {
+ "Disabled",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z"});
+ this.LockComboBox.Location = new System.Drawing.Point(310, 238);
+ this.LockComboBox.MaxDropDownItems = 27;
+ this.LockComboBox.Name = "LockComboBox";
+ this.LockComboBox.Size = new System.Drawing.Size(88, 21);
+ this.LockComboBox.TabIndex = 28;
+ this.LockComboBox.SelectedIndexChanged += new System.EventHandler(this.LockComboBox_SelectedIndexChanged);
+ //
+ // ReconnectComboBox
+ //
+ this.ReconnectComboBox.AutoCompleteCustomSource.AddRange(new string[] {
+ "Disabled",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z"});
+ this.ReconnectComboBox.DisplayMember = "M";
+ this.ReconnectComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.ReconnectComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.ReconnectComboBox.FormattingEnabled = true;
+ this.ReconnectComboBox.Items.AddRange(new object[] {
+ "Disabled",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z"});
+ this.ReconnectComboBox.Location = new System.Drawing.Point(310, 262);
+ this.ReconnectComboBox.MaxDropDownItems = 27;
+ this.ReconnectComboBox.Name = "ReconnectComboBox";
+ this.ReconnectComboBox.Size = new System.Drawing.Size(88, 21);
+ this.ReconnectComboBox.TabIndex = 29;
+ this.ReconnectComboBox.SelectedIndexChanged += new System.EventHandler(this.ReconnectComboBox_SelectedIndexChanged);
+ //
+ // ExitComboBox
+ //
+ this.ExitComboBox.AutoCompleteCustomSource.AddRange(new string[] {
+ "Disabled",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z"});
+ this.ExitComboBox.DisplayMember = "M";
+ this.ExitComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.ExitComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.ExitComboBox.FormattingEnabled = true;
+ this.ExitComboBox.Items.AddRange(new object[] {
+ "Disabled",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z"});
+ this.ExitComboBox.Location = new System.Drawing.Point(310, 286);
+ this.ExitComboBox.MaxDropDownItems = 27;
+ this.ExitComboBox.Name = "ExitComboBox";
+ this.ExitComboBox.Size = new System.Drawing.Size(88, 21);
+ this.ExitComboBox.TabIndex = 30;
+ this.ExitComboBox.SelectedIndexChanged += new System.EventHandler(this.ExitComboBox_SelectedIndexChanged);
+ //
+ // AllPcComboBox
+ //
+ this.AllPcComboBox.AutoCompleteCustomSource.AddRange(new string[] {
+ "Disabled",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z"});
+ this.AllPcComboBox.DisplayMember = "M";
+ this.AllPcComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.AllPcComboBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+ this.AllPcComboBox.FormattingEnabled = true;
+ this.AllPcComboBox.Items.AddRange(new object[] {
+ "Ctrl x 3",
+ "Disabled",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z"});
+ this.AllPcComboBox.Location = new System.Drawing.Point(310, 310);
+ this.AllPcComboBox.MaxDropDownItems = 27;
+ this.AllPcComboBox.Name = "AllPcComboBox";
+ this.AllPcComboBox.Size = new System.Drawing.Size(88, 21);
+ this.AllPcComboBox.TabIndex = 31;
+ this.AllPcComboBox.SelectedIndexChanged += new System.EventHandler(this.AllPcComboBox_SelectedIndexChanged);
+ //
+ // panel3
+ //
+ this.panel3.Controls.Add(this.DisabledRadioButton);
+ this.panel3.Controls.Add(this.NumbersRadioButton);
+ this.panel3.Controls.Add(this.FKeysRadioButton);
+ this.panel3.Location = new System.Drawing.Point(310, 144);
+ this.panel3.Name = "panel3";
+ this.panel3.Size = new System.Drawing.Size(88, 64);
+ this.panel3.TabIndex = 26;
+ //
+ // SettingsPage4
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.AllPcComboBox);
+ this.Controls.Add(this.ExitComboBox);
+ this.Controls.Add(this.ReconnectComboBox);
+ this.Controls.Add(this.LockComboBox);
+ this.Controls.Add(this.ShowSettingsComboBox);
+ this.Controls.Add(this.panel3);
+ this.Controls.Add(this.AllPcLabel);
+ this.Controls.Add(this.label13);
+ this.Controls.Add(this.label12);
+ this.Controls.Add(this.label11);
+ this.Controls.Add(this.label10);
+ this.Controls.Add(this.label9);
+ this.Controls.Add(this.label8);
+ this.Controls.Add(this.label7);
+ this.Controls.Add(this.label5);
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.label6);
+ this.Name = "SettingsPage4";
+ this.Controls.SetChildIndex(this.label6, 0);
+ this.Controls.SetChildIndex(this.label2, 0);
+ this.Controls.SetChildIndex(this.label3, 0);
+ this.Controls.SetChildIndex(this.label4, 0);
+ this.Controls.SetChildIndex(this.label5, 0);
+ this.Controls.SetChildIndex(this.label7, 0);
+ this.Controls.SetChildIndex(this.label8, 0);
+ this.Controls.SetChildIndex(this.label9, 0);
+ this.Controls.SetChildIndex(this.label10, 0);
+ this.Controls.SetChildIndex(this.label11, 0);
+ this.Controls.SetChildIndex(this.label12, 0);
+ this.Controls.SetChildIndex(this.label13, 0);
+ this.Controls.SetChildIndex(this.AllPcLabel, 0);
+ this.Controls.SetChildIndex(this.panel3, 0);
+ this.Controls.SetChildIndex(this.ShowSettingsComboBox, 0);
+ this.Controls.SetChildIndex(this.LockComboBox, 0);
+ this.Controls.SetChildIndex(this.ReconnectComboBox, 0);
+ this.Controls.SetChildIndex(this.ExitComboBox, 0);
+ this.Controls.SetChildIndex(this.AllPcComboBox, 0);
+ this.panel3.ResumeLayout(false);
+ this.panel3.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.Label label7;
+ private System.Windows.Forms.Label label8;
+ private System.Windows.Forms.Label label9;
+ private System.Windows.Forms.Label label10;
+ private System.Windows.Forms.Label label11;
+ private System.Windows.Forms.Label label12;
+ private System.Windows.Forms.Label label13;
+ private System.Windows.Forms.Label AllPcLabel;
+ private ImageRadioButton FKeysRadioButton;
+ private ImageRadioButton DisabledRadioButton;
+ private ImageRadioButton NumbersRadioButton;
+ private System.Windows.Forms.ComboBox ShowSettingsComboBox;
+ private System.Windows.Forms.ComboBox LockComboBox;
+ private System.Windows.Forms.ComboBox ReconnectComboBox;
+ private System.Windows.Forms.ComboBox ExitComboBox;
+ private System.Windows.Forms.ComboBox AllPcComboBox;
+ private System.Windows.Forms.Panel panel3;
+
+
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage4.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage4.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SettingsPage4.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage1.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage1.Designer.cs
new file mode 100644
index 000000000000..59e46a81f85f
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage1.Designer.cs
@@ -0,0 +1,196 @@
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ partial class SetupPage1
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.label1 = new System.Windows.Forms.Label();
+ this.panel2 = new System.Windows.Forms.Panel();
+ this.label2 = new System.Windows.Forms.Label();
+ this.label3 = new System.Windows.Forms.Label();
+ this.label4 = new System.Windows.Forms.Label();
+ this.NoButton = new MouseWithoutBorders.ImageButton();
+ this.YesButton = new MouseWithoutBorders.ImageButton();
+ this.pictureBox1 = new System.Windows.Forms.PictureBox();
+ ((System.ComponentModel.ISupportInitialize)(this.NoButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.YesButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+ this.SuspendLayout();
+ //
+ // panel1
+ //
+ this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel1.BackColor = System.Drawing.Color.White;
+ this.panel1.Location = new System.Drawing.Point(41, 96);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(370, 1);
+ this.panel1.TabIndex = 1;
+ //
+ // label1
+ //
+ this.label1.Font = new System.Drawing.Font(Control.DefaultFont.Name, 30F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.ForeColor = System.Drawing.Color.White;
+ this.label1.Location = new System.Drawing.Point(61, 102);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(330, 52);
+ this.label1.TabIndex = 2;
+ this.label1.Text = "Let\'s get started";
+ this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // panel2
+ //
+ this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel2.BackColor = System.Drawing.Color.White;
+ this.panel2.Location = new System.Drawing.Point(41, 166);
+ this.panel2.Name = "panel2";
+ this.panel2.Size = new System.Drawing.Size(370, 1);
+ this.panel2.TabIndex = 2;
+ //
+ // label2
+ //
+ this.label2.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9.75F);
+ this.label2.ForeColor = System.Drawing.Color.White;
+ this.label2.Location = new System.Drawing.Point(61, 185);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(310, 40);
+ this.label2.TabIndex = 3;
+ this.label2.Text = "We need to know if you have already set up Mouse w/o Borders on the computer you " +
+ "want to link to.";
+ //
+ // label3
+ //
+ this.label3.Font = new System.Drawing.Font(Control.DefaultFont.Name, 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label3.ForeColor = System.Drawing.Color.White;
+ this.label3.Location = new System.Drawing.Point(61, 240);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(310, 60);
+ this.label3.TabIndex = 4;
+ this.label3.Text = "Have you already installed Mouse without Borders on another computer?";
+ //
+ // label4
+ //
+ this.label4.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9.75F);
+ this.label4.ForeColor = System.Drawing.Color.White;
+ this.label4.Location = new System.Drawing.Point(61, 278);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(310, 20);
+ this.label4.TabIndex = 5;
+ this.label4.Text = "";
+ //
+ // NoButton
+ //
+ this.NoButton.BackColor = System.Drawing.Color.Transparent;
+ this.NoButton.DisabledImage = null;
+ this.NoButton.DownImage = global::MouseWithoutBorders.Properties.Resources.no_button_click;
+ this.NoButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.no_button_hover;
+ this.NoButton.Image = global::MouseWithoutBorders.Properties.Resources.no_button_normal;
+ this.NoButton.InitialImage = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
+ this.NoButton.Location = new System.Drawing.Point(234, 366);
+ this.NoButton.Name = "NoButton";
+ this.NoButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.no_button_normal;
+ this.NoButton.Size = new System.Drawing.Size(55, 55);
+ this.NoButton.TabIndex = 7;
+ this.NoButton.TabStop = false;
+ this.NoButton.Click += new System.EventHandler(this.NoButtonClick);
+ //
+ // YesButton
+ //
+ this.YesButton.BackColor = System.Drawing.Color.Transparent;
+ this.YesButton.DisabledImage = null;
+ this.YesButton.DownImage = global::MouseWithoutBorders.Properties.Resources.yes_button_click;
+ this.YesButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.yes_button_hover;
+ this.YesButton.Image = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
+ this.YesButton.InitialImage = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
+ this.YesButton.Location = new System.Drawing.Point(164, 366);
+ this.YesButton.Name = "YesButton";
+ this.YesButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.yes_button_normal;
+ this.YesButton.Size = new System.Drawing.Size(55, 55);
+ this.YesButton.TabIndex = 6;
+ this.YesButton.TabStop = false;
+ this.YesButton.Click += new System.EventHandler(this.YesButtonClick);
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.Image = global::MouseWithoutBorders.Properties.Resources.Mouse;
+ this.pictureBox1.Location = new System.Drawing.Point(206, 40);
+ this.pictureBox1.Margin = new System.Windows.Forms.Padding(0);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.Size = new System.Drawing.Size(41, 36);
+ this.pictureBox1.TabIndex = 0;
+ this.pictureBox1.TabStop = false;
+ //
+ // SetupPage1
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.NoButton);
+ this.Controls.Add(this.YesButton);
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.panel2);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.pictureBox1);
+ this.DoubleBuffered = true;
+ this.Name = "SetupPage1";
+ this.Size = new System.Drawing.Size(453, 438);
+ this.Controls.SetChildIndex(this.pictureBox1, 0);
+ this.Controls.SetChildIndex(this.panel1, 0);
+ this.Controls.SetChildIndex(this.label1, 0);
+ this.Controls.SetChildIndex(this.panel2, 0);
+ this.Controls.SetChildIndex(this.label2, 0);
+ this.Controls.SetChildIndex(this.label3, 0);
+ this.Controls.SetChildIndex(this.label4, 0);
+ this.Controls.SetChildIndex(this.YesButton, 0);
+ this.Controls.SetChildIndex(this.NoButton, 0);
+ ((System.ComponentModel.ISupportInitialize)(this.NoButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.YesButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.PictureBox pictureBox1;
+ private System.Windows.Forms.Panel panel1;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Panel panel2;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.Label label4;
+ private ImageButton YesButton;
+ private ImageButton NoButton;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage1.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage1.cs
new file mode 100644
index 000000000000..2020e2f9f5b7
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage1.cs
@@ -0,0 +1,28 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace MouseWithoutBorders
+{
+ public partial class SetupPage1 : SettingsFormPage
+ {
+ public SetupPage1()
+ {
+ InitializeComponent();
+
+ Common.ClearComputerMatrix();
+ }
+
+ private void NoButtonClick(object sender, EventArgs e)
+ {
+ SendNextPage(new SetupPage2b());
+ }
+
+ private void YesButtonClick(object sender, EventArgs e)
+ {
+ SendNextPage(new SetupPage2aa());
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage1.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage1.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage1.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2a.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2a.Designer.cs
new file mode 100644
index 000000000000..7338e1c4037d
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2a.Designer.cs
@@ -0,0 +1,214 @@
+namespace MouseWithoutBorders
+{
+ using System.Windows.Forms;
+
+ partial class SetupPage2a
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label6 = new System.Windows.Forms.Label();
+ this.SecurityCodeField = new MouseWithoutBorders.ColorBorderField();
+ this.ComputerNameField = new MouseWithoutBorders.ColorBorderField();
+ this.label3 = new System.Windows.Forms.Label();
+ this.LinkButton = new MouseWithoutBorders.ImageButton();
+ this.label2 = new System.Windows.Forms.Label();
+ this.ExpandHelpButton = new MouseWithoutBorders.ImageButton();
+ this.CollapseHelpButton = new MouseWithoutBorders.ImageButton();
+ this.HelpLabel = new System.Windows.Forms.Label();
+ ((System.ComponentModel.ISupportInitialize)(this.LinkButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.ExpandHelpButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.CollapseHelpButton)).BeginInit();
+ this.SuspendLayout();
+ //
+ // label6
+ //
+ this.label6.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label6.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.label6.Location = new System.Drawing.Point(98, 208);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(130, 18);
+ this.label6.TabIndex = 7;
+ this.label6.Text = "SECURITY CODE";
+ this.label6.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
+ //
+ // SecurityCodeField
+ //
+ this.SecurityCodeField.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(177)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.SecurityCodeField.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(177)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.SecurityCodeField.BorderSize = 2;
+ this.SecurityCodeField.FocusColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(176)))), ((int)(((byte)(64)))));
+ this.SecurityCodeField.Font = new System.Drawing.Font(Control.DefaultFont.Name, 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.SecurityCodeField.Location = new System.Drawing.Point(80, 226);
+ this.SecurityCodeField.Margin = new System.Windows.Forms.Padding(0);
+ this.SecurityCodeField.MaximumLength = 22;
+ this.SecurityCodeField.Name = "SecurityCodeField";
+ this.SecurityCodeField.Size = new System.Drawing.Size(300, 30);
+ this.SecurityCodeField.TabIndex = 0;
+ this.SecurityCodeField.FieldTextChanged += new System.EventHandler(this.SecurityCodeFieldFieldTextChanged);
+ //
+ // ComputerNameField
+ //
+ this.ComputerNameField.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(177)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.ComputerNameField.BorderColor = System.Drawing.Color.FromArgb(((int)(((byte)(177)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.ComputerNameField.BorderSize = 2;
+ this.ComputerNameField.FocusColor = System.Drawing.Color.FromArgb(((int)(((byte)(251)))), ((int)(((byte)(176)))), ((int)(((byte)(64)))));
+ this.ComputerNameField.Font = new System.Drawing.Font(Control.DefaultFont.Name, 18F);
+ this.ComputerNameField.Location = new System.Drawing.Point(80, 280);
+ this.ComputerNameField.Margin = new System.Windows.Forms.Padding(0);
+ this.ComputerNameField.MaximumLength = 126;
+ this.ComputerNameField.Name = "ComputerNameField";
+ this.ComputerNameField.Size = new System.Drawing.Size(300, 30);
+ this.ComputerNameField.TabIndex = 1;
+ this.ComputerNameField.FieldTextChanged += new System.EventHandler(this.ComputerNameFieldFieldTextChanged);
+ //
+ // label3
+ //
+ this.label3.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label3.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.label3.Location = new System.Drawing.Point(98, 262);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(262, 18);
+ this.label3.TabIndex = 13;
+ this.label3.Text = "OTHER COMPUTER\'S NAME";
+ this.label3.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
+ //
+ // LinkButton
+ //
+ this.LinkButton.DisabledImage = global::MouseWithoutBorders.Properties.Resources.link_button_disabled;
+ this.LinkButton.DownImage = global::MouseWithoutBorders.Properties.Resources.link_button_click;
+ this.LinkButton.Enabled = false;
+ this.LinkButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.link_button_hover;
+ this.LinkButton.Image = global::MouseWithoutBorders.Properties.Resources.link_button_normal;
+ this.LinkButton.Location = new System.Drawing.Point(199, 366);
+ this.LinkButton.Name = "LinkButton";
+ this.LinkButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.link_button_normal;
+ this.LinkButton.Size = new System.Drawing.Size(55, 55);
+ this.LinkButton.TabIndex = 15;
+ this.LinkButton.TabStop = false;
+ this.LinkButton.Click += new System.EventHandler(this.LinkButtonClick);
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.BackColor = System.Drawing.Color.Transparent;
+ this.label2.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label2.ForeColor = System.Drawing.Color.White;
+ this.label2.Location = new System.Drawing.Point(213, 208);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(128, 16);
+ this.label2.TabIndex = 23;
+ this.label2.Text = "Where can I find this?";
+ //
+ // ExpandHelpButton
+ //
+ this.ExpandHelpButton.DisabledImage = null;
+ this.ExpandHelpButton.DownImage = global::MouseWithoutBorders.Properties.Resources.expand_button_click;
+ this.ExpandHelpButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.expand_button_highlight;
+ this.ExpandHelpButton.Image = global::MouseWithoutBorders.Properties.Resources.expand_button_normal;
+ this.ExpandHelpButton.Location = new System.Drawing.Point(360, 211);
+ this.ExpandHelpButton.Name = "ExpandHelpButton";
+ this.ExpandHelpButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.expand_button_normal;
+ this.ExpandHelpButton.Size = new System.Drawing.Size(11, 11);
+ this.ExpandHelpButton.TabIndex = 24;
+ this.ExpandHelpButton.TabStop = false;
+ this.ExpandHelpButton.Click += new System.EventHandler(this.ExpandHelpButtonClick);
+ //
+ // CollapseHelpButton
+ //
+ this.CollapseHelpButton.DisabledImage = null;
+ this.CollapseHelpButton.DownImage = global::MouseWithoutBorders.Properties.Resources.collapse_button_click;
+ this.CollapseHelpButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.collapse_button_hover;
+ this.CollapseHelpButton.Image = global::MouseWithoutBorders.Properties.Resources.collapse_button_normal;
+ this.CollapseHelpButton.Location = new System.Drawing.Point(360, 211);
+ this.CollapseHelpButton.Name = "CollapseHelpButton";
+ this.CollapseHelpButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.collapse_button_normal;
+ this.CollapseHelpButton.Size = new System.Drawing.Size(11, 11);
+ this.CollapseHelpButton.TabIndex = 25;
+ this.CollapseHelpButton.TabStop = false;
+ this.CollapseHelpButton.Visible = false;
+ this.CollapseHelpButton.Click += new System.EventHandler(this.CollapseHelpButtonClick);
+ //
+ // HelpLabel
+ //
+ this.HelpLabel.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(49)))), ((int)(((byte)(159)))), ((int)(((byte)(217)))));
+ this.HelpLabel.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.HelpLabel.ForeColor = System.Drawing.Color.White;
+ this.HelpLabel.Location = new System.Drawing.Point(101, 226);
+ this.HelpLabel.Name = "HelpLabel";
+ this.HelpLabel.Size = new System.Drawing.Size(250, 94);
+ this.HelpLabel.TabIndex = 26;
+ this.HelpLabel.Text = "The security code can be found on the computer you want to link to by right click" +
+ "ing the system tray icon, selecting \"Settings\" (spaces in the key can be discarded)";
+ this.HelpLabel.Visible = false;
+ //
+ // SetupPage2a
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.HelpLabel);
+ this.Controls.Add(this.LinkButton);
+ this.Controls.Add(this.ComputerNameField);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.SecurityCodeField);
+ this.Controls.Add(this.CollapseHelpButton);
+ this.Controls.Add(this.ExpandHelpButton);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.label6);
+ this.DoubleBuffered = true;
+ this.Name = "SetupPage2a";
+ this.Size = new System.Drawing.Size(453, 438);
+ this.Controls.SetChildIndex(this.label6, 0);
+ this.Controls.SetChildIndex(this.label2, 0);
+ this.Controls.SetChildIndex(this.ExpandHelpButton, 0);
+ this.Controls.SetChildIndex(this.CollapseHelpButton, 0);
+ this.Controls.SetChildIndex(this.SecurityCodeField, 0);
+ this.Controls.SetChildIndex(this.label3, 0);
+ this.Controls.SetChildIndex(this.ComputerNameField, 0);
+ this.Controls.SetChildIndex(this.LinkButton, 0);
+ this.Controls.SetChildIndex(this.HelpLabel, 0);
+ ((System.ComponentModel.ISupportInitialize)(this.LinkButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.ExpandHelpButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.CollapseHelpButton)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label6;
+ private ColorBorderField SecurityCodeField;
+ private ColorBorderField ComputerNameField;
+ private System.Windows.Forms.Label label3;
+ private ImageButton LinkButton;
+ private System.Windows.Forms.Label label2;
+ private ImageButton ExpandHelpButton;
+ private ImageButton CollapseHelpButton;
+ private System.Windows.Forms.Label HelpLabel;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2a.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2a.cs
new file mode 100644
index 000000000000..c3c36e6f4728
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2a.cs
@@ -0,0 +1,115 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Globalization;
+using System.Text.RegularExpressions;
+using MouseWithoutBorders.Class;
+
+namespace MouseWithoutBorders
+{
+ public partial class SetupPage2a : SettingsFormPage
+ {
+ private static string _securityCode;
+
+ protected string SecurityCode
+ {
+ get => _securityCode;
+ set
+ {
+ _securityCode = value;
+ SecurityCodeField.Text = value;
+ }
+ }
+
+ private static string _computerName;
+
+ protected string ComputerName
+ {
+ get => _computerName;
+ set
+ {
+ _computerName = value;
+ ComputerNameField.Text = value;
+ }
+ }
+
+ public SetupPage2a()
+ {
+ InitializeComponent();
+ BackButtonVisible = true;
+ SecurityCodeField.Text = string.IsNullOrEmpty(SecurityCode) ? string.Empty : GetSecureKey();
+ ComputerNameField.Text = string.IsNullOrEmpty(ComputerName) ? string.Empty : ComputerName;
+ SetLinkButtonState();
+
+ if (Common.RunWithNoAdminRight)
+ {
+ BackButtonVisible = false;
+ }
+ }
+
+ protected override SettingsFormPage CreateBackPage()
+ {
+ return new SetupPage1();
+ }
+
+ protected override void OnLoad(System.EventArgs e)
+ {
+ base.OnLoad(e);
+ _ = SecurityCodeField.Focus();
+ }
+
+ private void SecurityCodeFieldFieldTextChanged(object sender, System.EventArgs e)
+ {
+ SetLinkButtonState();
+ }
+
+ private void ComputerNameFieldFieldTextChanged(object sender, System.EventArgs e)
+ {
+ SetLinkButtonState();
+ }
+
+ private void SetLinkButtonState()
+ {
+ LinkButton.Enabled = SecurityCodeField.Text.Length >= 16 && ComputerNameField.Text.Trim().Length > 0;
+ if (!string.IsNullOrEmpty(SecurityCodeField.Text))
+ {
+ _securityCode = SecurityCodeField.Text;
+ }
+
+ if (!string.IsNullOrEmpty(ComputerNameField.Text))
+ {
+ _computerName = ComputerNameField.Text;
+ }
+ }
+
+ private void LinkButtonClick(object sender, System.EventArgs e)
+ {
+ if (GetSecureKey() != SecurityCodeField.Text)
+ {
+ Common.MyKey = Regex.Replace(SecurityCodeField.Text, @"\s+", string.Empty);
+ SecurityCode = Common.MyKey;
+ }
+
+ Common.MachineMatrix = new string[Common.MAX_MACHINE] { ComputerNameField.Text.Trim().ToUpper(CultureInfo.CurrentCulture), Common.MachineName.Trim(), string.Empty, string.Empty };
+
+ string[] machines = Common.MachineMatrix;
+ Common.MachinePool.Initialize(machines);
+
+ Common.UpdateMachinePoolStringSetting();
+ SendNextPage(new SetupPage3a { ReturnToSettings = !Setting.Values.FirstRun });
+ }
+
+ private void ExpandHelpButtonClick(object sender, System.EventArgs e)
+ {
+ HelpLabel.Show();
+ CollapseHelpButton.Show();
+ }
+
+ private void CollapseHelpButtonClick(object sender, System.EventArgs e)
+ {
+ HelpLabel.Hide();
+ CollapseHelpButton.Hide();
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2a.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2a.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2a.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2aa.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2aa.Designer.cs
new file mode 100644
index 000000000000..1a909b0ee3ac
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2aa.Designer.cs
@@ -0,0 +1,104 @@
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ partial class SetupPage2aa
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.label6 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.Font = new System.Drawing.Font(Control.DefaultFont.Name, 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.ForeColor = System.Drawing.Color.White;
+ this.label1.Location = new System.Drawing.Point(49, 30);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(356, 150);
+ this.label1.TabIndex = 2;
+ this.label1.Text = "Just one more step\r\nand your computers\r\nwill be linked!";
+ this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // label6
+ //
+ this.label6.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label6.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.label6.Location = new System.Drawing.Point(98, 185);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(130, 18);
+ this.label6.TabIndex = 7;
+ this.label6.Text = "SECURITY CODE";
+ this.label6.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.BackColor = System.Drawing.Color.Transparent;
+ this.label2.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label2.ForeColor = System.Drawing.Color.White;
+ this.label2.Location = new System.Drawing.Point(213, 185);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(128, 16);
+ this.label2.TabIndex = 23;
+ this.label2.Text = "Where can I find this?";
+ //
+ // panel1
+ //
+ this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel1.BackColor = System.Drawing.Color.White;
+ this.panel1.Location = new System.Drawing.Point(41, 170);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(370, 1);
+ this.panel1.TabIndex = 1;
+ //
+ // SetupPage2aa
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.label1);
+ this.Name = "SetupPage2aa";
+ this.Controls.SetChildIndex(this.label1, 0);
+ this.Controls.SetChildIndex(this.panel1, 0);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Panel panel1;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2aa.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2aa.cs
new file mode 100644
index 000000000000..d010495d74c8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2aa.cs
@@ -0,0 +1,14 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace MouseWithoutBorders
+{
+ public partial class SetupPage2aa : SetupPage2a
+ {
+ public SetupPage2aa()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2aa.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2aa.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2aa.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2ab.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2ab.Designer.cs
new file mode 100644
index 000000000000..713979d81623
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2ab.Designer.cs
@@ -0,0 +1,166 @@
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ partial class SetupPage2ab
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.label6 = new System.Windows.Forms.Label();
+ this.label4 = new System.Windows.Forms.Label();
+ this.label2 = new System.Windows.Forms.Label();
+ this.ExpandHelpButton = new MouseWithoutBorders.ImageButton();
+ this.CollapseHelpButton = new MouseWithoutBorders.ImageButton();
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.panel2 = new System.Windows.Forms.Panel();
+ ((System.ComponentModel.ISupportInitialize)(this.ExpandHelpButton)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.CollapseHelpButton)).BeginInit();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.Font = new System.Drawing.Font(Control.DefaultFont.Name, 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.ForeColor = System.Drawing.Color.White;
+ this.label1.Location = new System.Drawing.Point(49, 30);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(356, 53);
+ this.label1.TabIndex = 2;
+ this.label1.Text = "Sorry!";
+ this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // label6
+ //
+ this.label6.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label6.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.label6.Location = new System.Drawing.Point(98, 208);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(130, 18);
+ this.label6.TabIndex = 7;
+ this.label6.Text = "SECURITY CODE";
+ this.label6.TextAlign = System.Drawing.ContentAlignment.BottomLeft;
+ //
+ // label4
+ //
+ this.label4.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9.75F);
+ this.label4.ForeColor = System.Drawing.Color.White;
+ this.label4.Location = new System.Drawing.Point(61, 95);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(332, 79);
+ this.label4.TabIndex = 27;
+ this.label4.Text = "It looks like we were unable to connect to your computer. Make sure that all of y" +
+ "our computers are on the same network and that you have the correct information " +
+ "filled in below.";
+ //
+ // label2
+ //
+ this.label2.AutoSize = true;
+ this.label2.BackColor = System.Drawing.Color.Transparent;
+ this.label2.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label2.ForeColor = System.Drawing.Color.White;
+ this.label2.Location = new System.Drawing.Point(213, 208);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(128, 16);
+ this.label2.TabIndex = 23;
+ this.label2.Text = "Where can I find this?";
+ //
+ // ExpandHelpButton
+ //
+ this.ExpandHelpButton.DisabledImage = null;
+ this.ExpandHelpButton.DownImage = null;
+ this.ExpandHelpButton.HoverImage = null;
+ this.ExpandHelpButton.Location = new System.Drawing.Point(0, 0);
+ this.ExpandHelpButton.Name = "ExpandHelpButton";
+ this.ExpandHelpButton.NormalImage = null;
+ this.ExpandHelpButton.Size = new System.Drawing.Size(80, 78);
+ this.ExpandHelpButton.TabIndex = 0;
+ this.ExpandHelpButton.TabStop = false;
+ //
+ // CollapseHelpButton
+ //
+ this.CollapseHelpButton.DisabledImage = null;
+ this.CollapseHelpButton.DownImage = null;
+ this.CollapseHelpButton.HoverImage = null;
+ this.CollapseHelpButton.Location = new System.Drawing.Point(0, 0);
+ this.CollapseHelpButton.Name = "CollapseHelpButton";
+ this.CollapseHelpButton.NormalImage = null;
+ this.CollapseHelpButton.Size = new System.Drawing.Size(80, 78);
+ this.CollapseHelpButton.TabIndex = 0;
+ this.CollapseHelpButton.TabStop = false;
+ //
+ // panel1
+ //
+ this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel1.BackColor = System.Drawing.Color.White;
+ this.panel1.Location = new System.Drawing.Point(41, 80);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(370, 1);
+ this.panel1.TabIndex = 1;
+ //
+ // panel2
+ //
+ this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel2.BackColor = System.Drawing.Color.White;
+ this.panel2.Location = new System.Drawing.Point(41, 170);
+ this.panel2.Name = "panel2";
+ this.panel2.Size = new System.Drawing.Size(370, 1);
+ this.panel2.TabIndex = 28;
+ //
+ // SetupPage2ab
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.panel2);
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.label1);
+ this.Name = "SetupPage2ab";
+ this.Controls.SetChildIndex(this.label1, 0);
+ this.Controls.SetChildIndex(this.panel1, 0);
+ this.Controls.SetChildIndex(this.label4, 0);
+ this.Controls.SetChildIndex(this.panel2, 0);
+ ((System.ComponentModel.ISupportInitialize)(this.ExpandHelpButton)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.CollapseHelpButton)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.Label label2;
+ private ImageButton ExpandHelpButton;
+ private ImageButton CollapseHelpButton;
+ private System.Windows.Forms.Panel panel1;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Panel panel2;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2ab.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2ab.cs
new file mode 100644
index 000000000000..1b52bd3e07df
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2ab.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace MouseWithoutBorders
+{
+ public partial class SetupPage2ab : SetupPage2a
+ {
+ public SetupPage2ab()
+ {
+ InitializeComponent();
+
+ // ComputerName = ComputerName;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2ab.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2ab.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2ab.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.Designer.cs
new file mode 100644
index 000000000000..bf9a0064a43d
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.Designer.cs
@@ -0,0 +1,199 @@
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ partial class SetupPage2b
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.label1 = new System.Windows.Forms.Label();
+ this.panel2 = new System.Windows.Forms.Panel();
+ this.label2 = new System.Windows.Forms.Label();
+ this.SecurityCodeLabel = new System.Windows.Forms.Label();
+ this.pictureBox1 = new System.Windows.Forms.PictureBox();
+ this.label5 = new System.Windows.Forms.Label();
+ this.label6 = new System.Windows.Forms.Label();
+ this.label4 = new System.Windows.Forms.Label();
+ this.MachineNameLabel = new System.Windows.Forms.Label();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+ this.SuspendLayout();
+ //
+ // panel1
+ //
+ this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel1.BackColor = System.Drawing.Color.White;
+ this.panel1.Location = new System.Drawing.Point(41, 326);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(370, 1);
+ this.panel1.TabIndex = 1;
+ //
+ // label1
+ //
+ this.label1.Font = new System.Drawing.Font(Control.DefaultFont.Name, 28F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.ForeColor = System.Drawing.Color.White;
+ this.label1.Location = new System.Drawing.Point(61, 28);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(330, 56);
+ this.label1.TabIndex = 2;
+ this.label1.Text = "Almost done here...";
+ this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // panel2
+ //
+ this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel2.BackColor = System.Drawing.Color.White;
+ this.panel2.Location = new System.Drawing.Point(41, 87);
+ this.panel2.Name = "panel2";
+ this.panel2.Size = new System.Drawing.Size(370, 1);
+ this.panel2.TabIndex = 2;
+ //
+ // label2
+ //
+ this.label2.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label2.ForeColor = System.Drawing.Color.White;
+ this.label2.Location = new System.Drawing.Point(61, 103);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(338, 80);
+ this.label2.TabIndex = 3;
+ this.label2.Text = "Just keep this window open or write down the information below. Then head over to your other computer and " +
+ "install Mouse w/o Borders. You can finish the setup and configuration over there" +
+ ".";
+ //
+ // SecurityCodeLabel
+ //
+ this.SecurityCodeLabel.Font = new System.Drawing.Font(Control.DefaultFont.Name, 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.SecurityCodeLabel.ForeColor = System.Drawing.Color.White;
+ this.SecurityCodeLabel.Location = new System.Drawing.Point(68, 207);
+ this.SecurityCodeLabel.Name = "SecurityCodeLabel";
+ this.SecurityCodeLabel.Size = new System.Drawing.Size(310, 40);
+ this.SecurityCodeLabel.TabIndex = 4;
+ this.SecurityCodeLabel.Text = "IlIlIlIlIl";
+ this.SecurityCodeLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.Image = global::MouseWithoutBorders.Properties.Resources.Mouse;
+ this.pictureBox1.Location = new System.Drawing.Point(206, 365);
+ this.pictureBox1.Margin = new System.Windows.Forms.Padding(0);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.Size = new System.Drawing.Size(44, 35);
+ this.pictureBox1.TabIndex = 0;
+ this.pictureBox1.TabStop = false;
+ //
+ // label5
+ //
+ this.label5.Font = new System.Drawing.Font(Control.DefaultFont.Name, 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label5.ForeColor = System.Drawing.Color.White;
+ this.label5.Location = new System.Drawing.Point(61, 170);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(310, 24);
+ this.label5.TabIndex = 6;
+ this.label5.Text = "Now you\'re all done over here!";
+ //
+ // label6
+ //
+ this.label6.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label6.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.label6.Location = new System.Drawing.Point(71, 199);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(310, 15);
+ this.label6.TabIndex = 7;
+ this.label6.Text = "SECURITY CODE";
+ this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // label4
+ //
+ this.label4.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label4.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(77)))), ((int)(((byte)(208)))), ((int)(((byte)(238)))));
+ this.label4.Location = new System.Drawing.Point(71, 258);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(310, 15);
+ this.label4.TabIndex = 9;
+ this.label4.Text = "THIS COMPUTER\'S NAME";
+ this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // MachineNameLabel
+ //
+ this.MachineNameLabel.Font = new System.Drawing.Font(Control.DefaultFont.Name, 18F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.MachineNameLabel.ForeColor = System.Drawing.Color.White;
+ this.MachineNameLabel.Location = new System.Drawing.Point(50, 266);
+ this.MachineNameLabel.Name = "MachineNameLabel";
+ this.MachineNameLabel.Size = new System.Drawing.Size(340, 40);
+ this.MachineNameLabel.TabIndex = 8;
+ this.MachineNameLabel.Text = "Alan - Desktop";
+ this.MachineNameLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // SetupPage2b
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.MachineNameLabel);
+ this.Controls.Add(this.label6);
+ this.Controls.Add(this.label5);
+ this.Controls.Add(this.SecurityCodeLabel);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.panel2);
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.pictureBox1);
+ this.Controls.Add(this.label1);
+ this.DoubleBuffered = true;
+ this.Name = "SetupPage2b";
+ this.Size = new System.Drawing.Size(453, 438);
+ this.Controls.SetChildIndex(this.label1, 0);
+ this.Controls.SetChildIndex(this.pictureBox1, 0);
+ this.Controls.SetChildIndex(this.panel1, 0);
+ this.Controls.SetChildIndex(this.panel2, 0);
+ this.Controls.SetChildIndex(this.label2, 0);
+ this.Controls.SetChildIndex(this.SecurityCodeLabel, 0);
+ this.Controls.SetChildIndex(this.label5, 0);
+ this.Controls.SetChildIndex(this.label6, 0);
+ this.Controls.SetChildIndex(this.MachineNameLabel, 0);
+ this.Controls.SetChildIndex(this.label4, 0);
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.PictureBox pictureBox1;
+ private System.Windows.Forms.Panel panel1;
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Panel panel2;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Label SecurityCodeLabel;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.Label label6;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Label MachineNameLabel;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.cs
new file mode 100644
index 000000000000..5649ae8d7fe7
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace MouseWithoutBorders
+{
+ public partial class SetupPage2b : SettingsFormPage
+ {
+ public SetupPage2b()
+ {
+ InitializeComponent();
+ SecurityCodeLabel.Text = GetSecureKey();
+ MachineNameLabel.Text = Common.MachineName.Trim();
+ BackButtonVisible = true;
+ Common.ReopenSockets(true);
+ }
+
+ protected override SettingsFormPage CreateBackPage()
+ {
+ return new SetupPage1();
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage2b.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.Designer.cs
new file mode 100644
index 000000000000..68375996f915
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.Designer.cs
@@ -0,0 +1,125 @@
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ partial class SetupPage3a
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.panel2 = new System.Windows.Forms.Panel();
+ this.MessageLabel = new System.Windows.Forms.Label();
+ this.ExamplePicture = new System.Windows.Forms.PictureBox();
+ this.labelStatus = new System.Windows.Forms.Label();
+ ((System.ComponentModel.ISupportInitialize)(this.ExamplePicture)).BeginInit();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.Font = new System.Drawing.Font(Control.DefaultFont.Name, 24F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.ForeColor = System.Drawing.Color.White;
+ this.label1.Location = new System.Drawing.Point(65, 56);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(330, 116);
+ this.label1.TabIndex = 2;
+ this.label1.Text = "Linking! Soon you will be able to...\r\n";
+ this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // panel2
+ //
+ this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel2.BackColor = System.Drawing.Color.White;
+ this.panel2.Location = new System.Drawing.Point(41, 178);
+ this.panel2.Name = "panel2";
+ this.panel2.Size = new System.Drawing.Size(370, 1);
+ this.panel2.TabIndex = 2;
+ //
+ // MessageLabel
+ //
+ this.MessageLabel.Font = new System.Drawing.Font(Control.DefaultFont.Name, 12F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.MessageLabel.ForeColor = System.Drawing.Color.White;
+ this.MessageLabel.Location = new System.Drawing.Point(71, 197);
+ this.MessageLabel.Name = "MessageLabel";
+ this.MessageLabel.Size = new System.Drawing.Size(310, 24);
+ this.MessageLabel.TabIndex = 4;
+ this.MessageLabel.Text = "Copy && paste across screens";
+ this.MessageLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // ExamplePicture
+ //
+ this.ExamplePicture.Image = global::MouseWithoutBorders.Properties.Resources.copy_paste_example;
+ this.ExamplePicture.Location = new System.Drawing.Point(101, 251);
+ this.ExamplePicture.Name = "ExamplePicture";
+ this.ExamplePicture.Size = new System.Drawing.Size(251, 79);
+ this.ExamplePicture.TabIndex = 7;
+ this.ExamplePicture.TabStop = false;
+ //
+ // labelStatus
+ //
+ this.labelStatus.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.labelStatus.Font = new System.Drawing.Font(Control.DefaultFont.Name, 10F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.labelStatus.ForeColor = System.Drawing.Color.White;
+ this.labelStatus.Location = new System.Drawing.Point(0, 418);
+ this.labelStatus.Name = "labelStatus";
+ this.labelStatus.Size = new System.Drawing.Size(453, 20);
+ this.labelStatus.TabIndex = 8;
+ this.labelStatus.Text = "Connecting...";
+ this.labelStatus.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // SetupPage3a
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.labelStatus);
+ this.Controls.Add(this.ExamplePicture);
+ this.Controls.Add(this.MessageLabel);
+ this.Controls.Add(this.panel2);
+ this.Controls.Add(this.label1);
+ this.DoubleBuffered = true;
+ this.Name = "SetupPage3a";
+ this.Size = new System.Drawing.Size(453, 438);
+ this.Controls.SetChildIndex(this.label1, 0);
+ this.Controls.SetChildIndex(this.panel2, 0);
+ this.Controls.SetChildIndex(this.MessageLabel, 0);
+ this.Controls.SetChildIndex(this.ExamplePicture, 0);
+ this.Controls.SetChildIndex(this.labelStatus, 0);
+ ((System.ComponentModel.ISupportInitialize)(this.ExamplePicture)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Panel panel2;
+ private System.Windows.Forms.Label MessageLabel;
+ private System.Windows.Forms.PictureBox ExamplePicture;
+ private System.Windows.Forms.Label labelStatus;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.cs
new file mode 100644
index 000000000000..4f0da5b20973
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.cs
@@ -0,0 +1,149 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Drawing;
+using System.Windows.Forms;
+using MouseWithoutBorders.Class;
+using MouseWithoutBorders.Properties;
+
+namespace MouseWithoutBorders
+{
+ public partial class SetupPage3a : SettingsFormPage
+ {
+ private readonly Image[] _frames = { Resources.copy_paste_example, Resources.drag_example, Resources.keyboard_example };
+ private readonly string[] _messages =
+ {
+ "Copy && paste across screens",
+ "Drag files across screens",
+ "Share keyboard across screens",
+ };
+
+ private readonly int[] _timing = { 1000, 1000, 2000 };
+#pragma warning disable CA2213 // Disposing is done by ComponentResourceManager
+ private readonly System.Timers.Timer _animationTimer;
+#pragma warning restore CA2213
+ private bool connected;
+ private bool done;
+ private bool invalidKey;
+
+ private int _animationFrame;
+
+ public bool ReturnToSettings { get; set; }
+
+ public SetupPage3a()
+ {
+ InitializeComponent();
+ _animationTimer = new System.Timers.Timer { Interval = 1000 };
+ }
+
+ private void ShowStatus(string status)
+ {
+ labelStatus.Text = status;
+ Common.Log(status);
+ }
+
+ public override void OnPageClosing()
+ {
+ _animationTimer.Stop();
+ base.OnPageClosing();
+ }
+
+ protected override void OnLoad(EventArgs e)
+ {
+ base.OnLoad(e);
+ _animationTimer.Elapsed += AnimationTimerTick;
+
+ Common.GetMachineName();
+ invalidKey = false;
+
+ UpdateAnimation();
+ _animationTimer.Start();
+
+ SocketStuff.InvalidKeyFound = false;
+ SocketStuff.InvalidKeyFoundOnClientSocket = false;
+
+ ShowStatus($"Connecting...");
+
+ Common.SwitchToMultipleMode(false, false);
+ Common.ReopenSockets(true);
+
+ int timeOut = 0;
+ TcpSk connectedClientSocket;
+
+ // Client sockets run in different threads.
+ while (timeOut < 10)
+ {
+ Common.MMSleep(1);
+
+ if ((connectedClientSocket = Common.GetConnectedClientSocket()) != null)
+ {
+ ShowStatus($"Connected from local IP Address: {connectedClientSocket.Address}.");
+ Common.UpdateMachineTimeAndID();
+
+ Common.MMSleep(1);
+ connected = true;
+ return;
+ }
+ else if (SocketStuff.InvalidKeyFoundOnClientSocket)
+ {
+ invalidKey = true;
+ ShowStatus("Status: InvalidKey.");
+ Common.MMSleep(3);
+ break;
+ }
+
+ timeOut++;
+ }
+
+ done = true;
+ }
+
+ private void AnimationTimerTick(object sender, EventArgs e)
+ {
+ _ = Invoke(new MethodInvoker(UpdateAnimation));
+ }
+
+ private void UpdateAnimation()
+ {
+ if ((ModifierKeys & Keys.Control) != 0)
+ {
+ _animationTimer.Stop();
+ SendNextPage(new SetupPage2ab());
+ return;
+ }
+
+ ExamplePicture.Image = _frames[_animationFrame];
+ MessageLabel.Text = _messages[_animationFrame];
+ _animationTimer.Interval = _timing[_animationFrame];
+ _animationFrame = (_animationFrame + 1) % _frames.Length;
+
+ if (connected)
+ {
+ _animationTimer.Stop();
+ SendNextPage(new SetupPage4());
+ }
+ else if (done)
+ {
+ _animationTimer.Stop();
+ SendNextPage(new SetupPage2ab());
+
+ if (invalidKey)
+ {
+ Common.ShowToolTip(
+ "Security Codes not matched.\r\nVerify that you entered the same code in all machines.\r\nAnd make sure you run the same version of "
+ + Application.ProductName + " in all machines.\r\nThis version: " + FrmAbout.AssemblyVersion,
+ 20000);
+ }
+ else
+ {
+ string helpText = "Connection error!";
+ helpText += "\r\nPlease check if your machines are connected to the same network, note that " + Application.ProductName + " works better with wired connection.";
+ helpText += "\r\nAnd double check if " + Application.ProductName + " is allowed through firewall in all machines.";
+ Common.ShowToolTip(helpText, 30000);
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage3a.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage4.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage4.Designer.cs
new file mode 100644
index 000000000000..7fb84ffc40d0
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage4.Designer.cs
@@ -0,0 +1,202 @@
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ partial class SetupPage4
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.label1 = new System.Windows.Forms.Label();
+ this.panel2 = new System.Windows.Forms.Panel();
+ this.label5 = new System.Windows.Forms.Label();
+ this.ExamplePicture = new System.Windows.Forms.PictureBox();
+ this.label2 = new System.Windows.Forms.Label();
+ this.label3 = new System.Windows.Forms.Label();
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.NextButton = new MouseWithoutBorders.ImageButton();
+ this.label4 = new System.Windows.Forms.Label();
+ this.label6 = new System.Windows.Forms.Label();
+ ((System.ComponentModel.ISupportInitialize)(this.ExamplePicture)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.NextButton)).BeginInit();
+ this.SuspendLayout();
+ //
+ // label1
+ //
+ this.label1.Font = new System.Drawing.Font(Control.DefaultFont.Name, 30F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.ForeColor = System.Drawing.Color.White;
+ this.label1.Location = new System.Drawing.Point(65, 58);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(330, 52);
+ this.label1.TabIndex = 2;
+ this.label1.Text = "Success! You\'re";
+ this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // panel2
+ //
+ this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel2.BackColor = System.Drawing.Color.White;
+ this.panel2.Location = new System.Drawing.Point(41, 175);
+ this.panel2.Name = "panel2";
+ this.panel2.Size = new System.Drawing.Size(370, 1);
+ this.panel2.TabIndex = 2;
+ //
+ // label5
+ //
+ this.label5.Font = new System.Drawing.Font(Control.DefaultFont.Name, 30F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label5.ForeColor = System.Drawing.Color.White;
+ this.label5.Location = new System.Drawing.Point(57, 108);
+ this.label5.Name = "label5";
+ this.label5.Size = new System.Drawing.Size(344, 52);
+ this.label5.TabIndex = 6;
+ this.label5.Text = "almost done here...";
+ this.label5.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // ExamplePicture
+ //
+ this.ExamplePicture.Image = global::MouseWithoutBorders.Properties.Resources.combined_example;
+ this.ExamplePicture.Location = new System.Drawing.Point(75, 283);
+ this.ExamplePicture.Name = "ExamplePicture";
+ this.ExamplePicture.Size = new System.Drawing.Size(307, 25);
+ this.ExamplePicture.TabIndex = 7;
+ this.ExamplePicture.TabStop = false;
+ //
+ // label2
+ //
+ this.label2.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9.75F);
+ this.label2.ForeColor = System.Drawing.Color.White;
+ this.label2.Location = new System.Drawing.Point(61, 200);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(310, 25);
+ this.label2.TabIndex = 8;
+ this.label2.Text = "Now you can do the magic of Mouse w/o Borders.";
+ //
+ // label3
+ //
+ this.label3.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9.75F);
+ this.label3.ForeColor = System.Drawing.Color.White;
+ this.label3.Location = new System.Drawing.Point(71, 242);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(88, 38);
+ this.label3.TabIndex = 9;
+ this.label3.Text = "Copy && Paste\r\nacross screens";
+ this.label3.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // panel1
+ //
+ this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel1.BackColor = System.Drawing.Color.White;
+ this.panel1.Location = new System.Drawing.Point(41, 345);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(370, 1);
+ this.panel1.TabIndex = 3;
+ //
+ // NextButton
+ //
+ this.NextButton.DisabledImage = null;
+ this.NextButton.DownImage = global::MouseWithoutBorders.Properties.Resources.next_button_click;
+ this.NextButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.next_button_hover;
+ this.NextButton.Image = global::MouseWithoutBorders.Properties.Resources.next_button_normal;
+ this.NextButton.Location = new System.Drawing.Point(199, 366);
+ this.NextButton.Name = "NextButton";
+ this.NextButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.next_button_normal;
+ this.NextButton.Size = new System.Drawing.Size(55, 55);
+ this.NextButton.TabIndex = 16;
+ this.NextButton.TabStop = false;
+ this.NextButton.Click += new System.EventHandler(this.NextButtonClick);
+ //
+ // label4
+ //
+ this.label4.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9.75F);
+ this.label4.ForeColor = System.Drawing.Color.White;
+ this.label4.Location = new System.Drawing.Point(185, 242);
+ this.label4.Name = "label4";
+ this.label4.Size = new System.Drawing.Size(88, 38);
+ this.label4.TabIndex = 17;
+ this.label4.Text = "Drag files\r\nacross screens";
+ this.label4.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // label6
+ //
+ this.label6.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9.75F);
+ this.label6.ForeColor = System.Drawing.Color.White;
+ this.label6.Location = new System.Drawing.Point(294, 242);
+ this.label6.Name = "label6";
+ this.label6.Size = new System.Drawing.Size(97, 38);
+ this.label6.TabIndex = 18;
+ this.label6.Text = "Share keyboard\r\nacross screens";
+ this.label6.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // SetupPage4
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.label6);
+ this.Controls.Add(this.label4);
+ this.Controls.Add(this.NextButton);
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.ExamplePicture);
+ this.Controls.Add(this.label5);
+ this.Controls.Add(this.panel2);
+ this.Controls.Add(this.label1);
+ this.DoubleBuffered = true;
+ this.Name = "SetupPage4";
+ this.Size = new System.Drawing.Size(453, 438);
+ this.Controls.SetChildIndex(this.label1, 0);
+ this.Controls.SetChildIndex(this.panel2, 0);
+ this.Controls.SetChildIndex(this.label5, 0);
+ this.Controls.SetChildIndex(this.ExamplePicture, 0);
+ this.Controls.SetChildIndex(this.label2, 0);
+ this.Controls.SetChildIndex(this.label3, 0);
+ this.Controls.SetChildIndex(this.panel1, 0);
+ this.Controls.SetChildIndex(this.NextButton, 0);
+ this.Controls.SetChildIndex(this.label4, 0);
+ this.Controls.SetChildIndex(this.label6, 0);
+ ((System.ComponentModel.ISupportInitialize)(this.ExamplePicture)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.NextButton)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label label1;
+ private System.Windows.Forms.Panel panel2;
+ private System.Windows.Forms.Label label5;
+ private System.Windows.Forms.PictureBox ExamplePicture;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.Panel panel1;
+ private ImageButton NextButton;
+ private System.Windows.Forms.Label label4;
+ private System.Windows.Forms.Label label6;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage4.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage4.cs
new file mode 100644
index 000000000000..983f4e8b1341
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage4.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using MouseWithoutBorders.Class;
+
+namespace MouseWithoutBorders
+{
+ public partial class SetupPage4 : SettingsFormPage
+ {
+ public SetupPage4()
+ {
+ Setting.Values.FirstRun = false;
+ InitializeComponent();
+ }
+
+ private void NextButtonClick(object sender, EventArgs e)
+ {
+ SendNextPage(new SetupPage5());
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage4.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage4.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage4.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage5.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage5.Designer.cs
new file mode 100644
index 000000000000..d4ff6334fc03
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage5.Designer.cs
@@ -0,0 +1,159 @@
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ partial class SetupPage5
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.pictureBox1 = new System.Windows.Forms.PictureBox();
+ this.label3 = new System.Windows.Forms.Label();
+ this.panel1 = new System.Windows.Forms.Panel();
+ this.label2 = new System.Windows.Forms.Label();
+ this.panel2 = new System.Windows.Forms.Panel();
+ this.label1 = new System.Windows.Forms.Label();
+ this.DoneButton = new MouseWithoutBorders.ImageButton();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit();
+ ((System.ComponentModel.ISupportInitialize)(this.DoneButton)).BeginInit();
+ this.SuspendLayout();
+ //
+ // pictureBox1
+ //
+ this.pictureBox1.Image = global::MouseWithoutBorders.Properties.Resources.Mouse;
+ this.pictureBox1.Location = new System.Drawing.Point(206, 40);
+ this.pictureBox1.Margin = new System.Windows.Forms.Padding(0);
+ this.pictureBox1.Name = "pictureBox1";
+ this.pictureBox1.Size = new System.Drawing.Size(41, 36);
+ this.pictureBox1.TabIndex = 25;
+ this.pictureBox1.TabStop = false;
+ //
+ // label3
+ //
+ this.label3.Font = new System.Drawing.Font(Control.DefaultFont.Name, 12F, System.Drawing.FontStyle.Bold);
+ this.label3.ForeColor = System.Drawing.Color.White;
+ this.label3.Location = new System.Drawing.Point(61, 271);
+ this.label3.Name = "label3";
+ this.label3.Size = new System.Drawing.Size(310, 25);
+ this.label3.TabIndex = 24;
+ this.label3.Text = "Have fun mousin\' around!";
+ //
+ // panel1
+ //
+ this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel1.BackColor = System.Drawing.Color.White;
+ this.panel1.Location = new System.Drawing.Point(41, 96);
+ this.panel1.Name = "panel1";
+ this.panel1.Size = new System.Drawing.Size(370, 1);
+ this.panel1.TabIndex = 20;
+ //
+ // label2
+ //
+ this.label2.Font = new System.Drawing.Font(Control.DefaultFont.Name, 9.75F);
+ this.label2.ForeColor = System.Drawing.Color.White;
+ this.label2.Location = new System.Drawing.Point(61, 226);
+ this.label2.Name = "label2";
+ this.label2.Size = new System.Drawing.Size(310, 40);
+ this.label2.TabIndex = 22;
+ this.label2.Text = "You can always get back to the settings for Mouse w/o Borders through the system " +
+ "tray icon.";
+ //
+ // panel2
+ //
+ this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.panel2.BackColor = System.Drawing.Color.White;
+ this.panel2.Location = new System.Drawing.Point(41, 208);
+ this.panel2.Name = "panel2";
+ this.panel2.Size = new System.Drawing.Size(370, 1);
+ this.panel2.TabIndex = 18;
+ //
+ // label1
+ //
+ this.label1.Font = new System.Drawing.Font(Control.DefaultFont.Name, 30F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.label1.ForeColor = System.Drawing.Color.White;
+ this.label1.Location = new System.Drawing.Point(62, 99);
+ this.label1.Name = "label1";
+ this.label1.Size = new System.Drawing.Size(330, 109);
+ this.label1.TabIndex = 19;
+ this.label1.Text = "All Done.\r\nNice Work!";
+ this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // DoneButton
+ //
+ this.DoneButton.DisabledImage = null;
+ this.DoneButton.DownImage = global::MouseWithoutBorders.Properties.Resources.done_button_click;
+ this.DoneButton.HoverImage = global::MouseWithoutBorders.Properties.Resources.done_button_hover;
+ this.DoneButton.Image = global::MouseWithoutBorders.Properties.Resources.done_button_normal;
+ this.DoneButton.Location = new System.Drawing.Point(199, 366);
+ this.DoneButton.Name = "DoneButton";
+ this.DoneButton.NormalImage = global::MouseWithoutBorders.Properties.Resources.done_button_normal;
+ this.DoneButton.Size = new System.Drawing.Size(55, 56);
+ this.DoneButton.TabIndex = 26;
+ this.DoneButton.TabStop = false;
+ this.DoneButton.Click += new System.EventHandler(this.DoneButtonClick);
+ //
+ // SetupPage5
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.DodgerBlue;
+ this.Controls.Add(this.DoneButton);
+ this.Controls.Add(this.panel1);
+ this.Controls.Add(this.label1);
+ this.Controls.Add(this.pictureBox1);
+ this.Controls.Add(this.label3);
+ this.Controls.Add(this.label2);
+ this.Controls.Add(this.panel2);
+ this.DoubleBuffered = true;
+ this.Name = "SetupPage5";
+ this.Size = new System.Drawing.Size(453, 438);
+ this.Controls.SetChildIndex(this.panel2, 0);
+ this.Controls.SetChildIndex(this.label2, 0);
+ this.Controls.SetChildIndex(this.label3, 0);
+ this.Controls.SetChildIndex(this.pictureBox1, 0);
+ this.Controls.SetChildIndex(this.label1, 0);
+ this.Controls.SetChildIndex(this.panel1, 0);
+ this.Controls.SetChildIndex(this.DoneButton, 0);
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit();
+ ((System.ComponentModel.ISupportInitialize)(this.DoneButton)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.PictureBox pictureBox1;
+ private System.Windows.Forms.Label label3;
+ private System.Windows.Forms.Panel panel1;
+ private System.Windows.Forms.Label label2;
+ private System.Windows.Forms.Panel panel2;
+ private System.Windows.Forms.Label label1;
+ private ImageButton DoneButton;
+
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage5.cs b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage5.cs
new file mode 100644
index 000000000000..fdcde4edda68
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage5.cs
@@ -0,0 +1,23 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+
+namespace MouseWithoutBorders
+{
+ public partial class SetupPage5 : SettingsFormPage
+ {
+ public SetupPage5()
+ {
+ InitializeComponent();
+ }
+
+ private void DoneButtonClick(object sender, EventArgs e)
+ {
+ // SendNextPage(new SettingsPage1());
+ Common.CloseSetupForm();
+ Common.ShowMachineMatrix();
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage5.resx b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage5.resx
new file mode 100644
index 000000000000..7080a7d118e8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/Settings/SetupPage5.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmAbout.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/frmAbout.Designer.cs
new file mode 100644
index 000000000000..75bc1aed18f3
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmAbout.Designer.cs
@@ -0,0 +1,164 @@
+namespace MouseWithoutBorders
+{
+ partial class FrmAbout
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmAbout));
+ this.logoPictureBox = new System.Windows.Forms.PictureBox();
+ this.labelProductName = new System.Windows.Forms.Label();
+ this.labelCopyright = new System.Windows.Forms.Label();
+ this.labelCompanyName = new System.Windows.Forms.Label();
+ this.groupBoxContributors = new System.Windows.Forms.GroupBox();
+ this.textBoxContributors = new System.Windows.Forms.TextBox();
+ this.okButton = new System.Windows.Forms.Button();
+ ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).BeginInit();
+ this.groupBoxContributors.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // logoPictureBox
+ //
+ this.logoPictureBox.ErrorImage = null;
+ this.logoPictureBox.Image = global::MouseWithoutBorders.Properties.Resources.Logo;
+ this.logoPictureBox.Location = new System.Drawing.Point(12, 12);
+ this.logoPictureBox.Name = "logoPictureBox";
+ this.logoPictureBox.Size = new System.Drawing.Size(131, 136);
+ this.logoPictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.StretchImage;
+ this.logoPictureBox.TabIndex = 12;
+ this.logoPictureBox.TabStop = false;
+ //
+ // labelProductName
+ //
+ this.labelProductName.AutoSize = true;
+ this.labelProductName.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.labelProductName.Location = new System.Drawing.Point(152, 12);
+ this.labelProductName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0);
+ this.labelProductName.MaximumSize = new System.Drawing.Size(0, 17);
+ this.labelProductName.Name = "labelProductName";
+ this.labelProductName.Size = new System.Drawing.Size(87, 13);
+ this.labelProductName.TabIndex = 27;
+ this.labelProductName.Text = "Product Name";
+ this.labelProductName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // labelCopyright
+ //
+ this.labelCopyright.AutoSize = true;
+ this.labelCopyright.Location = new System.Drawing.Point(152, 31);
+ this.labelCopyright.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0);
+ this.labelCopyright.MaximumSize = new System.Drawing.Size(0, 17);
+ this.labelCopyright.Name = "labelCopyright";
+ this.labelCopyright.Size = new System.Drawing.Size(51, 13);
+ this.labelCopyright.TabIndex = 28;
+ this.labelCopyright.Text = "Copyright";
+ this.labelCopyright.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // labelCompanyName
+ //
+ this.labelCompanyName.AutoSize = true;
+ this.labelCompanyName.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.labelCompanyName.Location = new System.Drawing.Point(9, 162);
+ this.labelCompanyName.Margin = new System.Windows.Forms.Padding(6, 0, 3, 0);
+ this.labelCompanyName.MaximumSize = new System.Drawing.Size(0, 17);
+ this.labelCompanyName.Name = "labelCompanyName";
+ this.labelCompanyName.Size = new System.Drawing.Size(94, 13);
+ this.labelCompanyName.TabIndex = 29;
+ this.labelCompanyName.Text = "Company Name";
+ this.labelCompanyName.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // groupBoxContributors
+ //
+ this.groupBoxContributors.Controls.Add(this.textBoxContributors);
+ this.groupBoxContributors.Location = new System.Drawing.Point(12, 178);
+ this.groupBoxContributors.Name = "groupBoxContributors";
+ this.groupBoxContributors.Size = new System.Drawing.Size(466, 350);
+ this.groupBoxContributors.TabIndex = 30;
+ this.groupBoxContributors.TabStop = false;
+ this.groupBoxContributors.Text = " Contributors ";
+ //
+ // textBoxContributors
+ //
+ this.textBoxContributors.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.textBoxContributors.Location = new System.Drawing.Point(3, 16);
+ this.textBoxContributors.Multiline = true;
+ this.textBoxContributors.Name = "textBoxContributors";
+ this.textBoxContributors.ReadOnly = true;
+ this.textBoxContributors.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
+ this.textBoxContributors.Size = new System.Drawing.Size(460, 331);
+ this.textBoxContributors.TabIndex = 31;
+ //
+ // okButton
+ //
+ this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this.okButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this.okButton.Location = new System.Drawing.Point(403, 534);
+ this.okButton.Name = "okButton";
+ this.okButton.Size = new System.Drawing.Size(75, 23);
+ this.okButton.TabIndex = 24;
+ this.okButton.Text = "&OK";
+ //
+ // frmAbout
+ //
+ this.AcceptButton = this.okButton;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+ this.ClientSize = new System.Drawing.Size(487, 561);
+ this.Controls.Add(this.okButton);
+ this.Controls.Add(this.logoPictureBox);
+ this.Controls.Add(this.labelProductName);
+ this.Controls.Add(this.labelCopyright);
+ this.Controls.Add(this.labelCompanyName);
+ this.Controls.Add(this.groupBoxContributors);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "frmAbout";
+ this.Opacity = 0.9D;
+ this.Padding = new System.Windows.Forms.Padding(9);
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "frmAbout";
+ this.TopMost = true;
+ this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FrmAbout_FormClosed);
+ ((System.ComponentModel.ISupportInitialize)(this.logoPictureBox)).EndInit();
+ this.groupBoxContributors.ResumeLayout(false);
+ this.groupBoxContributors.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.PictureBox logoPictureBox;
+ private System.Windows.Forms.Label labelProductName;
+ private System.Windows.Forms.Label labelCopyright;
+ private System.Windows.Forms.Label labelCompanyName;
+ private System.Windows.Forms.GroupBox groupBoxContributors;
+ private System.Windows.Forms.Button okButton;
+ private System.Windows.Forms.TextBox textBoxContributors;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmAbout.cs b/src/modules/MouseWithoutBorders/App/Form/frmAbout.cs
new file mode 100644
index 000000000000..3a7ae9901cf7
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmAbout.cs
@@ -0,0 +1,124 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// About box.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System;
+using System.Globalization;
+using System.Reflection;
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ internal partial class FrmAbout : System.Windows.Forms.Form, IDisposable
+ {
+ internal FrmAbout()
+ {
+ InitializeComponent();
+ Text = string.Format(CultureInfo.CurrentCulture, "About {0}", AssemblyTitle);
+ labelProductName.Text = string.Format(CultureInfo.CurrentCulture, "{0} {1}", AssemblyProduct, AssemblyVersion);
+ labelCopyright.Text = AssemblyCopyright;
+ labelCompanyName.Text = "Project creator: Truong Do (Đỗ Đức Trường)";
+
+ textBoxContributors.Text += "* Microsoft Garage: Quinn Hawkins, Michael Low, Joe Coplen, Nino Yuniardi, Gwyneth Marshall, David Andrews, Karen Luecking";
+ textBoxContributors.Text += "\r\n* Peter Hauge\t\t- Visual Studio";
+ textBoxContributors.Text += "\r\n* Bruce Dawson\t\t- Windows Fundamentals";
+ textBoxContributors.Text += "\r\n* Alan Myrvold\t\t- Office Security";
+ textBoxContributors.Text += "\r\n* Adrian Garside\t\t- WEX";
+ textBoxContributors.Text += "\r\n* Scott Bradner\t\t- Surface";
+ textBoxContributors.Text += "\r\n* Aleks Gershaft\t\t- Windows Azure";
+ textBoxContributors.Text += "\r\n* Chinh Huynh\t\t- Windows Azure";
+ textBoxContributors.Text += "\r\n* Long Nguyen\t\t- Data Center";
+ textBoxContributors.Text += "\r\n* Triet Le\t\t\t- Cloud Engineering";
+ textBoxContributors.Text += "\r\n* Luke Schoen\t\t- Excel";
+ textBoxContributors.Text += "\r\n* Bao Nguyen\t\t- Bing";
+ textBoxContributors.Text += "\r\n* Ross Nichols\t\t- Windows";
+ textBoxContributors.Text += "\r\n* Ryan Baltazar\t\t- Windows";
+ textBoxContributors.Text += "\r\n* Ed Essey\t\t- The Garage";
+ textBoxContributors.Text += "\r\n* Mario Madden\t\t- The Garage";
+ textBoxContributors.Text += "\r\n* Karthick Mahalingam\t- ACE";
+ textBoxContributors.Text += "\r\n* Pooja Kamra\t\t- ACE";
+ textBoxContributors.Text += "\r\n* Justin White\t\t- SA";
+ textBoxContributors.Text += "\r\n* Chris Ransom\t\t- SA";
+ textBoxContributors.Text += "\r\n* Mike Ricks\t\t- Red Team";
+ textBoxContributors.Text += "\r\n* Randy Santossio\t\t- Surface";
+ textBoxContributors.Text += "\r\n* Ashish Sen Jaswal\t\t- Device Health";
+ textBoxContributors.Text += "\r\n* Zoltan Harmath\t\t- Security Tools";
+ textBoxContributors.Text += "\r\n* Luciano Krigun\t\t- Security Products";
+ textBoxContributors.Text += "\r\n* Jo Hemmerlein\t\t- Red Team";
+ textBoxContributors.Text += "\r\n* Chris Johnson\t\t- Surface Hub";
+ textBoxContributors.Text += "\r\n* Loren Ponten\t\t- Surface Hub";
+ textBoxContributors.Text += "\r\n* Paul Schmitt\t\t- WWL";
+
+ textBoxContributors.Text += "\r\n\r\n* And many other Users!";
+ }
+
+ internal static string AssemblyTitle
+ {
+ get
+ {
+ object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false);
+ if (attributes.Length > 0)
+ {
+ AssemblyTitleAttribute titleAttribute = (AssemblyTitleAttribute)attributes[0];
+ if (titleAttribute.Title != null && titleAttribute.Title.Length > 0)
+ {
+ return titleAttribute.Title;
+ }
+ }
+
+ return System.IO.Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().Location);
+ }
+ }
+
+ internal static string AssemblyVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString();
+
+ internal static string AssemblyDescription
+ {
+ get
+ {
+ object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
+ return attributes.Length == 0 ? string.Empty : ((AssemblyDescriptionAttribute)attributes[0]).Description;
+ }
+ }
+
+ internal static string AssemblyProduct
+ {
+ get
+ {
+ object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false);
+ return attributes.Length == 0 ? string.Empty : ((AssemblyProductAttribute)attributes[0]).Product;
+ }
+ }
+
+ internal static string AssemblyCopyright
+ {
+ get
+ {
+ object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCopyrightAttribute), false);
+ return attributes.Length == 0 ? string.Empty : ((AssemblyCopyrightAttribute)attributes[0]).Copyright;
+ }
+ }
+
+ internal static string AssemblyCompany
+ {
+ get
+ {
+ object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyCompanyAttribute), false);
+ return attributes.Length == 0 ? string.Empty : ((AssemblyCompanyAttribute)attributes[0]).Company;
+ }
+ }
+
+ private void FrmAbout_FormClosed(object sender, FormClosedEventArgs e)
+ {
+ Common.AboutForm = null;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmAbout.resx b/src/modules/MouseWithoutBorders/App/Form/frmAbout.resx
new file mode 100644
index 000000000000..6d666394cbfc
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmAbout.resx
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ AAABAAIAICAAAAAAGACoDAAAJgAAABAQAAAAABgAaAMAAM4MAAAoAAAAIAAAAEAAAAABABgAAAAAAAAM
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32FIv3Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32EYv3Eo32AAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32BIf3GJD2Eov3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAEo32CYn3GZD2DIf4Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ QZv0FI72GpH2FIv3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32Con3HJH2FI72QJv0
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANJb1FI72GZD2Ho/2Eo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAEo32Eo32G5H2FI72NJb1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAPpr0Fo72GZD2Don3Eo32AAAAAAAAAAAAAAAAAAAAAAAAEo32BIj3HJH2
+ Fo72Ppr0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpn0
+ Fo/2GZD2II/2Eo32AAAAAAAAAAAAAAAAEo32E432HJH2Fo/2Opn0AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIo/2HJH2GZD2Foz3Eo32AAAAAAAAEo32
+ Cor3HJH2HJH2Io/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUZ7zA4f3Con3Con3Con3Con3
+ Con3Con3Con3DYv3HJH2HpL2HZH2GZD2GIz2Eo32Eo32C4v3HJH2HpL2HpL2HJH2DYv3Con3Con3Con3
+ Con3Con3Con3Con3AIX4Eo32WqLzD432Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2F4/2HZH2HpL2HpL2HZH2
+ EY32O5j0Npf0FI72HZH2HpL2HpL2HJH2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2C4v3Eo32frPvSaPy
+ TqTyTqTyTqTyTqTyTqTyTqTyT6XyV6jxIJH2HZH2HpL2Eo32Opv0AAAAAAAALJT2FY/2HpL2HJH2K5T1
+ V6nxT6TyTqTyTqTyTqTyTqTyTqTyTqTyRqHzEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2
+ GY72HZH2Eo32OJr0AAAAAAAAAAAAAAAAKZP1FY/2G5H2I5H2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2Ho/2GpH2Eo32PZz0AAAAAAAAAAAAAAAAAAAA
+ AAAAL5b1FY/2GJD2KJT2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAHZH2G472GZD2E432Npn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKJL1Fo/2Fo/2J5P2Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2HpD2GJD2FI72MZj1AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAJZL2Fo/2Fo/2KpT1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAHZH2FIv3GZD2E472MZf1AAAAAAAABAQEBAQEAAAAAAAAAAAAAAAABAQEBAQEAAAAAAAA
+ JZL2Fo/2Fo/2H4/3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32H5D2Doz2M5j0AAAA
+ AAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAJpL1D4z2J5T1Eo32AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32NJj1AAAAAAAAAAAABAQE//jwBAQEBAQEAAAAAAAABAQE
+ //jwBAQEBAQEAAAAAAAAAAAAMJb1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQE
+ AAAAAAAAAAAAAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////////////////////////v//f/x/
+ /j/4P/wf/B/4P/4P8H//B+D//4PB///Bg/8AAAAAAAAAAAABgAD/g8H//wfg//4P8H/8H/g/+DPMH/hh
+ hh/84Yc//+GH///zz/////////////////////////////////8oAAAAEAAAACAAAAABABgAAAAAAAAD
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32GJD2Eo32AAAAAAAAAAAAAAAAAAAA
+ AAAACYn3DIf4AAAAAAAAAAAAAAAAAAAAAAAANJb1GZD2Eo32AAAAAAAAAAAAAAAAEo32FI72AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAOpn0GZD2Eo32AAAAAAAAE432Fo/2AAAAAAAAAAAAAAAAAAAAA4f3Con3
+ Con3Con3DYv3HpL2GZD2Eo32C4v3HpL2HJH2Con3Con3Con3Con3Eo32SaPyTqTyTqTyTqTyV6jxHZH2
+ Eo32AAAALJT2HpL2K5T1T6TyTqTyTqTyTqTyEo32AAAAAAAAAAAAAAAAHo/2Eo32AAAAAAAAAAAAL5b1
+ GJD2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAHpD2FI72AAAAAAAAAAAAAAAAAAAAJZL2Fo/2Eo32AAAA
+ AAAAAAAAAAAAAAAAEo32Doz2AAAABAQEBAQEAAAABAQEBAQEAAAAJpL1J5T1AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAABAQEBAQEAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA//8AAP//AAD//wAA7/8AAMfnAADjzwAA8Z8AAAAAAAABAAAA848AAOfHAADJJwAA+T8AAP//
+ AAD//wAA//8AAA==
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.Designer.cs
new file mode 100644
index 000000000000..0f574470a814
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.Designer.cs
@@ -0,0 +1,59 @@
+namespace MouseWithoutBorders
+{
+ partial class FrmInputCallback
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmInputCallback));
+ this.SuspendLayout();
+ //
+ // frmInputCallback
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(61, 36);
+ this.ControlBox = false;
+ this.Enabled = false;
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "frmInputCallback";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
+ this.Text = "frmInputCallback";
+ this.Load += new System.EventHandler(this.FrmInputCallback_Load);
+ this.Shown += new System.EventHandler(this.FrmInputCallback_Shown);
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FrmInputCallback_FormClosing);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.cs b/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.cs
new file mode 100644
index 000000000000..fdb76ed90120
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.cs
@@ -0,0 +1,87 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.Windows.Forms;
+
+//
+// Keyboard/Mouse hook callbacks are handled in the message loop of this form.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+
+[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.frmInputCallback.#InstallKeyboardAndMouseHook()", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders
+{
+ internal partial class FrmInputCallback : System.Windows.Forms.Form
+ {
+ internal FrmInputCallback()
+ {
+ InitializeComponent();
+ }
+
+ private void FrmInputCallback_Load(object sender, EventArgs e)
+ {
+ InstallKeyboardAndMouseHook();
+ Left = 0;
+ Top = 0;
+ Width = 0;
+ Height = 0;
+ }
+
+ private void FrmInputCallback_Shown(object sender, EventArgs e)
+ {
+ Common.InputCallbackForm = this;
+ Visible = false;
+ }
+
+ private void FrmInputCallback_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ if (e.CloseReason != CloseReason.WindowsShutDown)
+ {
+ // e.Cancel = true;
+ }
+ }
+
+ internal void InstallKeyboardAndMouseHook()
+ {
+ /*
+ * Install hooks:
+ * According to http://msdn.microsoft.com/en-us/library/ms644986(VS.85).aspx
+ * we need to process the hook callback message fast enough so make the message loop thread a
+ * high priority thread. (Mouse/Keyboard event is important)
+ * */
+ try
+ {
+ Common.Hook = new InputHook();
+ Common.Hook.MouseEvent += new InputHook.MouseEvHandler(Common.MouseEvent);
+ Common.Hook.KeyboardEvent += new InputHook.KeybdEvHandler(Common.KeybdEvent);
+
+ Common.Log("(((((Keyboard/Mouse hooks installed/reinstalled!)))))");
+ /* The hook is called in the context of the thread that installed it.
+ * The call is made by sending a message to the thread that installed the hook.
+ * Therefore, the thread that installed the hook must have a message loop!!!
+ * */
+ }
+ catch (Win32Exception e)
+ {
+ _ = MessageBox.Show(
+ "Error installing Mouse/keyboard hook, error code: " + e.ErrorCode,
+ Application.ProductName,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Error);
+ Common.MainForm.Quit(false, false); // we are [STAThread] :)
+ }
+
+ // Thread.CurrentThread.Priority = ThreadPriority.Highest;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.resx b/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.resx
new file mode 100644
index 000000000000..26e4e779bd93
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmInputCallback.resx
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ AAABAAIAICAAAAAAGACoDAAAJgAAABAQAAAAABgAaAMAAM4MAAAoAAAAIAAAAEAAAAABABgAAAAAAAAM
+ AAAAAAAAAAAAAAAAAAAAAAAAuamfwamfxrS23c/O8ujl9+7q7+Xg49fR18zE1crD18/I2NDL2NLM2dPN
+ 2dTPw7y2uKacwamfxrS23c/O8ujl9+7q7+Xg49fR18zE1crD18/I2NDL2NLM2dPN2dTPwrqzx6uglXVi
+ 7qYbtIdFZ0pBbVBBcVVHdFpOd2BUemRYe2hcfGpgfm1jf3FlfW1j6ejmxKWZlXVi7qYbtIdFZ0pBbVBB
+ cVVHdFpOd2BUemRYe2hcfGpgfm1jf3FlfW1j5uLfw6afuo1bWKScp4hBZUlAYkc4ZEo5Y0w7ZU08ZU4+
+ ZlBAZlJAZ1NDZlNDYU076eflwKGYuo1bWKScp4hBZUlAYkc4ZEo5Y0w7ZU08ZU4+ZlBAZlJAZ1NDZlND
+ YU075uHew6adtJp9gHhQspJdsp2UsZuOrpyRrp6Srp6UsKKXsaKYsaSYsqSasqWasKOX4t/cwKCWtJp9
+ gHhQyp9kzqqZzamUs5+Srp6Srp6UsKKXsaKYsaSYsqSasqWasKOX39nVw6qhw29E2JRq4nU64WUb5G0n
+ 6HUu63027oU/8oxG9ZRN95pU+qFb/aZg/6le2NzfwKSbw29E/59qAAAAAAAAAAAAyWUn8X837oU/8oxG
+ 9ZRN95pU+qFb/aZg/6le1dbZxKuivm5Cyl8m1mAf22on3XAv4Xc25H4954VE6oxL7ZNS75lZ8p9f9KRj
+ +qdi19vewaWczms7PnhlAFVVAGJiAAACx2gu6YE+54VE6oxL7ZNS75lZ8p9f9KRj+qdi1dbXxKqhwnZO
+ zWs22GMk22gm3G4t33U04nw75YNC6IpJ65FQ7pdX8J1d9KNi+aVg19ncwaWb2nNFAHyBAqenAJOTAAAF
+ xWUr6H885YNC6IpJ65FQ7pdX8J1d9KNi+aVg1dTWw6qhw3hRz3RC12Uo2mcl3G0s33Qz4ns55YJB6YlI
+ 7JBP7ZZV8Zxc86Ji96Vg1tfawaWb83ZFAGprEv//AaKiAAABv2Eo53465YJB6YlI7JBP7ZZV8Zxc86Ji
+ 96Vg09LUw6mhw3hR1H9R2W802Wcm22sp3nIw4Xg35YA/54dG6o5N8JZU/6Zh8qBg96Rf1dTW2KSWAHF2
+ AO3tAIKCAAAA4mom6Hcy4Xg35YA/54dG6o5N7ZRT75pa8qBg96Rf08/Qw6igwnhR1YRZ3HhC2mor22sp
+ 3XEu4Hc25H4954VF7I5N44xONR0P/7Bp+KJe09HT4aWXAGxsDPT1AJOTAAAAyWAk4nMv4Hc25H4954VF
+ 6oxM7ZNS75lZ8p9f+KJe0c3OxKigwXNM1oZb34RT3HM422sq3m8u4XU05Hw754NC7YxK4YxOABQeuXRB
+ /6dg2c7PkJOJAJSUDdfXAF9hLxwR0GUo4XAv4XU05Hw754NC6opJ7JFQ75dX8p9d96Fcz8nKw6igvm5F
+ 1YZc3ohZ3XtE224w3W0s3nMy4Xo65IFB64lH4ZJUAIWNAAAA/8Nw6M/OAGpsAO7uAIODAAAA5XtD4XEy
+ 3W0s3nMy4Xo65IFB54hI6Y9P7JVW751b9Z9azsbGxKmgtmE0z4JZ14he14NW03M90Gov0m0v1HE01ng7
+ 3X9C1YVKAIGHAIiIAAAA/+3jAGVmFfr6AJSUAAAAzHtQ1nU/0Gov0m0v1HE01ng72X9D3IZI34tP4ZJU
+ 55VUzMPCxaqhrFAhxntVzoRbzoJbyXdJwmgzwGIpwWUsw2sxynE3wXZAAIGHAOnpAEhITR8cANnZBa2t
+ ABsejlo+1Ydf0n1Oym44wmQqwWUsw2sxx3E4yHc9y3xDzYJI0IVGzsG/xKSbokQXtGdEu3RSvXhXvHdW
+ uXBKtWhBtmo/t21EvHNJtnhSAICEAP//AKqqAAEBAK+vAFxcAAAAkFxAi1xCiFg9fUkqrmM9t2tAt21E
+ uXNJvHlRwIJZxIpiy49nzb231M3KzLq0y7q0yLavxrOsxbOtxrOtx7ev0MG83tLO7+Hf4t3bAHV2AP//
+ AP//AHt7AAAAAAAAAAAAAAAAAAAAAAAAAAAAn5ON1sbB3tLO6+De7OLh4tfU0sO+xbOru6qht6WbwKie
+ xrS339HR9u3q+/Pw8url5drV183F1MnD2M7HzcnEAHd4AP//AP//AP//AICAAJCQAJCQAJCQAKamAAAA
+ 5tvW8OTf183F1MnD1c3G1s7J19HM2dTP2tfSw7y2x6uglXVi7qYbtIdFZ0pBbVBBcVVHdFpOd2BUemRY
+ fmhceGpgAICBAP//AP//AP//AHBwAICAAICAAI6OACcoIRIJa09CdlxPd2BUemRYe2hcfGpgfm1jf3Fl
+ fW1j5uLfw6afuo1bWKScp4hBZUlAYkc4ZEo5Y0w7ZU08ZU4+aE8/Y1NCAIOEAP//AP//AN/fAHV1AICA
+ AISEAF5fIxwYZ0s8Z0w7Y0w7ZU08ZU4+ZlBAZlJAZ1NDZlNDYU075uHew6adtJp9gHhQspJdsp2UsZuO
+ rpyRrp6Srp6UsKKXtKOYq6CVAHx9AP//AP//AGZmAICAAICAAJ2dAAAArJOFtZ6RrpyRrp6Srp6UsKKX
+ saKYsaSYsqSasqWasKOX39nVw6qhw29E2JRq4nU64WUb5G0n6HUu63027oU/8oxG+ZRN7phVAHyDAP//
+ AP//AHBwAICAAJmZAAAA9YFB5mkf5G0n6HUu63027oU/8oxG9ZRN95pU+qFb/aZg/6le1dbZxKuivm5C
+ yl8m1mAf22on3XAv4Xc25H4954VE6oxL8JNR5pdYAH2EAP//AJ6eAHp6AI+PABYcjEIc2GEf3Goo3XAv
+ 4Xc25H4954VE6oxL7ZNS75lZ8p9f9KRj+qdi1dbXxKqhwnZOzWs22GMk22gm3G4t33U04nw75YNC6IpJ
+ 75JQ5pZYAH2EAP//AGtrAIWFAFpcLhML2nI62mQk22gm3G4t33U04nw75YNC6IpJ65FQ7pdX8J1d9KNi
+ +aVg1dTWw6qhw3hRz3RC12Uo2mcl3G0s33Qz4ns55YJB6YlI8JBO5ZRVAH+GAP//AHFxAKCgAAAA45Fm
+ 0XVD12Uo2mcl3G0s33Qz4ns55YJB6YlI7JBP7ZZV8Zxc86Ji96Vg09LUw6mhw3hR1H9R2W802Wcm22sp
+ 3nIw4Xg35YA/54dG7o9N5ZRVAHyDAHJyAJSUAAAA9NLHxHlR1H9R2W802Wcm22sp3nIw4Xg35YA/54dG
+ 6o5N7ZRT75pa8qBg96Rf08/Qw6igwnhR1YRZ3HhC2mor22sp3XEu4Hc25H4954VF7o1L5JJVAH+GAIeH
+ AA4RoZWRyqyjwnhR1YRZ3HhC2mor22sp3XEu4Hc25H4954VF6oxM7ZNS75lZ8p9f+KJe0c3OxKigwXNM
+ 1oZb34RT3HM422sq3m8u4XU05Hw754NC7YtI5JFTAH+GAFVWRxsF7ePfwqSbwXNM1oZb34RT3HM422sq
+ 3m8u4XU05Hw754NC6opJ7JFQ75dX8p9d96Fcz8nKw6igvm5F1YZc3ohZ3XtE224w3W0s3nMy4Xo65IFB
+ 64lH4ZNUAImSAAAA/75t0MrLwaSbvm5F1YZc3ohZ3XtE224w3W0s3nMy4Xo65IFB54hI6Y9P7JVW751b
+ 9Z9azsbGxKmgtmE0z4JZ14he14NW03M90Gov0m0v1HE01ng73YFE0HxCAAAA/7Ro55VUzsfGwqactmE0
+ z4JZ14he14NW03M90Gov0m0v1HE01ng72X9D3IZI34tP4ZJU55VUzMPCxaqhrFAhxntVzoRbzoJbyXdJ
+ wmgzwGIpwWUsw2sxyHI4xnU8hVAr1YdK0IVGz8TDw6edrFAhxntVzoRbzoJbyXdJwmgzwGIpwWUsw2sx
+ x3E4yHc9y3xDzYJI0IVGzsG/xKSbokQXtGdEu3RSvXhXvHdWuXBKtWhBtmo/t21EuXNJvXpRyIdbxIpi
+ y49nz8C7w6GYokQXtGdEu3RSvXhXvHdWuXBKtWhBtmo/t21EuXNJvHlRwIJZxIpiy49nzb230snGyriy
+ y7q0yrmyyriyybmzybiyybqz0MK93dHN6N7c6uDf4NbT0sXAxravuqmg1MzJyriyy7q0yrmyyriyybmz
+ ybiyybqz0MK93dHN6N7c6uDf4NbT0sXAxravvKyjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAEAAAACAAAAABABgAAAAAAAAD
+ AAAAAAAAAAAAAAAAAAAAAAAAsZqU4bR1sJ+es6CXqpmPraGZraOaxcG+r5SN4bR1rp6ds6CXqpmPraGZ
+ raObw7u2xKGKdI5ge2lpeG5meXBpenJqdmxktLKvwJqCjZZhq35vem9meXBpenJqdmxls6ymv4124W0y
+ 6mcY83ov+YtB/5pQ/6ZX9NCtzoRpS047AAAA/nws+4xB/5pQ/6ZX7cajwZWC0mIk22gn4Hg35oZG7JNT
+ +KBb6Mir+oRhALa+AEhW6nEs54dG7JNT851a5MCiwJN/2npH2WUi33My5oNC75JR0IFF98alaXp5AOPn
+ bRAA83435YJC7JBP85pW47yev45534lb3W8w4W8t54A//5lSABce/+SwCKGkAGZuxlch5nIu54A/7I5N
+ 9JpV4riZtnxg0IFV0ntNxl8gyGYn5nAqALG+XiwrAOboFSwp/5Rg02opyGUmznM01H071KmKw6CSvZCB
+ wpiHvpJ+yqCL8bKdAMnOAIODACkqKAAAOSAVWz4v1amU27Wk0a6aw6marpmT5Lh2sKOjs6SdppiRupiR
+ ALm7AP//AHZ2AKusABwez7auppiRp52XqKKcw7+6xKGKdI5ge2lpeG5lenBpjGlgAMbIAN3dAHh3AFhg
+ impje3BoeXBpe3Jqdmxls6umv4124W0y6mcY83ov+YtB/5VDAMbTAKOiAHJ7qjkJ928g8nov+YtB/5pQ
+ /6ZX7cajwZWC0mIk22gn4Hg35oZG/49HANPhAIKEMSAY8HQz2mgn4Hg35oZG7JNT851a5MCiwJN/2npH
+ 2WUi33My5oNC/5VMAHyKCi0y+Led2HhF2WUi33My5oNC7JBP85pW47yev45534lb3W8w4W8t54A//5hP
+ AEFX6beWvIdy34lc3W8w4W8t54A/7I5N9JpV4riZt3xg0IBV0XtMxl8gyGYn03Qzk08c5biVsnVZ0IFV
+ 0XtMxl8gyGYnznM01H071KmKwZ6Qv5SBwp2NvZWExZ+M1LOi17SfxK6iwZyPv5SBwp2NvZWExZ+M1LKi
+ zK6bw6yfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAA==
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmLogon.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/frmLogon.Designer.cs
new file mode 100644
index 000000000000..7ea4ffff7f10
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmLogon.Designer.cs
@@ -0,0 +1,77 @@
+namespace MouseWithoutBorders
+{
+ partial class frmLogon
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmLogon));
+ this.labelDesktop = new System.Windows.Forms.Label();
+ this.SuspendLayout();
+ //
+ // labelDesktop
+ //
+ this.labelDesktop.AutoSize = true;
+ this.labelDesktop.BackColor = System.Drawing.Color.White;
+ this.labelDesktop.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
+ this.labelDesktop.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.labelDesktop.ForeColor = System.Drawing.Color.LimeGreen;
+ this.labelDesktop.Location = new System.Drawing.Point(1, 1);
+ this.labelDesktop.Name = "labelDesktop";
+ this.labelDesktop.Size = new System.Drawing.Size(80, 15);
+ this.labelDesktop.TabIndex = 0;
+ this.labelDesktop.Text = "MouseWithoutBorders";
+ //
+ // frmLogon
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.ClientSize = new System.Drawing.Size(83, 17);
+ this.ControlBox = false;
+ this.Controls.Add(this.labelDesktop);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "frmLogon";
+ this.Opacity = 0.5;
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.Text = "MouseWithoutBorders";
+ this.TopMost = true;
+ this.Load += new System.EventHandler(this.frmLogon_Load);
+ this.Shown += new System.EventHandler(this.frmLogon_Shown);
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.frmLogon_FormClosing);
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label labelDesktop;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmLogon.cs b/src/modules/MouseWithoutBorders/App/Form/frmLogon.cs
new file mode 100644
index 000000000000..6b3ff4a26a23
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmLogon.cs
@@ -0,0 +1,51 @@
+/*
+ * File name: frmLogon.cs (not used)
+ * History:
+ * Truong Do (ductdo) 2008-10-XX Created/Updated
+ * */
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ internal partial class frmLogon : Form
+ {
+ internal System.Windows.Forms.Label LabelDesktop
+ {
+ get { return labelDesktop; }
+ set { labelDesktop = value; }
+ }
+
+ internal frmLogon()
+ {
+ InitializeComponent();
+ }
+
+ private void frmLogon_Load(object sender, EventArgs e)
+ {
+ Left = 10;
+ Top = 10;
+ Width = labelDesktop.Width + 2;
+ Height = labelDesktop.Height + 2;
+ }
+
+ private void frmLogon_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ if (e.CloseReason != CloseReason.WindowsShutDown)
+ {
+ e.Cancel = true;
+ }
+ }
+
+ private void frmLogon_Shown(object sender, EventArgs e)
+ {
+ //Common.SetForegroundWindow(Common.GetDesktopWindow());
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmLogon.resx b/src/modules/MouseWithoutBorders/App/Form/frmLogon.resx
new file mode 100644
index 000000000000..26e4e779bd93
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmLogon.resx
@@ -0,0 +1,195 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ AAABAAIAICAAAAAAGACoDAAAJgAAABAQAAAAABgAaAMAAM4MAAAoAAAAIAAAAEAAAAABABgAAAAAAAAM
+ AAAAAAAAAAAAAAAAAAAAAAAAuamfwamfxrS23c/O8ujl9+7q7+Xg49fR18zE1crD18/I2NDL2NLM2dPN
+ 2dTPw7y2uKacwamfxrS23c/O8ujl9+7q7+Xg49fR18zE1crD18/I2NDL2NLM2dPN2dTPwrqzx6uglXVi
+ 7qYbtIdFZ0pBbVBBcVVHdFpOd2BUemRYe2hcfGpgfm1jf3FlfW1j6ejmxKWZlXVi7qYbtIdFZ0pBbVBB
+ cVVHdFpOd2BUemRYe2hcfGpgfm1jf3FlfW1j5uLfw6afuo1bWKScp4hBZUlAYkc4ZEo5Y0w7ZU08ZU4+
+ ZlBAZlJAZ1NDZlNDYU076eflwKGYuo1bWKScp4hBZUlAYkc4ZEo5Y0w7ZU08ZU4+ZlBAZlJAZ1NDZlND
+ YU075uHew6adtJp9gHhQspJdsp2UsZuOrpyRrp6Srp6UsKKXsaKYsaSYsqSasqWasKOX4t/cwKCWtJp9
+ gHhQyp9kzqqZzamUs5+Srp6Srp6UsKKXsaKYsaSYsqSasqWasKOX39nVw6qhw29E2JRq4nU64WUb5G0n
+ 6HUu63027oU/8oxG9ZRN95pU+qFb/aZg/6le2NzfwKSbw29E/59qAAAAAAAAAAAAyWUn8X837oU/8oxG
+ 9ZRN95pU+qFb/aZg/6le1dbZxKuivm5Cyl8m1mAf22on3XAv4Xc25H4954VE6oxL7ZNS75lZ8p9f9KRj
+ +qdi19vewaWczms7PnhlAFVVAGJiAAACx2gu6YE+54VE6oxL7ZNS75lZ8p9f9KRj+qdi1dbXxKqhwnZO
+ zWs22GMk22gm3G4t33U04nw75YNC6IpJ65FQ7pdX8J1d9KNi+aVg19ncwaWb2nNFAHyBAqenAJOTAAAF
+ xWUr6H885YNC6IpJ65FQ7pdX8J1d9KNi+aVg1dTWw6qhw3hRz3RC12Uo2mcl3G0s33Qz4ns55YJB6YlI
+ 7JBP7ZZV8Zxc86Ji96Vg1tfawaWb83ZFAGprEv//AaKiAAABv2Eo53465YJB6YlI7JBP7ZZV8Zxc86Ji
+ 96Vg09LUw6mhw3hR1H9R2W802Wcm22sp3nIw4Xg35YA/54dG6o5N8JZU/6Zh8qBg96Rf1dTW2KSWAHF2
+ AO3tAIKCAAAA4mom6Hcy4Xg35YA/54dG6o5N7ZRT75pa8qBg96Rf08/Qw6igwnhR1YRZ3HhC2mor22sp
+ 3XEu4Hc25H4954VF7I5N44xONR0P/7Bp+KJe09HT4aWXAGxsDPT1AJOTAAAAyWAk4nMv4Hc25H4954VF
+ 6oxM7ZNS75lZ8p9f+KJe0c3OxKigwXNM1oZb34RT3HM422sq3m8u4XU05Hw754NC7YxK4YxOABQeuXRB
+ /6dg2c7PkJOJAJSUDdfXAF9hLxwR0GUo4XAv4XU05Hw754NC6opJ7JFQ75dX8p9d96Fcz8nKw6igvm5F
+ 1YZc3ohZ3XtE224w3W0s3nMy4Xo65IFB64lH4ZJUAIWNAAAA/8Nw6M/OAGpsAO7uAIODAAAA5XtD4XEy
+ 3W0s3nMy4Xo65IFB54hI6Y9P7JVW751b9Z9azsbGxKmgtmE0z4JZ14he14NW03M90Gov0m0v1HE01ng7
+ 3X9C1YVKAIGHAIiIAAAA/+3jAGVmFfr6AJSUAAAAzHtQ1nU/0Gov0m0v1HE01ng72X9D3IZI34tP4ZJU
+ 55VUzMPCxaqhrFAhxntVzoRbzoJbyXdJwmgzwGIpwWUsw2sxynE3wXZAAIGHAOnpAEhITR8cANnZBa2t
+ ABsejlo+1Ydf0n1Oym44wmQqwWUsw2sxx3E4yHc9y3xDzYJI0IVGzsG/xKSbokQXtGdEu3RSvXhXvHdW
+ uXBKtWhBtmo/t21EvHNJtnhSAICEAP//AKqqAAEBAK+vAFxcAAAAkFxAi1xCiFg9fUkqrmM9t2tAt21E
+ uXNJvHlRwIJZxIpiy49nzb231M3KzLq0y7q0yLavxrOsxbOtxrOtx7ev0MG83tLO7+Hf4t3bAHV2AP//
+ AP//AHt7AAAAAAAAAAAAAAAAAAAAAAAAAAAAn5ON1sbB3tLO6+De7OLh4tfU0sO+xbOru6qht6WbwKie
+ xrS339HR9u3q+/Pw8url5drV183F1MnD2M7HzcnEAHd4AP//AP//AP//AICAAJCQAJCQAJCQAKamAAAA
+ 5tvW8OTf183F1MnD1c3G1s7J19HM2dTP2tfSw7y2x6uglXVi7qYbtIdFZ0pBbVBBcVVHdFpOd2BUemRY
+ fmhceGpgAICBAP//AP//AP//AHBwAICAAICAAI6OACcoIRIJa09CdlxPd2BUemRYe2hcfGpgfm1jf3Fl
+ fW1j5uLfw6afuo1bWKScp4hBZUlAYkc4ZEo5Y0w7ZU08ZU4+aE8/Y1NCAIOEAP//AP//AN/fAHV1AICA
+ AISEAF5fIxwYZ0s8Z0w7Y0w7ZU08ZU4+ZlBAZlJAZ1NDZlNDYU075uHew6adtJp9gHhQspJdsp2UsZuO
+ rpyRrp6Srp6UsKKXtKOYq6CVAHx9AP//AP//AGZmAICAAICAAJ2dAAAArJOFtZ6RrpyRrp6Srp6UsKKX
+ saKYsaSYsqSasqWasKOX39nVw6qhw29E2JRq4nU64WUb5G0n6HUu63027oU/8oxG+ZRN7phVAHyDAP//
+ AP//AHBwAICAAJmZAAAA9YFB5mkf5G0n6HUu63027oU/8oxG9ZRN95pU+qFb/aZg/6le1dbZxKuivm5C
+ yl8m1mAf22on3XAv4Xc25H4954VE6oxL8JNR5pdYAH2EAP//AJ6eAHp6AI+PABYcjEIc2GEf3Goo3XAv
+ 4Xc25H4954VE6oxL7ZNS75lZ8p9f9KRj+qdi1dbXxKqhwnZOzWs22GMk22gm3G4t33U04nw75YNC6IpJ
+ 75JQ5pZYAH2EAP//AGtrAIWFAFpcLhML2nI62mQk22gm3G4t33U04nw75YNC6IpJ65FQ7pdX8J1d9KNi
+ +aVg1dTWw6qhw3hRz3RC12Uo2mcl3G0s33Qz4ns55YJB6YlI8JBO5ZRVAH+GAP//AHFxAKCgAAAA45Fm
+ 0XVD12Uo2mcl3G0s33Qz4ns55YJB6YlI7JBP7ZZV8Zxc86Ji96Vg09LUw6mhw3hR1H9R2W802Wcm22sp
+ 3nIw4Xg35YA/54dG7o9N5ZRVAHyDAHJyAJSUAAAA9NLHxHlR1H9R2W802Wcm22sp3nIw4Xg35YA/54dG
+ 6o5N7ZRT75pa8qBg96Rf08/Qw6igwnhR1YRZ3HhC2mor22sp3XEu4Hc25H4954VF7o1L5JJVAH+GAIeH
+ AA4RoZWRyqyjwnhR1YRZ3HhC2mor22sp3XEu4Hc25H4954VF6oxM7ZNS75lZ8p9f+KJe0c3OxKigwXNM
+ 1oZb34RT3HM422sq3m8u4XU05Hw754NC7YtI5JFTAH+GAFVWRxsF7ePfwqSbwXNM1oZb34RT3HM422sq
+ 3m8u4XU05Hw754NC6opJ7JFQ75dX8p9d96Fcz8nKw6igvm5F1YZc3ohZ3XtE224w3W0s3nMy4Xo65IFB
+ 64lH4ZNUAImSAAAA/75t0MrLwaSbvm5F1YZc3ohZ3XtE224w3W0s3nMy4Xo65IFB54hI6Y9P7JVW751b
+ 9Z9azsbGxKmgtmE0z4JZ14he14NW03M90Gov0m0v1HE01ng73YFE0HxCAAAA/7Ro55VUzsfGwqactmE0
+ z4JZ14he14NW03M90Gov0m0v1HE01ng72X9D3IZI34tP4ZJU55VUzMPCxaqhrFAhxntVzoRbzoJbyXdJ
+ wmgzwGIpwWUsw2sxyHI4xnU8hVAr1YdK0IVGz8TDw6edrFAhxntVzoRbzoJbyXdJwmgzwGIpwWUsw2sx
+ x3E4yHc9y3xDzYJI0IVGzsG/xKSbokQXtGdEu3RSvXhXvHdWuXBKtWhBtmo/t21EuXNJvXpRyIdbxIpi
+ y49nz8C7w6GYokQXtGdEu3RSvXhXvHdWuXBKtWhBtmo/t21EuXNJvHlRwIJZxIpiy49nzb230snGyriy
+ y7q0yrmyyriyybmzybiyybqz0MK93dHN6N7c6uDf4NbT0sXAxravuqmg1MzJyriyy7q0yrmyyriyybmz
+ ybiyybqz0MK93dHN6N7c6uDf4NbT0sXAxravvKyjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAEAAAACAAAAABABgAAAAAAAAD
+ AAAAAAAAAAAAAAAAAAAAAAAAsZqU4bR1sJ+es6CXqpmPraGZraOaxcG+r5SN4bR1rp6ds6CXqpmPraGZ
+ raObw7u2xKGKdI5ge2lpeG5meXBpenJqdmxktLKvwJqCjZZhq35vem9meXBpenJqdmxls6ymv4124W0y
+ 6mcY83ov+YtB/5pQ/6ZX9NCtzoRpS047AAAA/nws+4xB/5pQ/6ZX7cajwZWC0mIk22gn4Hg35oZG7JNT
+ +KBb6Mir+oRhALa+AEhW6nEs54dG7JNT851a5MCiwJN/2npH2WUi33My5oNC75JR0IFF98alaXp5AOPn
+ bRAA83435YJC7JBP85pW47yev45534lb3W8w4W8t54A//5lSABce/+SwCKGkAGZuxlch5nIu54A/7I5N
+ 9JpV4riZtnxg0IFV0ntNxl8gyGYn5nAqALG+XiwrAOboFSwp/5Rg02opyGUmznM01H071KmKw6CSvZCB
+ wpiHvpJ+yqCL8bKdAMnOAIODACkqKAAAOSAVWz4v1amU27Wk0a6aw6marpmT5Lh2sKOjs6SdppiRupiR
+ ALm7AP//AHZ2AKusABwez7auppiRp52XqKKcw7+6xKGKdI5ge2lpeG5lenBpjGlgAMbIAN3dAHh3AFhg
+ impje3BoeXBpe3Jqdmxls6umv4124W0y6mcY83ov+YtB/5VDAMbTAKOiAHJ7qjkJ928g8nov+YtB/5pQ
+ /6ZX7cajwZWC0mIk22gn4Hg35oZG/49HANPhAIKEMSAY8HQz2mgn4Hg35oZG7JNT851a5MCiwJN/2npH
+ 2WUi33My5oNC/5VMAHyKCi0y+Led2HhF2WUi33My5oNC7JBP85pW47yev45534lb3W8w4W8t54A//5hP
+ AEFX6beWvIdy34lc3W8w4W8t54A/7I5N9JpV4riZt3xg0IBV0XtMxl8gyGYn03Qzk08c5biVsnVZ0IFV
+ 0XtMxl8gyGYnznM01H071KmKwZ6Qv5SBwp2NvZWExZ+M1LOi17SfxK6iwZyPv5SBwp2NvZWExZ+M1LKi
+ zK6bw6yfAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAA==
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMatrix.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/frmMatrix.Designer.cs
new file mode 100644
index 000000000000..2071c8f1abd3
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmMatrix.Designer.cs
@@ -0,0 +1,1160 @@
+using System.Windows.Forms;
+using System.Collections.Generic;
+
+namespace MouseWithoutBorders
+{
+ partial class FrmMatrix
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMatrix));
+ this.pictureBoxMouseWithoutBorders0 = new System.Windows.Forms.PictureBox();
+ this.toolTip = new System.Windows.Forms.ToolTip(this.components);
+ this.comboBoxLockMachine = new System.Windows.Forms.ComboBox();
+ this.comboBoxSwitchToAllPC = new System.Windows.Forms.ComboBox();
+ this.comboBoxReconnect = new System.Windows.Forms.ComboBox();
+ this.checkBoxTwoRow = new System.Windows.Forms.CheckBox();
+ this.comboBoxEasyMouse = new System.Windows.Forms.ComboBox();
+ this.checkBoxDrawMouse = new System.Windows.Forms.CheckBox();
+ this.checkBoxMouseMoveRelatively = new System.Windows.Forms.CheckBox();
+ this.checkBoxHideMouse = new System.Windows.Forms.CheckBox();
+ this.checkBoxBlockMouseAtCorners = new System.Windows.Forms.CheckBox();
+ this.checkBoxCircle = new System.Windows.Forms.CheckBox();
+ this.checkBoxBlockScreenSaver = new System.Windows.Forms.CheckBox();
+ this.checkBoxHideLogo = new System.Windows.Forms.CheckBox();
+ this.checkBoxShareClipboard = new System.Windows.Forms.CheckBox();
+ this.checkBoxDisableCAD = new System.Windows.Forms.CheckBox();
+ this.buttonOK = new System.Windows.Forms.Button();
+ this.checkBoxReverseLookup = new System.Windows.Forms.CheckBox();
+ this.checkBoxVKMap = new System.Windows.Forms.CheckBox();
+ this.comboBoxScreenCapture = new System.Windows.Forms.ComboBox();
+ this.checkBoxSameSubNet = new System.Windows.Forms.CheckBox();
+ this.checkBoxClipNetStatus = new System.Windows.Forms.CheckBox();
+ this.checkBoxSendLog = new System.Windows.Forms.CheckBox();
+ this.groupBoxKeySetup = new System.Windows.Forms.GroupBox();
+ this.buttonNewKey = new System.Windows.Forms.Button();
+ this.textBoxEnc = new System.Windows.Forms.TextBox();
+ this.LabelEnc = new System.Windows.Forms.Label();
+ this.checkBoxShowKey = new System.Windows.Forms.CheckBox();
+ this.labelEasyMouse = new System.Windows.Forms.Label();
+ this.comboBoxEasyMouseOption = new System.Windows.Forms.ComboBox();
+ this.checkBoxTransferFile = new System.Windows.Forms.CheckBox();
+ this.toolTipManual = new System.Windows.Forms.ToolTip(this.components);
+ this.tabPageOther = new System.Windows.Forms.TabPage();
+ this.groupBoxOtherOptions = new System.Windows.Forms.GroupBox();
+ this.groupBoxShortcuts = new System.Windows.Forms.GroupBox();
+ this.labelScreenCapture = new System.Windows.Forms.Label();
+ this.LabelToggleEasyMouse = new System.Windows.Forms.Label();
+ this.comboBoxExitMM = new System.Windows.Forms.ComboBox();
+ this.comboBoxShowSettings = new System.Windows.Forms.ComboBox();
+ this.labelReconnect = new System.Windows.Forms.Label();
+ this.labelSwitch2AllPCMode = new System.Windows.Forms.Label();
+ this.radioButtonDisable = new System.Windows.Forms.RadioButton();
+ this.radioButtonNum = new System.Windows.Forms.RadioButton();
+ this.radioButtonF1 = new System.Windows.Forms.RadioButton();
+ this.labelLockMachine = new System.Windows.Forms.Label();
+ this.labelExitMM = new System.Windows.Forms.Label();
+ this.labelShowSettings = new System.Windows.Forms.Label();
+ this.labelSwitchBetweenMachine = new System.Windows.Forms.Label();
+ this.tabPageMain = new System.Windows.Forms.TabPage();
+ this.buttonCancel = new System.Windows.Forms.Button();
+ this.groupBoxMachineMatrix = new System.Windows.Forms.GroupBox();
+ this.linkLabelReConfigure = new System.Windows.Forms.LinkLabel();
+ this.tabControlSetting = new System.Windows.Forms.TabControl();
+ this.tabPageAdvancedSettings = new System.Windows.Forms.TabPage();
+ this.pictureBoxMouseWithoutBorders = new System.Windows.Forms.PictureBox();
+ this.groupBoxDNS = new System.Windows.Forms.GroupBox();
+ this.textBoxMachineName2IP = new System.Windows.Forms.TextBox();
+ this.textBoxDNS = new System.Windows.Forms.TextBox();
+ this.linkLabelHelp = new System.Windows.Forms.LinkLabel();
+ this.linkLabelMiniLog = new System.Windows.Forms.LinkLabel();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBoxMouseWithoutBorders0)).BeginInit();
+ this.groupBoxKeySetup.SuspendLayout();
+ this.tabPageOther.SuspendLayout();
+ this.groupBoxOtherOptions.SuspendLayout();
+ this.groupBoxShortcuts.SuspendLayout();
+ this.tabPageMain.SuspendLayout();
+ this.groupBoxMachineMatrix.SuspendLayout();
+ this.tabControlSetting.SuspendLayout();
+ this.tabPageAdvancedSettings.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBoxMouseWithoutBorders)).BeginInit();
+ this.groupBoxDNS.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // pictureBoxMouseWithoutBorders0
+ //
+ this.pictureBoxMouseWithoutBorders0.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("pictureBoxMouseWithoutBorders0.BackgroundImage")));
+ this.pictureBoxMouseWithoutBorders0.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ this.pictureBoxMouseWithoutBorders0.Location = new System.Drawing.Point(590, 271);
+ this.pictureBoxMouseWithoutBorders0.Name = "pictureBoxMouseWithoutBorders0";
+ this.pictureBoxMouseWithoutBorders0.Size = new System.Drawing.Size(190, 54);
+ this.pictureBoxMouseWithoutBorders0.TabIndex = 16;
+ this.pictureBoxMouseWithoutBorders0.TabStop = false;
+ this.pictureBoxMouseWithoutBorders0.Visible = false;
+ //
+ // toolTip
+ //
+ this.toolTip.AutomaticDelay = 100;
+ this.toolTip.AutoPopDelay = 5000;
+ this.toolTip.InitialDelay = 100;
+ this.toolTip.ReshowDelay = 20;
+ this.toolTip.ToolTipIcon = System.Windows.Forms.ToolTipIcon.Info;
+ this.toolTip.ToolTipTitle = "Microsoft® Visual Studio® 2010";
+ //
+ // comboBoxLockMachine
+ //
+ this.comboBoxLockMachine.Enabled = true;
+ this.comboBoxLockMachine.FormattingEnabled = true;
+ this.comboBoxLockMachine.Items.AddRange(new object[] {
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "Disable"});
+ this.comboBoxLockMachine.Location = new System.Drawing.Point(230, 68);
+ this.comboBoxLockMachine.Name = "comboBoxLockMachine";
+ this.comboBoxLockMachine.Size = new System.Drawing.Size(54, 21);
+ this.comboBoxLockMachine.TabIndex = 205;
+ this.comboBoxLockMachine.Text = "L";
+ this.toolTip.SetToolTip(this.comboBoxLockMachine, "Hit this hotkey twice to lock all machines.");
+ this.comboBoxLockMachine.TextChanged += new System.EventHandler(this.ComboBoxLockMachine_TextChanged);
+ //
+ // comboBoxSwitchToAllPC
+ //
+ this.comboBoxSwitchToAllPC.Enabled = true;
+ this.comboBoxSwitchToAllPC.FormattingEnabled = true;
+ this.comboBoxSwitchToAllPC.Items.AddRange(new object[] {
+ "Ctrl*3",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "Disable"});
+ this.comboBoxSwitchToAllPC.Location = new System.Drawing.Point(490, 68);
+ this.comboBoxSwitchToAllPC.Name = "comboBoxSwitchToAllPC";
+ this.comboBoxSwitchToAllPC.Size = new System.Drawing.Size(56, 21);
+ this.comboBoxSwitchToAllPC.TabIndex = 206;
+ this.comboBoxSwitchToAllPC.Text = "Disabled";
+ this.toolTip.SetToolTip(this.comboBoxSwitchToAllPC, "Press Ctrl key three times fast or use Ctrl+Alt+[?]");
+ this.comboBoxSwitchToAllPC.TextChanged += new System.EventHandler(this.ComboBoxSwitchToAllPC_TextChanged);
+ //
+ // comboBoxReconnect
+ //
+ this.comboBoxReconnect.Enabled = true;
+ this.comboBoxReconnect.FormattingEnabled = true;
+ this.comboBoxReconnect.Items.AddRange(new object[] {
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "Disable"});
+ this.comboBoxReconnect.Location = new System.Drawing.Point(230, 95);
+ this.comboBoxReconnect.Name = "comboBoxReconnect";
+ this.comboBoxReconnect.Size = new System.Drawing.Size(54, 21);
+ this.comboBoxReconnect.TabIndex = 207;
+ this.comboBoxReconnect.Text = "R";
+ this.toolTip.SetToolTip(this.comboBoxReconnect, "Just in case the connection is lost for any reason.");
+ this.comboBoxReconnect.TextChanged += new System.EventHandler(this.ComboBoxReconnect_TextChanged);
+ //
+ // checkBoxTwoRow
+ //
+ this.checkBoxTwoRow.AutoSize = true;
+ this.checkBoxTwoRow.Location = new System.Drawing.Point(9, 205);
+ this.checkBoxTwoRow.Name = "checkBoxTwoRow";
+ this.checkBoxTwoRow.Size = new System.Drawing.Size(72, 17);
+ this.checkBoxTwoRow.TabIndex = 6;
+ this.checkBoxTwoRow.Text = "Two &Row";
+ this.toolTip.SetToolTip(this.checkBoxTwoRow, "Check this if you have machines above or below of each other so you can move mous" +
+ "e up and down to switch machine.");
+ this.checkBoxTwoRow.UseVisualStyleBackColor = true;
+ this.checkBoxTwoRow.CheckedChanged += new System.EventHandler(this.CheckBoxTwoRow_CheckedChanged);
+ //
+ // comboBoxEasyMouse
+ //
+ this.comboBoxEasyMouse.Enabled = true;
+ this.comboBoxEasyMouse.FormattingEnabled = true;
+ this.comboBoxEasyMouse.Items.AddRange(new object[] {
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "Disable"});
+ this.comboBoxEasyMouse.Location = new System.Drawing.Point(490, 122);
+ this.comboBoxEasyMouse.Name = "comboBoxEasyMouse";
+ this.comboBoxEasyMouse.Size = new System.Drawing.Size(56, 21);
+ this.comboBoxEasyMouse.TabIndex = 208;
+ this.comboBoxEasyMouse.Text = "E";
+ this.toolTip.SetToolTip(this.comboBoxEasyMouse, "Toggle Enable or Disable easy mouse. (Only works when Easy Mouse option is set to" +
+ " Enable or Disable)");
+ this.comboBoxEasyMouse.TextChanged += new System.EventHandler(this.ComboBoxEasyMouse_TextChanged);
+ //
+ // checkBoxDrawMouse
+ //
+ this.checkBoxDrawMouse.AutoSize = true;
+ this.checkBoxDrawMouse.Checked = true;
+ this.checkBoxDrawMouse.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.checkBoxDrawMouse.Location = new System.Drawing.Point(9, 118);
+ this.checkBoxDrawMouse.Name = "checkBoxDrawMouse";
+ this.checkBoxDrawMouse.Size = new System.Drawing.Size(117, 17);
+ this.checkBoxDrawMouse.TabIndex = 171;
+ this.checkBoxDrawMouse.Text = "&Draw mouse cursor";
+ this.toolTip.SetToolTip(this.checkBoxDrawMouse, "Mouse cursor may not be visible in Windows 10 and later versions of Windows when t" +
+ "here is no physical mouse attached.");
+ this.checkBoxDrawMouse.UseVisualStyleBackColor = true;
+ this.checkBoxDrawMouse.CheckedChanged += new System.EventHandler(this.CheckBoxDrawMouse_CheckedChanged);
+ //
+ // checkBoxMouseMoveRelatively
+ //
+ this.checkBoxMouseMoveRelatively.AutoSize = true;
+ this.checkBoxMouseMoveRelatively.Checked = true;
+ this.checkBoxMouseMoveRelatively.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.checkBoxMouseMoveRelatively.Location = new System.Drawing.Point(268, 53);
+ this.checkBoxMouseMoveRelatively.Name = "checkBoxMouseMoveRelatively";
+ this.checkBoxMouseMoveRelatively.Size = new System.Drawing.Size(131, 17);
+ this.checkBoxMouseMoveRelatively.TabIndex = 170;
+ this.checkBoxMouseMoveRelatively.Text = "&Move mouse relatively";
+ this.toolTip.SetToolTip(this.checkBoxMouseMoveRelatively, "Use this option when remote machine\'s monitor settings are different, or remote m" +
+ "achine has multiple monitors.");
+ this.checkBoxMouseMoveRelatively.UseVisualStyleBackColor = true;
+ this.checkBoxMouseMoveRelatively.CheckedChanged += new System.EventHandler(this.CheckBoxMouseMoveRelatively_CheckedChanged);
+ //
+ // checkBoxHideMouse
+ //
+ this.checkBoxHideMouse.AutoSize = true;
+ this.checkBoxHideMouse.Checked = true;
+ this.checkBoxHideMouse.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.checkBoxHideMouse.Location = new System.Drawing.Point(9, 96);
+ this.checkBoxHideMouse.Name = "checkBoxHideMouse";
+ this.checkBoxHideMouse.Size = new System.Drawing.Size(156, 17);
+ this.checkBoxHideMouse.TabIndex = 169;
+ this.checkBoxHideMouse.Text = "&Hide mouse at screen edge";
+ this.toolTip.SetToolTip(this.checkBoxHideMouse, "Hide the mouse cursor at the top edge of the screen when switching to other machi" +
+ "ne. This option also steals the focus from any full-screen app to ensure the key" +
+ "board input is redirected.");
+ this.checkBoxHideMouse.UseVisualStyleBackColor = true;
+ this.checkBoxHideMouse.CheckedChanged += new System.EventHandler(this.CheckBoxHideMouse_CheckedChanged);
+ //
+ // checkBoxBlockMouseAtCorners
+ //
+ this.checkBoxBlockMouseAtCorners.AutoSize = true;
+ this.checkBoxBlockMouseAtCorners.Location = new System.Drawing.Point(268, 75);
+ this.checkBoxBlockMouseAtCorners.Name = "checkBoxBlockMouseAtCorners";
+ this.checkBoxBlockMouseAtCorners.Size = new System.Drawing.Size(172, 17);
+ this.checkBoxBlockMouseAtCorners.TabIndex = 172;
+ this.checkBoxBlockMouseAtCorners.Text = "Block mouse at screen corners";
+ this.toolTip.SetToolTip(this.checkBoxBlockMouseAtCorners, "To avoid accident machine-switch at screen corners.");
+ this.checkBoxBlockMouseAtCorners.UseVisualStyleBackColor = true;
+ this.checkBoxBlockMouseAtCorners.CheckedChanged += new System.EventHandler(this.CheckBoxBlockMouseAtCorners_CheckedChanged);
+ //
+ // checkBoxCircle
+ //
+ this.checkBoxCircle.AutoSize = true;
+ this.checkBoxCircle.Location = new System.Drawing.Point(9, 11);
+ this.checkBoxCircle.Name = "checkBoxCircle";
+ this.checkBoxCircle.Size = new System.Drawing.Size(87, 17);
+ this.checkBoxCircle.TabIndex = 163;
+ this.checkBoxCircle.Text = "&Wrap Mouse";
+ this.toolTip.SetToolTip(this.checkBoxCircle, "Move control back to the first machine when mouse moves passing the last one");
+ this.checkBoxCircle.UseVisualStyleBackColor = true;
+ this.checkBoxCircle.CheckedChanged += new System.EventHandler(this.CheckBoxCircle_CheckedChanged);
+ //
+ // checkBoxBlockScreenSaver
+ //
+ this.checkBoxBlockScreenSaver.AutoSize = true;
+ this.checkBoxBlockScreenSaver.Checked = true;
+ this.checkBoxBlockScreenSaver.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.checkBoxBlockScreenSaver.Location = new System.Drawing.Point(268, 32);
+ this.checkBoxBlockScreenSaver.Name = "checkBoxBlockScreenSaver";
+ this.checkBoxBlockScreenSaver.Size = new System.Drawing.Size(211, 17);
+ this.checkBoxBlockScreenSaver.TabIndex = 168;
+ this.checkBoxBlockScreenSaver.Text = "&Block Screen Saver on other machines";
+ this.toolTip.SetToolTip(this.checkBoxBlockScreenSaver, "Prevent screen saver from starting on other machines when user is actively workin" +
+ "g on this machine.");
+ this.checkBoxBlockScreenSaver.UseVisualStyleBackColor = true;
+ this.checkBoxBlockScreenSaver.CheckedChanged += new System.EventHandler(this.CheckBoxBlockScreenSaver_CheckedChanged);
+ //
+ // checkBoxHideLogo
+ //
+ this.checkBoxHideLogo.AutoSize = true;
+ this.checkBoxHideLogo.Location = new System.Drawing.Point(9, 75);
+ this.checkBoxHideLogo.Name = "checkBoxHideLogo";
+ this.checkBoxHideLogo.Size = new System.Drawing.Size(164, 17);
+ this.checkBoxHideLogo.TabIndex = 167;
+ this.checkBoxHideLogo.Text = "Hide &logo from Logon Screen";
+ this.toolTip.SetToolTip(this.checkBoxHideLogo, "Hide the \"MouseWithoutBorders\" text from the logon desktop");
+ this.checkBoxHideLogo.UseVisualStyleBackColor = true;
+ this.checkBoxHideLogo.CheckedChanged += new System.EventHandler(this.CheckBoxHideLogo_CheckedChanged);
+ //
+ // checkBoxShareClipboard
+ //
+ this.checkBoxShareClipboard.AutoSize = true;
+ this.checkBoxShareClipboard.Checked = true;
+ this.checkBoxShareClipboard.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.checkBoxShareClipboard.Location = new System.Drawing.Point(9, 32);
+ this.checkBoxShareClipboard.Name = "checkBoxShareClipboard";
+ this.checkBoxShareClipboard.Size = new System.Drawing.Size(101, 17);
+ this.checkBoxShareClipboard.TabIndex = 165;
+ this.checkBoxShareClipboard.Text = "&Share Clipboard";
+ this.toolTip.SetToolTip(this.checkBoxShareClipboard, "If share clipboard stops working, Ctrl+Alt+Del then Esc may solve the problem.");
+ this.checkBoxShareClipboard.UseVisualStyleBackColor = true;
+ this.checkBoxShareClipboard.CheckedChanged += new System.EventHandler(this.CheckBoxShareClipboard_CheckedChanged);
+ //
+ // checkBoxDisableCAD
+ //
+ this.checkBoxDisableCAD.AutoSize = true;
+ this.checkBoxDisableCAD.Checked = true;
+ this.checkBoxDisableCAD.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.checkBoxDisableCAD.Location = new System.Drawing.Point(268, 11);
+ this.checkBoxDisableCAD.Name = "checkBoxDisableCAD";
+ this.checkBoxDisableCAD.Size = new System.Drawing.Size(86, 17);
+ this.checkBoxDisableCAD.TabIndex = 166;
+ this.checkBoxDisableCAD.Text = "Disable &CAD";
+ this.toolTip.SetToolTip(this.checkBoxDisableCAD, "Ctrl+Alt+Del not required on Logon screen");
+ this.checkBoxDisableCAD.UseVisualStyleBackColor = true;
+ this.checkBoxDisableCAD.CheckedChanged += new System.EventHandler(this.CheckBoxDisableCAD_CheckedChanged);
+ //
+ // buttonOK
+ //
+ this.buttonOK.Location = new System.Drawing.Point(187, 328);
+ this.buttonOK.Name = "buttonOK";
+ this.buttonOK.Size = new System.Drawing.Size(75, 23);
+ this.buttonOK.TabIndex = 20;
+ this.buttonOK.Text = "&Apply";
+ this.toolTip.SetToolTip(this.buttonOK, "Save changes and reconnect to the machines in the matrix.");
+ this.buttonOK.UseVisualStyleBackColor = true;
+ this.buttonOK.Click += new System.EventHandler(this.ButtonOK_Click);
+ //
+ // checkBoxReverseLookup
+ //
+ this.checkBoxReverseLookup.AutoSize = true;
+ this.checkBoxReverseLookup.Location = new System.Drawing.Point(9, 141);
+ this.checkBoxReverseLookup.Name = "checkBoxReverseLookup";
+ this.checkBoxReverseLookup.Size = new System.Drawing.Size(196, 17);
+ this.checkBoxReverseLookup.TabIndex = 173;
+ this.checkBoxReverseLookup.Text = "&Validate remote machine IP Address";
+ this.toolTip.SetToolTip(this.checkBoxReverseLookup, "Reverse DNS lookup to validate machine IP Address (Advanced option, click Help fo" +
+ "r any question)");
+ this.checkBoxReverseLookup.UseVisualStyleBackColor = true;
+ this.checkBoxReverseLookup.CheckedChanged += new System.EventHandler(this.CheckBoxReverseLookup_CheckedChanged);
+ //
+ // checkBoxVKMap
+ //
+ this.checkBoxVKMap.AutoSize = true;
+ this.checkBoxVKMap.Location = new System.Drawing.Point(268, 98);
+ this.checkBoxVKMap.Name = "checkBoxVKMap";
+ this.checkBoxVKMap.Size = new System.Drawing.Size(115, 17);
+ this.checkBoxVKMap.TabIndex = 174;
+ this.checkBoxVKMap.Text = "&Use Key Mappings";
+ this.toolTip.SetToolTip(this.checkBoxVKMap, "Use key mappings to translate your key presses. See http://aka.ms/mm for help.");
+ this.checkBoxVKMap.UseVisualStyleBackColor = true;
+ this.checkBoxVKMap.CheckedChanged += new System.EventHandler(this.CheckBoxVKMap_CheckedChanged);
+ //
+ // comboBoxScreenCapture
+ //
+ this.comboBoxScreenCapture.Enabled = false;
+ this.comboBoxScreenCapture.FormattingEnabled = true;
+ this.comboBoxScreenCapture.Items.AddRange(new object[] {
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "Disable"});
+ this.comboBoxScreenCapture.Location = new System.Drawing.Point(230, 121);
+ this.comboBoxScreenCapture.Name = "comboBoxScreenCapture";
+ this.comboBoxScreenCapture.Size = new System.Drawing.Size(54, 21);
+ this.comboBoxScreenCapture.TabIndex = 210;
+ this.comboBoxScreenCapture.Text = "S";
+ this.toolTip.SetToolTip(this.comboBoxScreenCapture, "Capture a selected area on the screen. Press this hotkey then hold left mouse but" +
+ "ton down and drag to select a screen area.");
+ this.comboBoxScreenCapture.TextChanged += new System.EventHandler(this.ComboBoxScreenCapture_TextChanged);
+ //
+ // checkBoxSameSubNet
+ //
+ this.checkBoxSameSubNet.AutoSize = true;
+ this.checkBoxSameSubNet.Location = new System.Drawing.Point(9, 162);
+ this.checkBoxSameSubNet.Name = "checkBoxSameSubNet";
+ this.checkBoxSameSubNet.Size = new System.Drawing.Size(114, 18);
+ this.checkBoxSameSubNet.TabIndex = 175;
+ this.checkBoxSameSubNet.Text = "Same subnet only";
+ this.toolTip.SetToolTip(this.checkBoxSameSubNet, "Only connect to machines in the same intranet NNN.NNN.*.* (only works when both m" +
+ "achines have IPv4 enabled)");
+ this.checkBoxSameSubNet.UseCompatibleTextRendering = true;
+ this.checkBoxSameSubNet.UseVisualStyleBackColor = true;
+ this.checkBoxSameSubNet.CheckedChanged += new System.EventHandler(this.CheckBoxSameSubNet_CheckedChanged);
+ //
+ // checkBoxClipNetStatus
+ //
+ this.checkBoxClipNetStatus.AutoSize = true;
+ this.checkBoxClipNetStatus.Location = new System.Drawing.Point(268, 119);
+ this.checkBoxClipNetStatus.Name = "checkBoxClipNetStatus";
+ this.checkBoxClipNetStatus.Size = new System.Drawing.Size(231, 18);
+ this.checkBoxClipNetStatus.TabIndex = 176;
+ this.checkBoxClipNetStatus.Text = "Show clipboard/&network status messages";
+ this.toolTip.SetToolTip(this.checkBoxClipNetStatus, "Show clipboard activities and network status in system tray notifications");
+ this.checkBoxClipNetStatus.UseCompatibleTextRendering = true;
+ this.checkBoxClipNetStatus.UseVisualStyleBackColor = true;
+ this.checkBoxClipNetStatus.CheckedChanged += new System.EventHandler(this.CheckBoxClipNetStatus_CheckedChanged);
+ //
+ // checkBoxSendLog
+ //
+ this.checkBoxSendLog.AutoSize = true;
+ this.checkBoxSendLog.Location = new System.Drawing.Point(268, 142);
+ this.checkBoxSendLog.Name = "checkBoxSendLog";
+ this.checkBoxSendLog.Size = new System.Drawing.Size(95, 18);
+ this.checkBoxSendLog.TabIndex = 177;
+ this.checkBoxSendLog.Text = "Send &error log";
+ this.toolTip.SetToolTip(this.checkBoxSendLog, "Send anonymous error log to Microsoft Garage to help improve the app.");
+ this.checkBoxSendLog.UseCompatibleTextRendering = true;
+ this.checkBoxSendLog.UseVisualStyleBackColor = true;
+ this.checkBoxSendLog.Visible = false;
+ this.checkBoxSendLog.CheckedChanged += new System.EventHandler(this.CheckBoxSendLog_CheckedChanged);
+ //
+ // groupBoxKeySetup
+ //
+ this.groupBoxKeySetup.Controls.Add(this.buttonNewKey);
+ this.groupBoxKeySetup.Controls.Add(this.textBoxEnc);
+ this.groupBoxKeySetup.Controls.Add(this.LabelEnc);
+ this.groupBoxKeySetup.Controls.Add(this.checkBoxShowKey);
+ this.groupBoxKeySetup.Location = new System.Drawing.Point(3, 6);
+ this.groupBoxKeySetup.Name = "groupBoxKeySetup";
+ this.groupBoxKeySetup.Size = new System.Drawing.Size(558, 66);
+ this.groupBoxKeySetup.TabIndex = 0;
+ this.groupBoxKeySetup.TabStop = false;
+ this.groupBoxKeySetup.Text = " &Shared encryption key";
+ this.toolTip.SetToolTip(this.groupBoxKeySetup, "Data sent/received is encrypted/decrypted using this key.");
+ //
+ // buttonNewKey
+ //
+ this.buttonNewKey.Location = new System.Drawing.Point(471, 19);
+ this.buttonNewKey.Name = "buttonNewKey";
+ this.buttonNewKey.Size = new System.Drawing.Size(75, 23);
+ this.buttonNewKey.TabIndex = 22;
+ this.buttonNewKey.Text = "New &Key";
+ this.buttonNewKey.UseVisualStyleBackColor = true;
+ this.buttonNewKey.Click += new System.EventHandler(this.ButtonNewKey_Click);
+ //
+ // textBoxEnc
+ //
+ this.textBoxEnc.Location = new System.Drawing.Point(86, 19);
+ this.textBoxEnc.MaxLength = 22;
+ this.textBoxEnc.Name = "textBoxEnc";
+ this.textBoxEnc.PasswordChar = '*';
+ this.textBoxEnc.Size = new System.Drawing.Size(304, 20);
+ this.textBoxEnc.TabIndex = 3;
+ this.toolTip.SetToolTip(this.textBoxEnc, "The key must be auto generated in one machine by click on New Key, then typed in " +
+ "other machines.");
+ //
+ // LabelEnc
+ //
+ this.LabelEnc.AutoSize = true;
+ this.LabelEnc.Location = new System.Drawing.Point(7, 25);
+ this.LabelEnc.Name = "LabelEnc";
+ this.LabelEnc.Size = new System.Drawing.Size(69, 13);
+ this.LabelEnc.TabIndex = 19;
+ this.LabelEnc.Text = "Security Key:";
+ //
+ // checkBoxShowKey
+ //
+ this.checkBoxShowKey.AutoSize = true;
+ this.checkBoxShowKey.Location = new System.Drawing.Point(396, 21);
+ this.checkBoxShowKey.Name = "checkBoxShowKey";
+ this.checkBoxShowKey.Size = new System.Drawing.Size(73, 17);
+ this.checkBoxShowKey.TabIndex = 4;
+ this.checkBoxShowKey.Text = "&Show text";
+ this.checkBoxShowKey.UseVisualStyleBackColor = true;
+ this.checkBoxShowKey.CheckedChanged += new System.EventHandler(this.CheckBoxShowKey_CheckedChanged);
+ //
+ // labelEasyMouse
+ //
+ this.labelEasyMouse.AutoSize = true;
+ this.labelEasyMouse.Location = new System.Drawing.Point(309, 98);
+ this.labelEasyMouse.Name = "labelEasyMouse";
+ this.labelEasyMouse.Size = new System.Drawing.Size(68, 13);
+ this.labelEasyMouse.TabIndex = 211;
+ this.labelEasyMouse.Text = "Easy Mouse:";
+ this.toolTip.SetToolTip(this.labelEasyMouse, "If easy mouse is not enabled, you can select to hold down Ctrl or Shift key to sw" +
+ "itch to other machines by mouse move.");
+ //
+ // comboBoxEasyMouseOption
+ //
+ this.comboBoxEasyMouseOption.Enabled = true;
+ this.comboBoxEasyMouseOption.FormattingEnabled = true;
+ this.comboBoxEasyMouseOption.Items.AddRange(new object[] {
+ "Enable",
+ "Ctrl",
+ "Shift",
+ "Disable"});
+ this.comboBoxEasyMouseOption.Location = new System.Drawing.Point(490, 94);
+ this.comboBoxEasyMouseOption.Name = "comboBoxEasyMouseOption";
+ this.comboBoxEasyMouseOption.Size = new System.Drawing.Size(56, 21);
+ this.comboBoxEasyMouseOption.TabIndex = 212;
+ this.comboBoxEasyMouseOption.Text = "Enable";
+ this.toolTip.SetToolTip(this.comboBoxEasyMouseOption, "Enable or disable easy machine switch by moving mouse passing the screen edge.");
+ this.comboBoxEasyMouseOption.TextChanged += new System.EventHandler(this.ComboBoxEasyMouseOption_TextChanged);
+ //
+ // checkBoxTransferFile
+ //
+ this.checkBoxTransferFile.AutoSize = true;
+ this.checkBoxTransferFile.Checked = true;
+ this.checkBoxTransferFile.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.checkBoxTransferFile.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.checkBoxTransferFile.Location = new System.Drawing.Point(26, 51);
+ this.checkBoxTransferFile.Name = "checkBoxTransferFile";
+ this.checkBoxTransferFile.Size = new System.Drawing.Size(81, 17);
+ this.checkBoxTransferFile.TabIndex = 178;
+ this.checkBoxTransferFile.Text = "&Transfer file";
+ this.toolTip.SetToolTip(this.checkBoxTransferFile, "If a file (<100MB) is copied, it will be transferred to the remote machine clipbo" +
+ "ard.");
+ this.checkBoxTransferFile.UseVisualStyleBackColor = true;
+ this.checkBoxTransferFile.CheckedChanged += new System.EventHandler(this.CheckBoxTransferFile_CheckedChanged);
+ //
+ // toolTipManual
+ //
+ this.toolTipManual.ToolTipTitle = "Microsoft® Visual Studio® 2010";
+ //
+ // tabPageOther
+ //
+ this.tabPageOther.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(246)))), ((int)(((byte)(245)))), ((int)(((byte)(242)))));
+ this.tabPageOther.Controls.Add(this.groupBoxOtherOptions);
+ this.tabPageOther.Controls.Add(this.groupBoxShortcuts);
+ this.tabPageOther.Location = new System.Drawing.Point(4, 25);
+ this.tabPageOther.Name = "tabPageOther";
+ this.tabPageOther.Padding = new System.Windows.Forms.Padding(3);
+ this.tabPageOther.Size = new System.Drawing.Size(563, 362);
+ this.tabPageOther.TabIndex = 1;
+ this.tabPageOther.Text = "Other Options";
+ //
+ // groupBoxOtherOptions
+ //
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxTransferFile);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxSendLog);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxClipNetStatus);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxSameSubNet);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxVKMap);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxReverseLookup);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxDrawMouse);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxMouseMoveRelatively);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxHideMouse);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxBlockMouseAtCorners);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxCircle);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxBlockScreenSaver);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxHideLogo);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxShareClipboard);
+ this.groupBoxOtherOptions.Controls.Add(this.checkBoxDisableCAD);
+ this.groupBoxOtherOptions.Dock = System.Windows.Forms.DockStyle.Top;
+ this.groupBoxOtherOptions.Location = new System.Drawing.Point(3, 3);
+ this.groupBoxOtherOptions.Name = "groupBoxOtherOptions";
+ this.groupBoxOtherOptions.Size = new System.Drawing.Size(557, 189);
+ this.groupBoxOtherOptions.TabIndex = 163;
+ this.groupBoxOtherOptions.TabStop = false;
+ //
+ // groupBoxShortcuts
+ //
+ this.groupBoxShortcuts.Controls.Add(this.comboBoxEasyMouseOption);
+ this.groupBoxShortcuts.Controls.Add(this.labelEasyMouse);
+ this.groupBoxShortcuts.Controls.Add(this.comboBoxScreenCapture);
+ this.groupBoxShortcuts.Controls.Add(this.labelScreenCapture);
+ this.groupBoxShortcuts.Controls.Add(this.comboBoxEasyMouse);
+ this.groupBoxShortcuts.Controls.Add(this.LabelToggleEasyMouse);
+ this.groupBoxShortcuts.Controls.Add(this.comboBoxReconnect);
+ this.groupBoxShortcuts.Controls.Add(this.comboBoxSwitchToAllPC);
+ this.groupBoxShortcuts.Controls.Add(this.comboBoxExitMM);
+ this.groupBoxShortcuts.Controls.Add(this.comboBoxLockMachine);
+ this.groupBoxShortcuts.Controls.Add(this.comboBoxShowSettings);
+ this.groupBoxShortcuts.Controls.Add(this.labelReconnect);
+ this.groupBoxShortcuts.Controls.Add(this.labelSwitch2AllPCMode);
+ this.groupBoxShortcuts.Controls.Add(this.radioButtonDisable);
+ this.groupBoxShortcuts.Controls.Add(this.radioButtonNum);
+ this.groupBoxShortcuts.Controls.Add(this.radioButtonF1);
+ this.groupBoxShortcuts.Controls.Add(this.labelLockMachine);
+ this.groupBoxShortcuts.Controls.Add(this.labelExitMM);
+ this.groupBoxShortcuts.Controls.Add(this.labelShowSettings);
+ this.groupBoxShortcuts.Controls.Add(this.labelSwitchBetweenMachine);
+ this.groupBoxShortcuts.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.groupBoxShortcuts.Location = new System.Drawing.Point(3, 198);
+ this.groupBoxShortcuts.Name = "groupBoxShortcuts";
+ this.groupBoxShortcuts.Size = new System.Drawing.Size(557, 161);
+ this.groupBoxShortcuts.TabIndex = 200;
+ this.groupBoxShortcuts.TabStop = false;
+ this.groupBoxShortcuts.Text = " &Keyboard Shortcuts ";
+ //
+ // labelScreenCapture
+ //
+ this.labelScreenCapture.AutoSize = true;
+ this.labelScreenCapture.Location = new System.Drawing.Point(6, 124);
+ this.labelScreenCapture.Name = "labelScreenCapture";
+ this.labelScreenCapture.Size = new System.Drawing.Size(173, 13);
+ this.labelScreenCapture.TabIndex = 209;
+ this.labelScreenCapture.Text = "Custom screen capture, Ctrl+Shift+:";
+ //
+ // LabelToggleEasyMouse
+ //
+ this.LabelToggleEasyMouse.AutoSize = true;
+ this.LabelToggleEasyMouse.Location = new System.Drawing.Point(309, 125);
+ this.LabelToggleEasyMouse.Name = "LabelToggleEasyMouse";
+ this.LabelToggleEasyMouse.Size = new System.Drawing.Size(149, 13);
+ this.LabelToggleEasyMouse.TabIndex = 114;
+ this.LabelToggleEasyMouse.Text = "Toggle Easy Mouse, Ctrl+Alt+:";
+ //
+ // comboBoxExitMM
+ //
+ this.comboBoxExitMM.Enabled = false;
+ this.comboBoxExitMM.FormattingEnabled = true;
+ this.comboBoxExitMM.Items.AddRange(new object[] {
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "Disable"});
+ this.comboBoxExitMM.Location = new System.Drawing.Point(490, 41);
+ this.comboBoxExitMM.Name = "comboBoxExitMM";
+ this.comboBoxExitMM.Size = new System.Drawing.Size(56, 21);
+ this.comboBoxExitMM.TabIndex = 204;
+ this.comboBoxExitMM.Text = "Q";
+ this.comboBoxExitMM.TextChanged += new System.EventHandler(this.ComboBoxExitMM_TextChanged);
+ //
+ // comboBoxShowSettings
+ //
+ this.comboBoxShowSettings.Enabled = false;
+ this.comboBoxShowSettings.FormattingEnabled = true;
+ this.comboBoxShowSettings.Items.AddRange(new object[] {
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ "G",
+ "H",
+ "I",
+ "J",
+ "K",
+ "L",
+ "M",
+ "N",
+ "O",
+ "P",
+ "Q",
+ "R",
+ "S",
+ "T",
+ "U",
+ "V",
+ "W",
+ "X",
+ "Y",
+ "Z",
+ "Disable"});
+ this.comboBoxShowSettings.Location = new System.Drawing.Point(230, 41);
+ this.comboBoxShowSettings.Name = "comboBoxShowSettings";
+ this.comboBoxShowSettings.Size = new System.Drawing.Size(54, 21);
+ this.comboBoxShowSettings.TabIndex = 203;
+ this.comboBoxShowSettings.Text = "M";
+ this.comboBoxShowSettings.TextChanged += new System.EventHandler(this.ComboBoxShowSettings_TextChanged);
+ //
+ // labelReconnect
+ //
+ this.labelReconnect.AutoSize = true;
+ this.labelReconnect.Location = new System.Drawing.Point(6, 98);
+ this.labelReconnect.Name = "labelReconnect";
+ this.labelReconnect.Size = new System.Drawing.Size(195, 13);
+ this.labelReconnect.TabIndex = 59;
+ this.labelReconnect.Text = "Reconnect to other machines, Ctrl+Alt+:";
+ //
+ // labelSwitch2AllPCMode
+ //
+ this.labelSwitch2AllPCMode.AutoSize = true;
+ this.labelSwitch2AllPCMode.Location = new System.Drawing.Point(309, 71);
+ this.labelSwitch2AllPCMode.Name = "labelSwitch2AllPCMode";
+ this.labelSwitch2AllPCMode.Size = new System.Drawing.Size(122, 13);
+ this.labelSwitch2AllPCMode.TabIndex = 33;
+ this.labelSwitch2AllPCMode.Text = "Switch to ALL PC mode:";
+ //
+ // radioButtonDisable
+ //
+ this.radioButtonDisable.AutoSize = true;
+ this.radioButtonDisable.Location = new System.Drawing.Point(434, 14);
+ this.radioButtonDisable.Name = "radioButtonDisable";
+ this.radioButtonDisable.Size = new System.Drawing.Size(60, 17);
+ this.radioButtonDisable.TabIndex = 202;
+ this.radioButtonDisable.TabStop = true;
+ this.radioButtonDisable.Text = "&Disable";
+ this.radioButtonDisable.UseVisualStyleBackColor = true;
+ this.radioButtonDisable.CheckedChanged += new System.EventHandler(this.RadioButton_CheckedChanged);
+ //
+ // radioButtonNum
+ //
+ this.radioButtonNum.AutoSize = true;
+ this.radioButtonNum.Location = new System.Drawing.Point(346, 15);
+ this.radioButtonNum.Name = "radioButtonNum";
+ this.radioButtonNum.Size = new System.Drawing.Size(67, 17);
+ this.radioButtonNum.TabIndex = 201;
+ this.radioButtonNum.TabStop = true;
+ this.radioButtonNum.Text = "&1, 2, 3, 4";
+ this.radioButtonNum.UseVisualStyleBackColor = true;
+ this.radioButtonNum.CheckedChanged += new System.EventHandler(this.RadioButton_CheckedChanged);
+ //
+ // radioButtonF1
+ //
+ this.radioButtonF1.AutoSize = true;
+ this.radioButtonF1.Location = new System.Drawing.Point(230, 14);
+ this.radioButtonF1.Name = "radioButtonF1";
+ this.radioButtonF1.Size = new System.Drawing.Size(91, 17);
+ this.radioButtonF1.TabIndex = 200;
+ this.radioButtonF1.TabStop = true;
+ this.radioButtonF1.Text = "&F1, F2, F3, F4";
+ this.radioButtonF1.UseVisualStyleBackColor = true;
+ this.radioButtonF1.CheckedChanged += new System.EventHandler(this.RadioButton_CheckedChanged);
+ //
+ // labelLockMachine
+ //
+ this.labelLockMachine.AutoSize = true;
+ this.labelLockMachine.Location = new System.Drawing.Point(6, 71);
+ this.labelLockMachine.Name = "labelLockMachine";
+ this.labelLockMachine.Size = new System.Drawing.Size(133, 13);
+ this.labelLockMachine.TabIndex = 31;
+ this.labelLockMachine.Text = "Lock machine(s), Ctrl+Alt+:";
+ //
+ // labelExitMM
+ //
+ this.labelExitMM.AutoSize = true;
+ this.labelExitMM.Location = new System.Drawing.Point(309, 44);
+ this.labelExitMM.Name = "labelExitMM";
+ this.labelExitMM.Size = new System.Drawing.Size(138, 13);
+ this.labelExitMM.TabIndex = 29;
+ this.labelExitMM.Text = "Exit the app, Ctrl+Alt+Shift+:";
+ //
+ // labelShowSettings
+ //
+ this.labelShowSettings.AutoSize = true;
+ this.labelShowSettings.Location = new System.Drawing.Point(6, 44);
+ this.labelShowSettings.Name = "labelShowSettings";
+ this.labelShowSettings.Size = new System.Drawing.Size(149, 13);
+ this.labelShowSettings.TabIndex = 27;
+ this.labelShowSettings.Text = "Show Settings Form, Ctrl+Alt+:";
+ //
+ // labelSwitchBetweenMachine
+ //
+ this.labelSwitchBetweenMachine.AutoSize = true;
+ this.labelSwitchBetweenMachine.Location = new System.Drawing.Point(6, 18);
+ this.labelSwitchBetweenMachine.Name = "labelSwitchBetweenMachine";
+ this.labelSwitchBetweenMachine.Size = new System.Drawing.Size(179, 13);
+ this.labelSwitchBetweenMachine.TabIndex = 24;
+ this.labelSwitchBetweenMachine.Text = "Switch between machines, Ctrl+Alt+:";
+ //
+ // tabPageMain
+ //
+ this.tabPageMain.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(246)))), ((int)(((byte)(245)))), ((int)(((byte)(242)))));
+ this.tabPageMain.Controls.Add(this.buttonCancel);
+ this.tabPageMain.Controls.Add(this.groupBoxMachineMatrix);
+ this.tabPageMain.Controls.Add(this.groupBoxKeySetup);
+ this.tabPageMain.Controls.Add(this.buttonOK);
+ this.tabPageMain.Location = new System.Drawing.Point(4, 25);
+ this.tabPageMain.Name = "tabPageMain";
+ this.tabPageMain.Padding = new System.Windows.Forms.Padding(3);
+ this.tabPageMain.Size = new System.Drawing.Size(563, 362);
+ this.tabPageMain.TabIndex = 0;
+ this.tabPageMain.Text = "Machine Setup";
+ //
+ // buttonCancel
+ //
+ this.buttonCancel.Location = new System.Drawing.Point(290, 328);
+ this.buttonCancel.Name = "buttonCancel";
+ this.buttonCancel.Size = new System.Drawing.Size(75, 23);
+ this.buttonCancel.TabIndex = 21;
+ this.buttonCancel.Text = "&Close";
+ this.buttonCancel.UseVisualStyleBackColor = true;
+ this.buttonCancel.Click += new System.EventHandler(this.ButtonCancel_Click);
+ //
+ // groupBoxMachineMatrix
+ //
+ this.groupBoxMachineMatrix.BackColor = System.Drawing.Color.Transparent;
+ this.groupBoxMachineMatrix.Controls.Add(this.checkBoxTwoRow);
+ this.groupBoxMachineMatrix.Controls.Add(this.linkLabelReConfigure);
+ this.groupBoxMachineMatrix.Location = new System.Drawing.Point(3, 78);
+ this.groupBoxMachineMatrix.Name = "groupBoxMachineMatrix";
+ this.groupBoxMachineMatrix.Size = new System.Drawing.Size(558, 244);
+ this.groupBoxMachineMatrix.TabIndex = 5;
+ this.groupBoxMachineMatrix.TabStop = false;
+ this.groupBoxMachineMatrix.Text = " Computer &Matrix - Drag and drop computer thumbnails below to match computer ph" +
+ "ysical layout. Check the box next to each computer thumbnail to type in computer" +
+ " name. ";
+ //
+ // linkLabelReConfigure
+ //
+ this.linkLabelReConfigure.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.linkLabelReConfigure.Location = new System.Drawing.Point(3, 221);
+ this.linkLabelReConfigure.Name = "linkLabelReConfigure";
+ this.linkLabelReConfigure.Size = new System.Drawing.Size(552, 20);
+ this.linkLabelReConfigure.TabIndex = 304;
+ this.linkLabelReConfigure.TabStop = true;
+ this.linkLabelReConfigure.Text = "Go through the setup experience";
+ this.linkLabelReConfigure.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.linkLabelReConfigure.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelReConfigure_LinkClicked);
+ //
+ // tabControlSetting
+ //
+ this.tabControlSetting.Appearance = System.Windows.Forms.TabAppearance.FlatButtons;
+ this.tabControlSetting.Controls.Add(this.tabPageMain);
+ this.tabControlSetting.Controls.Add(this.tabPageOther);
+ this.tabControlSetting.Controls.Add(this.tabPageAdvancedSettings);
+ this.tabControlSetting.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.tabControlSetting.Location = new System.Drawing.Point(0, 0);
+ this.tabControlSetting.Name = "tabControlSetting";
+ this.tabControlSetting.SelectedIndex = 0;
+ this.tabControlSetting.Size = new System.Drawing.Size(571, 391);
+ this.tabControlSetting.TabIndex = 20;
+ //
+ // tabPageAdvancedSettings
+ //
+ this.tabPageAdvancedSettings.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(246)))), ((int)(((byte)(245)))), ((int)(((byte)(242)))));
+ this.tabPageAdvancedSettings.Controls.Add(this.pictureBoxMouseWithoutBorders);
+ this.tabPageAdvancedSettings.Controls.Add(this.groupBoxDNS);
+ this.tabPageAdvancedSettings.Controls.Add(this.textBoxDNS);
+ this.tabPageAdvancedSettings.Location = new System.Drawing.Point(4, 25);
+ this.tabPageAdvancedSettings.Name = "tabPageAdvancedSettings";
+ this.tabPageAdvancedSettings.Padding = new System.Windows.Forms.Padding(3);
+ this.tabPageAdvancedSettings.Size = new System.Drawing.Size(563, 362);
+ this.tabPageAdvancedSettings.TabIndex = 2;
+ this.tabPageAdvancedSettings.Text = "IP Mappings";
+ //
+ // pictureBoxMouseWithoutBorders
+ //
+ this.pictureBoxMouseWithoutBorders.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ this.pictureBoxMouseWithoutBorders.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.pictureBoxMouseWithoutBorders.Location = new System.Drawing.Point(3, 241);
+ this.pictureBoxMouseWithoutBorders.Name = "pictureBoxMouseWithoutBorders";
+ this.pictureBoxMouseWithoutBorders.Size = new System.Drawing.Size(557, 118);
+ this.pictureBoxMouseWithoutBorders.TabIndex = 16;
+ this.pictureBoxMouseWithoutBorders.TabStop = false;
+ //
+ // groupBoxDNS
+ //
+ this.groupBoxDNS.Controls.Add(this.textBoxMachineName2IP);
+ this.groupBoxDNS.Dock = System.Windows.Forms.DockStyle.Top;
+ this.groupBoxDNS.Location = new System.Drawing.Point(3, 85);
+ this.groupBoxDNS.Name = "groupBoxDNS";
+ this.groupBoxDNS.Size = new System.Drawing.Size(557, 150);
+ this.groupBoxDNS.TabIndex = 0;
+ this.groupBoxDNS.TabStop = false;
+ this.groupBoxDNS.Text = " Machine name to IP address mappings ";
+ //
+ // textBoxMachineName2IP
+ //
+ this.textBoxMachineName2IP.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.textBoxMachineName2IP.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.textBoxMachineName2IP.Location = new System.Drawing.Point(3, 16);
+ this.textBoxMachineName2IP.MaxLength = 1024;
+ this.textBoxMachineName2IP.Multiline = true;
+ this.textBoxMachineName2IP.Name = "textBoxMachineName2IP";
+ this.textBoxMachineName2IP.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
+ this.textBoxMachineName2IP.Size = new System.Drawing.Size(551, 131);
+ this.textBoxMachineName2IP.TabIndex = 0;
+ //
+ // textBoxDNS
+ //
+ this.textBoxDNS.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(246)))), ((int)(((byte)(245)))), ((int)(((byte)(242)))));
+ this.textBoxDNS.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.textBoxDNS.Dock = System.Windows.Forms.DockStyle.Top;
+ this.textBoxDNS.Location = new System.Drawing.Point(3, 3);
+ this.textBoxDNS.Multiline = true;
+ this.textBoxDNS.Name = "textBoxDNS";
+ this.textBoxDNS.ReadOnly = true;
+ this.textBoxDNS.Size = new System.Drawing.Size(557, 82);
+ this.textBoxDNS.TabIndex = 0;
+ this.textBoxDNS.TabStop = false;
+ this.textBoxDNS.Text = resources.GetString("textBoxDNS.Text");
+ //
+ // linkLabelHelp
+ //
+ this.linkLabelHelp.AutoSize = true;
+ this.linkLabelHelp.Dock = System.Windows.Forms.DockStyle.Right;
+ this.linkLabelHelp.Location = new System.Drawing.Point(400, 0);
+ this.linkLabelHelp.Name = "linkLabelHelp";
+ this.linkLabelHelp.Size = new System.Drawing.Size(124, 13);
+ this.linkLabelHelp.TabIndex = 300;
+ this.linkLabelHelp.TabStop = true;
+ this.linkLabelHelp.Text = "&Help - http://aka.ms/mm";
+ this.linkLabelHelp.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelHelp_LinkClicked);
+ //
+ // linkLabelMiniLog
+ //
+ this.linkLabelMiniLog.AutoSize = true;
+ this.linkLabelMiniLog.Dock = System.Windows.Forms.DockStyle.Right;
+ this.linkLabelMiniLog.Location = new System.Drawing.Point(524, 0);
+ this.linkLabelMiniLog.Name = "linkLabelMiniLog";
+ this.linkLabelMiniLog.Size = new System.Drawing.Size(47, 13);
+ this.linkLabelMiniLog.TabIndex = 301;
+ this.linkLabelMiniLog.TabStop = true;
+ this.linkLabelMiniLog.Text = "Mini Log";
+ this.linkLabelMiniLog.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.LinkLabelMiniLog_LinkClicked);
+ //
+ // frmMatrix
+ //
+ this.AllowDrop = true;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+ this.BackColor = System.Drawing.SystemColors.Control;
+ this.ClientSize = new System.Drawing.Size(571, 391);
+ this.Controls.Add(this.linkLabelHelp);
+ this.Controls.Add(this.linkLabelMiniLog);
+ this.Controls.Add(this.tabControlSetting);
+ this.Controls.Add(this.pictureBoxMouseWithoutBorders0);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MaximizeBox = false;
+ this.Name = "frmMatrix";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+ this.Text = "Mouse Without Borders - Settings";
+ this.TopMost = true;
+ this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FrmMatrix_FormClosed);
+ this.Load += new System.EventHandler(this.FrmMatrix_Load);
+ this.Shown += new System.EventHandler(this.FrmMatrix_Shown);
+ this.DragDrop += new System.Windows.Forms.DragEventHandler(this.Form_DragDrop);
+ this.DragEnter += new System.Windows.Forms.DragEventHandler(this.Form_DragEnter);
+ this.DragOver += new System.Windows.Forms.DragEventHandler(this.Form_DragOver);
+ this.DragLeave += new System.EventHandler(this.FrmMatrix_DragLeave);
+ this.Resize += new System.EventHandler(this.FrmMatrix_Resize);
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBoxMouseWithoutBorders0)).EndInit();
+ this.groupBoxKeySetup.ResumeLayout(false);
+ this.groupBoxKeySetup.PerformLayout();
+ this.tabPageOther.ResumeLayout(false);
+ this.groupBoxOtherOptions.ResumeLayout(false);
+ this.groupBoxOtherOptions.PerformLayout();
+ this.groupBoxShortcuts.ResumeLayout(false);
+ this.groupBoxShortcuts.PerformLayout();
+ this.tabPageMain.ResumeLayout(false);
+ this.groupBoxMachineMatrix.ResumeLayout(false);
+ this.groupBoxMachineMatrix.PerformLayout();
+ this.tabControlSetting.ResumeLayout(false);
+ this.tabPageAdvancedSettings.ResumeLayout(false);
+ this.tabPageAdvancedSettings.PerformLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBoxMouseWithoutBorders)).EndInit();
+ this.groupBoxDNS.ResumeLayout(false);
+ this.groupBoxDNS.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private PictureBox pictureBoxMouseWithoutBorders0;
+ private ToolTip toolTip;
+ private ToolTip toolTipManual;
+ private TabPage tabPageOther;
+ private GroupBox groupBoxShortcuts;
+ private ComboBox comboBoxReconnect;
+ private ComboBox comboBoxSwitchToAllPC;
+ private ComboBox comboBoxExitMM;
+ private ComboBox comboBoxLockMachine;
+ private ComboBox comboBoxShowSettings;
+ private Label labelReconnect;
+ private Label labelSwitch2AllPCMode;
+ private RadioButton radioButtonDisable;
+ private RadioButton radioButtonNum;
+ private RadioButton radioButtonF1;
+ private Label labelLockMachine;
+ private Label labelExitMM;
+ private Label labelShowSettings;
+ private Label labelSwitchBetweenMachine;
+ private TabPage tabPageMain;
+ private Button buttonCancel;
+ private GroupBox groupBoxMachineMatrix;
+ private CheckBox checkBoxTwoRow;
+ private Button buttonOK;
+ private TabControl tabControlSetting;
+ private ComboBox comboBoxEasyMouse;
+ private Label LabelToggleEasyMouse;
+ private LinkLabel linkLabelHelp;
+ private TabPage tabPageAdvancedSettings;
+ private GroupBox groupBoxDNS;
+ private TextBox textBoxDNS;
+ private TextBox textBoxMachineName2IP;
+ private PictureBox pictureBoxMouseWithoutBorders;
+ private GroupBox groupBoxOtherOptions;
+ private CheckBox checkBoxDrawMouse;
+ private CheckBox checkBoxMouseMoveRelatively;
+ private CheckBox checkBoxHideMouse;
+ private CheckBox checkBoxBlockMouseAtCorners;
+ private CheckBox checkBoxCircle;
+ private CheckBox checkBoxBlockScreenSaver;
+ private CheckBox checkBoxHideLogo;
+ private CheckBox checkBoxShareClipboard;
+ private CheckBox checkBoxDisableCAD;
+ private CheckBox checkBoxReverseLookup;
+ private CheckBox checkBoxVKMap;
+ private LinkLabel linkLabelMiniLog;
+ private ComboBox comboBoxScreenCapture;
+ private Label labelScreenCapture;
+ private LinkLabel linkLabelReConfigure;
+ private CheckBox checkBoxSameSubNet;
+ private CheckBox checkBoxClipNetStatus;
+ private CheckBox checkBoxSendLog;
+ private GroupBox groupBoxKeySetup;
+ private Button buttonNewKey;
+ private TextBox textBoxEnc;
+ private Label LabelEnc;
+ private CheckBox checkBoxShowKey;
+ private ComboBox comboBoxEasyMouseOption;
+ private Label labelEasyMouse;
+ private CheckBox checkBoxTransferFile;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs b/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs
new file mode 100644
index 000000000000..7551723c25e9
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmMatrix.cs
@@ -0,0 +1,1166 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing;
+using System.Globalization;
+using System.Text.RegularExpressions;
+using System.Windows.Forms;
+using Microsoft.PowerToys.Telemetry;
+
+//
+// Matrix/Settings form.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+using Timer = System.Windows.Forms.Timer;
+
+[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#buttonOK_Click(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#buttonSendHello_Click(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#frmMatrix_Load(System.Object,System.EventArgs)", MessageId = "System.String.ToLower", Justification = "Dotnet port with style preservation")]
+
+// [module: SuppressMessage("Microsoft.Mobility", "CA1601:DoNotUseTimersThatPreventPowerStateChanges", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#ChangeUI2OneRow(System.Boolean)")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#logoTimer_Tick(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#Dispose(System.Boolean)", MessageId = "logoBitmap", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Mobility", "CA1601:DoNotUseTimersThatPreventPowerStateChanges", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#frmMatrix_Shown(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmMatrix.#PaintMyLogo()", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders
+{
+ internal partial class FrmMatrix : System.Windows.Forms.Form, IDisposable
+ {
+#pragma warning disable CA2213 // Disposing is done by ComponentResourceManager
+ private Timer helperTimer;
+#pragma warning restore CA2213
+ private bool formShown;
+ private int formOrgHeight;
+ private bool matrixOneRow;
+
+ internal FrmMatrix()
+ {
+ InitializeComponent();
+
+ textBoxEnc.Font = new System.Drawing.Font(Control.DefaultFont.Name, 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, 0);
+
+ Text = Application.ProductName + " " + Application.ProductVersion + " - Settings";
+ toolTip.ToolTipTitle = Application.ProductName;
+ toolTipManual.ToolTipTitle = Application.ProductName;
+ labelExitMM.Text = "Exit the application, Ctrl+Alt+Shift+:";
+ textBoxMachineName2IP.Text = Setting.Values.Name2IP;
+ }
+
+ private void ButtonCancel_Click(object sender, EventArgs e)
+ {
+ buttonCancel.Enabled = false;
+ Close();
+ Common.MatrixForm = null;
+ }
+
+ private void ButtonOK_Click(object sender, EventArgs e)
+ {
+ buttonOK.Enabled = false;
+
+ if (!UpdateKey(Regex.Replace(textBoxEnc.Text, @"\s+", string.Empty)))
+ {
+ buttonOK.Enabled = true;
+ return;
+ }
+
+ string[] st = new string[Common.MAX_MACHINE];
+ for (int i = 0; i < Common.MAX_MACHINE; i++)
+ {
+ if (machines[i].MachineEnabled)
+ {
+ for (int j = 0; j < i; j++)
+ {
+ if (st[j].Equals(machines[i].MachineName, StringComparison.OrdinalIgnoreCase))
+ {
+ machines[i].MachineName = string.Empty;
+ machines[i].MachineEnabled = false;
+ }
+ }
+
+ st[i] = machines[i].MachineName;
+ }
+ else
+ {
+ st[i] = string.Empty;
+ }
+ }
+
+ Common.MachineMatrix = st;
+ Setting.Values.MatrixOneRow = matrixOneRow = !checkBoxTwoRow.Checked;
+
+ if (Process.GetCurrentProcess().SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
+ {
+ Program.StartService();
+ Common.ShowToolTip("New settings applied on the physical console session!", 3000, ToolTipIcon.Warning, false);
+ }
+ else
+ {
+ SocketStuff.InvalidKeyFound = false;
+ showInvalidKeyMessage = false;
+ Common.ReopenSocketDueToReadError = true;
+ Common.ReopenSockets(true);
+
+ for (int i = 0; i < 10; i++)
+ {
+ if (Common.AtLeastOneSocketConnected())
+ {
+ Common.MMSleep(0.5);
+ break;
+ }
+
+ Common.MMSleep(0.2);
+ }
+
+ Common.SendMachineMatrix();
+ }
+
+ buttonOK.Enabled = true;
+ }
+
+ internal void UpdateKeyTextBox()
+ {
+ _ = Common.GetUserName();
+ textBoxEnc.Text = Common.MyKey;
+ }
+
+ private void InitAll()
+ {
+ formOrgHeight = Height;
+ matrixOneRow = Setting.Values.MatrixOneRow;
+ CreateMachines();
+ LoadSettingsToUI();
+ UpdateKeyTextBox();
+ }
+
+ private void LoadMachines()
+ {
+ bool meAdded = false;
+ string machineName;
+
+ if (Common.MachineMatrix != null && Common.MachineMatrix.Length == Common.MAX_MACHINE)
+ {
+ Common.LogDebug("LoadMachines: Machine Matrix: " + Setting.Values.MachineMatrixString);
+
+ for (int i = 0; i < Common.MAX_MACHINE; i++)
+ {
+ machineName = Common.MachineMatrix[i].Trim();
+ machines[i].MachineName = machineName;
+
+ if (string.IsNullOrEmpty(machineName))
+ {
+ machines[i].CheckAble = true;
+ }
+ else
+ {
+ machines[i].MachineEnabled = true;
+ }
+
+ bool found = Common.MachinePool.TryFindMachineByName(machineName, out MachineInf machineInfo);
+ if (found)
+ {
+ if (machineInfo.Id == Common.MachineID)
+ {
+ machines[i].LocalHost = true;
+ meAdded = true;
+ }
+ }
+ }
+ }
+
+ if (!meAdded)
+ {
+ foreach (Machine m in machines)
+ {
+ if (string.IsNullOrEmpty(m.MachineName))
+ {
+ m.MachineName = Common.MachineName.Trim();
+ m.LocalHost = true;
+ meAdded = true;
+ break;
+ }
+ }
+ }
+ }
+
+ private void CheckBoxShowKey_CheckedChanged(object sender, EventArgs e)
+ {
+ textBoxEnc.PasswordChar = checkBoxShowKey.Checked ? (char)0 : '*';
+ }
+
+ private void FrmMatrix_Shown(object sender, EventArgs e)
+ {
+ if (Setting.Values.FirstRun)
+ {
+ Setting.Values.FirstRun = false;
+ Common.ReopenSockets(false);
+
+ /*
+ string fireWallLog = Path.GetDirectoryName(Application.ExecutablePath) + "\\FirewallError.log";
+
+ if (File.Exists(fireWallLog))
+ {
+ //@"http://bing.com/search?q=Allow+a+program+through+Windows+Firewall"
+
+ MessageBox.Show(Application.ProductName + " was unable to add itself to the Firewall exception list.\r\n" +
+ "The following application needs to be added to the Firewall exception list:\r\n\r\n" +
+ Application.ExecutablePath +
+ "\r\n\r\nYou can go to bing.com and do a search on" + "\r\n'Allow a program through Windows Firewall' to know how.",
+ Application.ProductName,
+ MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+
+ linkLabelHelp_LinkClicked(null, null);
+ * */
+ }
+
+ InitAll();
+
+ if (Setting.Values.IsMyKeyRandom)
+ {
+ Setting.Values.IsMyKeyRandom = false;
+ checkBoxShowKey.Checked = true;
+ }
+
+ if (helperTimer == null)
+ {
+ helperTimer = new Timer();
+ helperTimer.Interval = 200;
+ helperTimer.Tick += new EventHandler(HelperTimer_Tick);
+ helperTimer.Start();
+ }
+
+ formShown = true;
+ }
+
+ private void FrmMatrix_FormClosed(object sender, FormClosedEventArgs e)
+ {
+ /*
+ if (logoTimer != null)
+ {
+ logoTimer.Stop();
+ logoTimer.Dispose();
+ logoTimer = null;
+ }
+ * */
+
+ if (helperTimer != null)
+ {
+ helperTimer.Stop();
+ helperTimer.Dispose();
+ helperTimer = null;
+ }
+
+ // if (logoBitmap != null) logoBitmap.Dispose();
+ Common.MatrixForm = null;
+ }
+
+ private int pivot;
+ private Bitmap logoBitmap;
+
+ private void PaintMyLogo()
+ {
+ if (!Visible || !(tabControlSetting.SelectedTab == tabPageAdvancedSettings))
+ {
+ return;
+ }
+
+ uint rv = 0;
+ try
+ {
+ Color c;
+ uint cl;
+ double dC;
+ logoBitmap ??= new Bitmap(pictureBoxMouseWithoutBorders0.BackgroundImage);
+ int bWidth = logoBitmap.Width;
+ int bHeight = logoBitmap.Height;
+ double dx = (double)pictureBoxMouseWithoutBorders.Width / bWidth;
+ double dy = (double)pictureBoxMouseWithoutBorders.Height / bHeight;
+
+ IntPtr hdc = NativeMethods.GetWindowDC(pictureBoxMouseWithoutBorders.Handle);
+ for (int i = 0; i < bWidth; i++)
+ {
+ for (int j = 0; j < bHeight; j++)
+ {
+ c = logoBitmap.GetPixel(i, j);
+
+ // c.G > 245
+ if (c.R < 240 && c.B < 240)
+ {
+ dC = Math.Abs(pivot - i);
+ if (bWidth - pivot + i < dC)
+ {
+ dC = bWidth - pivot + i;
+ }
+
+ if (bWidth - i + pivot < dC)
+ {
+ dC = bWidth - i + pivot;
+ }
+
+ dC /= bWidth;
+
+ // c = Color.FromArgb(80, (int)(255 - 255 * dC), 80);
+ cl = (160 << 16) | ((uint)(255 - (255 * dC)) << 8) | 160;
+
+ // Using GDI SetPixel so we dont have to assign the image later on
+ // b.SetPixel(i, j, c);
+ rv = NativeMethods.SetPixel(hdc, (int)(i * dx), (int)(j * dy), cl);
+ }
+ }
+ }
+
+ // Image im = pictureBoxMouseWithoutBorders.BackgroundImage;
+ // pictureBoxMouseWithoutBorders.BackgroundImage = b;
+ // if (im != null) im.Dispose();
+ rv = (uint)NativeMethods.ReleaseDC(pictureBoxMouseWithoutBorders.Handle, hdc);
+ pivot = (pivot + 5) % bWidth;
+ }
+ catch (Exception ee)
+ {
+ Common.Log(ee);
+ Common.Log(rv.ToString(CultureInfo.CurrentCulture));
+ }
+ }
+
+ private void AddNewMachine()
+ {
+ string newMachine;
+ Machine unUsedMachine;
+
+ foreach (MachineInf inf in Common.MachinePool.ListAllMachines())
+ {
+ bool found = false;
+ unUsedMachine = null;
+ newMachine = inf.Name.Trim();
+ foreach (Machine m in machines)
+ {
+ if (m.MachineName.Equals(
+ newMachine,
+ StringComparison.OrdinalIgnoreCase))
+ {
+ found = true;
+ }
+ else if (unUsedMachine == null && string.IsNullOrEmpty(m.MachineName.Trim()))
+ {
+ unUsedMachine = m;
+ }
+ }
+
+ if (!found && unUsedMachine != null)
+ {
+ unUsedMachine.MachineName = newMachine;
+ }
+ }
+ }
+
+ private int helperTimerCounter;
+ private bool showInvalidKeyMessage;
+
+ private void HelperTimer_Tick(object sender, EventArgs e)
+ {
+ string keyNotMatchedMachines = string.Empty;
+
+ if (Setting.Values.Changed)
+ {
+ Setting.Values.Changed = false;
+ matrixOneRow = Setting.Values.MatrixOneRow;
+ LoadSettingsToUI();
+
+ /*
+ if (!Common.InMachineMatrix(Common.MachineName))
+ {
+ foreach (Machine m in machines)
+ {
+ if (!m.LocalHost)
+ {
+ m.MachineEnabled = false;
+ }
+ }
+ }
+ * */
+ }
+
+ helperTimerCounter++;
+
+ // 1 sec
+ if (helperTimerCounter % 5 == 0)
+ {
+ comboBoxEasyMouseOption.Text = ((EasyMouseOption)Setting.Values.EasyMouse).ToString();
+
+ if (!textBoxMachineName2IP.Text.Equals(Setting.Values.Name2IP, StringComparison.OrdinalIgnoreCase))
+ {
+ Setting.Values.Name2IP = textBoxMachineName2IP.Text;
+ }
+
+ // 2 times
+ if (helperTimerCounter < 15)
+ {
+ Common.SendHello();
+ }
+
+ AddNewMachine();
+ }
+
+ checkBoxVKMap.Checked = Setting.Values.UseVKMap;
+
+ foreach (Machine m in machines)
+ {
+ if (m.StatusClient != SocketStatus.NA)
+ {
+ m.StatusClient = SocketStatus.NA;
+ }
+
+ if (m.StatusServer != SocketStatus.NA)
+ {
+ m.StatusServer = SocketStatus.NA;
+ }
+ }
+
+ SocketStuff sk = Common.Sk;
+
+ if (sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ if (sk.TcpSockets != null)
+ {
+ foreach (TcpSk t in sk.TcpSockets)
+ {
+ if (t.Status == SocketStatus.InvalidKey)
+ {
+ keyNotMatchedMachines += string.Format(CultureInfo.CurrentCulture, "[{0}]", t.MachineName);
+ }
+
+ foreach (Machine m in machines)
+ {
+ if (m.MachineEnabled)
+ {
+ if (m.MachineName.Equals(t.MachineName, StringComparison.OrdinalIgnoreCase))
+ {
+ if (t.IsClient)
+ {
+ if (t.Status > m.StatusClient)
+ {
+ m.StatusClient = t.Status;
+ }
+ }
+ else
+ {
+ if (t.Status > m.StatusServer)
+ {
+ m.StatusServer = t.Status;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (SocketStuff.InvalidKeyFound)
+ {
+ if (!showInvalidKeyMessage)
+ {
+ showInvalidKeyMessage = true;
+
+ Common.ShowToolTip(
+ "Security Keys not matched.\r\nVerify that you entered the same key in all machines.\r\nAnd make sure you run the same version of "
+ + Application.ProductName + " in all machines.\r\n" + keyNotMatchedMachines + "\r\nThis version: " + FrmAbout.AssemblyVersion,
+ 20000,
+ ToolTipIcon.Warning,
+ Setting.Values.ShowClipNetStatus);
+ }
+ }
+ else
+ {
+ showInvalidKeyMessage = false;
+ }
+
+ PaintMyLogo();
+ }
+
+ private void ShowKeyErrorMsg(string msg)
+ {
+ Common.ShowToolTip(msg, 10000, ToolTipIcon.Error, false);
+ _ = textBoxEnc.Focus();
+ textBoxEnc.SelectAll();
+ }
+
+ private bool UpdateKey(string newKey)
+ {
+ if (!Common.IsKeyValid(newKey, out string rv))
+ {
+ ShowKeyErrorMsg(rv);
+ return false;
+ }
+
+ if (!newKey.Equals(Common.MyKey, StringComparison.OrdinalIgnoreCase))
+ {
+ Common.MyKey = newKey;
+ Common.GeneratedKey = false;
+ }
+
+ Common.MagicNumber = Common.Get24BitHash(Common.MyKey);
+ return true;
+ }
+
+ private readonly Machine[] machines = new Machine[Common.MAX_MACHINE];
+ private Machine dragDropMachine;
+ private Machine desMachine;
+ private Machine desMachineX;
+ private Machine desMachineY;
+ private Machine oldDesMachine;
+ private Point desMachinePos;
+ private Point oldDesMachinePos;
+
+ private void CreateMachines()
+ {
+ for (int i = 0; i < Common.MAX_MACHINE; i++)
+ {
+ Machine m = new();
+ m.MouseDown += Machine_MouseDown;
+ m.EnabledChanged += new EventHandler(M_EnabledChanged);
+ m.Parent = groupBoxMachineMatrix;
+ m.MachineEnabled = false;
+ machines[i] = m;
+ }
+
+ FrmMatrix_Resize(this, EventArgs.Empty);
+ ArrangeMachines();
+ }
+
+ private void ArrangeMachines()
+ {
+ Height = matrixOneRow ? formOrgHeight : formOrgHeight + 60;
+ int dx = (groupBoxMachineMatrix.Width - 40) / 4;
+ int yOffset = groupBoxMachineMatrix.Height / 3;
+
+ for (int i = 0; i < Common.MAX_MACHINE; i++)
+ {
+ machines[i].Left = matrixOneRow ? 22 + (i * dx) : 22 + dx + ((i % 2) * dx);
+ machines[i].Top = matrixOneRow ? yOffset : (yOffset / 2) + (i / 2 * (machines[i].Width + 2));
+ machines[i].Visible = true;
+ }
+ }
+
+ private void M_EnabledChanged(object sender, EventArgs e)
+ {
+ Machine m = sender as Machine;
+
+ SocketStuff sk = Common.Sk;
+
+ if (!m.MachineEnabled && sk != null)
+ {
+ lock (sk.TcpSocketsLock)
+ {
+ if (sk.TcpSockets != null)
+ {
+ foreach (TcpSk t in sk.TcpSockets)
+ {
+ if (t.MachineName != null && t.MachineName.Equals(m.MachineName.Trim(), StringComparison.OrdinalIgnoreCase))
+ {
+ t.Status = SocketStatus.NA;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private void Machine_MouseDown(object sender, MouseEventArgs e)
+ {
+ oldDesMachine = desMachine = dragDropMachine = sender as Machine;
+ desMachinePos.X = desMachine.Left;
+ desMachinePos.Y = desMachine.Top;
+ oldDesMachinePos.X = oldDesMachine.Left;
+ oldDesMachinePos.Y = oldDesMachine.Top;
+
+ dragDropMachineOrgX = dragDropMachine.Left;
+ dragDropMachineOrgY = dragDropMachine.Top;
+ dragDropMachine.BringToFront();
+ _ = DoDragDrop(dragDropMachine, DragDropEffects.Move);
+ }
+
+ private int startX;
+ private int startY;
+ private int dragDropMachineOrgX;
+ private int dragDropMachineOrgY;
+
+ private void Form_DragEnter(object sender, DragEventArgs e)
+ {
+ startX = e.X;
+ startY = e.Y;
+ e.Effect = DragDropEffects.Move;
+ }
+
+ private bool IsOnSameRow(Machine m1, Machine m2)
+ {
+ return matrixOneRow || (m1 == dragDropMachine ? desMachinePos.Y : m1.Top) == m2.Top;
+ }
+
+ private bool IsOnSameCol(Machine m1, Machine m2)
+ {
+ return !matrixOneRow && (m1 == dragDropMachine ? desMachinePos.X : m1.Left) == m2.Left;
+ }
+
+ private long lastMove;
+
+ private void Form_DragOver(object sender, DragEventArgs e)
+ {
+ if (dragDropMachine == null)
+ {
+ return;
+ }
+
+ e.Effect = DragDropEffects.Move;
+
+ dragDropMachine.Left = dragDropMachineOrgX + (e.X - startX);
+ dragDropMachine.Top = dragDropMachineOrgY + (e.Y - startY);
+
+ /*
+ dragDropMachine.Left = e.X - dragDropMachine.MouseDownPos.X - Left - 3
+ - groupBoxMachineMatrix.Left - tabControlSetting.Left;
+ dragDropMachine.Top = e.Y - dragDropMachine.MouseDownPos.Y - Top - 25
+ - groupBoxMachineMatrix.Top - tabControlSetting.Top;
+ * */
+
+ if (!matrixOneRow && Common.GetTick() - lastMove < 500)
+ {
+ return;
+ }
+
+ int minX = Math.Abs(dragDropMachine.Left - desMachinePos.X);
+ int minY = Math.Abs(dragDropMachine.Top - desMachinePos.Y);
+
+ desMachineX = desMachineY = desMachine;
+
+ for (int i = 0; i < Common.MAX_MACHINE; i++)
+ {
+ if (machines[i] == dragDropMachine)
+ {
+ continue;
+ }
+
+ if (IsOnSameRow(oldDesMachine, machines[i]))
+ {
+ if (minX > Math.Abs(dragDropMachine.Left - machines[i].Left))
+ {
+ minX = Math.Abs(dragDropMachine.Left - machines[i].Left);
+ desMachineX = machines[i];
+ }
+ }
+
+ if (IsOnSameCol(oldDesMachine, machines[i]))
+ {
+ if (minY > Math.Abs(dragDropMachine.Top - machines[i].Top))
+ {
+ minY = Math.Abs(dragDropMachine.Top - machines[i].Top);
+ desMachineY = machines[i];
+ }
+ }
+ }
+
+ oldDesMachine = desMachine;
+ desMachine = desMachineY == oldDesMachine ? desMachineX : desMachineX == oldDesMachine ? desMachineY : minX < minY ? desMachineX : desMachineY;
+
+ if (desMachine != oldDesMachine)
+ {
+ oldDesMachinePos.X = desMachinePos.X;
+ desMachinePos.X = desMachine.Left;
+
+ oldDesMachinePos.Y = desMachinePos.Y;
+ desMachinePos.Y = desMachine.Top;
+
+ desMachine.Left = oldDesMachinePos.X;
+ desMachine.Top = oldDesMachinePos.Y;
+
+ desMachine = dragDropMachine;
+
+ lastMove = Common.GetTick();
+ }
+ }
+
+ private void Form_DragDrop(object sender, DragEventArgs e)
+ {
+ if (desMachine != null)
+ {
+ dragDropMachine.Left = desMachinePos.X;
+ dragDropMachine.Top = desMachinePos.Y;
+
+ Machine tmp;
+ for (int i = 0; i < Common.MAX_MACHINE - 1; i++)
+ {
+ for (int j = 0; j < Common.MAX_MACHINE - 1 - i; j++)
+ {
+ if (machines[j + 1].Top < machines[j].Top || (machines[j + 1].Top == machines[j].Top && machines[j + 1].Left < machines[j].Left))
+ {
+ tmp = machines[j];
+ machines[j] = machines[j + 1];
+ machines[j + 1] = tmp;
+ }
+ }
+ }
+ }
+ }
+
+ private void FrmMatrix_DragLeave(object sender, EventArgs e)
+ {
+ Form_DragDrop(sender, null);
+ InputSimulation.MouseUp();
+ }
+
+ private void LoadSettingsToUI()
+ {
+ checkBoxCircle.Checked = Setting.Values.MatrixCircle;
+ checkBoxTwoRow.Checked = !matrixOneRow;
+ checkBoxBlockMouseAtCorners.Checked = Setting.Values.BlockMouseAtCorners;
+ checkBoxDrawMouse.Checked = Setting.Values.DrawMouse;
+ checkBoxReverseLookup.Checked = Setting.Values.ReverseLookup;
+ checkBoxSameSubNet.Checked = Setting.Values.SameSubNetOnly;
+ checkBoxVKMap.Checked = Setting.Values.UseVKMap;
+
+ foreach (Machine m in machines)
+ {
+ m.MachineName = string.Empty;
+ m.MachineEnabled = false;
+ m.LocalHost = false;
+ }
+
+ LoadMachines();
+ }
+
+ internal void ShowTip(ToolTipIcon icon, string text, int duration)
+ {
+ int x = 0;
+ text += "\r\n ";
+ int y = (-text.Split(new string[] { "\r\n" }, StringSplitOptions.None).Length * 15) - 30;
+
+ toolTipManual.Hide(this);
+
+ toolTipManual.ToolTipIcon = icon;
+ toolTipManual.Show(text, this, x, y, duration);
+ }
+
+ private void LinkLabelHelp_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ linkLabelHelp.Enabled = false;
+ linkLabelHelp.Enabled = true;
+ }
+
+ private void CheckBoxShareClipboard_CheckedChanged(object sender, EventArgs e)
+ {
+ Setting.Values.ShareClipboard = checkBoxShareClipboard.Checked;
+
+ checkBoxTransferFile.Enabled = checkBoxTransferFile.Checked = Setting.Values.ShareClipboard;
+
+ ShowUpdateMessage();
+ }
+
+ private void CheckBoxTransferFile_CheckedChanged(object sender, EventArgs e)
+ {
+ Setting.Values.TransferFile = checkBoxTransferFile.Checked;
+
+ ShowUpdateMessage();
+
+ Common.HasSwitchedMachineSinceLastCopy = true;
+ }
+
+ private void CheckBoxDisableCAD_CheckedChanged(object sender, EventArgs e)
+ {
+ if (!Common.RunWithNoAdminRight)
+ {
+ Common.ApplyCADSetting();
+ ShowUpdateMessage();
+ }
+ }
+
+ private void FrmMatrix_Load(object sender, EventArgs e)
+ {
+ if (Common.RunWithNoAdminRight)
+ {
+ checkBoxDisableCAD.Enabled = false;
+ checkBoxHideLogo.Enabled = false;
+ }
+
+ checkBoxShareClipboard.Checked = Setting.Values.ShareClipboard;
+
+ if (!Setting.Values.ShareClipboard)
+ {
+ checkBoxTransferFile.Enabled = checkBoxTransferFile.Checked = false;
+ }
+ else
+ {
+ checkBoxTransferFile.Checked = Setting.Values.TransferFile;
+ }
+
+ checkBoxDisableCAD.Checked = Setting.Values.DisableCAD;
+ checkBoxHideLogo.Checked = Setting.Values.HideLogonLogo;
+ checkBoxHideMouse.Checked = Setting.Values.HideMouse;
+ checkBoxBlockScreenSaver.Checked = Setting.Values.BlockScreenSaver;
+ checkBoxMouseMoveRelatively.Checked = Setting.Values.MoveMouseRelatively;
+ checkBoxClipNetStatus.Checked = Setting.Values.ShowClipNetStatus;
+ checkBoxSendLog.Checked = Setting.Values.SendErrorLogV2;
+
+ if (Setting.Values.HotKeySwitchMachine == (int)VK.F1)
+ {
+ radioButtonF1.Checked = true;
+ }
+ else if (Setting.Values.HotKeySwitchMachine == '1')
+ {
+ radioButtonNum.Checked = true;
+ }
+ else
+ {
+ radioButtonDisable.Checked = true;
+ }
+
+ comboBoxShowSettings.Text = "Disable";
+
+ comboBoxExitMM.Text = Setting.Values.HotKeyExitMM == 0 ? "Disable" : new string(new char[] { (char)Setting.Values.HotKeyExitMM });
+
+ comboBoxLockMachine.Text = Setting.Values.HotKeyLockMachine == 0 ? "Disable" : new string(new char[] { (char)Setting.Values.HotKeyLockMachine });
+
+ comboBoxReconnect.Text = Setting.Values.HotKeyReconnect == 0 ? "Disable" : new string(new char[] { (char)Setting.Values.HotKeyReconnect });
+
+ comboBoxScreenCapture.Text = Setting.Values.HotKeyCaptureScreen == 0 ? "Disable" : new string(new char[] { (char)Setting.Values.HotKeyCaptureScreen });
+
+ comboBoxSwitchToAllPC.Text = Setting.Values.HotKeySwitch2AllPC == 1
+ ? "Ctrl*3"
+ : Setting.Values.HotKeySwitch2AllPC == 0 ? "Disable" : new string(new char[] { (char)Setting.Values.HotKeySwitch2AllPC });
+
+ comboBoxEasyMouseOption.Text = ((EasyMouseOption)Setting.Values.EasyMouse).ToString();
+
+ comboBoxEasyMouse.Text = Setting.Values.HotKeyToggleEasyMouse == 0 ? "Disable" : new string(new char[] { (char)Setting.Values.HotKeyToggleEasyMouse });
+ }
+
+ private void RadioButton_CheckedChanged(object sender, EventArgs e)
+ {
+ RadioButton r = sender as RadioButton;
+
+ if (r.Checked)
+ {
+ Setting.Values.HotKeySwitchMachine = sender.Equals(radioButtonF1) ? (int)VK.F1 : sender.Equals(radioButtonNum) ? '1' : 0;
+
+ ShowUpdateMessage();
+ }
+ }
+
+ private void ComboBoxShowSettings_TextChanged(object sender, EventArgs e)
+ {
+ ShowUpdateMessage();
+ }
+
+ private void ComboBoxExitMM_TextChanged(object sender, EventArgs e)
+ {
+ ShowUpdateMessage();
+ }
+
+ private void ComboBoxLockMachine_TextChanged(object sender, EventArgs e)
+ {
+ if (comboBoxLockMachine.Text.Contains("Disable"))
+ {
+ Setting.Values.HotKeyLockMachine = 0;
+ }
+ else if (comboBoxLockMachine.Text.Length > 0)
+ {
+ Setting.Values.HotKeyLockMachine = comboBoxLockMachine.Text[0];
+ }
+ }
+
+ private void ComboBoxSwitchToAllPC_TextChanged(object sender, EventArgs e)
+ {
+ if (comboBoxSwitchToAllPC.Text.Contains("Disable"))
+ {
+ Setting.Values.HotKeySwitch2AllPC = 0;
+ }
+ else if (comboBoxSwitchToAllPC.Text.Contains("Ctrl*3"))
+ {
+ Setting.Values.HotKeySwitch2AllPC = 1;
+ }
+ else if (comboBoxSwitchToAllPC.Text.Length > 0)
+ {
+ Setting.Values.HotKeySwitch2AllPC = comboBoxSwitchToAllPC.Text[0];
+ }
+
+ ShowUpdateMessage();
+ }
+
+ private void CheckBoxHideLogo_CheckedChanged(object sender, EventArgs e)
+ {
+ ShowUpdateMessage();
+ }
+
+ private void ShowUpdateMessage()
+ {
+ if (!formShown)
+ {
+ return;
+ }
+
+ foreach (Control c in tabPageOther.Controls)
+ {
+ if (c != groupBoxShortcuts)
+ {
+ c.Enabled = false;
+ }
+ }
+
+ foreach (Control c in groupBoxShortcuts.Controls)
+ {
+ if (c != pictureBoxMouseWithoutBorders)
+ {
+ c.Enabled = false;
+ }
+ }
+
+ for (int i = 0; i < 3; i++)
+ {
+ Application.DoEvents();
+ Thread.Sleep(20);
+ }
+
+ foreach (Control c in tabPageOther.Controls)
+ {
+ if (c != groupBoxShortcuts)
+ {
+ c.Enabled = true;
+ }
+ }
+
+ foreach (Control c in groupBoxShortcuts.Controls)
+ {
+ if (c != pictureBoxMouseWithoutBorders && c != comboBoxExitMM && c != comboBoxShowSettings && c != comboBoxScreenCapture)
+ {
+ c.Enabled = true;
+ }
+ }
+ }
+
+ private void CheckBoxBlockScreenSaver_CheckedChanged(object sender, EventArgs e)
+ {
+ Setting.Values.BlockScreenSaver = checkBoxBlockScreenSaver.Checked;
+ ShowUpdateMessage();
+ }
+
+ private void ComboBoxReconnect_TextChanged(object sender, EventArgs e)
+ {
+ if (comboBoxReconnect.Text.Contains("Disable"))
+ {
+ Setting.Values.HotKeyReconnect = 0;
+ }
+ else if (comboBoxReconnect.Text.Length > 0)
+ {
+ Setting.Values.HotKeyReconnect = comboBoxReconnect.Text[0];
+ }
+
+ ShowUpdateMessage();
+ }
+
+ private void CheckBoxCircle_CheckedChanged(object sender, EventArgs e)
+ {
+ if (Setting.Values.MatrixCircle != checkBoxCircle.Checked)
+ {
+ Setting.Values.MatrixCircle = checkBoxCircle.Checked;
+ ShowUpdateMessage();
+ Common.SendMachineMatrix();
+ }
+ }
+
+ private void CheckBoxBlockMouseAtCorners_CheckedChanged(object sender, EventArgs e)
+ {
+ Setting.Values.BlockMouseAtCorners = checkBoxBlockMouseAtCorners.Checked;
+ ShowUpdateMessage();
+ }
+
+ private void CheckBoxHideMouse_CheckedChanged(object sender, EventArgs e)
+ {
+ Setting.Values.HideMouse = checkBoxHideMouse.Checked;
+ ShowUpdateMessage();
+ }
+
+ private void ComboBoxEasyMouseOption_TextChanged(object sender, EventArgs e)
+ {
+ string selectedOption = comboBoxEasyMouseOption.Text;
+ int oldEasyMouseOption = Setting.Values.EasyMouse;
+
+ Setting.Values.EasyMouse = Enum.TryParse(selectedOption, out EasyMouseOption easyMouseOption) ? (int)easyMouseOption : (int)EasyMouseOption.Enable;
+
+ if (oldEasyMouseOption != Setting.Values.EasyMouse)
+ {
+ ShowUpdateMessage();
+ }
+ }
+
+ private void ComboBoxEasyMouse_TextChanged(object sender, EventArgs e)
+ {
+ if (comboBoxEasyMouse.Text.Contains("Disable"))
+ {
+ Setting.Values.HotKeyToggleEasyMouse = 0;
+ }
+ else if (comboBoxEasyMouse.Text.Length > 0)
+ {
+ Setting.Values.HotKeyToggleEasyMouse = comboBoxEasyMouse.Text[0];
+ }
+
+ ShowUpdateMessage();
+ }
+
+ private void CheckBoxMouseMoveRelatively_CheckedChanged(object sender, EventArgs e)
+ {
+ Setting.Values.MoveMouseRelatively = checkBoxMouseMoveRelatively.Checked;
+ ShowUpdateMessage();
+ }
+
+ private void CheckBoxDrawMouse_CheckedChanged(object sender, EventArgs e)
+ {
+ if (!(Setting.Values.DrawMouse = checkBoxDrawMouse.Checked))
+ {
+ CustomCursor.ShowFakeMouseCursor(int.MinValue, int.MinValue);
+ }
+
+ ShowUpdateMessage();
+ }
+
+ private void CheckBoxTwoRow_CheckedChanged(object sender, EventArgs e)
+ {
+ matrixOneRow = !checkBoxTwoRow.Checked;
+ ArrangeMachines();
+ }
+
+ private void ButtonNewKey_Click(object sender, EventArgs e)
+ {
+ string message = "Do you really want to generate a new key?\r\n" +
+ "(You would need to enter this key in all other machines to re-establish the connections)";
+
+ if (MessageBox.Show(message, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
+ {
+ Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
+ textBoxEnc.Text = Common.MyKey;
+ checkBoxShowKey.Checked = true;
+ Common.GeneratedKey = true;
+ ButtonOK_Click(null, null);
+ Common.ShowToolTip("New security key was generated, update other machines to the same key.", 10000, ToolTipIcon.Info, false);
+ }
+ }
+
+ private void CheckBoxClipNetStatus_CheckedChanged(object sender, EventArgs e)
+ {
+ Setting.Values.ShowClipNetStatus = checkBoxClipNetStatus.Checked;
+ ShowUpdateMessage();
+ }
+
+ private void CheckBoxSendLog_CheckedChanged(object sender, EventArgs e)
+ {
+ ShowUpdateMessage();
+ }
+
+ private void FrmMatrix_Resize(object sender, EventArgs e)
+ {
+ if (WindowState != FormWindowState.Minimized)
+ {
+ groupBoxMachineMatrix.Top = groupBoxKeySetup.Top + groupBoxKeySetup.Height + 10;
+ groupBoxMachineMatrix.Height = ClientSize.Height - groupBoxKeySetup.Height - (int)(buttonOK.Height * 3.5);
+ checkBoxTwoRow.Top = groupBoxMachineMatrix.Height - (int)(checkBoxTwoRow.Height * 1.4);
+ buttonOK.Top = groupBoxMachineMatrix.Bottom + (int)(buttonOK.Height * 0.3);
+ buttonCancel.Top = groupBoxMachineMatrix.Bottom + (int)(buttonCancel.Height * 0.3);
+ groupBoxShortcuts.Height = ClientSize.Height - groupBoxOtherOptions.Bottom - 40;
+ groupBoxDNS.Height = ClientSize.Height - pictureBoxMouseWithoutBorders.Height - textBoxDNS.Height - 70;
+ }
+ }
+
+ private void CheckBoxReverseLookup_CheckedChanged(object sender, EventArgs e)
+ {
+ Setting.Values.ReverseLookup = checkBoxReverseLookup.Checked;
+ ShowUpdateMessage();
+ }
+
+ private void CheckBoxVKMap_CheckedChanged(object sender, EventArgs e)
+ {
+ Setting.Values.UseVKMap = checkBoxVKMap.Checked;
+ ShowUpdateMessage();
+ }
+
+ private void LinkLabelMiniLog_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ string miniLog = Common.GetMiniLog(new[] { groupBoxOtherOptions.Controls, groupBoxShortcuts.Controls });
+
+ Clipboard.SetText(miniLog);
+ Common.ShowToolTip("Log has been placed in the clipboard.", 30000, ToolTipIcon.Info, false);
+ }
+
+ private void ComboBoxScreenCapture_TextChanged(object sender, EventArgs e)
+ {
+ ShowUpdateMessage();
+ }
+
+ private void LinkLabelReConfigure_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ string message = "WARNING: This will clear the Computer Matrix and allows you to run the setup experience like the first time you installed the program.\r\n";
+ message += "You need to start this setup experience in all machines. In the next Dialog, click NO in the first machine and click YES in the rest of the machines.\r\n";
+ message += "And then follow the steps to complete the configuration.\r\n\r\n";
+ message += "Are you sure you want to continue?";
+
+ if (MessageBox.Show(message, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == System.Windows.Forms.DialogResult.Yes)
+ {
+ PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersOldUIReconfigureEvent());
+ ButtonCancel_Click(this, new EventArgs());
+ Setting.Values.FirstRun = true;
+ Setting.Values.EasyMouse = (int)EasyMouseOption.Enable;
+ Common.ClearComputerMatrix();
+ Common.ShowSetupForm(true);
+ }
+ }
+
+ private void CheckBoxSameSubNet_CheckedChanged(object sender, EventArgs e)
+ {
+ Setting.Values.SameSubNetOnly = checkBoxSameSubNet.Checked;
+ ShowUpdateMessage();
+ }
+
+#if USE_TO_CREATE_LOGO_BITMAP
+ private void PaintMyLogo()
+ {
+ Graphics g = Graphics.FromHwnd(this.Handle);
+ Font font = new Font("Chiller", 40);
+ g.DrawString(Common.BinaryName, font, Brushes.Lime, comboBoxIPs.Right + 50, comboBoxIPs.Bottom - 5);
+
+ Bitmap b = new Bitmap(220, 100);
+ Graphics g2 = Graphics.FromImage(b);
+ g2.FillRectangle(Brushes.WhiteSmoke, 0, 0, 220, 100);
+ g2.DrawString(Common.BinaryName, font, Brushes.Lime, 0, 0);
+ b.Save("c:\\zzz.bmp");
+ string p = "";
+ Color c;
+ int l = 0;
+ for (int i = 0; i < b.Width; i++)
+ {
+ for (int j = 0; j < b.Height; j++)
+ {
+ c = b.GetPixel(i, j);
+ if (c.G > 0)
+ {
+ p += "{" + i + "," + j + "},";
+ l++;
+ }
+ }
+ p += "\r\n";
+ }
+ //File.WriteAllText("c:\\zzz.txt", l + ":" + p, Encoding.Unicode);
+ b.Dispose();
+ g2.Dispose();
+ }
+#endif
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMatrix.resx b/src/modules/MouseWithoutBorders/App/Form/frmMatrix.resx
new file mode 100644
index 000000000000..9a702ae090d5
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmMatrix.resx
@@ -0,0 +1,241 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAAN4AAAAaCAYAAADYHuIVAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
+ vAAADrwBlbxySQAABjpJREFUeF7tmzF25DYQROeCvocPsUfwCXwB58433tSpQ4fOfAOZf96WWFtqkIA4
+ Inae+CtYTRMgGo1GExxpby8XFw/mj++6aNPceF++6+Li4vFcT7yLh/H3olunfl3036LPyvDG+7rIA/jv
+ oovjkIQe178WPRu/LPI5uH5bpFxh02H7fdHZaGzp26IZvNl4BEdO/bPIqSoawb44TibEM8bV/Zco1ImK
+ zIw5rp6tmsGbUXmvk0P5guzXXBfHyafFjKfBUdx/tPU0UZuzIac1Npr1PcYPM88nGlVY8PTza66Ll/tR
+ Cr0X+npMn/H9x/1HLZgbhWZe0q86smZH+CE6WnyvvjqX57ud62KFAvWe994/Fz1zTPMdFbUgRuTYrKe6
+ H+uro/AZvEbHA8eTj6Dws44LW99YfXZy07xnMb2wzXj3eQTyX2pB4jPHWU91f2XK7zHO4jU6vvCgjaZH
+ MclFsPi2Te2kz46fEFrxIMm2Es3j70f8Gez52iKPyxUkPfGa+W34no9n8DqykscXnc/YgYCh6l3vs+Mx
+ qd4ZdHpAFLCKLGiz6PG1Bacj9UWOjpfk18xNBy0fz+Q+sv8Kwc/dOhKQFPzMQlQbb9bj+lkgdh6viozr
+ LHp8bZFzIK/8WOca3dSPxP2YxX1kr1T+fuLVjwXh+OGbVLo23jZ+BCMRW6gNmkWvry3U10Xu6A8CfHOe
+ 8UcCjI0cjY9mcR/ZN5j/7sW/UPFFkE068+jA5s/fxaCf5fhSfbGS7z4ur/xuT52RpNDrawtvX8UCPK8+
+ mmoc2dL+SPby9D5ydUFoIQiWoIKsPd4639qwvTAmcphIHmVcehcV1ZMZ9SawH5Fam1pjZDw0ZxLV7Yhr
+ rS8u9J7dkq8BHIlzxnjU1xbefwsV+9ycvXNyf7f+J4Riyroj5qN+yOnNma2xe/P0zcbrgQXzPr44OTHU
+ SlwCqzaanDud+JM55Unki8dEGT/77h2PfRPkUYXAI1W0rGyKh89P8kXEJyRyA+Mj7fXZ2/bGuTfGo75W
+ pE9baI08tiO5k0XKN4OSGzJXU2IkZ/bGzn4u5ektG/XgyZB93AlEMJVQmexrqzVYSoqq2vmEW8cY8Dlp
+ E+SiarwW1RxZDP8sfzyRUeLXWokEHjuvpNrY7nNvnNcWfTFeW2/7WuHxQXtku5HcyfWR3OcsiORFK3dH
+ cmZvbOUFauXpzRuhXrw6O15hlDzuqAcwq5ESgX+rpPD2XG8lhtpsiUDv4e3BF8c3G7hvTi7eFh4nKrAj
+ u+iN80iMR3ytIMm8vxcKzzN8An0WvXMSsqOcC/h1jdmao9ta8pxxe47t8+Balac3LqhRTzIKryaOB1iV
+ A/TNqR8t0kGNL1tFVrGqonhRcOEbfrhfW3hfFj1jpZ9FfobRZG61S3tvnEdiPOqrk32RNg9koVb71ubc
+ mpNQW+RfCkL6wwYWbhejOeNtcmzYy9Ox6BpeiRzZ0g5przavP0mywjl+Jkf+hPDKewRfDBKWRdC/squS
+ gmyJ7NW1hPv5PUX212e3CbePxlh2NIr3RWx0oc2D8InPXN/bEKKyy5Z20bpe2UdzRm332rfy9LUXSZYV
+ ZQ/dzBfPK6zbqRjc35OqOkYoUUjurBK8A3Dd0YL6IoPum+1HyHcO/Nc8ZPP5yJbIXl1L8LfyOfv3xnk0
+ xmqLRsj3O8nj4ycGxia+Tu+chNqiCj+V+P1ka92vJ2fUFiU9eToW3UCB8sXLBWCHEzg9JTKgasd1JQnO
+ Ve3VNqnsLT9QL14FkYLpG88DLFsie3UtIQaMm35m/944Y1ObkRijEXxTVWJcfKmO6GIkd0DtuN5CbRD3
+ 93jkxhvJGbWpxta1xO1j0Q1wjBvpvUEwAU9OifYJk/JKRz9sCoJPzBeNCsL9tCitKpVPLUQS9KD5ZT/G
+ ks3nJFviSbmH5pTzqfr3xnkkxiO+OloHF/GqfMx8cUZyR9dyAzncr/INtfr15Izs1T168vTQxgOChM5C
+ j2xXHlkeiS8aiwgsgmw9T+RciC2qzSDbGXEe8dXxmFSb5CNQkRhdf9aMfh7jUfbG3svTp9t4Z6OnW1Y2
+ BdPRYmiDOp7QtNuC63ttPpIRX58Rnvaa3ywOj8z7iL/jXVw8AxQUnnhswvN5efkf+nnqL5jaAGcAAAAA
+ SUVORK5CYII=
+
+
+
+ 17, 17
+
+
+ 107, 17
+
+
+ You should always connect to other machines by name but if there is problem Resolving machine name to IP address (rarely), you can manually enter the mappings below. The app will use the IP Addresses from the mappings below and the DNS resolution result.
+Note: If your machine IP address is dynamic, you will need to change the mapping each time the machine IP address changes.
+
+
+ 58
+
+
+
+ AAABAAIAICAAAAAAGACoDAAAJgAAABAQAAAAABgAaAMAAM4MAAAoAAAAIAAAAEAAAAABABgAAAAAAAAM
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32FIv3Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32EYv3Eo32AAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32BIf3GJD2Eov3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAEo32CYn3GZD2DIf4Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ QZv0FI72GpH2FIv3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32Con3HJH2FI72QJv0
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANJb1FI72GZD2Ho/2Eo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAEo32Eo32G5H2FI72NJb1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAPpr0Fo72GZD2Don3Eo32AAAAAAAAAAAAAAAAAAAAAAAAEo32BIj3HJH2
+ Fo72Ppr0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpn0
+ Fo/2GZD2II/2Eo32AAAAAAAAAAAAAAAAEo32E432HJH2Fo/2Opn0AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIo/2HJH2GZD2Foz3Eo32AAAAAAAAEo32
+ Cor3HJH2HJH2Io/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUZ7zA4f3Con3Con3Con3Con3
+ Con3Con3Con3DYv3HJH2HpL2HZH2GZD2GIz2Eo32Eo32C4v3HJH2HpL2HpL2HJH2DYv3Con3Con3Con3
+ Con3Con3Con3Con3AIX4Eo32WqLzD432Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2F4/2HZH2HpL2HpL2HZH2
+ EY32O5j0Npf0FI72HZH2HpL2HpL2HJH2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2C4v3Eo32frPvSaPy
+ TqTyTqTyTqTyTqTyTqTyTqTyT6XyV6jxIJH2HZH2HpL2Eo32Opv0AAAAAAAALJT2FY/2HpL2HJH2K5T1
+ V6nxT6TyTqTyTqTyTqTyTqTyTqTyTqTyRqHzEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2
+ GY72HZH2Eo32OJr0AAAAAAAAAAAAAAAAKZP1FY/2G5H2I5H2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2Ho/2GpH2Eo32PZz0AAAAAAAAAAAAAAAAAAAA
+ AAAAL5b1FY/2GJD2KJT2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAHZH2G472GZD2E432Npn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKJL1Fo/2Fo/2J5P2Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2HpD2GJD2FI72MZj1AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAJZL2Fo/2Fo/2KpT1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAHZH2FIv3GZD2E472MZf1AAAAAAAABAQEBAQEAAAAAAAAAAAAAAAABAQEBAQEAAAAAAAA
+ JZL2Fo/2Fo/2H4/3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32H5D2Doz2M5j0AAAA
+ AAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAJpL1D4z2J5T1Eo32AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32NJj1AAAAAAAAAAAABAQE//jwBAQEBAQEAAAAAAAABAQE
+ //jwBAQEBAQEAAAAAAAAAAAAMJb1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQE
+ AAAAAAAAAAAAAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////////////////////////v//f/x/
+ /j/4P/wf/B/4P/4P8H//B+D//4PB///Bg/8AAAAAAAAAAAABgAD/g8H//wfg//4P8H/8H/g/+DPMH/hh
+ hh/84Yc//+GH///zz/////////////////////////////////8oAAAAEAAAACAAAAABABgAAAAAAAAD
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32GJD2Eo32AAAAAAAAAAAAAAAAAAAA
+ AAAACYn3DIf4AAAAAAAAAAAAAAAAAAAAAAAANJb1GZD2Eo32AAAAAAAAAAAAAAAAEo32FI72AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAOpn0GZD2Eo32AAAAAAAAE432Fo/2AAAAAAAAAAAAAAAAAAAAA4f3Con3
+ Con3Con3DYv3HpL2GZD2Eo32C4v3HpL2HJH2Con3Con3Con3Con3Eo32SaPyTqTyTqTyTqTyV6jxHZH2
+ Eo32AAAALJT2HpL2K5T1T6TyTqTyTqTyTqTyEo32AAAAAAAAAAAAAAAAHo/2Eo32AAAAAAAAAAAAL5b1
+ GJD2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAHpD2FI72AAAAAAAAAAAAAAAAAAAAJZL2Fo/2Eo32AAAA
+ AAAAAAAAAAAAAAAAEo32Doz2AAAABAQEBAQEAAAABAQEBAQEAAAAJpL1J5T1AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAABAQEBAQEAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA//8AAP//AAD//wAA7/8AAMfnAADjzwAA8Z8AAAAAAAABAAAA848AAOfHAADJJwAA+T8AAP//
+ AAD//wAA//8AAA==
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMessage.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/frmMessage.Designer.cs
new file mode 100644
index 000000000000..f489e8bedb3f
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmMessage.Designer.cs
@@ -0,0 +1,146 @@
+namespace MouseWithoutBorders
+{
+ partial class FrmMessage
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMessage));
+ this.labelTitle = new System.Windows.Forms.Label();
+ this.textExtraInfo = new System.Windows.Forms.TextBox();
+ this.timerLife = new System.Windows.Forms.Timer(this.components);
+ this.labelLifeTime = new System.Windows.Forms.Label();
+ this.textBoxMessage = new System.Windows.Forms.TextBox();
+ this.pictureBoxIcon = new System.Windows.Forms.PictureBox();
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBoxIcon)).BeginInit();
+ this.SuspendLayout();
+ //
+ // labelTitle
+ //
+ this.labelTitle.AutoSize = true;
+ this.labelTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.labelTitle.Location = new System.Drawing.Point(21, 0);
+ this.labelTitle.Name = "labelTitle";
+ this.labelTitle.Size = new System.Drawing.Size(168, 16);
+ this.labelTitle.TabIndex = 0;
+ this.labelTitle.Text = "Mouse Without Borders";
+ //
+ // textExtraInfo
+ //
+ this.textExtraInfo.BackColor = System.Drawing.SystemColors.Info;
+ this.textExtraInfo.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.textExtraInfo.Dock = System.Windows.Forms.DockStyle.Bottom;
+ this.textExtraInfo.Enabled = false;
+ this.textExtraInfo.Font = new System.Drawing.Font("Microsoft Sans Serif", 63.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.textExtraInfo.Location = new System.Drawing.Point(0, 161);
+ this.textExtraInfo.Margin = new System.Windows.Forms.Padding(20);
+ this.textExtraInfo.Multiline = true;
+ this.textExtraInfo.Name = "textExtraInfo";
+ this.textExtraInfo.ReadOnly = true;
+ this.textExtraInfo.Size = new System.Drawing.Size(720, 239);
+ this.textExtraInfo.TabIndex = 3;
+ this.textExtraInfo.Text = "???\r\nLLL";
+ this.textExtraInfo.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
+ //
+ // timerLife
+ //
+ this.timerLife.Enabled = true;
+ this.timerLife.Interval = 1000;
+ this.timerLife.Tick += new System.EventHandler(this.TimerLife_Tick);
+ //
+ // labelLifeTime
+ //
+ this.labelLifeTime.AutoSize = true;
+ this.labelLifeTime.Dock = System.Windows.Forms.DockStyle.Right;
+ this.labelLifeTime.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.labelLifeTime.Location = new System.Drawing.Point(720, 0);
+ this.labelLifeTime.Name = "labelLifeTime";
+ this.labelLifeTime.Size = new System.Drawing.Size(0, 16);
+ this.labelLifeTime.TabIndex = 4;
+ //
+ // textBoxMessage
+ //
+ this.textBoxMessage.BackColor = System.Drawing.SystemColors.Info;
+ this.textBoxMessage.BorderStyle = System.Windows.Forms.BorderStyle.None;
+ this.textBoxMessage.Dock = System.Windows.Forms.DockStyle.Fill;
+ this.textBoxMessage.Enabled = false;
+ this.textBoxMessage.Font = new System.Drawing.Font("Microsoft Sans Serif", 20.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.textBoxMessage.Location = new System.Drawing.Point(0, 0);
+ this.textBoxMessage.Margin = new System.Windows.Forms.Padding(20);
+ this.textBoxMessage.Multiline = true;
+ this.textBoxMessage.Name = "textBoxMessage";
+ this.textBoxMessage.ReadOnly = true;
+ this.textBoxMessage.Size = new System.Drawing.Size(720, 400);
+ this.textBoxMessage.TabIndex = 2;
+ this.textBoxMessage.Text = "Message Text";
+ this.textBoxMessage.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
+ //
+ // pictureBoxIcon
+ //
+ this.pictureBoxIcon.Image = ((System.Drawing.Image)(resources.GetObject("pictureBoxIcon.Image")));
+ this.pictureBoxIcon.Location = new System.Drawing.Point(0, 0);
+ this.pictureBoxIcon.Name = "pictureBoxIcon";
+ this.pictureBoxIcon.Size = new System.Drawing.Size(16, 16);
+ this.pictureBoxIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
+ this.pictureBoxIcon.TabIndex = 5;
+ this.pictureBoxIcon.TabStop = false;
+ //
+ // frmMessage
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(231)))));
+ this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ this.ClientSize = new System.Drawing.Size(720, 400);
+ this.Controls.Add(this.pictureBoxIcon);
+ this.Controls.Add(this.labelLifeTime);
+ this.Controls.Add(this.textExtraInfo);
+ this.Controls.Add(this.labelTitle);
+ this.Controls.Add(this.textBoxMessage);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.Name = "frmMessage";
+ this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
+ this.Text = "frmMessage";
+ this.TopMost = true;
+ this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FrmMessage_FormClosed);
+ ((System.ComponentModel.ISupportInitialize)(this.pictureBoxIcon)).EndInit();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label labelTitle;
+ private System.Windows.Forms.TextBox textExtraInfo;
+ private System.Windows.Forms.Timer timerLife;
+ private System.Windows.Forms.Label labelLifeTime;
+ private System.Windows.Forms.TextBox textBoxMessage;
+ private System.Windows.Forms.PictureBox pictureBoxIcon;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMessage.cs b/src/modules/MouseWithoutBorders/App/Form/frmMessage.cs
new file mode 100644
index 000000000000..2abb18f9327c
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmMessage.cs
@@ -0,0 +1,53 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Globalization;
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ public partial class FrmMessage : System.Windows.Forms.Form
+ {
+ private int lifeTime = 10;
+ private int lifeSpent;
+
+ public FrmMessage(string text, string bigText, int lifeTime)
+ {
+ InitializeComponent();
+
+ Left = Top = 10;
+ UpdateInfo(text, bigText, lifeTime);
+ }
+
+ public void UpdateInfo(string text, string bigText, int lifeTime)
+ {
+ textExtraInfo.Visible = !string.IsNullOrEmpty(bigText);
+ textBoxMessage.Text = "\r\n" + text;
+ textExtraInfo.Text = bigText;
+ lifeSpent = 0;
+ this.lifeTime = lifeTime;
+ }
+
+ public void UpdateBigText(string bigText)
+ {
+ textExtraInfo.Text = bigText;
+ }
+
+ private void TimerLife_Tick(object sender, EventArgs e)
+ {
+ if (lifeSpent++ >= lifeTime)
+ {
+ Common.HideTopMostMessage();
+ }
+
+ labelLifeTime.Text = (lifeTime - lifeSpent).ToString(CultureInfo.CurrentCulture);
+ }
+
+ private void FrmMessage_FormClosed(object sender, FormClosedEventArgs e)
+ {
+ Common.NullTopMostMessage();
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMessage.resx b/src/modules/MouseWithoutBorders/App/Form/frmMessage.resx
new file mode 100644
index 000000000000..ab8c30af49cd
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmMessage.resx
@@ -0,0 +1,208 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADRSURBVDhPY2AYnoCFheU/CIN8h8zG69tvvUL/v/XwYWhC
+ NuDrJLX/X6eog9VgBd8myP3/1ieCVcG3Sar/v/WL/QdZhN8l/UBD0BR9nab//9sECeyaPy32/P9piR8c
+ f1wR/v/bRFm44m9TdP5/myQHdLo2UI0/ilqwRd/bmf9/7+RC4G5esIZvEyTBhnzv5obwJ8qgqgPqweqd
+ LzOt4Jphfv3WKwz2P8E093WaCYZmhCHAWMIRwGA14GjEFVBQU753cv7/0c6DJxoJRRFBPwxJBQDap6md
+ Ol5mFwAAAABJRU5ErkJggg==
+
+
+
+
+ AAABAAIAICAAAAAAGACoDAAAJgAAABAQAAAAABgAaAMAAM4MAAAoAAAAIAAAAEAAAAABABgAAAAAAAAM
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32FIv3Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32EYv3Eo32AAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32BIf3GJD2Eov3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAEo32CYn3GZD2DIf4Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ QZv0FI72GpH2FIv3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32Con3HJH2FI72QJv0
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANJb1FI72GZD2Ho/2Eo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAEo32Eo32G5H2FI72NJb1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAPpr0Fo72GZD2Don3Eo32AAAAAAAAAAAAAAAAAAAAAAAAEo32BIj3HJH2
+ Fo72Ppr0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpn0
+ Fo/2GZD2II/2Eo32AAAAAAAAAAAAAAAAEo32E432HJH2Fo/2Opn0AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIo/2HJH2GZD2Foz3Eo32AAAAAAAAEo32
+ Cor3HJH2HJH2Io/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUZ7zA4f3Con3Con3Con3Con3
+ Con3Con3Con3DYv3HJH2HpL2HZH2GZD2GIz2Eo32Eo32C4v3HJH2HpL2HpL2HJH2DYv3Con3Con3Con3
+ Con3Con3Con3Con3AIX4Eo32WqLzD432Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2F4/2HZH2HpL2HpL2HZH2
+ EY32O5j0Npf0FI72HZH2HpL2HpL2HJH2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2C4v3Eo32frPvSaPy
+ TqTyTqTyTqTyTqTyTqTyTqTyT6XyV6jxIJH2HZH2HpL2Eo32Opv0AAAAAAAALJT2FY/2HpL2HJH2K5T1
+ V6nxT6TyTqTyTqTyTqTyTqTyTqTyTqTyRqHzEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2
+ GY72HZH2Eo32OJr0AAAAAAAAAAAAAAAAKZP1FY/2G5H2I5H2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2Ho/2GpH2Eo32PZz0AAAAAAAAAAAAAAAAAAAA
+ AAAAL5b1FY/2GJD2KJT2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAHZH2G472GZD2E432Npn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKJL1Fo/2Fo/2J5P2Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2HpD2GJD2FI72MZj1AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAJZL2Fo/2Fo/2KpT1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAHZH2FIv3GZD2E472MZf1AAAAAAAABAQEBAQEAAAAAAAAAAAAAAAABAQEBAQEAAAAAAAA
+ JZL2Fo/2Fo/2H4/3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32H5D2Doz2M5j0AAAA
+ AAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAJpL1D4z2J5T1Eo32AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32NJj1AAAAAAAAAAAABAQE//jwBAQEBAQEAAAAAAAABAQE
+ //jwBAQEBAQEAAAAAAAAAAAAMJb1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQE
+ AAAAAAAAAAAAAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////////////////////////v//f/x/
+ /j/4P/wf/B/4P/4P8H//B+D//4PB///Bg/8AAAAAAAAAAAABgAD/g8H//wfg//4P8H/8H/g/+DPMH/hh
+ hh/84Yc//+GH///zz/////////////////////////////////8oAAAAEAAAACAAAAABABgAAAAAAAAD
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32GJD2Eo32AAAAAAAAAAAAAAAAAAAA
+ AAAACYn3DIf4AAAAAAAAAAAAAAAAAAAAAAAANJb1GZD2Eo32AAAAAAAAAAAAAAAAEo32FI72AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAOpn0GZD2Eo32AAAAAAAAE432Fo/2AAAAAAAAAAAAAAAAAAAAA4f3Con3
+ Con3Con3DYv3HpL2GZD2Eo32C4v3HpL2HJH2Con3Con3Con3Con3Eo32SaPyTqTyTqTyTqTyV6jxHZH2
+ Eo32AAAALJT2HpL2K5T1T6TyTqTyTqTyTqTyEo32AAAAAAAAAAAAAAAAHo/2Eo32AAAAAAAAAAAAL5b1
+ GJD2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAHpD2FI72AAAAAAAAAAAAAAAAAAAAJZL2Fo/2Eo32AAAA
+ AAAAAAAAAAAAAAAAEo32Doz2AAAABAQEBAQEAAAABAQEBAQEAAAAJpL1J5T1AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAABAQEBAQEAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA//8AAP//AAD//wAA7/8AAMfnAADjzwAA8Z8AAAAAAAABAAAA848AAOfHAADJJwAA+T8AAP//
+ AAD//wAA//8AAA==
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.Designer.cs
new file mode 100644
index 000000000000..2d8c0394c90f
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.Designer.cs
@@ -0,0 +1,60 @@
+namespace MouseWithoutBorders
+{
+ partial class FrmMouseCursor
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmMouseCursor));
+ this.SuspendLayout();
+ //
+ // frmMouseCursor
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackgroundImage = ((System.Drawing.Image)(resources.GetObject("$this.BackgroundImage")));
+ this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ this.ClientSize = new System.Drawing.Size(32, 32);
+ this.ControlBox = false;
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "frmMouseCursor";
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
+ this.Text = "Mouse without Borders\'s mouse cursor";
+ this.TopMost = true;
+ this.TransparencyKey = System.Drawing.Color.Teal;
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FrmMouseCursor_FormClosing);
+ this.LocationChanged += new System.EventHandler(this.FrmMouseCursor_LocationChanged);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.cs b/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.cs
new file mode 100644
index 000000000000..b37bc3271dde
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.cs
@@ -0,0 +1,54 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Windows.Forms;
+using MouseWithoutBorders.Class;
+
+namespace MouseWithoutBorders
+{
+ public partial class FrmMouseCursor : System.Windows.Forms.Form
+ {
+ public FrmMouseCursor()
+ {
+ InitializeComponent();
+ Width = Height = 32;
+ }
+
+ private void FrmMouseCursor_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ if (e.CloseReason == CloseReason.UserClosing)
+ {
+ e.Cancel = true;
+ }
+ else
+ {
+ Common.MouseCursorForm = null;
+ }
+ }
+
+ private void FrmMouseCursor_LocationChanged(object sender, EventArgs e)
+ {
+ if (Setting.Values.DrawMouseEx)
+ {
+ const int DX = 0, DY = 2;
+ IntPtr hDesktop = NativeMethods.GetDesktopWindow();
+ IntPtr hdc = NativeMethods.GetWindowDC(hDesktop);
+
+ if (hdc != IntPtr.Zero)
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ _ = NativeMethods.SetPixel(hdc, DX + Left + i, DY + Top + i, 0xFFFFFF);
+ _ = NativeMethods.SetPixel(hdc, DX + Left + 1, DY + Top + i, 0xFFFFFF);
+ _ = NativeMethods.SetPixel(hdc, DX + Left + i + 1, DY + Top + i, 0);
+ _ = NativeMethods.SetPixel(hdc, DX + Left, DY + Top + i, 0);
+ }
+
+ _ = NativeMethods.ReleaseDC(hDesktop, hdc);
+ }
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.resx b/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.resx
new file mode 100644
index 000000000000..f4e3ed6c679f
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmMouseCursor.resx
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+
+ iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
+ YQUAAAAJcEhZcwAADr4AAA6+AepCscAAAACkSURBVEhLxdbhDoAgCARgH503N0trTVEJ7lZr619fDONI
+ SYR7p3JRjROgGuXlOWeiUQGi8QAs4w1QjA7AGyMANlQAacwAmLEAMMYaABhbIGpYgJBhBPyGHXAanwCP
+ sfkPWlwMD3tGjcOuTm/Px6qqMq7vhMAYSuAwgD4ygYYe+mBg0hxMt6dLEaqI1dYFMX4FSm/iRWwWUzpw
+ FaEfZeM44q7WIgf0vwZLBDa8/AAAAABJRU5ErkJggg==
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmScreen.Designer.cs b/src/modules/MouseWithoutBorders/App/Form/frmScreen.Designer.cs
new file mode 100644
index 000000000000..9f7d30064fdc
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmScreen.Designer.cs
@@ -0,0 +1,308 @@
+namespace MouseWithoutBorders
+{
+ partial class FrmScreen
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FrmScreen));
+ this.MainMenu = new System.Windows.Forms.ContextMenuStrip(this.components);
+ this.menuExit = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator2 = new System.Windows.Forms.ToolStripSeparator();
+ this.menuAbout = new System.Windows.Forms.ToolStripMenuItem();
+ this.menuHelp = new System.Windows.Forms.ToolStripMenuItem();
+ this.menuGenDumpFile = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripSeparator1 = new System.Windows.Forms.ToolStripSeparator();
+ this.menuGetScreenCapture = new System.Windows.Forms.ToolStripMenuItem();
+ this.menuGetFromAll = new System.Windows.Forms.ToolStripMenuItem();
+ this.menuSendScreenCapture = new System.Windows.Forms.ToolStripMenuItem();
+ this.allToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.menuSend2Myself = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
+ this.menuWindowsPhone = new System.Windows.Forms.ToolStripMenuItem();
+ this.menuWindowsPhoneEnable = new System.Windows.Forms.ToolStripMenuItem();
+ this.menuWindowsPhoneDownload = new System.Windows.Forms.ToolStripMenuItem();
+ this.menuWindowsPhoneInformation = new System.Windows.Forms.ToolStripMenuItem();
+ this.menuReinstallKeyboardAndMouseHook = new System.Windows.Forms.ToolStripMenuItem();
+ this.menuMachineMatrix = new System.Windows.Forms.ToolStripMenuItem();
+ this.toolStripMenuItem2 = new System.Windows.Forms.ToolStripSeparator();
+ this.MenuAllPC = new System.Windows.Forms.ToolStripMenuItem();
+ this.dUCTDOToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.tRUONG2DToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.NotifyIcon = new System.Windows.Forms.NotifyIcon(this.components);
+ this.imgListIcon = new System.Windows.Forms.ImageList(this.components);
+ this.picLogonLogo = new System.Windows.Forms.PictureBox();
+ this.MainMenu.SuspendLayout();
+ ((System.ComponentModel.ISupportInitialize)(this.picLogonLogo)).BeginInit();
+ this.SuspendLayout();
+ //
+ // MainMenu
+ //
+ this.MainMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.menuExit,
+ this.toolStripSeparator2,
+ this.menuAbout,
+ this.menuHelp,
+ this.menuGenDumpFile,
+ this.toolStripSeparator1,
+ this.menuGetScreenCapture,
+ this.menuSendScreenCapture,
+ this.toolStripMenuItem1,
+ this.menuWindowsPhone,
+ this.menuReinstallKeyboardAndMouseHook,
+ this.menuMachineMatrix,
+ this.toolStripMenuItem2,
+ this.MenuAllPC,
+ this.dUCTDOToolStripMenuItem,
+ this.tRUONG2DToolStripMenuItem});
+ this.MainMenu.Name = "MainMenu";
+ this.MainMenu.Size = new System.Drawing.Size(197, 292);
+ this.MainMenu.Opening += new System.ComponentModel.CancelEventHandler(this.MainMenu_Opening);
+ this.MainMenu.MouseLeave += new System.EventHandler(this.MainMenu_MouseLeave);
+ //
+ // menuExit
+ //
+ this.menuExit.ForeColor = System.Drawing.Color.Black;
+ this.menuExit.Name = "menuExit";
+ this.menuExit.Size = new System.Drawing.Size(196, 22);
+ this.menuExit.Text = "&Exit";
+ this.menuExit.Click += new System.EventHandler(this.MenuExit_Click);
+ //
+ // toolStripSeparator2
+ //
+ this.toolStripSeparator2.Name = "toolStripSeparator2";
+ this.toolStripSeparator2.Size = new System.Drawing.Size(193, 6);
+ //
+ // menuAbout
+ //
+ this.menuAbout.ForeColor = System.Drawing.Color.Black;
+ this.menuAbout.Name = "menuAbout";
+ this.menuAbout.Size = new System.Drawing.Size(196, 22);
+ this.menuAbout.Text = "A&bout";
+ this.menuAbout.Click += new System.EventHandler(this.MenuAbout_Click);
+ //
+ // menuHelp
+ //
+ this.menuHelp.Name = "menuHelp";
+ this.menuHelp.Size = new System.Drawing.Size(196, 22);
+ this.menuHelp.Text = "&Help && Questions";
+ this.menuHelp.Click += new System.EventHandler(this.MenuHelp_Click);
+ //
+ // menuGenDumpFile
+ //
+ this.menuGenDumpFile.Name = "menuGenDumpFile";
+ this.menuGenDumpFile.Size = new System.Drawing.Size(196, 22);
+ this.menuGenDumpFile.Text = "&Generate log";
+ this.menuGenDumpFile.ToolTipText = "Create logfile for triage, logfile will be generated under program directory.";
+ this.menuGenDumpFile.Visible = false;
+ this.menuGenDumpFile.Click += new System.EventHandler(this.MenuGenDumpFile_Click);
+ //
+ // toolStripSeparator1
+ //
+ this.toolStripSeparator1.Name = "toolStripSeparator1";
+ this.toolStripSeparator1.Size = new System.Drawing.Size(193, 6);
+ //
+ // menuGetScreenCapture
+ //
+ this.menuGetScreenCapture.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.menuGetFromAll});
+ this.menuGetScreenCapture.ForeColor = System.Drawing.Color.Black;
+ this.menuGetScreenCapture.Name = "menuGetScreenCapture";
+ this.menuGetScreenCapture.Size = new System.Drawing.Size(196, 22);
+ this.menuGetScreenCapture.Text = "&Get Screen Capture from";
+ //
+ // menuGetFromAll
+ //
+ this.menuGetFromAll.Enabled = false;
+ this.menuGetFromAll.Name = "menuGetFromAll";
+ this.menuGetFromAll.Size = new System.Drawing.Size(85, 22);
+ this.menuGetFromAll.Text = "All";
+ this.menuGetFromAll.Click += new System.EventHandler(this.MenuGetScreenCaptureClick);
+ //
+ // menuSendScreenCapture
+ //
+ this.menuSendScreenCapture.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this.allToolStripMenuItem,
+ this.menuSend2Myself});
+ this.menuSendScreenCapture.ForeColor = System.Drawing.Color.Black;
+ this.menuSendScreenCapture.Name = "menuSendScreenCapture";
+ this.menuSendScreenCapture.Size = new System.Drawing.Size(196, 22);
+ this.menuSendScreenCapture.Text = "Send Screen &Capture to";
+ //
+ // allToolStripMenuItem
+ //
+ this.allToolStripMenuItem.Name = "allToolStripMenuItem";
+ this.allToolStripMenuItem.Size = new System.Drawing.Size(105, 22);
+ this.allToolStripMenuItem.Text = "All";
+ this.allToolStripMenuItem.Click += new System.EventHandler(this.MenuSendScreenCaptureClick);
+ //
+ // menuSend2Myself
+ //
+ this.menuSend2Myself.Name = "menuSend2Myself";
+ this.menuSend2Myself.Size = new System.Drawing.Size(105, 22);
+ this.menuSend2Myself.Text = "Myself";
+ this.menuSend2Myself.Click += new System.EventHandler(this.MenuSendScreenCaptureClick);
+ //
+ // toolStripMenuItem1
+ //
+ this.toolStripMenuItem1.Name = "toolStripMenuItem1";
+ this.toolStripMenuItem1.Size = new System.Drawing.Size(193, 6);
+ //
+ // menuReinstallKeyboardAndMouseHook
+ //
+ this.menuReinstallKeyboardAndMouseHook.Name = "menuReinstallKeyboardAndMouseHook";
+ this.menuReinstallKeyboardAndMouseHook.Size = new System.Drawing.Size(196, 22);
+ this.menuReinstallKeyboardAndMouseHook.Text = "&Reinstall Input hook";
+ this.menuReinstallKeyboardAndMouseHook.ToolTipText = "This might help when keyboard/Mouse redirection stops working";
+ this.menuReinstallKeyboardAndMouseHook.Visible = false;
+ this.menuReinstallKeyboardAndMouseHook.Click += new System.EventHandler(this.MenuReinstallKeyboardAndMouseHook_Click);
+ //
+ // menuMachineMatrix
+ //
+ this.menuMachineMatrix.Font = new System.Drawing.Font(System.Windows.Forms.Control.DefaultFont.Name, System.Windows.Forms.Control.DefaultFont.Size, System.Drawing.FontStyle.Bold);
+ this.menuMachineMatrix.ForeColor = System.Drawing.Color.Black;
+ this.menuMachineMatrix.Name = "menuMachineMatrix";
+ this.menuMachineMatrix.Size = new System.Drawing.Size(196, 22);
+ this.menuMachineMatrix.Text = "&Settings";
+ this.menuMachineMatrix.Click += new System.EventHandler(this.MenuMachineMatrix_Click);
+ //
+ // toolStripMenuItem2
+ //
+ this.toolStripMenuItem2.Name = "toolStripMenuItem2";
+ this.toolStripMenuItem2.Size = new System.Drawing.Size(193, 6);
+ //
+ // menuAllPC
+ //
+ this.MenuAllPC.CheckOnClick = true;
+ this.MenuAllPC.Name = "menuAllPC";
+ this.MenuAllPC.Size = new System.Drawing.Size(196, 22);
+ this.MenuAllPC.Text = "&ALL COMPUTERS";
+ this.MenuAllPC.ToolTipText = "Repeat Mouse/keyboard in all machines.";
+ this.MenuAllPC.Click += new System.EventHandler(this.MenuAllPC_Click);
+ //
+ // dUCTDOToolStripMenuItem
+ //
+ this.dUCTDOToolStripMenuItem.Name = "dUCTDOToolStripMenuItem";
+ this.dUCTDOToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
+ this.dUCTDOToolStripMenuItem.Tag = "MACHINE: TEST1";
+ this.dUCTDOToolStripMenuItem.Text = "DUCTDO";
+ //
+ // tRUONG2DToolStripMenuItem
+ //
+ this.tRUONG2DToolStripMenuItem.Name = "tRUONG2DToolStripMenuItem";
+ this.tRUONG2DToolStripMenuItem.Size = new System.Drawing.Size(196, 22);
+ this.tRUONG2DToolStripMenuItem.Tag = "MACHINE: TEST2";
+ this.tRUONG2DToolStripMenuItem.Text = "TRUONG2D";
+ //
+ // notifyIcon
+ //
+ this.NotifyIcon.BalloonTipIcon = System.Windows.Forms.ToolTipIcon.Info;
+ this.NotifyIcon.BalloonTipText = "Microsoft® Visual Studio® 2010";
+ this.NotifyIcon.BalloonTipTitle = "Microsoft® Visual Studio® 2010";
+ this.NotifyIcon.ContextMenuStrip = this.MainMenu;
+ this.NotifyIcon.Icon = ((System.Drawing.Icon)(resources.GetObject("notifyIcon.Icon")));
+ this.NotifyIcon.Text = "Microsoft® Visual Studio® 2010";
+ this.NotifyIcon.MouseDown += new System.Windows.Forms.MouseEventHandler(this.NotifyIcon_MouseDown);
+ //
+ // imgListIcon
+ //
+ this.imgListIcon.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imgListIcon.ImageStream")));
+ this.imgListIcon.TransparentColor = System.Drawing.Color.Transparent;
+ this.imgListIcon.Images.SetKeyName(0, "Logo.ico");
+ //
+ // picLogonLogo
+ //
+ this.picLogonLogo.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ this.picLogonLogo.Image = global::MouseWithoutBorders.Properties.Resources.MouseWithoutBorders;
+ this.picLogonLogo.Location = new System.Drawing.Point(99, 62);
+ this.picLogonLogo.Name = "picLogonLogo";
+ this.picLogonLogo.Size = new System.Drawing.Size(95, 17);
+ this.picLogonLogo.TabIndex = 1;
+ this.picLogonLogo.TabStop = false;
+ this.picLogonLogo.Visible = false;
+ //
+ // frmScreen
+ //
+ this.AllowDrop = true;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackColor = System.Drawing.Color.Black;
+ this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ this.ClientSize = new System.Drawing.Size(10, 10);
+ this.ControlBox = false;
+ this.Controls.Add(this.picLogonLogo);
+ this.Cursor = System.Windows.Forms.Cursors.Default;
+ this.Enabled = false;
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "frmScreen";
+ this.Opacity = 0.5D;
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
+ this.Text = "Microsoft® Visual Studio® 2010 Application";
+ this.TopMost = true;
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FrmScreen_FormClosing);
+ this.Load += new System.EventHandler(this.FrmScreen_Load);
+ this.Shown += new System.EventHandler(this.FrmScreen_Shown);
+ this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.FrmScreen_MouseMove);
+ this.MainMenu.ResumeLayout(false);
+ ((System.ComponentModel.ISupportInitialize)(this.picLogonLogo)).EndInit();
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.ToolStripMenuItem menuExit;
+ private System.Windows.Forms.ToolStripSeparator toolStripMenuItem1;
+ private System.Windows.Forms.ToolStripMenuItem menuMachineMatrix;
+ private System.Windows.Forms.ToolStripSeparator toolStripMenuItem2;
+ private System.Windows.Forms.ToolStripMenuItem dUCTDOToolStripMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem tRUONG2DToolStripMenuItem;
+ private System.Windows.Forms.ImageList imgListIcon;
+ private System.Windows.Forms.ToolStripMenuItem menuSendScreenCapture;
+ private System.Windows.Forms.ToolStripMenuItem menuSend2Myself;
+ private System.Windows.Forms.ToolStripMenuItem menuGetScreenCapture;
+ private System.Windows.Forms.ToolStripMenuItem menuGetFromAll;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator1;
+ private System.Windows.Forms.ToolStripMenuItem allToolStripMenuItem;
+ private System.Windows.Forms.ToolStripSeparator toolStripSeparator2;
+ private System.Windows.Forms.ToolStripMenuItem menuAbout;
+ private System.Windows.Forms.PictureBox picLogonLogo;
+ private System.Windows.Forms.ToolStripMenuItem menuHelp;
+ private System.Windows.Forms.ToolStripMenuItem menuReinstallKeyboardAndMouseHook;
+ private System.Windows.Forms.ToolStripMenuItem menuGenDumpFile;
+ private System.Windows.Forms.ToolStripMenuItem menuWindowsPhone;
+ private System.Windows.Forms.ToolStripMenuItem menuWindowsPhoneEnable;
+ private System.Windows.Forms.ToolStripMenuItem menuWindowsPhoneInformation;
+ private System.Windows.Forms.ToolStripMenuItem menuWindowsPhoneDownload;
+ }
+}
+
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs b/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs
new file mode 100644
index 000000000000..ec66e2e4dddc
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmScreen.cs
@@ -0,0 +1,1202 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing;
+using System.Globalization;
+using System.IO;
+using System.Windows.Forms;
+using Microsoft.PowerToys.Telemetry;
+
+//
+// Startup/main form + helper methods.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using MouseWithoutBorders.Class;
+using MouseWithoutBorders.Form;
+using Timer = System.Windows.Forms.Timer;
+
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#ShowMouseWithoutBordersUiOnWinLogonDesktop(System.Boolean)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#ChangeIcon(System.Int32)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#UpdateMenu(MouseWithoutBorders.MachineInf[])", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#frmScreen_Load(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#MenuNewVersion(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#.ctor()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#helperTimer_Tick(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#LoadPlugins()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#menuPersonalizeLogonScrPluginClick(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#helperTimer_Tick(System.Object,System.EventArgs)", MessageId = "System.String.ToLower", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#helperTimer_Tick(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#LogonLogo", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#frmScreen_Load(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#LoadNewLogonBackground()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#UncheckAllMenus()", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#WndProc(System.Windows.Forms.Message&)", MessageId = "MouseWithoutBorders.NativeMethods.SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#Destroy()", MessageId = "MouseWithoutBorders.NativeMethods.SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#helperTimer_Tick(System.Object,System.EventArgs)", MessageId = "MouseWithoutBorders.NativeMethods.SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions", Scope = "member", Target = "MouseWithoutBorders.frmScreen.#menuPersonalizeLogonScrPluginClick(System.Object,System.EventArgs)", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders
+{
+ internal partial class FrmScreen : System.Windows.Forms.Form
+ {
+#pragma warning disable CA2213 // Disposing is done by ComponentResourceManager
+ private Cursor dotCur;
+ private Cursor dropCur;
+ private int[,] logonLogo;
+ private Timer helperTimer;
+#pragma warning restore CA2213
+
+ internal int CurIcon { get; set; }
+
+ internal NotifyIcon NotifyIcon { get; set; }
+
+ internal System.Windows.Forms.ToolStripMenuItem MenuAllPC { get; set; }
+
+ internal System.Windows.Forms.ContextMenuStrip MainMenu { get; set; }
+
+ internal FrmScreen()
+ {
+ InitializeComponent();
+ Text = Setting.Values.MyID;
+ NotifyIcon.BalloonTipText = Application.ProductName;
+ NotifyIcon.BalloonTipTitle = Application.ProductName;
+ menuGenDumpFile.Visible = true;
+
+ Common.WndProcCounter++;
+
+ try
+ {
+ menuWindowsPhone.Visible = false; // No longer supported.
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ private void FrmScreen_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ if (e.CloseReason != CloseReason.WindowsShutDown)
+ {
+ if (Tag == null)
+ {
+ e.Cancel = true;
+ }
+ }
+ else
+ {
+ Common.StartServiceAndSendLogoffSignal();
+ Quit(true, true);
+ }
+ }
+
+ internal void Destroy()
+ {
+ if (helperTimer != null)
+ {
+ helperTimer.Stop();
+ helperTimer.Dispose();
+ helperTimer = null;
+ }
+
+ NotifyIcon.Visible = false;
+ NotifyIcon.Dispose();
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ Common.RunDDHelper(true);
+ }
+
+ // Common.UnhookClipboard();
+ Tag = "myself";
+ Close();
+ }
+
+ internal void Quit(bool cleanup, bool isFormClosing)
+ {
+ Tag = "Quitting...";
+
+ Setting.Values.SwitchCount += Common.SwitchCount;
+ Process me = Process.GetCurrentProcess();
+ Common.WndProcCounter++;
+
+ try
+ {
+ if (cleanup)
+ {
+ Common.Cleanup();
+ }
+
+ Common.WndProcCounter++;
+ if (!Common.RunOnScrSaverDesktop)
+ {
+ Common.ReleaseAllKeys();
+ }
+
+ Common.RunDDHelper(true);
+ }
+ catch (Exception e)
+ {
+ _ = MessageBox.Show(e.ToString());
+ }
+
+ Common.MMSleep(1);
+
+ Application.Exit();
+ me.KillProcess();
+ }
+
+ private void MenuExit_Click(object sender, EventArgs e)
+ {
+ PowerToysTelemetry.Log.WriteEvent(new MouseWithoutBorders.Telemetry.MouseWithoutBordersOldUIQuitEvent());
+
+ Quit(true, false);
+ }
+
+ internal void MenuOnClick(object sender, EventArgs e)
+ {
+ string name = (sender as ToolStripMenuItem).Text;
+ Common.SwitchToMachine(name);
+ }
+
+ internal void UpdateMenu()
+ {
+ try
+ {
+ ChangeIcon(-1);
+ while (MainMenu.Items[MainMenu.Items.Count - 1].Tag != null &&
+ ((string)MainMenu.Items[MainMenu.Items.Count - 1].Tag).StartsWith("MACHINE: ", StringComparison.CurrentCultureIgnoreCase))
+ {
+ MainMenu.Items.Remove(MainMenu.Items[MainMenu.Items.Count - 1]);
+ }
+
+ while (!menuSendScreenCapture.DropDown.Items[
+ menuSendScreenCapture.DropDown.Items.Count - 1].Text.Equals("Myself", StringComparison.OrdinalIgnoreCase))
+ {
+ menuSendScreenCapture.DropDown.Items.Remove(menuSendScreenCapture.DropDown.Items[
+ menuSendScreenCapture.DropDown.Items.Count - 1]);
+ }
+
+ while (!menuGetScreenCapture.DropDown.Items[
+ menuGetScreenCapture.DropDown.Items.Count - 1].Text.Equals("All", StringComparison.OrdinalIgnoreCase))
+ {
+ menuGetScreenCapture.DropDown.Items.Remove(menuGetScreenCapture.DropDown.Items[
+ menuGetScreenCapture.DropDown.Items.Count - 1]);
+ }
+
+ for (int i = 0; i < Common.MAX_MACHINE; i++)
+ {
+ string newMachine = Common.MachineMatrix[i].Trim();
+
+ if (Common.MachinePool.TryFindMachineByName(newMachine, out MachineInf inf) && MachinePool.IsAlive(inf))
+ {
+ ToolStripMenuItem newItem = new(
+ newMachine,
+ null,
+ new EventHandler(MenuOnClick));
+ newItem.Tag = "MACHINE: " + inf.Name;
+ newItem.ToolTipText = "Switch Mouse/keyboard to " + newMachine;
+ newItem.Visible = true;
+ _ = MainMenu.Items.Add(newItem);
+
+ if (!newMachine.Equals(Common.MachineName.Trim(), StringComparison.OrdinalIgnoreCase))
+ {
+ ToolStripMenuItem newItem2 = new(
+ inf.Name.Trim(),
+ null,
+ new EventHandler(MenuSendScreenCaptureClick));
+ newItem2.Visible = true;
+ _ = menuSendScreenCapture.DropDown.Items.Add(newItem2);
+
+ ToolStripMenuItem newItem3 = new(
+ inf.Name.Trim(),
+ null,
+ new EventHandler(MenuGetScreenCaptureClick));
+ newItem3.Visible = true;
+ _ = menuGetScreenCapture.DropDown.Items.Add(newItem3);
+ }
+ }
+ }
+
+ menuGetScreenCapture.DropDown.Items[0].Enabled = menuGetScreenCapture.DropDown.Items.Count > 1;
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ // We dont do something heavy in our timer
+ private void FrmScreen_Load(object sender, EventArgs e)
+ {
+ try
+ {
+ // Common.UpdateMenu();
+ // Common.HookClipboard();
+ CurIcon = Common.ICON_ONE;
+ ChangeIcon(-1);
+ dotCur = CustomCursor.CreateDotCursor();
+ Cursor = dotCur;
+ dropCur = CustomCursor.CreateCursor(Icon.ToBitmap(), 0, 0);
+ BackColor = Color.White;
+ Opacity = 0.15;
+ UpdateNotifyIcon();
+
+ if (picLogonLogo.Image != null)
+ {
+ Bitmap b = new(picLogonLogo.Image);
+ logonLogo = new int[b.Width, b.Height];
+
+ for (int i = 0; i < b.Width; i++)
+ {
+ for (int j = 0; j < b.Height; j++)
+ {
+ Color c = b.GetPixel(i, j);
+ logonLogo[i, j] = !(c.G == 255 && c.R == 0 && c.B == 0) ? (c.B << 16) | (c.G << 8) | c.R : -1;
+ }
+ }
+
+ b.Dispose();
+ }
+ }
+ catch (Exception ex)
+ {
+ BackColor = Color.White;
+ Opacity = 0.15;
+ Common.Log(ex);
+ }
+
+ helperTimer = new System.Windows.Forms.Timer();
+ helperTimer.Interval = 100;
+ helperTimer.Tick += new EventHandler(HelperTimer_Tick);
+ helperTimer.Start();
+ Common.WndProcCounter++;
+
+ if (Environment.OSVersion.Version.Major > 6 ||
+ (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1))
+ {
+ // Win7 up
+ _ = NativeMethods.ChangeWindowMessageFilterEx(Handle, NativeMethods.WM_SHOW_SETTINGS_FORM, 1, IntPtr.Zero);
+ }
+ }
+
+ private long count = 21;
+
+ // private bool checkForNewVersion;
+#if USING_FORM
+ private static frmLogon fLogon = null;
+#endif
+ private bool busy;
+ private bool shownSetupFormOneTime;
+ private bool myDesktopNotActive;
+
+ private void HelperTimer_Tick(object sender, EventArgs e)
+ {
+ Common.WndProcCounter++;
+
+ if (busy)
+ {
+ return;
+ }
+
+ busy = true;
+
+ try
+ {
+ if (!Common.IsMyDesktopActive() || Common.CurrentProcess.SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
+ {
+ myDesktopNotActive = true;
+
+ SocketStuff sk = Common.Sk;
+
+ // We are not on application desktop
+ if (sk != null)
+ {
+ turnedOff = true;
+ Common.SecondOpenSocketTry = false;
+ sk.Close(false);
+ Common.Sk = null;
+ count = 21;
+#if USING_FORM
+ if (fLogon != null) fLogon.Hide();
+#endif
+
+ if (Common.MainFormVisible)
+ {
+ Common.MainFormDot();
+ }
+
+ InputSimulation.ResetSystemKeyFlags();
+
+ Common.DoSomethingInTheInputCallbackThread(() =>
+ {
+ Common.Hook?.ResetLastSwitchKeys();
+ });
+
+ Common.CheckForDesktopSwitchEvent(true);
+ }
+ }
+ else
+ {
+ if (Common.Sk == null)
+ {
+ if (!Common.SecondOpenSocketTry)
+ {
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && !Common.GetUserName())
+ {
+ // While Windows 8 is hybrid-shutting down, user name would be empty (as returned from the .Net API), we should not do anything in this case.
+ Common.LogDebug("No active user.");
+ Thread.Sleep(1000);
+ busy = false;
+ return;
+ }
+
+ if (myDesktopNotActive)
+ {
+ myDesktopNotActive = false;
+ Common.MyKey = Setting.Values.MyKey;
+ }
+
+ Common.UpdateMachinePoolStringSetting();
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && (Setting.Values.FirstRun || Common.KeyCorrupted))
+ {
+ if (!shownSetupFormOneTime)
+ {
+ shownSetupFormOneTime = true;
+ Common.ShowMachineMatrix();
+
+ if (Common.KeyCorrupted && !Setting.Values.FirstRun)
+ {
+ Common.KeyCorrupted = false;
+ string msg = "The security key is corrupted for some reason, please re-setup.";
+ MessageBox.Show(msg, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
+ }
+ }
+ }
+ }
+
+ Common.ReopenSockets(false);
+ Common.SecondOpenSocketTry = true;
+
+ if (Common.Sk != null)
+ {
+ Common.SendHello();
+ Common.SendHeartBeat();
+
+ if (!Common.RunOnScrSaverDesktop && !Common.RunOnLogonDesktop)
+ {
+ NotifyIcon.Visible = false;
+ NotifyIcon.Visible = Setting.Values.ShowOriginalUI;
+
+ // Common.ReHookClipboard();
+ }
+
+ Common.RunDDHelper();
+ }
+
+ count = 0;
+
+ Common.InitDone = true;
+#if SHOW_ON_WINLOGON
+ if (Common.RunOnLogonDesktop)
+ {
+ ShowMouseWithoutBordersUiOnWinLogonDesktop(true);
+ }
+#endif
+ }
+
+ if ((count % 2) == 0)
+ {
+ if (Common.PleaseReopenSocket == 10 || (Common.PleaseReopenSocket > 0 && count > 0 && count % 300 == 0))
+ {
+ if (!Common.AtLeastOneSocketEstablished() || Common.PleaseReopenSocket == 10)
+ {
+ Thread.Sleep(1000);
+ if (Common.PleaseReopenSocket > 0)
+ {
+ Common.PleaseReopenSocket--;
+ }
+
+ // Double check.
+ if (!Common.AtLeastOneSocketEstablished())
+ {
+ Common.GetMachineName();
+ Common.LogDebug("Common.pleaseReopenSocket: " + Common.PleaseReopenSocket.ToString(CultureInfo.InvariantCulture));
+ Common.ReopenSockets(false);
+ Common.NewDesMachineID = Common.DesMachineID = Common.MachineID;
+ }
+ }
+ else
+ {
+ Common.PleaseReopenSocket = 0;
+ }
+ }
+
+ if (Common.PleaseReopenSocket == Common.REOPEN_WHEN_HOTKEY)
+ {
+ Common.PleaseReopenSocket = 0;
+ Common.ReopenSockets(true);
+ }
+ else if (Common.PleaseReopenSocket == Common.REOPEN_WHEN_WSAECONNRESET)
+ {
+ Common.PleaseReopenSocket = 0;
+ Thread.Sleep(1000);
+ Common.UpdateClientSockets("REOPEN_WHEN_WSAECONNRESET");
+ }
+
+ if (Common.RunOnLogonDesktop)
+ {
+ PaintMyNameOnDesktop();
+ }
+
+ /*
+ if (checkClipboard)
+ {
+ Common.CtrlC = -1;
+ checkClipboard = false;
+ Common.CheckClipboard();
+ }
+ else if (--Common.CtrlC == 0)//Giving some timeout from the time Ctrl+C
+ {
+ if ((Common.GetTick() - Common.LastClipboardEventTime > 5000) && Common.CheckClipboard())
+ {
+ Common.ReHookClipboard();
+ }
+ }
+ * */
+ }
+
+ // One more time after 1/3 minutes (Sometimes XP has explorer started late)
+ if (count == 600 || count == 1800)
+ {
+ Common.RunDDHelper();
+ }
+
+ if (count == 600)
+ {
+ if (!Common.GeneratedKey)
+ {
+ Common.MyKey = Setting.Values.MyKey;
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ Common.ShowMachineMatrix();
+
+ Common.MatrixForm?.UpdateKeyTextBox();
+
+ Common.Sk?.Close(false);
+
+ Common.ShowToolTip("The security key must be auto generated in one of the machines.", 10000);
+ }
+ }
+ else if (!Common.KeyCorrupted && !Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && !Setting.Values.FirstRun && Common.AtLeastOneSocketConnected())
+ {
+ int myKeyDaysToExpire = Setting.Values.MyKeyDaysToExpire;
+
+ if (myKeyDaysToExpire <= 0)
+ {
+ Common.ShowMachineMatrix();
+
+ Common.Sk?.Close(false);
+
+ string msg = "The security key has expired, please generate a new key.";
+ Common.ShowToolTip(msg, 10000);
+ }
+ else if (myKeyDaysToExpire <= 15)
+ {
+ Common.ShowToolTip($"The security key will expire in {myKeyDaysToExpire} days! Please regenerate a new key.", 10000);
+ }
+ }
+ }
+ }
+
+ if (count == 20)
+ {
+#if SHOW_ON_WINLOGON
+ // if (Common.RunOnLogonDesktop) ShowMouseWithoutBordersUiOnWinLogonDesktop(false);
+#endif
+ Common.CheckForDesktopSwitchEvent(true);
+ Common.UpdateClientSockets("helperTimer_Tick"); // Sockets may be closed by the remote host when both machines switch desktop at the same time.
+ }
+
+ count++;
+ if (count % 5 == 0)
+ {
+ if (Common.RunOnLogonDesktop)
+ {
+ ShowMessageOnLogonDesktop(Common.DesMachineID != ID.ALL);
+ }
+
+ if (Common.ToggleIcons != null)
+ {
+ Common.ToggleIcon();
+ }
+
+ if (count % 20 == 0)
+ {
+ Common.LogAll();
+
+ // Need to review this code on why it is needed (moved from MoveToMyNeighbourIfNeeded(...))
+ for (int i = 0; i < Common.MachineMatrix.Length; i++)
+ {
+ if (string.IsNullOrEmpty(Common.MachineMatrix[i]) && !Common.InMachineMatrix(Common.MachineName))
+ {
+ Common.MachineMatrix[i] = Common.MachineName;
+ }
+ }
+
+ if (count % 600 == 0 && Common.Sk != null)
+ {
+ // Send out Heartbeat every 1 or 5 mins
+ if (Setting.Values.BlockScreenSaver || count % 3000 == 0)
+ {
+ Common.SendAwakeBeat();
+ Common.RemoveDeadMachines();
+
+ // GC.Collect();
+ // GC.WaitForPendingFinalizers();
+ }
+
+ Common.CloseAnUnusedSocket();
+ }
+ }
+ else if ((count % 36005) == 0)
+ {// One hour
+ Common.SaveSwitchCount();
+
+ int rv = 0;
+
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && Common.IsMyDesktopActive() && (rv = Common.SendMessageToHelper(0x400, IntPtr.Zero, IntPtr.Zero)) <= 0)
+ {
+ Common.TelemetryLogTrace($"{Common.HELPER_FORM_TEXT} not found: {rv}", SeverityLevel.Warning);
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Common.Log(ex);
+ }
+ finally
+ {
+ busy = false;
+ }
+ }
+
+ private void MenuMachineMatrix_Click(object sender, EventArgs e)
+ {
+ Common.ShowMachineMatrix();
+ }
+
+ private void FrmScreen_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (!Common.IsDropping)
+ {
+ if (Cursor != dotCur)
+ {
+ Cursor = dotCur;
+ Refresh();
+
+ // Application.DoEvents();
+ }
+ }
+ }
+
+ internal void ChangeIcon(int iconCode)
+ {
+ try
+ {
+ Graphics g;
+ Pen p;
+ Bitmap bm = new(imgListIcon.Images[0]);
+
+ /*
+ if (curIcon == Common.ICON_ONE)
+ {
+ string[] x = Common.MachineMatrix;
+ Graphics g = Graphics.FromImage(bm);
+ if (x != null)
+ {
+ for (int i = 0; i < Common.MAX_MACHINE; i++)
+ {
+ if (x[i].Trim().Length > 0) g.FillEllipse(
+ #if DEBUG
+ Brushes.White,
+ #else
+ Brushes.Salmon,
+ #endif
+ 3 + (i % 2) * 16, 3 + (i / 2) * 16, 10, 10);
+ }
+ }
+ g.Dispose();
+ }
+ */
+
+ if (CurIcon != Common.ICON_ONE)
+ {
+ p = new Pen(Color.Red, 2);
+ g = Graphics.FromImage(bm);
+ g.DrawRectangle(p, 1, 1, bm.Width - 2, bm.Height - 2);
+ g.Dispose();
+ }
+
+ if (iconCode == Common.ICON_SMALL_CLIPBOARD)
+ {
+ g = Graphics.FromImage(bm);
+ g.FillEllipse(Brushes.Blue, 8, 8, 16, 16);
+ g.Dispose();
+ }
+ else if (iconCode == Common.ICON_BIG_CLIPBOARD)
+ {
+ g = Graphics.FromImage(bm);
+ g.FillEllipse(Brushes.Yellow, 8, 8, 16, 16);
+ g.Dispose();
+ }
+ else if (iconCode == Common.ICON_ERROR)
+ {
+ g = Graphics.FromImage(bm);
+ g.FillEllipse(Brushes.Red, 8, 8, 16, 16);
+ g.Dispose();
+ }
+
+#if DEBUG
+ p = new Pen(Color.White, 4);
+ g = Graphics.FromImage(bm);
+ g.DrawRectangle(p, 6, 6, bm.Width - 12, bm.Height - 12);
+ g.Dispose();
+ p.Dispose();
+#endif
+
+ Common.LogDebug($"Changing icon to {iconCode}.");
+
+ if (NotifyIcon.Icon != null)
+ {
+ NativeMethods.DestroyIcon(NotifyIcon.Icon.Handle);
+ }
+
+ NotifyIcon.Icon = Icon.FromHandle(bm.GetHicon());
+ bm.Dispose();
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ internal void MenuAllPC_Click(object sender, EventArgs e)
+ {
+ Common.LogDebug("menuAllPC_Click");
+ Common.SwitchToMultipleMode(MenuAllPC.Checked, true);
+ CurIcon = MenuAllPC.Checked ? Common.ICON_ALL : Common.ICON_ONE;
+ ChangeIcon(CurIcon);
+ }
+
+ internal void UpdateMultipleModeIconAndMenu()
+ {
+ Common.DoSomethingInUIThread(() =>
+ {
+ MenuAllPC.Checked = Common.NewDesMachineID == ID.ALL;
+ CurIcon = MenuAllPC.Checked ? Common.ICON_ALL : Common.ICON_ONE;
+ ChangeIcon(CurIcon);
+ });
+ }
+
+ // private bool checkClipboard = false;
+ protected override void WndProc(ref Message m)
+ {
+ const int WM_ENDSESSION = 0x0016;
+ const int WM_QUERYENDSESSION = 0x0011;
+
+ // const int WM_DRAWCLIPBOARD = 0x0308;
+ // const int WM_CHANGECBCHAIN = 0x030D;
+ switch (m.Msg)
+ {
+ /*
+ case WM_DRAWCLIPBOARD:
+ if (Common.NextClipboardViewer != IntPtr.Zero && Common.NextClipboardViewer != this.Handle)
+ {
+ int rv = NativeMethods.SendMessage(Common.NextClipboardViewer, m.Msg, m.WParam, m.LParam);
+ Common.Log("SendMessage returned " + rv.ToString(CultureInfo.CurrentCulture));
+ }
+
+ if (Common.GetTick() - Common.LastClipboardEventTime < 1000)
+ {
+ Common.Log("GetTick() - lastClipboardEventTime < 1000");
+ Common.LastClipboardEventTime = Common.GetTick();
+ return;
+ }
+ Common.LastClipboardEventTime = Common.GetTick();
+
+ checkClipboard = true;//Do the task in a next message loop.
+ break;
+
+ case WM_CHANGECBCHAIN:
+ if (m.WParam == Common.NextClipboardViewer)
+ Common.NextClipboardViewer = m.LParam;
+ else
+ if (Common.NextClipboardViewer != IntPtr.Zero && Common.NextClipboardViewer != this.Handle)
+ {
+ int rv = NativeMethods.SendMessage(Common.NextClipboardViewer, m.Msg, m.WParam, m.LParam);
+ Common.Log("SendMessage returned " + rv.ToString(CultureInfo.CurrentCulture));
+ }
+ break;
+ */
+
+ case NativeMethods.WM_SHOW_DRAG_DROP:
+ Point p = default;
+ _ = NativeMethods.GetCursorPos(ref p);
+ Width = 70;
+ Height = 70;
+ Left = p.X - (Width / 3);
+ Top = p.Y - (Height / 3);
+ BackColor = Color.White;
+ Opacity = 0.15;
+ if (Cursor != dropCur)
+ {
+ Cursor = dropCur;
+ }
+
+ Show();
+ break;
+
+ case NativeMethods.WM_HIDE_DRAG_DROP:
+ Common.MainFormDot();
+
+ /*
+ this.Width = 1;
+ this.Height = 1;
+ this.Left = 0;
+ this.Top = 0;
+ //this.Hide();
+ //Common.MainFormVisible = false;
+ * */
+
+ if (Cursor != dotCur)
+ {
+ Cursor = dotCur;
+ }
+
+ break;
+
+ case NativeMethods.WM_HIDE_DD_HELPER:
+ Common.MainForm3Pixels();
+ Common.MMSleep(0.2);
+ if (m.WParam.ToInt32() == 1)
+ {
+ InputSimulation.MouseUp(); // A file is being dragged
+ }
+
+ IntPtr h = (IntPtr)NativeMethods.FindWindow(null, Common.HELPER_FORM_TEXT);
+
+ if (h.ToInt32() > 0)
+ {
+ Common.LogDebug("Hide Mouse Without Borders Helper.");
+
+ // Common.ShowWindow(h, 1);
+ _ = NativeMethods.ShowWindow(h, 0);
+
+ // Common.SetWindowPos(h, Common.HWND_NOTOPMOST, 10, 10, 50, 50, 0);
+ // Common.SetWindowPos(h, Common.HWND_TOPMOST, 0, 0, 800, 60, 0);// For debug
+ }
+
+ break;
+
+ case NativeMethods.WM_CHECK_EXPLORER_DRAG_DROP:
+ Common.LogDebug("Got WM_CHECK_EXPLORER_DRAG_DROP!");
+ Common.DragDropStep04();
+ break;
+
+ case NativeMethods.WM_QUIT:
+ // Quit(true);
+ break;
+
+ case NativeMethods.WM_SWITCH:
+ break;
+
+ case WM_QUERYENDSESSION:
+ Common.LogDebug("WM_QUERYENDSESSION...");
+ Common.StartServiceAndSendLogoffSignal();
+ break;
+
+ case WM_ENDSESSION:
+ Quit(true, true);
+ break;
+
+ case NativeMethods.WM_SHOW_SETTINGS_FORM:
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ Common.ShowMachineMatrix();
+ }
+
+ break;
+
+ default:
+ base.WndProc(ref m);
+ break;
+ }
+ }
+
+ private void NotifyIcon_MouseDown(object sender, MouseEventArgs e)
+ {
+ if (e.Button == MouseButtons.Left)
+ {
+ Common.ShowMachineMatrix();
+ }
+ }
+
+ internal void SetTrayIconText(string value)
+ {
+ if (value.Length > 63)
+ {
+ value = value[..63];
+ }
+
+ NotifyIcon.Text = value;
+ }
+
+ internal void UpdateNotifyIcon()
+ {
+ string[] x = Common.MachineMatrix;
+ string iconText;
+ if (x != null && (x[0].Length > 0 || x[1].Length > 0 || x[2].Length > 0 || x[3].Length > 0))
+ {
+ iconText = Setting.Values.MatrixOneRow
+ ? string.Format(
+ CultureInfo.CurrentCulture,
+ "[{0}][{1}][{2}][{3}]",
+ x[0].Trim(),
+ x[1].Trim(),
+ x[2].Trim(),
+ x[3].Trim())
+ : string.Format(
+ CultureInfo.CurrentCulture,
+ "[{0}][{1}]\r\n[{2}][{3}]",
+ x[0].Trim(),
+ x[1].Trim(),
+ x[2].Trim(),
+ x[3].Trim());
+
+ SetTrayIconText(iconText);
+ }
+ else
+ {
+ SetTrayIconText(Application.ProductName);
+ }
+ }
+
+ internal void ShowToolTip(string txt, int timeOutInMilliseconds, ToolTipIcon icon = ToolTipIcon.Info)
+ {
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ NotifyIcon.ShowBalloonTip(timeOutInMilliseconds, Application.ProductName, txt, icon);
+ }
+ }
+
+ private void MenuSendScreenCaptureClick(object sender, EventArgs e)
+ {
+ string menuCaption = (sender as ToolStripMenuItem).Text;
+ string captureFile = Common.CaptureScreen();
+
+ if (captureFile != null && File.Exists(captureFile))
+ {
+ if (menuCaption.Equals("Myself", StringComparison.OrdinalIgnoreCase))
+ {
+ Common.OpenImage(captureFile);
+ }
+ else
+ {
+ Common.SendImage(menuCaption, captureFile);
+ }
+ }
+ }
+
+ private void MenuGetScreenCaptureClick(object sender, EventArgs e)
+ {
+ string menuCaption = (sender as ToolStripMenuItem).Text;
+
+ // Send CaptureScreenCommand
+ ID des = menuCaption.Equals("All", StringComparison.OrdinalIgnoreCase) ? ID.ALL : Common.IdFromName(menuCaption);
+ Common.SendPackage(des, PackageType.CaptureScreenCommand);
+ }
+
+ private void FrmScreen_Shown(object sender, EventArgs e)
+ {
+ Common.AssertOneInstancePerDesktopSession();
+
+ Common.MainForm = this;
+ Hide();
+ if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
+ {
+ NotifyIcon.Visible = false;
+ NotifyIcon.Visible = Setting.Values.ShowOriginalUI;
+ }
+ }
+
+ private void MenuAbout_Click(object sender, EventArgs e)
+ {
+ if (Common.AboutForm == null)
+ {
+ _ = (Common.AboutForm = new FrmAbout()).ShowDialog();
+ }
+ else
+ {
+ Common.AboutForm.Activate();
+ }
+ }
+
+#if SHOW_ON_WINLOGON
+ private void ShowMouseWithoutBordersUiOnWinLogonDesktop(bool initMenuState)
+ {
+ Common.PaintCount = 0;
+ try
+ {
+ if (initMenuState)
+ {
+ HideMenuWhenRunOnLogonDesktop();
+ }
+
+#if !USING_FORM
+ PaintMyNameOnDesktop();
+#else
+ if (fLogon == null) fLogon = new frmLogon();
+ fLogon.Show();
+ fLogon.LabelDesktop.ContextMenuStrip = fLogon.ContextMenuStrip = MainMenu;
+#endif
+ }
+ catch (Exception e)
+ {
+ Common.Log(e);
+ }
+ }
+
+ internal void HideMenuWhenRunOnLogonDesktop()
+ {
+ menuHelp.Visible = false;
+ menuGetScreenCapture.Visible = false;
+ menuSendScreenCapture.Visible = false;
+ toolStripSeparator1.Visible = false;
+ toolStripSeparator2.Visible = false;
+ menuAbout.Visible = false;
+ menuMachineMatrix.Visible = false;
+ menuReinstallKeyboardAndMouseHook.Visible = false;
+ toolStripMenuItem1.Visible = false;
+ toolStripMenuItem2.Visible = false;
+ menuExit.Visible = false;
+ }
+#endif
+
+ private void MainMenu_MouseLeave(object sender, EventArgs e)
+ {
+#if SHOW_ON_WINLOGON
+ if (Common.RunOnLogonDesktop)
+ {
+ MainMenu.Hide();
+ Thread.Sleep(50);
+ PaintMyNameOnDesktop();
+ }
+#endif
+ }
+
+ private int colorB = 240;
+ private int colorBlueDelta = 5;
+ private bool turnedOff = true;
+
+ internal void ShowMessageOnLogonDesktop(bool turnOff)
+ {
+ if (turnOff && turnedOff)
+ {
+ colorB = 240;
+ colorBlueDelta = 5;
+ return;
+ }
+
+ turnedOff = false;
+ IntPtr hDesktop = NativeMethods.GetDesktopWindow();
+ IntPtr hdc = NativeMethods.GetWindowDC(hDesktop);
+ int textLengthInPixels;
+
+ if (hdc != IntPtr.Zero)
+ {
+ NativeMethods.RECT r;
+ string machineMatrix = Application.ProductName + " is in multiple mode, keyboard may repeat in all machines: ";
+ r.Top = 0;
+ r.Left = Common.ScreenWidth / 5;
+ r.Right = Common.ScreenWidth - (Common.ScreenWidth / 5);
+ r.Bottom = 20;
+
+ for (int i = 0; i < Common.MAX_MACHINE; i++)
+ {
+ string newMachine = Common.MachineMatrix[i].Trim();
+
+ if (Common.MachinePool.TryFindMachineByName(newMachine, out MachineInf inf) && MachinePool.IsAlive(inf))
+ {
+ machineMatrix += "[" + inf.Name.Trim() + "]";
+ }
+ }
+
+ if (turnOff)
+ {
+ turnedOff = true;
+ colorBlueDelta = -40;
+ colorB = 0;
+ }
+ else
+ {
+ colorBlueDelta = colorB == 255 ? -colorBlueDelta : colorB == 240 ? colorBlueDelta > 0 ? 5 : -40 : colorB == 0 ? -colorBlueDelta : colorBlueDelta;
+ colorB += colorBlueDelta;
+ }
+
+ _ = NativeMethods.SetBkColor(hdc, 0);
+ _ = NativeMethods.SetTextColor(hdc, colorB << 8);
+ _ = NativeMethods.DrawText(hdc, machineMatrix, machineMatrix.Length, ref r, 0x1 | 0x4 | 0x100 | 0x400);
+ textLengthInPixels = r.Right - r.Left;
+ r.Left = (Common.ScreenWidth - textLengthInPixels) / 2;
+ r.Right = r.Left + textLengthInPixels;
+ _ = NativeMethods.DrawText(hdc, machineMatrix, machineMatrix.Length, ref r, 0x1 | 0x4 | 0x100);
+ _ = NativeMethods.ReleaseDC(hDesktop, hdc);
+ }
+ }
+
+#if SHOW_ON_WINLOGON
+ private const byte MIN_COLOR = 185;
+ private const byte MAX_COLOR = 255;
+ private const byte MIN_COLOR_DOWN = 10;
+ private byte paintColorR = MIN_COLOR;
+ private byte paintColorG = MIN_COLOR;
+ private byte paintColorB = MIN_COLOR;
+ private bool paintColorDown;
+
+ internal void PaintMyNameOnDesktop()
+ {
+ if (Setting.Values.HideLogonLogo)
+ {
+ return;
+ }
+
+ if (Common.PaintCount > 1500)
+ {
+ return; // running for 5 mins only
+ }
+
+ Common.PaintCount++;
+ IntPtr hDesktop = NativeMethods.GetDesktopWindow();
+ IntPtr hdc = NativeMethods.GetWindowDC(hDesktop);
+ if (hdc != IntPtr.Zero)
+ {
+ int c;
+
+ // int rv = NativeMethods.DrawText(hdc, Common.BinaryName, 10, ref r, 0);
+ for (int i = 0; i < logonLogo.GetUpperBound(0); i++)
+ {
+ for (int j = 0; j < logonLogo.GetUpperBound(1); j++)
+ {
+ if (logonLogo[i, j] != -1)
+ {
+ c = logonLogo[i, j];
+ if (c == 0xFFFFFF)
+ {
+ c = (paintColorB << 16) | (paintColorG << 8) | paintColorR;
+ }
+
+ int rv = (int)NativeMethods.SetPixel(hdc, i, j, (uint)c);
+ }
+ }
+ }
+
+ // Common.Log("PaintMyNameOnDesktop: last rv = " + rv.ToString(CultureInfo.CurrentCulture));
+ _ = NativeMethods.ReleaseDC(hDesktop, hdc);
+ }
+
+ if (!paintColorDown)
+ {
+ if (paintColorR < MAX_COLOR)
+ {
+ paintColorR += MIN_COLOR_DOWN;
+ }
+ else
+ {
+ if (paintColorG < MAX_COLOR)
+ {
+ paintColorG += MIN_COLOR_DOWN;
+ }
+ else
+ {
+ if (paintColorB < MAX_COLOR)
+ {
+ paintColorB += MIN_COLOR_DOWN;
+ }
+ else
+ {
+ paintColorDown = true;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (paintColorB > MIN_COLOR)
+ {
+ paintColorB -= MIN_COLOR_DOWN;
+ }
+ else
+ {
+ if (paintColorR > MIN_COLOR)
+ {
+ paintColorR -= MIN_COLOR_DOWN;
+ }
+ else
+ {
+ if (paintColorG > MIN_COLOR)
+ {
+ paintColorG -= MIN_COLOR_DOWN;
+ }
+ else
+ {
+ paintColorDown = false;
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ private void MenuHelp_Click(object sender, EventArgs e)
+ {
+ }
+
+ internal void MenuReinstallKeyboardAndMouseHook_Click(object sender, EventArgs e)
+ {
+ Common.DoSomethingInTheInputCallbackThread(() =>
+ {
+ if (Common.Hook != null)
+ {
+ Common.Hook.Stop();
+ Common.Hook = null;
+ }
+
+ Common.InputCallbackForm.Close();
+ Common.InputCallbackForm = null;
+ Program.StartInputCallbackThread();
+ });
+ }
+
+ private void MenuGenDumpFile_Click(object sender, EventArgs e)
+ {
+ Common.GenerateLog();
+ }
+
+ private void MainMenu_Opening(object sender, CancelEventArgs e)
+ {
+ UpdateMenu();
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Form/frmScreen.resx b/src/modules/MouseWithoutBorders/App/Form/frmScreen.resx
new file mode 100644
index 000000000000..076454b8c374
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Form/frmScreen.resx
@@ -0,0 +1,302 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+ 127, 17
+
+
+
+
+ AAABAAIAICAAAAAAGACoDAAAJgAAABAQAAAAABgAaAMAAM4MAAAoAAAAIAAAAEAAAAABABgAAAAAAAAM
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32FIv3Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32EYv3Eo32AAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32BIf3GJD2Eov3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAEo32CYn3GZD2DIf4Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ QZv0FI72GpH2FIv3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32Con3HJH2FI72QJv0
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANJb1FI72GZD2Ho/2Eo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAEo32Eo32G5H2FI72NJb1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAPpr0Fo72GZD2Don3Eo32AAAAAAAAAAAAAAAAAAAAAAAAEo32BIj3HJH2
+ Fo72Ppr0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpn0
+ Fo/2GZD2II/2Eo32AAAAAAAAAAAAAAAAEo32E432HJH2Fo/2Opn0AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIo/2HJH2GZD2Foz3Eo32AAAAAAAAEo32
+ Cor3HJH2HJH2Io/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUZ7zA4f3Con3Con3Con3Con3
+ Con3Con3Con3DYv3HJH2HpL2HZH2GZD2GIz2Eo32Eo32C4v3HJH2HpL2HpL2HJH2DYv3Con3Con3Con3
+ Con3Con3Con3Con3AIX4Eo32WqLzD432Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2F4/2HZH2HpL2HpL2HZH2
+ EY32O5j0Npf0FI72HZH2HpL2HpL2HJH2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2C4v3Eo32frPvSaPy
+ TqTyTqTyTqTyTqTyTqTyTqTyT6XyV6jxIJH2HZH2HpL2Eo32Opv0AAAAAAAALJT2FY/2HpL2HJH2K5T1
+ V6nxT6TyTqTyTqTyTqTyTqTyTqTyTqTyRqHzEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2
+ GY72HZH2Eo32OJr0AAAAAAAAAAAAAAAAKZP1FY/2G5H2I5H2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2Ho/2GpH2Eo32PZz0AAAAAAAAAAAAAAAAAAAA
+ AAAAL5b1FY/2GJD2KJT2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAHZH2G472GZD2E432Npn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKJL1Fo/2Fo/2J5P2Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2HpD2GJD2FI72MZj1AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAJZL2Fo/2Fo/2KpT1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAHZH2FIv3GZD2E472MZf1AAAAAAAABAQEBAQEAAAAAAAAAAAAAAAABAQEBAQEAAAAAAAA
+ JZL2Fo/2Fo/2H4/3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32H5D2Doz2M5j0AAAA
+ AAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAJpL1D4z2J5T1Eo32AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32NJj1AAAAAAAAAAAABAQE//jwBAQEBAQEAAAAAAAABAQE
+ //jwBAQEBAQEAAAAAAAAAAAAMJb1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQE
+ AAAAAAAAAAAAAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////////////////////////v//f/x/
+ /j/4P/wf/B/4P/4P8H//B+D//4PB///Bg/8AAAAAAAAAAAABgAD/g8H//wfg//4P8H/8H/g/+DPMH/hh
+ hh/84Yc//+GH///zz/////////////////////////////////8oAAAAEAAAACAAAAABABgAAAAAAAAD
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32GJD2Eo32AAAAAAAAAAAAAAAAAAAA
+ AAAACYn3DIf4AAAAAAAAAAAAAAAAAAAAAAAANJb1GZD2Eo32AAAAAAAAAAAAAAAAEo32FI72AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAOpn0GZD2Eo32AAAAAAAAE432Fo/2AAAAAAAAAAAAAAAAAAAAA4f3Con3
+ Con3Con3DYv3HpL2GZD2Eo32C4v3HpL2HJH2Con3Con3Con3Con3Eo32SaPyTqTyTqTyTqTyV6jxHZH2
+ Eo32AAAALJT2HpL2K5T1T6TyTqTyTqTyTqTyEo32AAAAAAAAAAAAAAAAHo/2Eo32AAAAAAAAAAAAL5b1
+ GJD2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAHpD2FI72AAAAAAAAAAAAAAAAAAAAJZL2Fo/2Eo32AAAA
+ AAAAAAAAAAAAAAAAEo32Doz2AAAABAQEBAQEAAAABAQEBAQEAAAAJpL1J5T1AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAABAQEBAQEAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA//8AAP//AAD//wAA7/8AAMfnAADjzwAA8Z8AAAAAAAABAAAA848AAOfHAADJJwAA+T8AAP//
+ AAD//wAA//8AAA==
+
+
+
+ 233, 17
+
+
+
+ AAEAAAD/////AQAAAAAAAAAMAgAAAFdTeXN0ZW0uV2luZG93cy5Gb3JtcywgVmVyc2lvbj00LjAuMC4w
+ LCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkzNGUwODkFAQAAACZTeXN0
+ ZW0uV2luZG93cy5Gb3Jtcy5JbWFnZUxpc3RTdHJlYW1lcgEAAAAERGF0YQcCAgAAAAkDAAAADwMAAABW
+ BwAAAk1TRnQBSQFMAwEBAAHEAQABxAEAASABAAEgAQAE/wEZAQAI/wFCAU0BNgcAATYDAAEoAwABgAMA
+ ASADAAEBAQABGAYAATD/AP8A/wD/AP8A/wD/AP8A/wAwAAESAY0B9jAAARIBjQH2/wBIAAESAY0B9gEU
+ AYsB9wESAY0B9ioAARIBjQH2AREBiwH3ARIBjQH2/wBCAAESAY0B9gEEAYcB9wEYAZAB9gESAYsB9wES
+ AY0B9iQAARIBjQH2AQkBiQH3ARkBkAH2AQwBhwH4ARIBjQH2/wBCAAFBAZsB9AEUAY4B9gEaAZEB9gEU
+ AYsB9wESAY0B9h4AARIBjQH2AQoBiQH3ARwBkQH2ARQBjgH2AUABmwH0/wBIAAE0AZYB9QEUAY4B9gEZ
+ AZAB9gEeAY8B9gESAY0B9hgAARIBjQH2ARIBjQH2ARsBkQH2ARQBjgH2ATQBlgH1/wBOAAE+AZoB9AEW
+ AY4B9gEZAZAB9gEOAYkB9wESAY0B9hIAARIBjQH2AQQBiAH3ARwBkQH2ARYBjgH2AT4BmgH0/wBUAAE6
+ AZkB9AEWAY8B9gEZAZAB9gEgAY8B9gESAY0B9gwAARIBjQH2ARMBjQH2ARwBkQH2ARYBjwH2AToBmQH0
+ /wBaAAEiAY8B9gEcAZEB9gEZAZAB9gEWAYwB9wESAY0B9gYAARIBjQH2AQoBigH3ARwBkQH2ARwBkQH2
+ ASIBjwH2/wA/AAFRAZ4B8wEDAYcB9wEKAYkB9wEKAYkB9wEKAYkB9wEKAYkB9wEKAYkB9wEKAYkB9wEK
+ AYkB9wENAYsB9wEcAZEB9gEeAZIB9gEdAZEB9gEZAZAB9gEYAYwB9gESAY0B9gESAY0B9gELAYsB9wEc
+ AZEB9gEeAZIB9gEeAZIB9gEcAZEB9gENAYsB9wEKAYkB9wEKAYkB9wEKAYkB9wEKAYkB9wEKAYkB9wEK
+ AYkB9wEKAYkB9wEAAYUB+AESAY0B9v8AIQABWgGiAfMBDwGNAfYBFgGPAfYBFgGPAfYBFgGPAfYBFgGP
+ AfYBFgGPAfYBFgGPAfYBFgGPAfYBFwGPAfYBHQGRAfYBHgGSAfYBHgGSAfYBHQGRAfYBEQGNAfYBOwGY
+ AfQBNgGXAfQBFAGOAfYBHQGRAfYBHgGSAfYBHgGSAfYBHAGRAfYBFgGPAfYBFgGPAfYBFgGPAfYBFgGP
+ AfYBFgGPAfYBFgGPAfYBFgGPAfYBFgGPAfYBCwGLAfcBEgGNAfb/ACEAAX4BswHvAUkBowHyAU4BpAHy
+ AU4BpAHyAU4BpAHyAU4BpAHyAU4BpAHyAU4BpAHyAU8BpQHyAVcBqAHxASABkQH2AR0BkQH2AR4BkgH2
+ ARIBjQH2AToBmwH0BgABLAGUAfYBFQGPAfYBHgGSAfYBHAGRAfYBKwGUAfUBVwGpAfEBTwGkAfIBTgGk
+ AfIBTgGkAfIBTgGkAfIBTgGkAfIBTgGkAfIBTgGkAfIBRgGhAfMBEgGNAfb/ADwAAR0BkQH2ARkBjgH2
+ AR0BkQH2ARIBjQH2ATgBmgH0DAABKQGTAfUBFQGPAfYBGwGRAfYBIwGRAfYBEgGNAfb/AFQAAR0BkQH2
+ AR4BjwH2ARoBkQH2ARIBjQH2AT0BnAH0EgABLwGWAfUBFQGPAfYBGAGQAfYBKAGUAfYBEgGNAfb/AE4A
+ AR0BkQH2ARsBjgH2ARkBkAH2ARMBjQH2ATYBmQH0GAABKAGSAfUBFgGPAfYBFgGPAfYBJwGTAfYBEgGN
+ Afb/AEgAAR0BkQH2AR4BkAH2ARgBkAH2ARQBjgH2ATEBmAH1HgABJQGSAfYBFgGPAfYBFgGPAfYBKgGU
+ AfUBEgGNAfb/AEIAAR0BkQH2ARQBiwH3ARkBkAH2ARMBjgH2ATEBlwH1BgAGBAwABgQGAAElAZIB9gEW
+ AY8B9gEWAY8B9gEfAY8B9wESAY0B9v8APwABEgGNAfYBHwGQAfYBDgGMAfYBMwGYAfQGAAwEBgAMBAYA
+ ASYBkgH1AQ8BjAH2AScBlAH1ARIBjQH2/wBCAAESAY0B9gE0AZgB9QkAAwQB/wH4AfAGBAYAAwQB/wH4
+ AfAGBAkAATABlgH1ARIBjQH2/wBUAAwEBgAMBP8AZgAGBAwABgT/AP8A/wD/AP8A/wD/AP8A/wD/AE4A
+ AUIBTQE+BwABPgMAASgDAAGAAwABIAMAAQEBAAEBBgABAhYAA/8BAAT/DAAE/wwABP8MAAT/DAAE/wwA
+ BP8MAAH+Av8BfwwAAfwBfwH+AT8MAAH4AT8B/AEfDAAB/AEfAfgBPwwAAf4BDwHwAX8MAAH/AQcB4AH/
+ DAAB/wGDAcEB/wwAAf8BwQGDAf8tAAEBAYANAAH/AYMBwQH/DAAB/wEHAeAB/wwAAf4BDwHwAX8MAAH8
+ AR8B+AE/DAAB+AEzAcwBHwwAAfgBYQGGAR8MAAH8AeEBhwE/DAAB/wHhAYcB/wwAAf8B8wHPAf8MAAT/
+ DAAE/wwABP8MAAT/DAAE/wwABP8MAAs=
+
+
+
+
+ AAABAAEAICAAAAAAGACoDAAAFgAAACgAAAAgAAAAQAAAAAEAGAAAAAAAAAwAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQgAAQsAAQ8ABBMAABEA
+ BRcAAhIAAxEAARIAARIAABIAABIAABIAAREAAhAAAAoAFRsAAQQAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAABAd3q75O2j0dyez9+Vx9ml1+uZy9+f0OCf0OCjzuGkzuGozeOozeOozeGo
+ zuCv1uW02uaqydIABgoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAd3rP//+i
+ 3een4vKn4vWx7P+d2Oyu7P6Y1uaz7f+Xz+K88f+h0+m46v+i1emd0eKh0uChzNUAAwgAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAd3q39f2q7/m8//+q8P+KzuGz9/+Y4PG2/v+Lz+K4
+ +v+S0ea9/P+Qzuau7f+W1Oap4vGcz9kAAwgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAABAd3rA//+2//+C0dy2//+n8f+N1+mh7/+H1eWr9/+W3/Oi6P+M0umt9f+X3fSh5vmY2eie1uEA
+ DhUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABFgIKn8fWo/P+U6fOn+/+F1uWp
+ 9/+M3uqt//+F0+Og7P6O2e+p8/+AzOOk7/+U3fGv8f+Y0t4AAwsAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAA6enqp+fqe+f2e+f+i/f+P4++v//+s/P+H1uGr+f+R3Oym7/+L1e2x/f+O
+ 2PCg6f+V1+mc1eQADBcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvcXC1//+j
+ //+K6++g/v+n/v+K3Oee7fa0//+N1+Oh6fqY3/Ou9/+H0eme6P+U2vGs6/+Yz94AAQ0AAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA7fnup//2c/fuo//+R8vZ1z9ao+/+0//+T2+O9//+L
+ 0N+0+P+IzOOy+P+S2PCi5fye2++h1OQACBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAzc3Ow//+g//+R9/ak//+k//+o/v+q9vy9//+e5e+2/v+Q2Omp9f+Q2/Gj7v+b4vaq6Pqh1eIA
+ Aw0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9eHq2//+U9vah//+J9PKm//+D
+ 3d6t/P+k8fSv//+Q4+ui+f+D3eiS6/mH3+2o9/+M092f1t8AAgoAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAyZWi8//+b+PeN9PGc//+d/f2a8vKn9/ih8fKp/P6S6++f+v+L6vOY9f6T
+ 7veG2eG6//+Jw8kABQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABiiom6+/m4
+ //+m//2t//+l+/u2//+z//+z//+x//+t//+s//+p//+u//+v//+o9v21+f6i2t8ADxAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVfXg2bmk9gHswdHMwbW89eHo4dHQ7d3czcHI5
+ eX0ucHU3eIAwcXo2dH5bkpsmWF5TfH8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/
+ AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAD/AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAD/AAD/AAD/AAD/AAD/AAD/AAD/AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/
+ AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAD/AAD/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAskAAAZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAskAAAZgAAAAAAAAAlZgAz/wAz/wAz
+ /wALkAAAAAALAAAz2wAz/wAd2wAAAAAUAAAz/wAz/wAl/wAAAAAskAAAZgAAAAAztgALkAAlZgAs/wAL
+ OgAz2wAz/wAUtgAAAAAskAAs2wAz/wAUtgAlZgAAZgAAAAALAAAs2wAAOgAskAALkAAAAAAskAAAZgAs
+ kAAAZgAAAAAlZgALkAAskAAAZgAdOgAd2wAAAAAskAAAZgAskAALkAAAAAAztgAAZgAskAALkAAAAAAz
+ tgAlZgAAZgAAAAAAAAAlZgALkAAstgAAOgAAAAAAAAAAAAAAAAALAAAz2wAz/wAAZgAskAAUkAAs2wAA
+ OgAAAAAskAAAZgAstgAAOgAAAAAdOgAUtgAlkAAAOgAAAAAlZgAlZgAAZgAAAAAAAAAdOgAUtgAztgAz
+ /wAz/wAz/wAUtgAlZgAs/wAAOgAAAAAAAAAskAAz/wAUtgAAAAAAAAAskAAAZgAstgAAOgAAAAAdOgAU
+ tgAlkAAAOgAAAAAlZgAlZgAAZgAAAAAAAAAdOgAUtgAskAAAZgAAAAAlZgALkAAskAAAZgAAAAAskAAA
+ ZgAskAALZgAs2wAAOgAAAAAskAAAZgAskAALkAAAAAAztgAAZgAskAALkAAAAAAztgAlZgAAZgAAAAAA
+ AAAlZgALkAALAAAz2wAz/wAd2wAAAAAUAAAz/wAz/wAd2wAAAAAskAAAZgAUAAAz/wAUZgAz/wAs/wAL
+ OgAz2wAz/wAUtgAAAAAlkAAstgAz/wAUtgAlZgAAZgAAAAALAAAs2wAAOgAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAskAAAZgAAAAAAAAAAAAAskAAAZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAlZgAz/wAz/wAz/wALkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAskAAAZgAAAAAA
+ AAAAAAAUAAAAZgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAD//AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4AAD/+AAA//gAAP/4
+ AAD/+AAA//wAAf/n////5////+f///8A////AP///+f////n////5//3////9x5zaTVtrWrSdfta1nQ3
+ OtZ1rVrSdmNhNW//e/8f/3v//////w==
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Helper/FormDot.Designer.cs b/src/modules/MouseWithoutBorders/App/Helper/FormDot.Designer.cs
new file mode 100644
index 000000000000..fa580ff222fc
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Helper/FormDot.Designer.cs
@@ -0,0 +1,59 @@
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ partial class FormDot
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.SuspendLayout();
+ //
+ // FormDot
+ //
+ this.BackColor = System.Drawing.Color.Black;
+ this.ClientSize = new System.Drawing.Size(2, 2);
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.MaximizeBox = false;
+ this.MinimizeBox = false;
+ this.Name = "FormDot";
+ this.Opacity = 0.5D;
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
+ this.TopMost = true;
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormDot_FormClosing);
+ this.Shown += new System.EventHandler(this.FormDot_Shown);
+ this.VisibleChanged += new System.EventHandler(this.FormDot_VisibleChanged);
+ this.Click += new System.EventHandler(this.FormDot_Click);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+ }
+}
+
diff --git a/src/modules/MouseWithoutBorders/App/Helper/FormDot.cs b/src/modules/MouseWithoutBorders/App/Helper/FormDot.cs
new file mode 100644
index 000000000000..81bf1f0a7a2f
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Helper/FormDot.cs
@@ -0,0 +1,84 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Windows.Forms;
+using static MouseWithoutBorders.NativeMethods;
+
+namespace MouseWithoutBorders
+{
+ internal sealed partial class FormDot : System.Windows.Forms.Form
+ {
+ private int left;
+ private int top;
+
+ internal FormDot()
+ {
+ InitializeComponent();
+ Cursor = CreateDotCursor();
+ }
+
+ public void SetPosition(int left, int top)
+ {
+ this.left = left - 2;
+ this.top = top - 2;
+ }
+
+ private Cursor CreateCursor(Bitmap bmp, int xHotSpot, int yHotSpot)
+ {
+ IconInfo tmp = default;
+ tmp.xHotspot = xHotSpot;
+ tmp.yHotspot = yHotSpot;
+ tmp.fIcon = false;
+ tmp.hbmColor = bmp.GetHbitmap();
+ tmp.hbmMask = bmp.GetHbitmap();
+ return new Cursor(NativeMethods.CreateIconIndirect(ref tmp));
+ }
+
+ private Cursor CreateDotCursor()
+ {
+ Bitmap bitmap = new(32, 32, PixelFormat.Format24bppRgb);
+ bitmap.MakeTransparent(Color.Black);
+ Graphics g = Graphics.FromImage(bitmap);
+ g.DrawLine(Pens.Gray, 0, 0, 1, 1);
+ Cursor c = CreateCursor(bitmap, 0, 0);
+ bitmap.Dispose();
+ return c;
+ }
+
+ private void FormDot_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ if (e.CloseReason == CloseReason.UserClosing)
+ {
+ e.Cancel = true;
+ }
+ }
+
+ private void FormDot_Shown(object sender, EventArgs e)
+ {
+ MoveMe();
+ }
+
+ private void MoveMe()
+ {
+ Left = left;
+ Top = top;
+ Width = 4;
+ Height = 4;
+ }
+
+ private void FormDot_Click(object sender, EventArgs e)
+ {
+ IntPtr foreGroundWindow = NativeMethods.GetForegroundWindow();
+ Program.FormHelper.SendLog($"{nameof(FormDot_Click)}.Foreground window ({foreGroundWindow}) is " + (foreGroundWindow == Handle ? string.Empty : "not ") + $"the dot form: {Program.DotForm.Handle}.");
+ }
+
+ private void FormDot_VisibleChanged(object sender, EventArgs e)
+ {
+ MoveMe();
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Helper/FormDot.resx b/src/modules/MouseWithoutBorders/App/Helper/FormDot.resx
new file mode 100644
index 000000000000..d58980a38d71
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Helper/FormDot.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Helper/FormHelper.Designer.cs b/src/modules/MouseWithoutBorders/App/Helper/FormHelper.Designer.cs
new file mode 100644
index 000000000000..80f7017d92b4
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Helper/FormHelper.Designer.cs
@@ -0,0 +1,77 @@
+namespace MouseWithoutBorders
+{
+ partial class FormHelper
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ this.components = new System.ComponentModel.Container();
+ System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormHelper));
+ this.timerHelper = new System.Windows.Forms.Timer(this.components);
+ this.SuspendLayout();
+ //
+ // timerHelper
+ //
+ this.timerHelper.Interval = 2000;
+ this.timerHelper.Tick += new System.EventHandler(this.TimerHelper_Tick);
+ //
+ // FormHelper
+ //
+ this.AllowDrop = true;
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None;
+ this.ClientSize = new System.Drawing.Size(60, 60);
+ this.ControlBox = false;
+ this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+ this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+ this.KeyPreview = true;
+ this.Name = "FormHelper";
+ this.Opacity = 0.11D;
+ this.ShowIcon = false;
+ this.ShowInTaskbar = false;
+ this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
+ this.Text = "Mouse without Borders Helper";
+ this.TopMost = true;
+ this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.FormHelper_FormClosing);
+ this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormHelper_FormClosed);
+ this.Shown += new System.EventHandler(this.FormHelper_Shown);
+ this.LocationChanged += new System.EventHandler(this.FormHelper_LocationChanged);
+ this.DragEnter += new System.Windows.Forms.DragEventHandler(this.FormHelper_DragEnter);
+ this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.FormHelper_KeyDown);
+ this.KeyUp += new System.Windows.Forms.KeyEventHandler(this.FormHelper_KeyUp);
+ this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.FormHelper_MouseDown);
+ this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.FormHelper_MouseMove);
+ this.MouseUp += new System.Windows.Forms.MouseEventHandler(this.FormHelper_MouseUp);
+ this.ResumeLayout(false);
+
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Timer timerHelper;
+ }
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Helper/FormHelper.cs b/src/modules/MouseWithoutBorders/App/Helper/FormHelper.cs
new file mode 100644
index 000000000000..ee485263ff2f
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Helper/FormHelper.cs
@@ -0,0 +1,782 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Diagnostics;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Globalization;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Windows.Forms;
+
+namespace MouseWithoutBorders
+{
+ public partial class FormHelper : System.Windows.Forms.Form
+ {
+ private readonly List focusZone = new();
+ private readonly object bmScreenLock = new();
+ private long lastClipboardEventTime;
+
+ private IClipboardHelper remoteClipboardHelper;
+ private const string TEXT_TYPE_SEP = "{4CFF57F7-BEDD-43d5-AE8F-27A61E886F2F}";
+
+ private const int MAX_TEXT_SIZE = 20 * 1024 * 1024;
+ private const int MAX_IMAGE_SIZE = 50 * 1024 * 1024;
+
+ private struct FocusArea
+ {
+ internal RectangleF Rec;
+ internal Color Color;
+
+ internal FocusArea(RectangleF rec, Color color)
+ {
+ Rec = rec;
+ Color = color;
+ }
+ }
+
+ private Point focus1 = Point.Empty;
+ private Point focus2 = Point.Empty;
+
+ public FormHelper()
+ {
+ remoteClipboardHelper = IpcHelper.CreateIpcClient();
+
+ if (remoteClipboardHelper == null)
+ {
+ QuitDueToCommunicationError();
+ return;
+ }
+
+ SetDPIAwareness();
+ InitializeComponent();
+ lastClipboardEventTime = GetTick();
+ ClipboardMMHelper.HookClipboard(this);
+ }
+
+ private void SetDPIAwareness()
+ {
+ int setProcessDpiAwarenessResult = -1;
+
+ try
+ {
+ setProcessDpiAwarenessResult = NativeMethods.SetProcessDpiAwareness(2);
+ SendLog(string.Format(CultureInfo.InvariantCulture, "SetProcessDpiAwareness: {0}.", setProcessDpiAwarenessResult));
+ }
+ catch (DllNotFoundException)
+ {
+ SendLog("SetProcessDpiAwareness is unsupported in Windows 7 and lower.");
+ }
+ catch (Exception e)
+ {
+ SendLog(e.ToString());
+ }
+
+ try
+ {
+ if (setProcessDpiAwarenessResult != 0)
+ {
+ SendLog(string.Format(CultureInfo.InvariantCulture, "SetProcessDPIAware: {0}.", NativeMethods.SetProcessDPIAware()));
+ }
+ }
+ catch (Exception e)
+ {
+ SendLog(e.ToString());
+ }
+ }
+
+ private bool quitDueToCommunicationError;
+
+ private void QuitDueToCommunicationError()
+ {
+ if (!quitDueToCommunicationError)
+ {
+ quitDueToCommunicationError = true;
+
+ if (Process.GetCurrentProcess().SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
+ {
+ Logger.LogEvent(Application.ProductName + " cannot be used in a remote desktop or virtual machine session.");
+ }
+ else
+ {
+ _ = MessageBox.Show(
+ "Unable to connect to Mouse Without Borders process, clipboard sharing is no longer working.\r\nSee EventLog for more information.",
+ Text,
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Error);
+ }
+
+ Process.GetCurrentProcess().Kill();
+ }
+ }
+
+ private void FormHelper_DragEnter(object sender, DragEventArgs e)
+ {
+ object o = e.Data.GetData(DataFormats.FileDrop);
+
+ if (o != null)
+ {
+ e.Effect = DragDropEffects.Copy;
+ Array ar = (string[])o;
+
+ if (ar.Length > 0)
+ {
+ string fileName = ar.GetValue(0).ToString();
+ Hide();
+
+ try
+ {
+ remoteClipboardHelper.SendDragFile(fileName);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogEvent("FormHelper_DragEnter: " + ex.Message, EventLogEntryType.Error);
+ QuitDueToCommunicationError();
+ }
+ }
+ }
+ }
+
+ private void TimerHelper_Tick(object sender, EventArgs e)
+ {
+ lock (bmScreenLock)
+ {
+ if (picScr == null)
+ {
+ timerHelper.Stop();
+ Hide();
+ }
+ }
+ }
+
+ private void FormHelper_Shown(object sender, EventArgs e)
+ {
+ timerHelper.Start(); // To be sure.
+ Hide();
+ }
+
+ internal void SendLog(string log)
+ {
+ try
+ {
+ Logger.LogEvent(log, EventLogEntryType.Warning);
+ }
+ catch (Exception e)
+ {
+ Logger.LogEvent(log + " ==> SendLog Exception: " + e.Message, EventLogEntryType.Warning);
+ }
+ }
+
+ private long GetTick() // ms
+ {
+ return DateTime.Now.Ticks / 10000;
+ }
+
+ private string GetClipboardText()
+ {
+ string st = string.Empty, tmp = ClipboardMMHelper.GetText(TextDataFormat.UnicodeText);
+ int txtL = 0, rtfL = 0, htmL = 0;
+
+ if (tmp != null && (txtL = tmp.Length) > 0)
+ {
+ st += "TXT" + tmp + TEXT_TYPE_SEP;
+ }
+
+ tmp = ClipboardMMHelper.GetText(TextDataFormat.Rtf);
+
+ if (tmp != null && (rtfL = tmp.Length) > 0)
+ {
+ st += "RTF" + tmp + TEXT_TYPE_SEP;
+ }
+
+ tmp = ClipboardMMHelper.GetText(TextDataFormat.Html);
+
+ if (tmp != null && (htmL = tmp.Length) > 0)
+ {
+ st += "HTM" + tmp + TEXT_TYPE_SEP;
+ }
+
+ if (st.Length > 0)
+ {
+ if (st.Length > MAX_TEXT_SIZE)
+ {
+ st = null;
+
+ SendLog(string.Format(CultureInfo.CurrentCulture, "GetClipboardText, Text too big: TXT = {0}, RTF = {1}, HTM = {2}.", txtL, rtfL, htmL));
+ }
+ else
+ {
+ SendLog(string.Format(CultureInfo.CurrentCulture, "GetClipboardText: TXT = {0}, RTF = {1}, HTM = {2}.", txtL, rtfL, htmL));
+ }
+ }
+
+ return st;
+ }
+
+#pragma warning disable CA2213 // Disposing is done by ComponentResourceManager
+ private Image bmScreen;
+ private Point startOrg;
+ private Point start;
+ private Point stop;
+ private PictureBox left;
+ private PictureBox top;
+ private PictureBox right;
+ private PictureBox bottom;
+ private PictureBox picScr;
+#pragma warning restore CA2213
+ private int customScreenCaptureInProgress;
+ private int screenLeft;
+ private int screenTop;
+
+ protected override void WndProc(ref Message m)
+ {
+ const int WM_DRAWCLIPBOARD = 0x0308;
+ const int WM_CHANGECBCHAIN = 0x030D;
+ const int WM_CLIPBOARDUPDATE = 0x031D;
+
+ switch (m.Msg)
+ {
+ case WM_DRAWCLIPBOARD:
+ case WM_CLIPBOARDUPDATE:
+ ClipboardMMHelper.PassMessageToTheNextViewer(m);
+
+ if (GetTick() - lastClipboardEventTime < 1000)
+ {
+ lastClipboardEventTime = GetTick();
+ return;
+ }
+
+ if (customScreenCaptureInProgress > 0)
+ {
+ // 10 secs timeout for a failed capture.
+ if (GetTick() - lastClipboardEventTime < 10000)
+ {
+ return;
+ }
+ else
+ {
+ customScreenCaptureInProgress = 0;
+ }
+ }
+
+ lastClipboardEventTime = GetTick();
+
+ ByteArrayOrString? data = null;
+ bool isFile = false;
+
+ if (ClipboardMMHelper.ContainsText())
+ {
+ data = GetClipboardText();
+ }
+ else if (ClipboardMMHelper.ContainsImage())
+ {
+ MemoryStream ms = new();
+ Image im = ClipboardMMHelper.GetImage();
+
+ if (im != null)
+ {
+ im.Save(ms, ImageFormat.Png);
+
+ if (ms.Length > 0)
+ {
+ if (ms.Length > MAX_IMAGE_SIZE)
+ {
+ SendLog("Image from clipboard, image too big: " + ms.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ else
+ {
+ data = ms.GetBuffer();
+ SendLog("Image from clipboard: " + ms.Length.ToString(CultureInfo.InvariantCulture));
+ }
+ }
+ else
+ {
+ SendLog("ClipboardMMHelper image is 0 in length.");
+ }
+ }
+ else
+ {
+ SendLog("ClipboardMMHelper image (GetImage) is null.");
+ }
+
+ ms.Dispose();
+ }
+ else if (ClipboardMMHelper.ContainsFileDropList())
+ {
+ StringCollection files = ClipboardMMHelper.GetFileDropList();
+
+ if (files != null)
+ {
+ if (files.Count > 0)
+ {
+ data = files[0];
+ isFile = true;
+
+ SendLog("File from clipboard: " + files[0]);
+ }
+ else
+ {
+ SendLog("GetFileDropList returned no file.");
+ }
+ }
+ else
+ {
+ SendLog("GetFileDropList returned null.");
+ }
+ }
+ else
+ {
+ SendLog("ClipboardMMHelper does not have text/image/file data.");
+ return;
+ }
+
+ if (data != null)
+ {
+ try
+ {
+ remoteClipboardHelper.SendClipboardData((ByteArrayOrString)data, isFile);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogEvent("WM_DRAWCLIPBOARD: " + ex.Message, EventLogEntryType.Error);
+ QuitDueToCommunicationError();
+ }
+
+ GC.Collect();
+ }
+ else
+ {
+ SendLog("Null clipboard data returned. See previous messages (if any) for more information.");
+ }
+
+ break;
+
+ case WM_CHANGECBCHAIN:
+ if (!ClipboardMMHelper.UpdateNextClipboardViewer(m))
+ {
+ ClipboardMMHelper.PassMessageToTheNextViewer(m);
+ }
+
+ break;
+
+ case 0x401:
+ screenLeft = 0;
+ screenTop = 0;
+
+ foreach (Screen s in Screen.AllScreens)
+ {
+ if (s.Bounds.Left < screenLeft)
+ {
+ screenLeft = s.Bounds.Left;
+ }
+
+ if (s.Bounds.Top < screenTop)
+ {
+ screenTop = s.Bounds.Top;
+ }
+ }
+
+ customScreenCaptureInProgress = 1;
+ lastClipboardEventTime = GetTick();
+ SendLog("**************************************************\r\nScreen capture triggered.");
+ m.Result = new IntPtr(1);
+ break;
+
+ case 0x406:
+ if (m.Msg == 0x406)
+ {
+ lock (bmScreenLock)
+ {
+ bmScreen = null;
+
+ for (int i = 0; i < 30; i++)
+ {
+ Thread.Sleep(100);
+
+ if (ClipboardMMHelper.ContainsImage())
+ {
+ bmScreen = ClipboardMMHelper.GetImage();
+ customScreenCaptureInProgress = 1;
+ break;
+ }
+ }
+
+ if (bmScreen == null)
+ {
+ customScreenCaptureInProgress = 0;
+ SendLog("No image found in the clipboard.");
+ }
+ else
+ {
+ Opacity = 1;
+ picScr = new PictureBox();
+ picScr.Dock = DockStyle.Fill;
+ picScr.SizeMode = PictureBoxSizeMode.StretchImage;
+ picScr.Image = bmScreen;
+ picScr.Refresh();
+ Controls.Add(picScr);
+ AssignEventHandlers(picScr);
+ }
+ }
+ }
+
+ MouseMoveHandler();
+ break;
+
+ case 0x407:
+ Program.DotForm.SetPosition(m.WParam.ToInt32(), m.LParam.ToInt32());
+ Program.DotForm.TopMost = true;
+ Program.DotForm.Show();
+ Application.DoEvents();
+ m.Result = SetForeGround() ? new IntPtr(1) : IntPtr.Zero;
+ break;
+
+ case 0x408:
+ Program.DotForm.Hide();
+ break;
+
+ case 0x400:
+ m.Result = Handle;
+ break;
+
+ case SharedConst.QUIT_CMD:
+ Process.GetCurrentProcess().Kill();
+ break;
+
+ default:
+ base.WndProc(ref m);
+ break;
+ }
+ }
+
+ private bool SetForeGround()
+ {
+ string logTag = nameof(SetForeGround);
+ IntPtr foreGroundWindow = NativeMethods.GetForegroundWindow();
+
+ if (foreGroundWindow == Program.DotForm.Handle)
+ {
+ SendLog($"{logTag}.Foreground window is already the dot form: {foreGroundWindow}.");
+ return true;
+ }
+
+ Program.DotForm.Activate();
+
+ bool setForegroundWindow = NativeMethods.SetForegroundWindow(Program.DotForm.Handle);
+ SendLog($"{logTag}.{nameof(NativeMethods.SetForegroundWindow)}({Program.DotForm.Handle}) returned: {setForegroundWindow}.");
+
+ return LogForeGroundWindow(logTag);
+ }
+
+ private bool LogForeGroundWindow(string logTag)
+ {
+ IntPtr foreGroundWindow = NativeMethods.GetForegroundWindow();
+
+ if (foreGroundWindow == Program.DotForm.Handle)
+ {
+ SendLog($"{logTag}.Foreground window is now the dot form: {Program.DotForm.Handle}.");
+ return true;
+ }
+ else
+ {
+ SendLog($"{logTag}.Foreground window is: [{foreGroundWindow}].");
+ return false;
+ }
+ }
+
+ private void AssignEventHandlers(PictureBox p)
+ {
+ p.MouseDown += new System.Windows.Forms.MouseEventHandler(FormHelper_MouseDown);
+ p.MouseMove += new System.Windows.Forms.MouseEventHandler(FormHelper_MouseMove);
+ p.MouseUp += new System.Windows.Forms.MouseEventHandler(FormHelper_MouseUp);
+ }
+
+ private void MouseMoveHandler()
+ {
+ lock (bmScreenLock)
+ {
+ if (bmScreen != null && Opacity == 1)
+ {
+ focusZone.Clear();
+ TopMost = true;
+ Show();
+
+ startOrg = new Point(MousePosition.X - screenLeft, MousePosition.Y - screenTop);
+
+ if (left == null)
+ {
+ left = new PictureBox();
+ left.BackColor = Color.Red;
+ Controls.Add(left);
+ left.BringToFront();
+ AssignEventHandlers(left);
+ }
+
+ left.Left = startOrg.X;
+ left.Top = startOrg.Y;
+ left.Width = 2;
+ left.Height = 100;
+ left.Show();
+ left.Refresh();
+
+ if (top == null)
+ {
+ top = new PictureBox();
+ top.BackColor = Color.Red;
+ Controls.Add(top);
+ top.BringToFront();
+ AssignEventHandlers(top);
+ }
+
+ top.Left = startOrg.X;
+ top.Top = startOrg.Y;
+ top.Height = 2;
+ top.Width = 100;
+ top.Show();
+ top.Refresh();
+ }
+ }
+ }
+
+ private void MouseDownMoveHandler()
+ {
+ lock (bmScreenLock)
+ {
+ if (bmScreen != null && left != null && top != null)
+ {
+ int x = MousePosition.X - screenLeft;
+ int y = MousePosition.Y - screenTop;
+
+ start = new Point(startOrg.X < x ? startOrg.X : x, startOrg.Y < y ? startOrg.Y : y);
+ stop = new Point(startOrg.X > x ? startOrg.X : x, startOrg.Y > y ? startOrg.Y : y);
+
+ left.Left = start.X;
+ left.Top = start.Y;
+ left.Width = 2;
+ left.Height = stop.Y - start.Y;
+ left.Show();
+
+ top.Left = start.X;
+ top.Top = start.Y;
+ top.Height = 2;
+ top.Width = stop.X - start.X;
+ top.Show();
+
+ if (right == null)
+ {
+ right = new PictureBox();
+ right.BackColor = Color.Red;
+ Controls.Add(right);
+ right.BringToFront();
+ AssignEventHandlers(right);
+ }
+
+ right.Left = stop.X;
+ right.Top = start.Y;
+ right.Width = 2;
+ right.Height = stop.Y - start.Y;
+ right.Show();
+
+ if (bottom == null)
+ {
+ bottom = new PictureBox();
+ bottom.BackColor = Color.Red;
+ Controls.Add(bottom);
+ bottom.BringToFront();
+ AssignEventHandlers(bottom);
+ }
+
+ bottom.Left = start.X;
+ bottom.Top = stop.Y;
+ bottom.Height = 2;
+ bottom.Width = stop.X - start.X;
+ bottom.Show();
+
+ TopMost = true;
+ Show();
+ }
+ }
+ }
+
+ private void MouseUpHandler(bool canceled = false, bool rightMouseButton = false)
+ {
+ lock (bmScreenLock)
+ {
+ MouseDownMoveHandler();
+ customScreenCaptureInProgress = 0;
+
+ if (!canceled && bmScreen != null && left != null && top != null && right != null && bottom != null
+ && stop.X - start.X > 0 && stop.Y - start.Y > 0)
+ {
+ start = PointInStandardDPI(start);
+ stop = PointInStandardDPI(stop);
+ Bitmap bm = new(stop.X - start.X, stop.Y - start.Y);
+ Graphics g = Graphics.FromImage(bm);
+
+ try
+ {
+ g.DrawImage(bmScreen, 0, 0, new Rectangle(start, bm.Size), GraphicsUnit.Pixel);
+ g.DrawRectangle(Pens.DarkOrange, 0, 0, stop.X - start.X - 1, stop.Y - start.Y - 1);
+
+ foreach (FocusArea f in focusZone)
+ {
+ RectangleF rec = RectangleFInStandardDPI(f.Rec);
+ rec.X -= start.X;
+ rec.Y -= start.Y;
+
+ g.DrawEllipse(new Pen(f.Color, 2), rec);
+ }
+
+ if (rightMouseButton)
+ {
+ try
+ {
+ string tempFile = Path.GetTempPath() + Path.GetFileNameWithoutExtension(Path.GetTempFileName()) + ".png";
+ SendLog(tempFile);
+ bm.Save(tempFile, ImageFormat.Png);
+ lastClipboardEventTime = GetTick();
+ ClipboardMMHelper.SetText(tempFile);
+ }
+ catch (IOException ioException)
+ {
+ SendLog("IO!Exception!: " + ioException.Message);
+ }
+ catch (ArgumentNullException argException)
+ {
+ SendLog("ArgNull!Exception!: " + argException.Message);
+ }
+ catch (ExternalException internalException)
+ {
+ SendLog("Internal!Exception!: " + internalException.Message);
+ }
+ }
+ else
+ {
+ lastClipboardEventTime = GetTick() - 10000;
+ ClipboardMMHelper.SetImage(bm);
+ }
+ }
+ finally
+ {
+ g.Dispose();
+ bm.Dispose();
+ bmScreen.Dispose();
+ bmScreen = null;
+ }
+ }
+
+ ShowInTaskbar = false;
+ Hide();
+ Controls.Clear();
+ Opacity = 0.11;
+ left?.Dispose();
+ top?.Dispose();
+ right?.Dispose();
+ bottom?.Dispose();
+ picScr?.Dispose();
+ left = top = right = bottom = picScr = null;
+
+ SendLog("Screen capture ended.\r\n**************************************************");
+ }
+ }
+
+ private void FormHelper_FormClosed(object sender, FormClosedEventArgs e)
+ {
+ ClipboardMMHelper.UnhookClipboard();
+ }
+
+ private void FormHelper_LocationChanged(object sender, EventArgs e)
+ {
+ lock (bmScreenLock)
+ {
+ if (picScr == null && !timerHelper.Enabled)
+ {
+ Opacity = 0.11;
+ timerHelper.Start();
+ }
+ }
+ }
+
+ private void FormHelper_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Escape)
+ {
+ MouseUpHandler(true);
+ }
+
+ if (focus1.IsEmpty)
+ {
+ focus1 = stop;
+ }
+ }
+
+ private void FormHelper_KeyUp(object sender, KeyEventArgs e)
+ {
+ focus2 = stop;
+
+ float x = Math.Min(focus1.X, focus2.X);
+ float y = Math.Min(focus1.Y, focus2.Y);
+ float w = Math.Abs(focus1.X - focus2.X);
+ float h = Math.Abs(focus1.Y - focus2.Y);
+ x -= 0.25F * w;
+ y -= 0.25F * h;
+ w *= 1.5F;
+ h *= 1.5F;
+
+ focusZone.Add(new FocusArea(new RectangleF(x, y, w, h), e.KeyCode == Keys.B ? Color.Blue : e.KeyCode == Keys.G ? Color.Green : Color.Red));
+
+ focus1 = focus2 = Point.Empty;
+ }
+
+ private void FormHelper_FormClosing(object sender, FormClosingEventArgs e)
+ {
+ if (e.CloseReason == CloseReason.UserClosing)
+ {
+ e.Cancel = true;
+ }
+ }
+
+ private void FormHelper_MouseDown(object sender, MouseEventArgs e)
+ {
+ SendLog("Screen capture Mouse down.");
+ MouseMoveHandler();
+ customScreenCaptureInProgress = 2;
+ }
+
+ private void FormHelper_MouseMove(object sender, MouseEventArgs e)
+ {
+ if (customScreenCaptureInProgress == 1)
+ {
+ MouseMoveHandler();
+ }
+ else if (customScreenCaptureInProgress == 2)
+ {
+ MouseDownMoveHandler();
+ }
+ }
+
+ private void FormHelper_MouseUp(object sender, MouseEventArgs e)
+ {
+ MouseUpHandler(false, e.Button == MouseButtons.Right);
+ }
+
+ private Point PointInStandardDPI(Point p)
+ {
+ // Since the process is DPI awareness, just log and return.
+ // TODO: Test in Win8/7/XP.
+ SendLog(string.Format(CultureInfo.CurrentCulture, "this.Width={0}, this.Height={1}, bmScreen.Width={2}, bmScreen.Height={3}, x={4}, y={5}", Width, Height, bmScreen.Width, bmScreen.Height, p.X, p.Y));
+ return p;
+ }
+
+ private RectangleF RectangleFInStandardDPI(RectangleF r)
+ {
+ // Since the process is DPI awareness, just return.
+ return r;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Helper/FormHelper.resx b/src/modules/MouseWithoutBorders/App/Helper/FormHelper.resx
new file mode 100644
index 000000000000..50f553959f2c
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Helper/FormHelper.resx
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+
+
+ AAABAAIAICAAAAAAGACoDAAAJgAAABAQAAAAABgAaAMAAM4MAAAoAAAAIAAAAEAAAAABABgAAAAAAAAM
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32FIv3Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32EYv3Eo32AAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32BIf3GJD2Eov3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAEo32CYn3GZD2DIf4Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ QZv0FI72GpH2FIv3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32Con3HJH2FI72QJv0
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANJb1FI72GZD2Ho/2Eo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAEo32Eo32G5H2FI72NJb1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAPpr0Fo72GZD2Don3Eo32AAAAAAAAAAAAAAAAAAAAAAAAEo32BIj3HJH2
+ Fo72Ppr0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOpn0
+ Fo/2GZD2II/2Eo32AAAAAAAAAAAAAAAAEo32E432HJH2Fo/2Opn0AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIo/2HJH2GZD2Foz3Eo32AAAAAAAAEo32
+ Cor3HJH2HJH2Io/2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUZ7zA4f3Con3Con3Con3Con3
+ Con3Con3Con3DYv3HJH2HpL2HZH2GZD2GIz2Eo32Eo32C4v3HJH2HpL2HpL2HJH2DYv3Con3Con3Con3
+ Con3Con3Con3Con3AIX4Eo32WqLzD432Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2F4/2HZH2HpL2HpL2HZH2
+ EY32O5j0Npf0FI72HZH2HpL2HpL2HJH2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2Fo/2C4v3Eo32frPvSaPy
+ TqTyTqTyTqTyTqTyTqTyTqTyT6XyV6jxIJH2HZH2HpL2Eo32Opv0AAAAAAAALJT2FY/2HpL2HJH2K5T1
+ V6nxT6TyTqTyTqTyTqTyTqTyTqTyTqTyRqHzEo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2
+ GY72HZH2Eo32OJr0AAAAAAAAAAAAAAAAKZP1FY/2G5H2I5H2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2Ho/2GpH2Eo32PZz0AAAAAAAAAAAAAAAAAAAA
+ AAAAL5b1FY/2GJD2KJT2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAHZH2G472GZD2E432Npn0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKJL1Fo/2Fo/2J5P2Eo32AAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHZH2HpD2GJD2FI72MZj1AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAJZL2Fo/2Fo/2KpT1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAHZH2FIv3GZD2E472MZf1AAAAAAAABAQEBAQEAAAAAAAAAAAAAAAABAQEBAQEAAAAAAAA
+ JZL2Fo/2Fo/2H4/3Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32H5D2Doz2M5j0AAAA
+ AAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAJpL1D4z2J5T1Eo32AAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32NJj1AAAAAAAAAAAABAQE//jwBAQEBAQEAAAAAAAABAQE
+ //jwBAQEBAQEAAAAAAAAAAAAMJb1Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQE
+ AAAAAAAAAAAAAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////////////////////////////////v//f/x/
+ /j/4P/wf/B/4P/4P8H//B+D//4PB///Bg/8AAAAAAAAAAAABgAD/g8H//wfg//4P8H/8H/g/+DPMH/hh
+ hh/84Yc//+GH///zz/////////////////////////////////8oAAAAEAAAACAAAAABABgAAAAAAAAD
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEo32GJD2Eo32AAAAAAAAAAAAAAAAAAAA
+ AAAACYn3DIf4AAAAAAAAAAAAAAAAAAAAAAAANJb1GZD2Eo32AAAAAAAAAAAAAAAAEo32FI72AAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAOpn0GZD2Eo32AAAAAAAAE432Fo/2AAAAAAAAAAAAAAAAAAAAA4f3Con3
+ Con3Con3DYv3HpL2GZD2Eo32C4v3HpL2HJH2Con3Con3Con3Con3Eo32SaPyTqTyTqTyTqTyV6jxHZH2
+ Eo32AAAALJT2HpL2K5T1T6TyTqTyTqTyTqTyEo32AAAAAAAAAAAAAAAAHo/2Eo32AAAAAAAAAAAAL5b1
+ GJD2Eo32AAAAAAAAAAAAAAAAAAAAAAAAAAAAHpD2FI72AAAAAAAAAAAAAAAAAAAAJZL2Fo/2Eo32AAAA
+ AAAAAAAAAAAAAAAAEo32Doz2AAAABAQEBAQEAAAABAQEBAQEAAAAJpL1J5T1AAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAABAQEBAQEAAAABAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+ AAAAAAAA//8AAP//AAD//wAA7/8AAMfnAADjzwAA8Z8AAAAAAAABAAAA848AAOfHAADJJwAA+T8AAP//
+ AAD//wAA//8AAA==
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj b/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj
new file mode 100644
index 000000000000..9d5d403e5927
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Helper/MouseWithoutBordersHelper.csproj
@@ -0,0 +1,84 @@
+
+
+
+ net7.0-windows10.0.19041.0
+ WinExe
+ true
+ false
+ false
+ PowerToys.MouseWithoutBordersHelper
+ true
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\MouseWithoutBorders
+ true
+ true
+ $(Version).0
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
+
+
+
+ MM_HELPER;TRACE;DEBUG;SHOW_ON_WINLOGON CODE_ANALYSIS CUSTOMIZE_LOGON_SCREEN
+ false
+
+
+ MM_HELPER;TRACE;SHOW_ON_WINLOGON CODE_ANALYSIS CUSTOMIZE_LOGON_SCREEN
+ false
+
+
+
+
+ ..\Logo.ico
+
+
+ true
+
+
+
+ PowerToys.GPOWrapper
+ $(OutDir)
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IClipboardHelper.cs
+
+
+
+
+
+ PreserveNewest
+
+
+
+
+
+ all
+
+
+
+
+
+
+
+
+
+ True
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Helper/NativeMethods.cs b/src/modules/MouseWithoutBorders/App/Helper/NativeMethods.cs
new file mode 100644
index 000000000000..9911116903e5
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Helper/NativeMethods.cs
@@ -0,0 +1,874 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Windows APIs.
+//
+//
+// 2008 created by Truong Do (ductdo).
+// 2009-... modified by Truong Do (TruongDo).
+// 2023- Included in PowerToys.
+//
+using System;
+using System.Diagnostics.CodeAnalysis;
+using System.Drawing;
+using System.Runtime.InteropServices;
+using System.Text;
+
+// We are sure we dont have managed resource in KEYBDINPUT, IntPtr just holds a value
+[module: SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable", Scope = "type", Target = "MouseWithoutBorders.NativeMethods+KEYBDINPUT", Justification = "Dotnet port with style preservation")]
+
+// Some other minor issues
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#ConvertStringSidToSid(System.String,System.IntPtr&)", MessageId = "0", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#DrawText(System.IntPtr,System.String,System.Int32,MouseWithoutBorders.NativeMethods+RECT&,System.UInt32)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#SetWindowText(System.IntPtr,System.String)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#FindWindow(System.String,System.String)", MessageId = "0", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#FindWindow(System.String,System.String)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetWindowText(System.IntPtr,System.Text.StringBuilder,System.Int32)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#keybd_event(System.Byte,System.Byte,System.UInt32,System.Int32)", MessageId = "3", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#SendMessage(System.IntPtr,System.Int32,System.IntPtr,System.IntPtr)", MessageId = "return", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources", Scope = "member", Target = "MouseWithoutBorders.NativeMethods+KEYBDINPUT.#dwExtraInfo", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Scope = "member", Target = "MouseWithoutBorders.NativeMethods+INPUT64.#type", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#TerminateProcess(System.IntPtr,System.IntPtr)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetClassName(System.IntPtr,System.Text.StringBuilder,System.Int32)", MessageId = "1", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetClassName(System.IntPtr,System.Text.StringBuilder,System.Int32)", MessageId = "return", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetAsyncKeyState(System.IntPtr)", MessageId = "0", Justification = "Dotnet port with style preservation")]
+[module: SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Scope = "member", Target = "MouseWithoutBorders.NativeMethods.#GetAsyncKeyState(System.IntPtr)", MessageId = "return", Justification = "Dotnet port with style preservation")]
+
+namespace MouseWithoutBorders
+{
+ internal sealed partial class NativeMethods
+ {
+ internal struct IconInfo
+ {
+ internal bool fIcon;
+ internal int xHotspot;
+ internal int yHotspot;
+ internal IntPtr hbmMask;
+ internal IntPtr hbmColor;
+ }
+
+ [DllImport("user32.dll")]
+ internal static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ internal static extern IntPtr SendMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll")]
+ internal static extern IntPtr GetForegroundWindow();
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetForegroundWindow(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ internal static extern IntPtr CreateIconIndirect(ref IconInfo icon);
+
+ [return: MarshalAs(UnmanagedType.Bool)]
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern bool SetProcessDPIAware();
+
+ [DllImport("Shcore.dll", SetLastError = true)]
+ internal static extern int SetProcessDpiAwareness(uint type); // Win 8.1 and up, DPI can be per monitor.
+
+ [DllImport("kernel32.dll")]
+ internal static extern uint WTSGetActiveConsoleSessionId();
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern bool ChangeWindowMessageFilterEx(IntPtr hWnd, uint msg, int action, IntPtr changeInfo);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool PostMessage(IntPtr hwnd, int wMsg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll", SetLastError = false)]
+ internal static extern IntPtr GetDesktopWindow();
+
+ [DllImport("user32.dll")]
+ internal static extern IntPtr GetWindowDC(IntPtr hWnd);
+
+ [DllImport("user32.dll")]
+ internal static extern int DrawText(IntPtr hDC, string lpString, int nCount, ref RECT lpRect, uint uFormat);
+
+ [DllImport("gdi32.dll")]
+ internal static extern uint SetTextColor(IntPtr hdc, int crColor);
+
+ [DllImport("gdi32.dll")]
+ internal static extern uint SetBkColor(IntPtr hdc, int crColor);
+
+ [DllImport("user32.dll")]
+ internal static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ internal static extern IntPtr GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetWindowText(IntPtr hWnd, string lpString);
+
+ [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ internal static extern int GetWindowTextLength(IntPtr hWnd);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ internal static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool DestroyIcon(IntPtr handle);
+
+ [DllImport("user32")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetCursorPos(int X, int Y);
+
+ [DllImport("user32", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool GetCursorPos(ref Point p);
+
+ [DllImport("advapi32", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle);
+
+ [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool DuplicateToken(IntPtr ExistingTokenHandle, int SECURITY_IMPERSONATION_LEVEL, ref IntPtr DuplicateTokenHandle);
+
+ [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool DuplicateTokenEx(
+ IntPtr ExistingTokenHandle,
+ uint dwDesiredAccess,
+ ref SECURITY_ATTRIBUTES lpThreadAttributes,
+ int TokenType,
+ int ImpersonationLevel,
+ ref IntPtr DuplicateTokenHandle);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ConvertStringSidToSid(string StringSid, out IntPtr ptrSid);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetTokenInformation(IntPtr TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass, ref TOKEN_MANDATORY_LABEL TokenInformation, uint TokenInformationLength);
+
+ [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Justification = "Dotnet port with style preservation")]
+ [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CreateProcessAsUser(
+ IntPtr hToken,
+ string lpApplicationName,
+ string lpCommandLine,
+ ref SECURITY_ATTRIBUTES lpProcessAttributes,
+ ref SECURITY_ATTRIBUTES lpThreadAttributes,
+ [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle,
+ int dwCreationFlags,
+ IntPtr lpEnvironment,
+ string lpCurrentDirectory,
+ ref STARTUPINFO lpStartupInfo,
+ out PROCESS_INFORMATION lpProcessInformation);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool EnumDisplayMonitors(
+ IntPtr hdc,
+ IntPtr lprcClip,
+ EnumMonitorsDelegate lpfnEnum,
+ IntPtr dwData);
+
+ [DllImport("user32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfoEx lpmi);
+
+ [DllImport("User32.dll")]
+ internal static extern int FindWindow(string ClassName, string WindowName);
+
+ [DllImport("kernel32.dll")]
+ internal static extern uint GetCurrentThreadId();
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern IntPtr GetThreadDesktop(uint dwThreadId);
+
+ [DllImport("user32.dll")]
+ internal static extern short GetAsyncKeyState(IntPtr vKey);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct POINT
+ {
+ internal int x;
+ internal int y;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct CURSORINFO
+ {
+ public int cbSize;
+ public int flags;
+ public IntPtr hCursor;
+ public POINT ptScreenPos;
+ }
+
+ [DllImport("user32.dll")]
+ internal static extern bool GetCursorInfo(out CURSORINFO ci);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool AddClipboardFormatListener(IntPtr hwnd);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool RemoveClipboardFormatListener(IntPtr hwnd);
+
+#if USE_GetSecurityDescriptorSacl
+ internal enum SE_OBJECT_TYPE
+ {
+ SE_UNKNOWN_OBJECT_TYPE = 0,
+ SE_FILE_OBJECT,
+ SE_SERVICE,
+ SE_PRINTER,
+ SE_REGISTRY_KEY,
+ SE_LMSHARE,
+ SE_KERNEL_OBJECT,
+ SE_WINDOW_OBJECT,
+ SE_DS_OBJECT,
+ SE_DS_OBJECT_ALL,
+ SE_PROVIDER_DEFINED_OBJECT,
+ SE_WMIGUID_OBJECT,
+ SE_REGISTRY_WOW64_32KEY
+ }
+
+ [Flags]
+ internal enum SECURITY_INFORMATION : uint
+ {
+ LABEL_SECURITY_INFORMATION = 0x00000010
+ }
+
+ [StructLayoutAttribute(LayoutKind.Explicit)]
+ internal struct SECURITY_DESCRIPTOR
+ {
+ [FieldOffset(0)]
+ public byte revision;
+
+ [FieldOffset(1)]
+ public byte size;
+
+ [FieldOffset(2)]
+ public short control;
+
+ [FieldOffset(4)]
+ public IntPtr owner;
+
+ [FieldOffset(8)]
+ public IntPtr group;
+
+ [FieldOffset(12)]
+ public IntPtr sacl;
+
+ [FieldOffset(16)]
+ public IntPtr dacl;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct ACL { public byte AclRevision; public byte Sbz1; public int AclSize; public int AceCount; public int Sbz2; }
+
+ [DllImport("advapi32", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ConvertStringSecurityDescriptorToSecurityDescriptor(string StringSecurityDescriptor,
+ UInt32 StringSDRevision, out SECURITY_DESCRIPTOR SecurityDescriptor, out UInt64 SecurityDescriptorSize);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ internal static extern int GetSecurityDescriptorSacl([MarshalAs(UnmanagedType.Struct)] ref SECURITY_DESCRIPTOR pSecurityDescriptor, int lpbSaclPresent, [MarshalAs(UnmanagedType.Struct)] ref ACL pSacl, int lpbSaclDefaulted);
+
+ [DllImport("advapi32.dll", CharSet = CharSet.Auto)]
+ internal static extern uint SetNamedSecurityInfo(
+ string pObjectName,
+ SE_OBJECT_TYPE ObjectType,
+ SECURITY_INFORMATION SecurityInfo,
+ IntPtr psidOwner,
+ IntPtr psidGroup,
+ IntPtr pDacl,
+ IntPtr pSacl);
+#endif
+
+#if SINGLE_PROCESS
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool SetThreadDesktop(IntPtr hDesktop);
+#endif
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern IntPtr OpenInputDesktop(uint dwFlags, [MarshalAs(UnmanagedType.Bool)] bool fInherit, uint dwDesiredAccess);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, [Out] byte[] pvInfo, int nLength, out uint lpnLengthNeeded);
+
+ [DllImport("gdi32.dll")]
+ internal static extern uint SetPixel(IntPtr hdc, int X, int Y, uint crColor);
+
+ internal const int WM_SHOW_DRAG_DROP = 0x400;
+ internal const int WM_HIDE_DRAG_DROP = 0x401;
+ internal const int WM_CHECK_EXPLORER_DRAG_DROP = 0x402;
+ internal const int WM_QUIT = 0x403;
+ internal const int WM_SWITCH = 0x404;
+ internal const int WM_HIDE_DD_HELPER = 0x405;
+ internal const int WM_SHOW_SETTINGS_FORM = 0x406;
+
+ internal static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
+
+ // internal static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
+ // internal static readonly IntPtr HWND_TOP = new IntPtr(0);
+ // internal static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
+ internal const uint SWP_NOSIZE = 0x0001;
+ internal const uint SWP_NOMOVE = 0x0002;
+ internal const uint SWP_NOZORDER = 0x0004;
+ internal const uint SWP_NOREDRAW = 0x0008;
+ internal const uint SWP_SHOWWINDOW = 0x0040;
+ internal const uint SWP_HIDEWINDOW = 0x0080;
+
+ internal const int UOI_FLAGS = 1;
+ internal const int UOI_NAME = 2;
+ internal const int UOI_TYPE = 3;
+ internal const int UOI_USER_SID = 4;
+ internal const uint DESKTOP_WRITEOBJECTS = 0x0080;
+ internal const uint DESKTOP_READOBJECTS = 0x0001;
+ internal const uint DF_ALLOWOTHERACCOUNTHOOK = 0x0001;
+
+ // internal const UInt32 GENERIC_READ = 0x80000000;
+ internal const uint GENERIC_WRITE = 0x40000000;
+
+ // internal const UInt32 GENERIC_EXECUTE = 0x20000000;
+ internal const uint GENERIC_ALL = 0x10000000;
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ internal struct RECT
+ {
+ internal int Left;
+ internal int Top;
+ internal int Right;
+ internal int Bottom;
+ }
+
+ // size of a device name string
+ internal const int CCHDEVICENAME = 32;
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ internal struct MonitorInfoEx
+ {
+ internal int cbSize;
+ internal RECT rcMonitor;
+ internal RECT rcWork;
+ internal uint dwFlags;
+
+ // [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
+ // internal string szDeviceName;
+ }
+
+ // We are WOW
+ [SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Justification = "Dotnet port with style preservation")]
+ [DllImport(
+ "user32.dll",
+ CharSet = CharSet.Auto,
+ CallingConvention = CallingConvention.StdCall,
+ SetLastError = true)]
+ internal static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
+
+ [DllImport(
+ "user32.dll",
+ CharSet = CharSet.Auto,
+ CallingConvention = CallingConvention.StdCall,
+ SetLastError = true)]
+ internal static extern int UnhookWindowsHookEx(int idHook);
+
+ // In X64, we are running WOW
+ [SuppressMessage("Microsoft.Portability", "CA1901:PInvokeDeclarationsShouldBePortable", Justification = "Dotnet port with style preservation")]
+ [DllImport(
+ "user32.dll",
+ CharSet = CharSet.Auto,
+ CallingConvention = CallingConvention.StdCall)]
+ internal static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
+
+ private enum InputType
+ {
+ INPUT_MOUSE = 0,
+ INPUT_KEYBOARD = 1,
+ INPUT_HARDWARE = 2,
+ }
+
+ [Flags]
+ internal enum MOUSEEVENTF
+ {
+ MOVE = 0x0001,
+ LEFTDOWN = 0x0002,
+ LEFTUP = 0x0004,
+ RIGHTDOWN = 0x0008,
+ RIGHTUP = 0x0010,
+ MIDDLEDOWN = 0x0020,
+ MIDDLEUP = 0x0040,
+ XDOWN = 0x0080,
+ XUP = 0x0100,
+ WHEEL = 0x0800,
+ VIRTUALDESK = 0x4000,
+ ABSOLUTE = 0x8000,
+ }
+
+ [Flags]
+ internal enum KEYEVENTF
+ {
+ KEYDOWN = 0x0000,
+ EXTENDEDKEY = 0x0001,
+ KEYUP = 0x0002,
+ UNICODE = 0x0004,
+ SCANCODE = 0x0008,
+ }
+
+ // http://msdn.microsoft.com/en-us/library/ms646273(VS.85).aspx
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MOUSEINPUT
+ {
+ internal int dx;
+ internal int dy;
+ internal int mouseData;
+ internal int dwFlags;
+ internal int time;
+ internal IntPtr dwExtraInfo;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct KEYBDINPUT
+ {
+ internal short wVk;
+ internal short wScan;
+ internal int dwFlags;
+ internal int time;
+ internal IntPtr dwExtraInfo;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct HARDWAREINPUT
+ {
+ internal int uMsg;
+ internal short wParamL;
+ internal short wParamH;
+ }
+
+ [SuppressMessage("Microsoft.Portability", "CA1900:ValueTypeFieldsShouldBePortable", Justification = "Dotnet port with style preservation")]
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct INPUT
+ {
+ [FieldOffset(0)]
+ internal int type;
+
+ [FieldOffset(4)]
+ internal MOUSEINPUT mi;
+
+ [FieldOffset(4)]
+ internal KEYBDINPUT ki;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ internal struct INPUT64
+ {
+ [FieldOffset(0)]
+ internal int type;
+
+ [FieldOffset(8)]
+ internal MOUSEINPUT mi;
+
+ [FieldOffset(8)]
+ internal KEYBDINPUT ki;
+ }
+
+ [DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
+ internal static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
+
+ [DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
+ internal static extern uint SendInput64(uint nInputs, INPUT64[] pInputs, int cbSize);
+
+ [DllImport("user32.dll", EntryPoint = "GetMessageExtraInfo", SetLastError = true)]
+ internal static extern IntPtr GetMessageExtraInfo();
+
+ [DllImport("user32.dll", EntryPoint = "LockWorkStation", SetLastError = true)]
+ internal static extern uint LockWorkStation();
+
+ // [DllImport("user32.dll")]
+ // internal static extern void keybd_event(byte bVk, byte bScan, UInt32 dwFlags, int dwExtraInfo);
+ [DllImport("user32.dll")]
+ internal static extern uint MapVirtualKey(uint uCode, uint uMapType);
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct LUID
+ {
+ internal int LowPart;
+ internal int HighPart;
+ }// end struct
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct LUID_AND_ATTRIBUTES
+ {
+ internal LUID Luid;
+ internal int Attributes;
+ }// end struct
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct TOKEN_PRIVILEGES
+ {
+ internal int PrivilegeCount;
+
+ // LUID_AND_ATTRIBUTES
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ internal int[] Privileges;
+ }
+
+ internal const int READ_CONTROL = 0x00020000;
+
+ internal const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
+
+ internal const int STANDARD_RIGHTS_READ = READ_CONTROL;
+ internal const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
+ internal const int STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
+
+ internal const int STANDARD_RIGHTS_ALL = 0x001F0000;
+
+ internal const int SPECIFIC_RIGHTS_ALL = 0x0000FFFF;
+
+ internal const int TOKEN_IMPERSONATE = 0x0004;
+ internal const int TOKEN_QUERY_SOURCE = 0x0010;
+ internal const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
+ internal const int TOKEN_ADJUST_GROUPS = 0x0040;
+ internal const int TOKEN_ADJUST_SESSIONID = 0x0100;
+
+ internal const int TOKEN_ALL_ACCESS_P = STANDARD_RIGHTS_REQUIRED |
+ TOKEN_ASSIGN_PRIMARY |
+ TOKEN_DUPLICATE |
+ TOKEN_IMPERSONATE |
+ TOKEN_QUERY |
+ TOKEN_QUERY_SOURCE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT;
+
+ internal const int TOKEN_ALL_ACCESS = TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID;
+
+ internal const int TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY;
+
+ internal const int TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT;
+
+ internal const int TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE;
+
+ internal const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
+ internal const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
+
+ internal const int IDLE_PRIORITY_CLASS = 0x40;
+ internal const int NORMAL_PRIORITY_CLASS = 0x20;
+ internal const int HIGH_PRIORITY_CLASS = 0x80;
+ internal const int REALTIME_PRIORITY_CLASS = 0x100;
+
+ internal const int CREATE_NEW_CONSOLE = 0x00000010;
+
+ internal const string SE_DEBUG_NAME = "SeDebugPrivilege";
+ internal const string SE_RESTORE_NAME = "SeRestorePrivilege";
+ internal const string SE_BACKUP_NAME = "SeBackupPrivilege";
+
+ internal const int SE_PRIVILEGE_ENABLED = 0x0002;
+
+ internal const int ERROR_NOT_ALL_ASSIGNED = 1300;
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PROCESSENTRY32
+ {
+ internal uint dwSize;
+ internal uint cntUsage;
+ internal uint th32ProcessID;
+ internal IntPtr th32DefaultHeapID;
+ internal uint th32ModuleID;
+ internal uint cntThreads;
+ internal uint th32ParentProcessID;
+ internal int pcPriClassBase;
+ internal uint dwFlags;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ internal string szExeFile;
+ }
+
+ internal const uint TH32CS_SNAPPROCESS = 0x00000002;
+
+ // internal static int INVALID_HANDLE_VALUE = -1;
+ [DllImport("kernel32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CloseHandle(IntPtr hSnapshot);
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SECURITY_ATTRIBUTES
+ {
+ internal int Length;
+ internal IntPtr lpSecurityDescriptor;
+ internal bool bInheritHandle;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PROCESS_INFORMATION
+ {
+ internal IntPtr hProcess;
+ internal IntPtr hThread;
+ internal uint dwProcessId;
+ internal uint dwThreadId;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct STARTUPINFO
+ {
+ internal int cb;
+ internal string lpReserved;
+ internal string lpDesktop;
+ internal string lpTitle;
+ internal uint dwX;
+ internal uint dwY;
+ internal uint dwXSize;
+ internal uint dwYSize;
+ internal uint dwXCountChars;
+ internal uint dwYCountChars;
+ internal uint dwFillAttribute;
+ internal uint dwFlags;
+ internal short wShowWindow;
+ internal short cbReserved2;
+ internal IntPtr lpReserved2;
+ internal IntPtr hStdInput;
+ internal IntPtr hStdOutput;
+ internal IntPtr hStdError;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct SID_AND_ATTRIBUTES
+ {
+ internal IntPtr Sid;
+ internal int Attributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct TOKEN_MANDATORY_LABEL
+ {
+ internal SID_AND_ATTRIBUTES Label;
+ }
+
+ internal const int TOKEN_DUPLICATE = 0x0002;
+ internal const int TOKEN_QUERY = 0x0008;
+ internal const int TOKEN_ADJUST_DEFAULT = 0x0080;
+ internal const int TOKEN_ASSIGN_PRIMARY = 0x0001;
+ internal const uint MAXIMUM_ALLOWED = 0x2000000;
+ internal const int SE_GROUP_INTEGRITY = 0x00000020;
+
+ internal enum SECURITY_IMPERSONATION_LEVEL : int
+ {
+ SecurityAnonymous = 0,
+ SecurityIdentification = 1,
+ SecurityImpersonation = 2,
+ SecurityDelegation = 3,
+ }
+
+ internal enum TOKEN_TYPE : int
+ {
+ TokenPrimary = 1,
+ TokenImpersonation = 2,
+ }
+
+ internal enum TOKEN_INFORMATION_CLASS : int
+ {
+ TokenUser = 1,
+ TokenGroups,
+ TokenPrivileges,
+ TokenOwner,
+ TokenPrimaryGroup,
+ TokenDefaultDacl,
+ TokenSource,
+ TokenType,
+ TokenImpersonationLevel,
+ TokenStatistics,
+ TokenRestrictedSids,
+ TokenSessionId,
+ TokenGroupsAndPrivileges,
+ TokenSessionReference,
+ TokenSandBoxInert,
+ TokenAuditPolicy,
+ TokenOrigin,
+ TokenElevationType,
+ TokenLinkedToken,
+ TokenElevation,
+ TokenHasRestrictions,
+ TokenAccessInformation,
+ TokenVirtualizationAllowed,
+ TokenVirtualizationEnabled,
+ TokenIntegrityLevel,
+ TokenUIAccess,
+ TokenMandatoryPolicy,
+ TokenLogonSid,
+ MaxTokenInfoClass,
+ }
+
+ // [DllImport("kernel32.dll")]
+ // internal static extern int Process32First(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
+
+ // [DllImport("kernel32.dll")]
+ // internal static extern int Process32Next(IntPtr hSnapshot, ref PROCESSENTRY32 lppe);
+
+ // [DllImport("kernel32.dll", SetLastError = true)]
+ // internal static extern IntPtr CreateToolhelp32Snapshot(UInt32 dwFlags, UInt32 th32ProcessID);
+ [DllImport("Wtsapi32.dll")]
+ internal static extern uint WTSQueryUserToken(uint SessionId, ref IntPtr phToken);
+
+ [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "1", Justification = "Dotnet port with style preservation")]
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
+
+ // [DllImport("kernel32.dll")]
+ // [return: MarshalAs(UnmanagedType.Bool)]
+ // static extern bool ProcessIdToSessionId(UInt32 dwProcessId, ref UInt32 pSessionId);
+ [DllImport("kernel32.dll")]
+ internal static extern IntPtr OpenProcess(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength);
+
+ [DllImport("userenv.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, [MarshalAs(UnmanagedType.Bool)] bool bInherit);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool RevertToSelf();
+
+ internal delegate bool EnumMonitorsDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref NativeMethods.RECT lprcMonitor, IntPtr dwData);
+
+ internal delegate int HookProc(int nCode, int wParam, IntPtr lParam);
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
+ internal sealed class MEMORYSTATUSEX
+ {
+ public uint dwLength;
+ public uint dwMemoryLoad;
+ public ulong ullTotalPhys;
+ public ulong ullAvailPhys;
+ public ulong ullTotalPageFile;
+ public ulong ullAvailPageFile;
+ public ulong ullTotalVirtual;
+ public ulong ullAvailVirtual;
+ public ulong ullAvailExtendedVirtual;
+
+ public MEMORYSTATUSEX()
+ {
+ this.dwLength = (uint)Marshal.SizeOf(typeof(NativeMethods.MEMORYSTATUSEX));
+ }
+ }
+
+ [return: MarshalAs(UnmanagedType.Bool)]
+ [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
+ internal static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
+
+ /*
+ [DllImport("Netapi32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
+ internal extern static int NetUserGetInfo([MarshalAs(UnmanagedType.LPWStr)] string ServerName,
+ [MarshalAs(UnmanagedType.LPWStr)] string UserName, int level,out IntPtr BufPtr);
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ internal struct USER_INFO_10
+ {
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string usri10_name;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string usri10_comment;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string usri10_usr_comment;
+ [MarshalAs(UnmanagedType.LPWStr)]
+ public string usri10_full_name;
+ }
+
+ [DllImport("Netapi32.dll", SetLastError = true)]
+ internal static extern int NetApiBufferFree(IntPtr Buffer);
+ */
+
+ internal enum EXTENDED_NAME_FORMAT
+ {
+ NameUnknown = 0,
+ NameFullyQualifiedDN = 1,
+ NameSamCompatible = 2,
+ NameDisplay = 3,
+ NameUniqueId = 6,
+ NameCanonical = 7,
+ NameUserPrincipal = 8,
+ NameCanonicalEx = 9,
+ NameServicePrincipal = 10,
+ NameDnsDomain = 12,
+ }
+
+ [DllImport("secur32.dll", CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.I1)]
+ internal static extern bool GetUserNameEx(int nameFormat, StringBuilder userName, ref uint userNameSize);
+
+ [DllImport("Shcore.dll", SetLastError = true)]
+ internal static extern int GetDpiForMonitor(IntPtr hMonitor, uint dpiType, out uint dpiX, out uint dpiY);
+
+ private static string GetDNSDomain()
+ {
+ if (Environment.OSVersion.Platform != PlatformID.Win32NT)
+ {
+ return null;
+ }
+
+ StringBuilder userName = new StringBuilder(1024);
+ uint userNameSize = (uint)userName.Capacity;
+
+ if (GetUserNameEx((int)EXTENDED_NAME_FORMAT.NameDnsDomain, userName, ref userNameSize))
+ {
+ string[] nameParts = userName.ToString().Split('\\');
+ if (nameParts.Length != 2)
+ {
+ return null;
+ }
+
+ return nameParts[0];
+ }
+
+ return null;
+ }
+
+ ///
+ /// Use this method to figure out if your code is running on a Microsoft computer.
+ ///
+ internal static bool IsRunningAtMicrosoft()
+ {
+ string domain = GetDNSDomain();
+
+ if (!string.IsNullOrEmpty(domain) && domain.EndsWith("microsoft.com", true, System.Globalization.CultureInfo.CurrentCulture))
+ {
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Helper/Program.cs b/src/modules/MouseWithoutBorders/App/Helper/Program.cs
new file mode 100644
index 000000000000..07bdb4f3f4df
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Helper/Program.cs
@@ -0,0 +1,80 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Windows.Forms;
+using ManagedCommon;
+
+namespace MouseWithoutBorders
+{
+ internal static class Program
+ {
+ internal static FormHelper FormHelper;
+
+ private static FormDot dotForm;
+
+ internal static FormDot DotForm
+ {
+ get
+ {
+ return dotForm != null && !dotForm.IsDisposed ? dotForm : (dotForm = new FormDot());
+ }
+ }
+
+ ///
+ /// The main entry point for the application.
+ ///
+ [STAThread]
+ private static void Main()
+ {
+ if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
+ {
+ // TODO: Add logging.
+ // Logger.LogWarning("Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.");
+ return;
+ }
+
+ RunnerHelper.WaitForPowerToysRunnerExitFallback(() =>
+ {
+ Application.Exit();
+ });
+
+ string[] args = Environment.GetCommandLineArgs();
+
+ if (args.Length > 1 && !string.IsNullOrEmpty(args[1]))
+ {
+ string command = args[1];
+ string arg = args.Length > 2 && !string.IsNullOrEmpty(args[2]) ? args[2] : string.Empty;
+
+ if (command.Equals("SvcExec", StringComparison.OrdinalIgnoreCase))
+ {
+ Process.Start(Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBorders.exe", "\"" + arg + "\"");
+ }
+ else if (command.Equals("install", StringComparison.OrdinalIgnoreCase))
+ {
+ Process.Start(Path.GetDirectoryName(Application.ExecutablePath) + "\\MouseWithoutBorders.exe");
+ }
+ else if (command.Equals("help-ex", StringComparison.OrdinalIgnoreCase))
+ {
+ Process.Start(@"http://www.aka.ms/mm");
+ }
+ else if (command.Equals("InternalError", StringComparison.OrdinalIgnoreCase))
+ {
+ MessageBox.Show(arg, Application.ProductName);
+ }
+
+ return;
+ }
+
+ Application.EnableVisualStyles();
+ Application.SetHighDpiMode(HighDpiMode.SystemAware);
+ Application.SetCompatibleTextRenderingDefault(false);
+
+ dotForm = new FormDot();
+ Application.Run(FormHelper = new FormHelper());
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Icon/BigClipboard.ico b/src/modules/MouseWithoutBorders/App/Icon/BigClipboard.ico
new file mode 100644
index 000000000000..7dadd0e20a0e
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/BigClipboard.ico differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/DragDrop.ico b/src/modules/MouseWithoutBorders/App/Icon/DragDrop.ico
new file mode 100644
index 000000000000..f3d202849338
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/DragDrop.ico differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/DragDrop.jpg b/src/modules/MouseWithoutBorders/App/Icon/DragDrop.jpg
new file mode 100644
index 000000000000..5eae82d4c997
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/DragDrop.jpg differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/MachineDisabled.bmp b/src/modules/MouseWithoutBorders/App/Icon/MachineDisabled.bmp
new file mode 100644
index 000000000000..2bd2f61955a0
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/MachineDisabled.bmp differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/MachineEnabled.bmp b/src/modules/MouseWithoutBorders/App/Icon/MachineEnabled.bmp
new file mode 100644
index 000000000000..f919c80ae8d7
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/MachineEnabled.bmp differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/Multiple.ico b/src/modules/MouseWithoutBorders/App/Icon/Multiple.ico
new file mode 100644
index 000000000000..aaefcf5b425c
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/Multiple.ico differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/Single.ico b/src/modules/MouseWithoutBorders/App/Icon/Single.ico
new file mode 100644
index 000000000000..c70908b7a0fc
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/Single.ico differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/SmallClipboard.ico b/src/modules/MouseWithoutBorders/App/Icon/SmallClipboard.ico
new file mode 100644
index 000000000000..fbd3dc10519e
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/SmallClipboard.ico differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/advanced_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/advanced_button_click.png
new file mode 100644
index 000000000000..75f330a0ebf5
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/advanced_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/advanced_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/advanced_button_hover.png
new file mode 100644
index 000000000000..b01091bce6a3
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/advanced_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/advanced_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/advanced_button_normal.png
new file mode 100644
index 000000000000..794666045d14
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/advanced_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/back_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/back_button_click.png
new file mode 100644
index 000000000000..ea76ebaed825
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/back_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/back_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/back_button_hover.png
new file mode 100644
index 000000000000..36a43d273ea5
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/back_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/back_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/back_button_normal.png
new file mode 100644
index 000000000000..e9cf620403b9
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/back_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/checkbox_checked.png b/src/modules/MouseWithoutBorders/App/Icon/checkbox_checked.png
new file mode 100644
index 000000000000..722cd1803f89
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/checkbox_checked.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/checkbox_unchecked.png b/src/modules/MouseWithoutBorders/App/Icon/checkbox_unchecked.png
new file mode 100644
index 000000000000..895cae09874f
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/checkbox_unchecked.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/close_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/close_button_click.png
new file mode 100644
index 000000000000..bf2865df71fd
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/close_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/close_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/close_button_hover.png
new file mode 100644
index 000000000000..e7019773893a
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/close_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/close_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/close_button_normal.png
new file mode 100644
index 000000000000..dd8a767b0fca
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/close_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/close_window_click.png b/src/modules/MouseWithoutBorders/App/Icon/close_window_click.png
new file mode 100644
index 000000000000..2aecb8bc2f2a
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/close_window_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/close_window_hover.png b/src/modules/MouseWithoutBorders/App/Icon/close_window_hover.png
new file mode 100644
index 000000000000..f2264bbbcbb6
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/close_window_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/collapse_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/collapse_button_click.png
new file mode 100644
index 000000000000..7b7f0d7efe8c
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/collapse_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/collapse_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/collapse_button_hover.png
new file mode 100644
index 000000000000..de872934ab92
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/collapse_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/collapse_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/collapse_button_normal.png
new file mode 100644
index 000000000000..78eaaf447873
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/collapse_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/combined_example.png b/src/modules/MouseWithoutBorders/App/Icon/combined_example.png
new file mode 100644
index 000000000000..56630ee2ad1f
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/combined_example.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/computer_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/computer_button_click.png
new file mode 100644
index 000000000000..ed5a8eceb20d
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/computer_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/computer_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/computer_button_hover.png
new file mode 100644
index 000000000000..105566f8e15f
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/computer_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/computer_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/computer_button_normal.png
new file mode 100644
index 000000000000..c5a7b13ea9c9
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/computer_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/computer_connected.png b/src/modules/MouseWithoutBorders/App/Icon/computer_connected.png
new file mode 100644
index 000000000000..13269a5947bf
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/computer_connected.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/computer_disconnected.png b/src/modules/MouseWithoutBorders/App/Icon/computer_disconnected.png
new file mode 100644
index 000000000000..fa5a87576654
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/computer_disconnected.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/computer_small_connected.png b/src/modules/MouseWithoutBorders/App/Icon/computer_small_connected.png
new file mode 100644
index 000000000000..c2993d543781
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/computer_small_connected.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/computer_small_disconnected.png b/src/modules/MouseWithoutBorders/App/Icon/computer_small_disconnected.png
new file mode 100644
index 000000000000..798b77f4dcc4
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/computer_small_disconnected.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/copy_paste_example.png b/src/modules/MouseWithoutBorders/App/Icon/copy_paste_example.png
new file mode 100644
index 000000000000..ad26b39e72e7
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/copy_paste_example.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/dialog_background.png b/src/modules/MouseWithoutBorders/App/Icon/dialog_background.png
new file mode 100644
index 000000000000..537266c21acf
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/dialog_background.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/done_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/done_button_click.png
new file mode 100644
index 000000000000..7565893ae5d4
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/done_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/done_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/done_button_hover.png
new file mode 100644
index 000000000000..1e272303d11c
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/done_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/done_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/done_button_normal.png
new file mode 100644
index 000000000000..de7a6247e782
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/done_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/drag_example.png b/src/modules/MouseWithoutBorders/App/Icon/drag_example.png
new file mode 100644
index 000000000000..0f2b9bc4d9e3
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/drag_example.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/expand_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/expand_button_click.png
new file mode 100644
index 000000000000..4441ed0b0190
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/expand_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/expand_button_highlight.png b/src/modules/MouseWithoutBorders/App/Icon/expand_button_highlight.png
new file mode 100644
index 000000000000..f339726f8ac9
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/expand_button_highlight.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/expand_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/expand_button_normal.png
new file mode 100644
index 000000000000..345cfe0620b7
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/expand_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/ico_disable.ico b/src/modules/MouseWithoutBorders/App/Icon/ico_disable.ico
new file mode 100644
index 000000000000..c02cc24db042
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/ico_disable.ico differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/ico_enable_all.ico b/src/modules/MouseWithoutBorders/App/Icon/ico_enable_all.ico
new file mode 100644
index 000000000000..b243f2efac8c
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/ico_enable_all.ico differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/ico_enable_all_s.ico b/src/modules/MouseWithoutBorders/App/Icon/ico_enable_all_s.ico
new file mode 100644
index 000000000000..b7b473458f44
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/ico_enable_all_s.ico differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/ico_enable_one.ico b/src/modules/MouseWithoutBorders/App/Icon/ico_enable_one.ico
new file mode 100644
index 000000000000..4ffe1915d5d2
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/ico_enable_one.ico differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/keyboard_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/keyboard_button_click.png
new file mode 100644
index 000000000000..d330da45bb98
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/keyboard_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/keyboard_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/keyboard_button_hover.png
new file mode 100644
index 000000000000..06989aaf9bca
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/keyboard_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/keyboard_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/keyboard_button_normal.png
new file mode 100644
index 000000000000..e6d03ab3a9f6
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/keyboard_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/keyboard_example.png b/src/modules/MouseWithoutBorders/App/Icon/keyboard_example.png
new file mode 100644
index 000000000000..787f1a51ee30
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/keyboard_example.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/large_drag_tile.png b/src/modules/MouseWithoutBorders/App/Icon/large_drag_tile.png
new file mode 100644
index 000000000000..87567127c75c
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/large_drag_tile.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/link_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/link_button_click.png
new file mode 100644
index 000000000000..c535293ab538
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/link_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/link_button_disabled.png b/src/modules/MouseWithoutBorders/App/Icon/link_button_disabled.png
new file mode 100644
index 000000000000..2516e8b7b7c2
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/link_button_disabled.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/link_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/link_button_hover.png
new file mode 100644
index 000000000000..0b088aa11708
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/link_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/link_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/link_button_normal.png
new file mode 100644
index 000000000000..4b6b0efa32fa
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/link_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/mouse.png b/src/modules/MouseWithoutBorders/App/Icon/mouse.png
new file mode 100644
index 000000000000..1a1194b851ae
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/mouse.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/next_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/next_button_click.png
new file mode 100644
index 000000000000..ab9cd9e605c1
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/next_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/next_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/next_button_hover.png
new file mode 100644
index 000000000000..9dca622e23f8
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/next_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/next_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/next_button_normal.png
new file mode 100644
index 000000000000..e29fa1829654
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/next_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/no_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/no_button_click.png
new file mode 100644
index 000000000000..d3fe80abdf4d
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/no_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/no_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/no_button_hover.png
new file mode 100644
index 000000000000..7b875c3d89ff
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/no_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/no_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/no_button_normal.png
new file mode 100644
index 000000000000..ebb11e889283
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/no_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/one_row_button_checked.png b/src/modules/MouseWithoutBorders/App/Icon/one_row_button_checked.png
new file mode 100644
index 000000000000..9ff55d832251
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/one_row_button_checked.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/one_row_button_unchecked.png b/src/modules/MouseWithoutBorders/App/Icon/one_row_button_unchecked.png
new file mode 100644
index 000000000000..27dce76edee4
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/one_row_button_unchecked.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/radio_button_checked.png b/src/modules/MouseWithoutBorders/App/Icon/radio_button_checked.png
new file mode 100644
index 000000000000..688e6a48cb3c
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/radio_button_checked.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/radio_button_unchecked.png b/src/modules/MouseWithoutBorders/App/Icon/radio_button_unchecked.png
new file mode 100644
index 000000000000..1d6a8b483747
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/radio_button_unchecked.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/red_close_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/red_close_button_click.png
new file mode 100644
index 000000000000..589b0643b198
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/red_close_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/red_close_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/red_close_button_hover.png
new file mode 100644
index 000000000000..6f4e195f3bd4
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/red_close_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/red_close_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/red_close_button_normal.png
new file mode 100644
index 000000000000..1f4f64d2dee4
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/red_close_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/small_drag_tile.png b/src/modules/MouseWithoutBorders/App/Icon/small_drag_tile.png
new file mode 100644
index 000000000000..7d0c14005263
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/small_drag_tile.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/small_link_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/small_link_button_click.png
new file mode 100644
index 000000000000..56e742aa9877
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/small_link_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/small_link_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/small_link_button_hover.png
new file mode 100644
index 000000000000..6ce45e2bc8f9
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/small_link_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/small_link_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/small_link_button_normal.png
new file mode 100644
index 000000000000..a5744c2271bc
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/small_link_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/switch_off_click.png b/src/modules/MouseWithoutBorders/App/Icon/switch_off_click.png
new file mode 100644
index 000000000000..ec906d48bbbb
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/switch_off_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/switch_off_hover.png b/src/modules/MouseWithoutBorders/App/Icon/switch_off_hover.png
new file mode 100644
index 000000000000..645a3562268b
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/switch_off_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/switch_off_normal.png b/src/modules/MouseWithoutBorders/App/Icon/switch_off_normal.png
new file mode 100644
index 000000000000..730b6080482e
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/switch_off_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/switch_on_click.png b/src/modules/MouseWithoutBorders/App/Icon/switch_on_click.png
new file mode 100644
index 000000000000..96a5e1b43813
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/switch_on_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/switch_on_hover.png b/src/modules/MouseWithoutBorders/App/Icon/switch_on_hover.png
new file mode 100644
index 000000000000..8d68f6f2d284
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/switch_on_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/switch_on_normal.png b/src/modules/MouseWithoutBorders/App/Icon/switch_on_normal.png
new file mode 100644
index 000000000000..a39da6dff3fd
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/switch_on_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/text_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/text_button_click.png
new file mode 100644
index 000000000000..54f841222b94
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/text_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/text_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/text_button_hover.png
new file mode 100644
index 000000000000..6f7d500aabb6
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/text_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/text_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/text_button_normal.png
new file mode 100644
index 000000000000..51f2d8bf37a4
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/text_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/two_row_button_checked.png b/src/modules/MouseWithoutBorders/App/Icon/two_row_button_checked.png
new file mode 100644
index 000000000000..b074598c8e5b
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/two_row_button_checked.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/two_row_button_unchecked.png b/src/modules/MouseWithoutBorders/App/Icon/two_row_button_unchecked.png
new file mode 100644
index 000000000000..0099e253798c
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/two_row_button_unchecked.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/yes_button_click.png b/src/modules/MouseWithoutBorders/App/Icon/yes_button_click.png
new file mode 100644
index 000000000000..1e28f94836e2
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/yes_button_click.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/yes_button_hover.png b/src/modules/MouseWithoutBorders/App/Icon/yes_button_hover.png
new file mode 100644
index 000000000000..864530fd958c
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/yes_button_hover.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Icon/yes_button_normal.png b/src/modules/MouseWithoutBorders/App/Icon/yes_button_normal.png
new file mode 100644
index 000000000000..8c12341cfa07
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Icon/yes_button_normal.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Logo.ico b/src/modules/MouseWithoutBorders/App/Logo.ico
new file mode 100644
index 000000000000..e899268e4737
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Logo.ico differ
diff --git a/src/modules/MouseWithoutBorders/App/Logo/Logo.png b/src/modules/MouseWithoutBorders/App/Logo/Logo.png
new file mode 100644
index 000000000000..7486da1ca680
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Logo/Logo.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Logo/MWB.png b/src/modules/MouseWithoutBorders/App/Logo/MWB.png
new file mode 100644
index 000000000000..64df1708cca5
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Logo/MWB.png differ
diff --git a/src/modules/MouseWithoutBorders/App/Logo/MWBEx.png b/src/modules/MouseWithoutBorders/App/Logo/MWBEx.png
new file mode 100644
index 000000000000..a7c0e231fa74
Binary files /dev/null and b/src/modules/MouseWithoutBorders/App/Logo/MWBEx.png differ
diff --git a/src/modules/MouseWithoutBorders/App/MouseWithoutBorders.csproj b/src/modules/MouseWithoutBorders/App/MouseWithoutBorders.csproj
new file mode 100644
index 000000000000..60e75ccb6370
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/MouseWithoutBorders.csproj
@@ -0,0 +1,248 @@
+
+
+
+ net7.0-windows10.0.19041.0
+ WinExe
+ true
+ false
+ false
+ PowerToys.MouseWithoutBorders
+ true
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\MouseWithoutBorders
+ true
+ true
+ $(Version).0
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
+
+
+
+ TRACE;DEBUG;SHOW_ON_WINLOGON CODE_ANALYSIS CUSTOMIZE_LOGON_SCREEN
+ false
+
+
+ TRACE;SHOW_ON_WINLOGON CODE_ANALYSIS CUSTOMIZE_LOGON_SCREEN
+ false
+
+
+
+
+ Logo.ico
+
+
+ true
+
+
+
+ PowerToys.GPOWrapper
+ $(OutDir)
+ false
+
+
+
+ <_Parameter1>false
+ <_Parameter1_IsLiteral>true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UserControl
+
+
+ Component
+
+
+ Component
+
+
+ UserControl
+
+
+ UserControl
+
+
+ UserControl
+
+
+ UserControl
+
+
+ UserControl
+
+
+ UserControl
+
+
+ UserControl
+
+
+ UserControl
+
+
+ UserControl
+
+
+ UserControl
+
+
+
+
+ PreserveNewest
+
+
+
+
+ False
+ .NET Framework 3.5 SP1 Client Profile
+ false
+
+
+ False
+ .NET Framework 2.0 %28x86%29
+ true
+
+
+ False
+ .NET Framework 3.0 %28x86%29
+ false
+
+
+ False
+ .NET Framework 3.5
+ false
+
+
+ False
+ .NET Framework 3.5 SP1
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/MouseWithoutBorders.exe.manifest b/src/modules/MouseWithoutBorders/App/MouseWithoutBorders.exe.manifest
new file mode 100644
index 000000000000..63feb1d04f34
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/MouseWithoutBorders.exe.manifest
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true/PM
+
+
+
+
+
+
+
diff --git a/src/modules/MouseWithoutBorders/App/Properties/Resources.Designer.cs b/src/modules/MouseWithoutBorders/App/Properties/Resources.Designer.cs
new file mode 100644
index 000000000000..7672c141652a
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Properties/Resources.Designer.cs
@@ -0,0 +1,853 @@
+
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+
+
+namespace MouseWithoutBorders.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MouseWithoutBorders.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap advanced_button_click {
+ get {
+ object obj = ResourceManager.GetObject("advanced_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap advanced_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("advanced_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap advanced_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("advanced_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap back_button_click {
+ get {
+ object obj = ResourceManager.GetObject("back_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap back_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("back_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap back_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("back_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap checkbox_checked {
+ get {
+ object obj = ResourceManager.GetObject("checkbox_checked", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap checkbox_unchecked {
+ get {
+ object obj = ResourceManager.GetObject("checkbox_unchecked", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap close_button_click {
+ get {
+ object obj = ResourceManager.GetObject("close_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap close_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("close_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap close_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("close_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap close_window_click {
+ get {
+ object obj = ResourceManager.GetObject("close_window_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap close_window_hover {
+ get {
+ object obj = ResourceManager.GetObject("close_window_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap collapse_button_click {
+ get {
+ object obj = ResourceManager.GetObject("collapse_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap collapse_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("collapse_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap collapse_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("collapse_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap combined_example {
+ get {
+ object obj = ResourceManager.GetObject("combined_example", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap computer_button_click {
+ get {
+ object obj = ResourceManager.GetObject("computer_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap computer_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("computer_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap computer_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("computer_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap computer_connected {
+ get {
+ object obj = ResourceManager.GetObject("computer_connected", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap computer_disconnected {
+ get {
+ object obj = ResourceManager.GetObject("computer_disconnected", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap computer_small_connected {
+ get {
+ object obj = ResourceManager.GetObject("computer_small_connected", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap computer_small_disconnected {
+ get {
+ object obj = ResourceManager.GetObject("computer_small_disconnected", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap copy_paste_example {
+ get {
+ object obj = ResourceManager.GetObject("copy_paste_example", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap dialog_background {
+ get {
+ object obj = ResourceManager.GetObject("dialog_background", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap done_button_click {
+ get {
+ object obj = ResourceManager.GetObject("done_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap done_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("done_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap done_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("done_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap drag_example {
+ get {
+ object obj = ResourceManager.GetObject("drag_example", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap expand_button_click {
+ get {
+ object obj = ResourceManager.GetObject("expand_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap expand_button_highlight {
+ get {
+ object obj = ResourceManager.GetObject("expand_button_highlight", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap expand_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("expand_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap keyboard_button_click {
+ get {
+ object obj = ResourceManager.GetObject("keyboard_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap keyboard_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("keyboard_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap keyboard_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("keyboard_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap keyboard_example {
+ get {
+ object obj = ResourceManager.GetObject("keyboard_example", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap large_drag_tile {
+ get {
+ object obj = ResourceManager.GetObject("large_drag_tile", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap link_button_click {
+ get {
+ object obj = ResourceManager.GetObject("link_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap link_button_disabled {
+ get {
+ object obj = ResourceManager.GetObject("link_button_disabled", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap link_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("link_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap link_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("link_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap Logo {
+ get {
+ object obj = ResourceManager.GetObject("Logo", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap MachineDisabled {
+ get {
+ object obj = ResourceManager.GetObject("MachineDisabled", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap MachineEnabled {
+ get {
+ object obj = ResourceManager.GetObject("MachineEnabled", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap Mouse {
+ get {
+ object obj = ResourceManager.GetObject("Mouse", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap MouseWithoutBorders {
+ get {
+ object obj = ResourceManager.GetObject("MouseWithoutBorders", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap MouseWithoutBordersEx {
+ get {
+ object obj = ResourceManager.GetObject("MouseWithoutBordersEx", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap next_button_click {
+ get {
+ object obj = ResourceManager.GetObject("next_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap next_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("next_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap next_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("next_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap no_button_click {
+ get {
+ object obj = ResourceManager.GetObject("no_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap no_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("no_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap no_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("no_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap one_row_button_checked {
+ get {
+ object obj = ResourceManager.GetObject("one_row_button_checked", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap one_row_button_unchecked {
+ get {
+ object obj = ResourceManager.GetObject("one_row_button_unchecked", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap radio_button_checked {
+ get {
+ object obj = ResourceManager.GetObject("radio_button_checked", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap radio_button_unchecked {
+ get {
+ object obj = ResourceManager.GetObject("radio_button_unchecked", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap red_close_button_click {
+ get {
+ object obj = ResourceManager.GetObject("red_close_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap red_close_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("red_close_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap red_close_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("red_close_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap small_drag_tile {
+ get {
+ object obj = ResourceManager.GetObject("small_drag_tile", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap small_link_button_click {
+ get {
+ object obj = ResourceManager.GetObject("small_link_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap small_link_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("small_link_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap small_link_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("small_link_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap switch_off_click {
+ get {
+ object obj = ResourceManager.GetObject("switch_off_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap switch_off_hover {
+ get {
+ object obj = ResourceManager.GetObject("switch_off_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap switch_off_normal {
+ get {
+ object obj = ResourceManager.GetObject("switch_off_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap switch_on_click {
+ get {
+ object obj = ResourceManager.GetObject("switch_on_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap switch_on_hover {
+ get {
+ object obj = ResourceManager.GetObject("switch_on_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap switch_on_normal {
+ get {
+ object obj = ResourceManager.GetObject("switch_on_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap text_button_click {
+ get {
+ object obj = ResourceManager.GetObject("text_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap text_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("text_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap text_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("text_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap two_row_button_checked {
+ get {
+ object obj = ResourceManager.GetObject("two_row_button_checked", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap two_row_button_unchecked {
+ get {
+ object obj = ResourceManager.GetObject("two_row_button_unchecked", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap yes_button_click {
+ get {
+ object obj = ResourceManager.GetObject("yes_button_click", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap yes_button_hover {
+ get {
+ object obj = ResourceManager.GetObject("yes_button_hover", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+
+ ///
+ /// Looks up a localized resource of type System.Drawing.Bitmap.
+ ///
+ internal static System.Drawing.Bitmap yes_button_normal {
+ get {
+ object obj = ResourceManager.GetObject("yes_button_normal", resourceCulture);
+ return ((System.Drawing.Bitmap)(obj));
+ }
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Properties/Resources.resx b/src/modules/MouseWithoutBorders/App/Properties/Resources.resx
new file mode 100644
index 000000000000..91dad667f054
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Properties/Resources.resx
@@ -0,0 +1,358 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+
+ ..\Logo\Logo.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\MachineDisabled.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\MachineEnabled.bmp;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Logo\MWB.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Logo\MWBEx.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\dialog_background.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\Mouse.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\yes_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\yes_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\yes_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\close_window_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\close_window_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\no_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\no_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\no_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\back_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\back_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\back_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\collapse_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\collapse_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\collapse_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\combined_example.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\copy_paste_example.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\done_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\done_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\done_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\drag_example.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\expand_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\expand_button_highlight.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\expand_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\keyboard_example.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\link_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\link_button_disabled.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\link_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\link_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\next_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\next_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\next_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\close_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\close_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\close_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\checkbox_checked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\checkbox_unchecked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\advanced_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\advanced_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\advanced_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\computer_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\computer_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\computer_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\keyboard_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\keyboard_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\keyboard_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\text_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\text_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\text_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\radio_button_checked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\radio_button_unchecked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\small_link_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\small_link_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\small_link_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\computer_connected.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\computer_disconnected.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\computer_small_connected.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\computer_small_disconnected.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\large_drag_tile.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\red_close_button_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\red_close_button_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\red_close_button_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\small_drag_tile.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\switch_off_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\switch_off_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\switch_off_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\switch_on_click.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\switch_on_hover.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\switch_on_normal.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\one_row_button_checked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\one_row_button_unchecked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\two_row_button_checked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
+ ..\Icon\two_row_button_unchecked.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/App/Service/MouseWithoutBordersService.csproj b/src/modules/MouseWithoutBorders/App/Service/MouseWithoutBordersService.csproj
new file mode 100644
index 000000000000..c4dcbd5a0f39
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Service/MouseWithoutBordersService.csproj
@@ -0,0 +1,89 @@
+
+
+
+ net7.0-windows10.0.19041.0
+ true
+ WinExe
+ true
+ false
+ false
+ PowerToys.MouseWithoutBordersService
+ true
+ true
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\MouseWithoutBorders
+ true
+ true
+ $(Version).0
+
+
+
+
+ win10-x64
+
+
+ win10-arm64
+
+
+ TRACE;DEBUG;SHOW_ON_WINLOGON CODE_ANALYSIS CUSTOMIZE_LOGON_SCREEN
+ false
+
+
+ TRACE;SHOW_ON_WINLOGON CODE_ANALYSIS CUSTOMIZE_LOGON_SCREEN
+ false
+
+
+
+
+ ..\Logo.ico
+
+
+ true
+
+
+
+ PowerToys.GPOWrapper
+ $(OutDir)
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ True
+
+
+
diff --git a/src/modules/MouseWithoutBorders/App/Service/NativeMethods.cs b/src/modules/MouseWithoutBorders/App/Service/NativeMethods.cs
new file mode 100644
index 000000000000..2adc6090001e
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Service/NativeMethods.cs
@@ -0,0 +1,424 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.ServiceProcess;
+
+namespace MouseWithoutBordersService
+{
+ internal sealed class NativeMethods
+ {
+ private NativeMethods()
+ {
+ }
+
+ private const string MY_KEY = @"SOFTWARE\Microsoft\MouseWithoutBorders";
+ private const string MY_KEY_EX = @"S-1-5-19\SOFTWARE\Microsoft\MouseWithoutBorders";
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct SECURITY_ATTRIBUTES
+ {
+ internal int Length;
+ internal IntPtr lpSecurityDescriptor;
+ internal bool bInheritHandle;
+ }
+
+ private enum TOKEN_TYPE : int
+ {
+ TokenPrimary = 1,
+ TokenImpersonation = 2,
+ }
+
+ private enum TOKEN_INFORMATION_CLASS : int
+ {
+ TokenUser = 1,
+ TokenGroups,
+ TokenPrivileges,
+ TokenOwner,
+ TokenPrimaryGroup,
+ TokenDefaultDacl,
+ TokenSource,
+ TokenType,
+ TokenImpersonationLevel,
+ TokenStatistics,
+ TokenRestrictedSids,
+ TokenSessionId,
+ TokenGroupsAndPrivileges,
+ TokenSessionReference,
+ TokenSandBoxInert,
+ TokenAuditPolicy,
+ TokenOrigin,
+ MaxTokenInfoClass, // MaxTokenInfoClass should always be the last enum
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct STARTUPINFO
+ {
+ internal int cb;
+ internal string lpReserved;
+ internal string lpDesktop;
+ internal string lpTitle;
+ internal uint dwX;
+ internal uint dwY;
+ internal uint dwXSize;
+ internal uint dwYSize;
+ internal uint dwXCountChars;
+ internal uint dwYCountChars;
+ internal uint dwFillAttribute;
+ internal uint dwFlags;
+ internal short wShowWindow;
+ internal short cbReserved2;
+ internal IntPtr lpReserved2;
+ internal IntPtr hStdInput;
+ internal IntPtr hStdOutput;
+ internal IntPtr hStdError;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct SID_AND_ATTRIBUTES
+ {
+ internal IntPtr Sid;
+ internal int Attributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct TOKEN_MANDATORY_LABEL
+ {
+ internal SID_AND_ATTRIBUTES Label;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct PROCESS_INFORMATION
+ {
+ internal IntPtr hProcess;
+ internal IntPtr hThread;
+ internal uint dwProcessId;
+ internal uint dwThreadId;
+ }
+
+ private enum SECURITY_IMPERSONATION_LEVEL : int
+ {
+ SecurityAnonymous = 0,
+ SecurityIdentification = 1,
+ SecurityImpersonation = 2,
+ SecurityDelegation = 3,
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct LUID
+ {
+ internal int LowPart;
+ internal int HighPart;
+ }// end struct
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct LUID_AND_ATTRIBUTES
+ {
+ internal LUID Luid;
+ internal int Attributes;
+ }// end struct
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct TOKEN_PRIVILEGES
+ {
+ internal int PrivilegeCount;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ internal int[] Privileges;
+ }
+
+ private const int READ_CONTROL = 0x00020000;
+
+ private const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
+
+ private const int STANDARD_RIGHTS_READ = READ_CONTROL;
+ private const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
+ private const int STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
+
+ private const int STANDARD_RIGHTS_ALL = 0x001F0000;
+
+ private const int SPECIFIC_RIGHTS_ALL = 0x0000FFFF;
+
+ private const int TOKEN_ASSIGN_PRIMARY = 0x0001;
+ private const int TOKEN_DUPLICATE = 0x0002;
+ private const int TOKEN_IMPERSONATE = 0x0004;
+ private const int TOKEN_QUERY = 0x0008;
+ private const int TOKEN_QUERY_SOURCE = 0x0010;
+ private const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
+ private const int TOKEN_ADJUST_GROUPS = 0x0040;
+ private const int TOKEN_ADJUST_DEFAULT = 0x0080;
+ private const int TOKEN_ADJUST_SESSIONID = 0x0100;
+
+ private const int TOKEN_ALL_ACCESS_P = STANDARD_RIGHTS_REQUIRED |
+ TOKEN_ASSIGN_PRIMARY |
+ TOKEN_DUPLICATE |
+ TOKEN_IMPERSONATE |
+ TOKEN_QUERY |
+ TOKEN_QUERY_SOURCE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT;
+
+ private const int TOKEN_ALL_ACCESS = TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID;
+
+ private const int TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY;
+
+ private const int TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
+ TOKEN_ADJUST_PRIVILEGES |
+ TOKEN_ADJUST_GROUPS |
+ TOKEN_ADJUST_DEFAULT;
+
+ private const int TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE;
+
+ private const uint MAXIMUM_ALLOWED = 0x2000000;
+
+ private const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
+ private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
+
+ private const int IDLE_PRIORITY_CLASS = 0x40;
+ private const int NORMAL_PRIORITY_CLASS = 0x20;
+ private const int HIGH_PRIORITY_CLASS = 0x80;
+ private const int REALTIME_PRIORITY_CLASS = 0x100;
+
+ private const int CREATE_NEW_CONSOLE = 0x00000010;
+
+ private const string SE_DEBUG_NAME = "SeDebugPrivilege";
+ private const string SE_RESTORE_NAME = "SeRestorePrivilege";
+ private const string SE_BACKUP_NAME = "SeBackupPrivilege";
+
+ private const int SE_PRIVILEGE_ENABLED = 0x0002;
+
+ private const int ERROR_NOT_ALL_ASSIGNED = 1300;
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct PROCESSENTRY32
+ {
+ internal uint dwSize;
+ internal uint cntUsage;
+ internal uint th32ProcessID;
+ internal IntPtr th32DefaultHeapID;
+ internal uint th32ModuleID;
+ internal uint cntThreads;
+ internal uint th32ParentProcessID;
+ internal int pcPriClassBase;
+ internal uint dwFlags;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ internal string szExeFile;
+ }
+
+ private const uint TH32CS_SNAPPROCESS = 0x00000002;
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool CloseHandle(IntPtr hSnapshot);
+
+ [DllImport("kernel32.dll")]
+ internal static extern uint WTSGetActiveConsoleSessionId();
+
+ [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "1", Justification = "Dotnet port with style preservation")]
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
+
+ [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Justification = "Dotnet port with style preservation")]
+ [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
+
+ [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
+
+ [DllImport("kernel32.dll")]
+ private static extern IntPtr OpenProcess(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);
+
+ [DllImport("advapi32", SetLastError = true)]
+ [SuppressUnmanagedCodeSecurityAttribute]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool OpenProcessToken(
+ IntPtr ProcessHandle, // handle to process
+ int DesiredAccess, // desired access to process
+ ref IntPtr TokenHandle); // handle to open access token
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength);
+
+ [DllImport("userenv.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, [MarshalAs(UnmanagedType.Bool)] bool bInherit);
+
+ [DllImport("sas.dll", SetLastError = true)]
+ internal static extern IntPtr SendSAS([MarshalAs(UnmanagedType.Bool)] bool AsUser);
+
+ [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Dotnet port with style preservation")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static bool CreateProcessAsSystemAccountOnSpecificDesktop(string CommandLine, string Desktop, int NoOfTry, int sessionId = -1)
+ {
+ int lastError;
+ int dwSessionId = sessionId < 0 ? (int)WTSGetActiveConsoleSessionId() : sessionId;
+ int winlogonPid = 0;
+ IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
+
+ try
+ {
+ int noTry = 0;
+
+ // At startup, services may start before winlogon.
+ do
+ {
+ Process[] p = Process.GetProcessesByName("winlogon");
+ if (p != null)
+ {
+ for (int i = 0; i < p.Length; i++)
+ {
+ if (p[i].SessionId == dwSessionId)
+ {
+ winlogonPid = p[i].Id;
+ break;
+ }
+ }
+ }
+
+ noTry++;
+ if (winlogonPid == 0 && noTry < NoOfTry)
+ {
+ Thread.Sleep(1000);
+ }
+ }
+ while (winlogonPid == 0 && noTry < NoOfTry);
+
+ if (winlogonPid == 0)
+ {
+ return false;
+ }
+
+ STARTUPINFO si = default(STARTUPINFO);
+ si.cb = (int)Marshal.SizeOf(si);
+ si.lpDesktop = "winsta0\\" + Desktop;
+
+ hProcess = OpenProcess(MAXIMUM_ALLOWED, false, (uint)winlogonPid);
+
+ if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, ref hPToken))
+ {
+ lastError = Marshal.GetLastWin32Error();
+ CloseHandle(hProcess);
+ return false;
+ }
+
+ SECURITY_ATTRIBUTES sa = default(SECURITY_ATTRIBUTES);
+ sa.Length = Marshal.SizeOf(sa);
+
+ if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
+ {
+ lastError = Marshal.GetLastWin32Error();
+ CloseHandle(hProcess);
+ CloseHandle(hPToken);
+ return false;
+ }
+
+ uint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
+ IntPtr pEnv = IntPtr.Zero;
+
+ if (CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true))
+ {
+ dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
+ }
+ else
+ {
+ lastError = Marshal.GetLastWin32Error();
+ pEnv = IntPtr.Zero;
+ }
+
+ // Launch the process
+ PROCESS_INFORMATION pi = default(PROCESS_INFORMATION);
+ bool rv = CreateProcessAsUser(
+ hUserTokenDup, // client's access token
+ null, // file to execute
+ CommandLine, // command line
+ ref sa, // pointer to process SECURITY_ATTRIBUTES
+ ref sa, // pointer to thread SECURITY_ATTRIBUTES
+ false, // handles are not inheritable
+ (int)dwCreationFlags, // creation flags
+ pEnv, // pointer to new environment block
+ null, // name of current directory
+ ref si, // pointer to STARTUPINFO structure
+ out pi); // receives information about new process
+
+ // GetLastError should be nonezero
+ int createProcessAsUserRv = Marshal.GetLastWin32Error();
+
+ // Close handles task
+ CloseHandle(hProcess);
+ CloseHandle(hUserTokenDup);
+ CloseHandle(hPToken);
+
+ if (rv)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ catch (Exception)
+ {
+ return false;
+ }
+ }
+
+#if DESKTOP_STUFFS
+ [DllImport("kernel32.dll")]
+ private static extern UInt32 GetCurrentThreadId();
+
+ [DllImport("user32.dll", SetLastError = true)]
+ private static extern IntPtr GetThreadDesktop(UInt32 dwThreadId);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ private static extern bool SetThreadDesktop(IntPtr hDesktop);
+
+ [DllImport("user32.dll", SetLastError = true)]
+ private static extern IntPtr OpenInputDesktop(UInt32 dwFlags, bool fInherit, UInt32 dwDesiredAccess);
+
+ private const int UOI_FLAGS = 1;
+ private const int UOI_NAME = 2;
+ private const int UOI_TYPE = 3;
+ private const int UOI_USER_SID = 4;
+ private const UInt32 DESKTOP_WRITEOBJECTS = 0x0080;
+ private const UInt32 DESKTOP_READOBJECTS = 0x0001;
+
+ [DllImport("user32.dll", SetLastError = true)]
+ private static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, [Out] byte[] pvInfo, int nLength, out UInt32 lpnLengthNeeded);
+
+ internal static string GetMyDesktop()
+ {
+ UInt32 nLengthNeeded;
+ byte[] arThreadDesktop = new byte[256];
+ IntPtr hD = GetThreadDesktop(GetCurrentThreadId());
+ if (hD != IntPtr.Zero)
+ {
+ GetUserObjectInformation(hD, UOI_NAME, arThreadDesktop, arThreadDesktop.Length, out nLengthNeeded);
+ return ASCIIEncoding.ASCII.GetString(arThreadDesktop);
+ }
+ return "";
+ }
+
+ internal static string GetInputDesktop()
+ {
+ UInt32 nLengthNeeded;
+ byte[] arInputDesktop = new byte[256];
+ IntPtr hD = OpenInputDesktop(0, false, DESKTOP_READOBJECTS);
+ if (hD != IntPtr.Zero)
+ {
+ GetUserObjectInformation(hD, UOI_NAME, arInputDesktop, arInputDesktop.Length, out nLengthNeeded);
+ return ASCIIEncoding.ASCII.GetString(arInputDesktop);
+ }
+ return "";
+ }
+#endif
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Service/Program.cs b/src/modules/MouseWithoutBorders/App/Service/Program.cs
new file mode 100644
index 000000000000..736a90127427
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Service/Program.cs
@@ -0,0 +1,57 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+
+namespace MouseWithoutBordersService
+{
+ public delegate void StopService();
+
+#pragma warning disable SA1402 // File may only contain a single type
+#pragma warning disable SA1649 // File name should match first type name
+ public static class CmdArgs
+#pragma warning restore SA1649 // File name should match first type name
+#pragma warning restore SA1402 // File may only contain a single type
+ {
+ public static string[] Value { get; set; }
+
+ public static StopService StopServiceDelegate { get; set; }
+ }
+
+ internal sealed class Program
+ {
+ [STAThread]
+ private static void Main()
+ {
+ if (PowerToys.GPOWrapper.GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue() == PowerToys.GPOWrapper.GpoRuleConfigured.Disabled)
+ {
+ // TODO: Add logging.
+ // Logger.LogWarning("Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.");
+ return;
+ }
+
+ string[] args = Environment.GetCommandLineArgs();
+ CmdArgs.Value = args;
+ var builder = Host.CreateDefaultBuilder(args);
+
+ var host = builder
+ .UseWindowsService(options =>
+ {
+ options.ServiceName = "PowerToys.MWB.Service";
+ })
+ .ConfigureServices(services =>
+ {
+ services.AddHostedService();
+ })
+ .Build();
+
+ CmdArgs.StopServiceDelegate = async () => { await host.StopAsync(); };
+ host.Run();
+ host.StopAsync();
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Service/Worker.cs b/src/modules/MouseWithoutBorders/App/Service/Worker.cs
new file mode 100644
index 000000000000..e90f3e37a6b9
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Service/Worker.cs
@@ -0,0 +1,179 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Reflection;
+using System.ServiceProcess;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+
+namespace MouseWithoutBordersService
+{
+ internal sealed class Worker : IHostedService
+ {
+ private readonly ILogger _logger;
+ private readonly Action _infoLogger;
+ private readonly string processName = "PowerToys.MouseWithoutBorders";
+ private readonly IHostApplicationLifetime _lifetime;
+
+ private string[] _cmdArgs;
+ private int appSessionId = -1;
+ private string myBinary = Assembly.GetExecutingAssembly().Location;
+
+ public Worker(ILogger logger, IHostEnvironment environment, IHostApplicationLifetime lifeTime)
+ {
+ _cmdArgs = CmdArgs.Value;
+ _lifetime = lifeTime;
+ _logger = logger;
+ _infoLogger = LoggerMessage.Define(
+ LogLevel.Information,
+ new EventId(0, "Info"),
+ "{Message}");
+ }
+
+ private void Log(string message)
+ {
+ _infoLogger(_logger, message, null);
+ }
+
+ private void LogDebug(string message)
+ {
+#if DEBUG
+ Log(message);
+#endif
+ }
+
+ private int RunMeUnderSystemAccount(int noOfTry, string activeDesktop, string userLocalAppDataPath)
+ {
+ int rv = 0;
+
+ try
+ {
+ string me = "\"" + Path.GetDirectoryName(myBinary) + "\\" + processName + "\"";
+ int waitCount = 20;
+
+ while (NativeMethods.WTSGetActiveConsoleSessionId() == 0xFFFFFFFF && waitCount > 0)
+ {
+ waitCount--;
+ LogDebug("The session is detached/attached.");
+ Thread.Sleep(500);
+ }
+
+ LogDebug("====================");
+ if (activeDesktop != null)
+ {
+ LogDebug($"Executing {me} on [{activeDesktop}], {NativeMethods.WTSGetActiveConsoleSessionId()}");
+ rv += NativeMethods.CreateProcessAsSystemAccountOnSpecificDesktop(me + " \"" + activeDesktop + "\"" + userLocalAppDataPath, activeDesktop, noOfTry) ? 1 : 0;
+ }
+ else
+ {
+ LogDebug($"Executing {me} winlogon, {NativeMethods.WTSGetActiveConsoleSessionId()}");
+ rv += NativeMethods.CreateProcessAsSystemAccountOnSpecificDesktop(me + " \"winlogon\" " + userLocalAppDataPath, "winlogon", noOfTry) ? 1 : 0;
+ LogDebug("====================");
+
+ // BEGIN: This may happen in some slow machine, this is a tentative fix
+ // http://social.msdn.microsoft.com/Forums/en-CA/clr/thread/9f00bdf0-3ea7-4a1f-b5a7-9b5bbc009888
+ Thread.Sleep(1000);
+
+ // END
+ LogDebug($"Executing {me} default, {NativeMethods.WTSGetActiveConsoleSessionId()}");
+ rv += NativeMethods.CreateProcessAsSystemAccountOnSpecificDesktop(me + " \"default\" " + userLocalAppDataPath, "default", noOfTry) ? 1 : 0;
+
+ if (appSessionId >= 0 && appSessionId != NativeMethods.WTSGetActiveConsoleSessionId())
+ {
+ Thread.Sleep(1000);
+ LogDebug($"Executing {me} default, {(appSessionId >= 0 ? appSessionId : (int)NativeMethods.WTSGetActiveConsoleSessionId())}");
+ rv += NativeMethods.CreateProcessAsSystemAccountOnSpecificDesktop(me + " \"default\" " + userLocalAppDataPath, "default", noOfTry, appSessionId) ? 1 : 0;
+
+ Thread.Sleep(1000);
+ LogDebug("Executing " + me + " \"winlogon\" on session " + appSessionId.ToString(CultureInfo.InvariantCulture));
+ rv += NativeMethods.CreateProcessAsSystemAccountOnSpecificDesktop(me + " \"winlogon\" " + userLocalAppDataPath, "winlogon", noOfTry, appSessionId) ? 1 : 0;
+ LogDebug("====================");
+ }
+ }
+
+ LogDebug("====================");
+ }
+ catch (Exception e)
+ {
+ Log($"Exception: {e.Message}");
+ }
+
+ return rv;
+ }
+
+ public Task StartAsync(CancellationToken cancellationToken)
+ {
+ var args = _cmdArgs;
+ string userLocalAppDataPath = args.Length > 1 && args[1] != null ? args[1].Trim() : null;
+
+ int noOfTry = 30;
+ bool isLoggingOff = false;
+ bool isByWindows = false;
+ string activeDesktop = null;
+ int successRunCount, expectedRunCount, processCount;
+
+ try
+ {
+ successRunCount = RunMeUnderSystemAccount(noOfTry, activeDesktop, userLocalAppDataPath);
+
+ Process[] p = Process.GetProcessesByName(processName);
+ processCount = p != null ? p.Length : 0;
+ expectedRunCount = 2;
+ LogDebug($"successRunCount = {successRunCount}, processCount = {processCount}");
+
+ if (isLoggingOff || isByWindows)
+ {
+ int c = 0;
+
+ while ((successRunCount < expectedRunCount || processCount < expectedRunCount) && c++ < 30)
+ {
+ Thread.Sleep(5000);
+ successRunCount = RunMeUnderSystemAccount(noOfTry, activeDesktop, userLocalAppDataPath);
+ Thread.Sleep(5000);
+ p = Process.GetProcessesByName(processName);
+ processCount = p != null ? p.Length : 0;
+
+ LogDebug($"successRunCount(2) = {successRunCount}, processCount = {processCount}");
+ }
+
+ Thread.Sleep(30000);
+
+ p = Process.GetProcessesByName(processName);
+ if (p == null || p.Length < 2)
+ {
+ LogDebug("Found none or one process, one more try...");
+ successRunCount = RunMeUnderSystemAccount(noOfTry, activeDesktop, userLocalAppDataPath);
+ Thread.Sleep(5000);
+ p = Process.GetProcessesByName(processName);
+ processCount = p != null ? p.Length : 0;
+ LogDebug($"successRunCount(3) = {successRunCount}, processCount = {processCount}");
+ }
+ }
+ else
+ {
+ RunMeUnderSystemAccount(noOfTry, null, userLocalAppDataPath);
+ }
+ }
+ catch (Exception ex)
+ {
+ Log($"Exception: {ex.Message}");
+ Thread.Sleep(1000);
+ }
+
+ CmdArgs.StopServiceDelegate();
+ return Task.CompletedTask;
+ }
+
+ public Task StopAsync(CancellationToken cancellationToken)
+ {
+ return Task.CompletedTask;
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersClipboardFileTransferEvent.cs b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersClipboardFileTransferEvent.cs
new file mode 100644
index 000000000000..e207f83896f8
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersClipboardFileTransferEvent.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Tracing;
+using Microsoft.PowerToys.Telemetry;
+using Microsoft.PowerToys.Telemetry.Events;
+
+namespace MouseWithoutBorders.Telemetry
+{
+ [EventData]
+ public class MouseWithoutBordersClipboardFileTransferEvent : EventBase, IEvent
+ {
+ public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersDragAndDropEvent.cs b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersDragAndDropEvent.cs
new file mode 100644
index 000000000000..fcd24cbb5448
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersDragAndDropEvent.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Tracing;
+using Microsoft.PowerToys.Telemetry;
+using Microsoft.PowerToys.Telemetry.Events;
+
+namespace MouseWithoutBorders.Telemetry
+{
+ [EventData]
+ public class MouseWithoutBordersDragAndDropEvent : EventBase, IEvent
+ {
+ public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersMultipleModeEvent.cs b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersMultipleModeEvent.cs
new file mode 100644
index 000000000000..10853e497911
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersMultipleModeEvent.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Tracing;
+using Microsoft.PowerToys.Telemetry;
+using Microsoft.PowerToys.Telemetry.Events;
+
+namespace MouseWithoutBorders.Telemetry
+{
+ [EventData]
+ public class MouseWithoutBordersMultipleModeEvent : EventBase, IEvent
+ {
+ public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersOldUIOpenedEvent.cs b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersOldUIOpenedEvent.cs
new file mode 100644
index 000000000000..7e618d8add31
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersOldUIOpenedEvent.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Tracing;
+using Microsoft.PowerToys.Telemetry;
+using Microsoft.PowerToys.Telemetry.Events;
+
+namespace MouseWithoutBorders.Telemetry
+{
+ [EventData]
+ public class MouseWithoutBordersOldUIOpenedEvent : EventBase, IEvent
+ {
+ public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersOldUIQuitEvent.cs b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersOldUIQuitEvent.cs
new file mode 100644
index 000000000000..4d4aaea178e9
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersOldUIQuitEvent.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Tracing;
+using Microsoft.PowerToys.Telemetry;
+using Microsoft.PowerToys.Telemetry.Events;
+
+namespace MouseWithoutBorders.Telemetry
+{
+ [EventData]
+ public class MouseWithoutBordersOldUIQuitEvent : EventBase, IEvent
+ {
+ public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersOldUIReconfigureEvent.cs b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersOldUIReconfigureEvent.cs
new file mode 100644
index 000000000000..4112aeb5c38e
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersOldUIReconfigureEvent.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Tracing;
+using Microsoft.PowerToys.Telemetry;
+using Microsoft.PowerToys.Telemetry.Events;
+
+namespace MouseWithoutBorders.Telemetry
+{
+ [EventData]
+ public class MouseWithoutBordersOldUIReconfigureEvent : EventBase, IEvent
+ {
+ public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersStartedEvent.cs b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersStartedEvent.cs
new file mode 100644
index 000000000000..da0e48467a50
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/Telemetry/MouseWithoutBordersStartedEvent.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Diagnostics.Tracing;
+using Microsoft.PowerToys.Telemetry;
+using Microsoft.PowerToys.Telemetry.Events;
+
+namespace MouseWithoutBorders.Telemetry
+{
+ [EventData]
+ public class MouseWithoutBordersStartedEvent : EventBase, IEvent
+ {
+ public PartA_PrivTags PartA_PrivTags => PartA_PrivTags.ProductAndServiceUsage;
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/App/appsettings.json b/src/modules/MouseWithoutBorders/App/appsettings.json
new file mode 100644
index 000000000000..b2dcdb67421c
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/App/appsettings.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ }
+}
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.rc b/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.rc
new file mode 100644
index 000000000000..5fa3c8b90d58
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.rc
@@ -0,0 +1,40 @@
+#include
+#include "resource.h"
+#include "../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.vcxproj b/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.vcxproj
new file mode 100644
index 000000000000..ea4339f06511
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.vcxproj
@@ -0,0 +1,77 @@
+
+
+
+
+ 15.0
+ {2833C9C6-AB32-4048-A5C7-A70898337B57}
+ Win32Proj
+ MouseWithoutBordersModuleInterface
+
+
+
+ DynamicLibrary
+
+
+ v143
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\modules\MouseWithoutBorders\
+ PowerToys.MouseWithoutBordersModuleInterface
+
+
+
+ FANCYZONES_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)
+ ..\;..\..\..\common\inc;..\..\..\common\Telemetry;..\..\;..\..\..\;%(AdditionalIncludeDirectories)
+
+
+ $(OutDir)$(TargetName)$(TargetExt)
+ windowsapp.lib;gdiplus.lib;dwmapi.lib;shlwapi.lib;uxtheme.lib;shcore.lib;wbemuuid.lib;comsuppw.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+
+
+
+
+ Create
+
+
+
+
+
+ {d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}
+
+
+ {6955446d-23f7-4023-9bb3-8657f904af99}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.vcxproj.filters b/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.vcxproj.filters
new file mode 100644
index 000000000000..27d483b17418
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.vcxproj.filters
@@ -0,0 +1,46 @@
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+
+ Header Files
+
+
+
+
+
+ Header Files
+
+
+
+
+ {21926bf1-03b3-482d-8f60-8bc4fbfc6564}
+
+
+ {2f10207d-d8d1-4a42-8027-8ca597b3cb23}
+
+
+ {a4241930-ecae-44e2-be82-25eff2499fcd}
+
+
+ {8d479404-964b-4eb1-8fe8-554be3e68c9b}
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.vcxproj.rc b/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.vcxproj.rc
new file mode 100644
index 000000000000..5fa3c8b90d58
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/MouseWithoutBordersModuleInterface.vcxproj.rc
@@ -0,0 +1,40 @@
+#include
+#include "resource.h"
+#include "../../../common/version/version.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+#include "winres.h"
+#undef APSTUDIO_READONLY_SYMBOLS
+
+1 VERSIONINFO
+FILEVERSION FILE_VERSION
+PRODUCTVERSION PRODUCT_VERSION
+FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+FILEFLAGS VS_FF_DEBUG
+#else
+FILEFLAGS 0x0L
+#endif
+FILEOS VOS_NT_WINDOWS32
+FILETYPE VFT_DLL
+FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0" // US English (0x0409), Unicode (0x04B0) charset
+ BEGIN
+ VALUE "CompanyName", COMPANY_NAME
+ VALUE "FileDescription", FILE_DESCRIPTION
+ VALUE "FileVersion", FILE_VERSION_STRING
+ VALUE "InternalName", INTERNAL_NAME
+ VALUE "LegalCopyright", COPYRIGHT_NOTE
+ VALUE "OriginalFilename", ORIGINAL_FILENAME
+ VALUE "ProductName", PRODUCT_NAME
+ VALUE "ProductVersion", PRODUCT_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200 // US English (0x0409), Unicode (1200) charset
+ END
+END
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/dllmain.cpp b/src/modules/MouseWithoutBorders/ModuleInterface/dllmain.cpp
new file mode 100644
index 000000000000..e942dfe734ee
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/dllmain.cpp
@@ -0,0 +1,616 @@
+#include "pch.h"
+#include
+#include
+#include
+#include "trace.h"
+#include "generateSecurityDescriptor.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+HINSTANCE g_hInst_MouseWithoutBorders = 0;
+
+BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID /*lpReserved*/)
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ g_hInst_MouseWithoutBorders = hModule;
+ Trace::RegisterProvider();
+ break;
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ Trace::UnregisterProvider();
+ break;
+ }
+ return TRUE;
+}
+
+bool GetUserSid(const wchar_t* username, PSID& sid)
+{
+ DWORD sidSize = 0;
+ DWORD domainNameSize = 0;
+ SID_NAME_USE sidNameUse;
+
+ LookupAccountName(nullptr, username, nullptr, &sidSize, nullptr, &domainNameSize, &sidNameUse);
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ Logger::error("Failed to get buffer sizes");
+ return false;
+ }
+
+ sid = LocalAlloc(LPTR, sidSize);
+ LPWSTR domainName = static_cast(LocalAlloc(LPTR, domainNameSize * sizeof(wchar_t)));
+
+ if (!LookupAccountNameW(nullptr, username, sid, &sidSize, domainName, &domainNameSize, &sidNameUse))
+ {
+ Logger::error("Failed to lookup account name");
+ LocalFree(sid);
+ LocalFree(domainName);
+ return false;
+ }
+
+ LocalFree(domainName);
+ return true;
+}
+
+std::wstring GetCurrentUserSid()
+{
+ wchar_t username[UNLEN + 1];
+ DWORD usernameSize = UNLEN + 1;
+
+ std::wstring result;
+ if (!GetUserNameW(username, &usernameSize))
+ {
+ Logger::error("Failed to get the current user name");
+ return result;
+ }
+
+ PSID sid;
+ if (GetUserSid(username, sid))
+ {
+ LPWSTR sidString;
+ if (ConvertSidToStringSid(sid, &sidString))
+ {
+ result = sidString;
+ LocalFree(sidString);
+ }
+ LocalFree(sid);
+ }
+ else
+ {
+ Logger::error(L"Failed to get SID for user \"");
+ }
+
+ return result;
+}
+
+std::wstring escapeDoubleQuotes(const std::wstring& input)
+{
+ std::wstring output;
+ output.reserve(input.size());
+
+ for (const wchar_t& ch : input)
+ {
+ if (ch == L'"')
+ {
+ output += L'\\';
+ }
+ output += ch;
+ }
+
+ return output;
+}
+
+const static wchar_t* MODULE_NAME = L"MouseWithoutBorders";
+const static wchar_t* MODULE_DESC = L"A module to move your mouse across computers.";
+const static wchar_t* SERVICE_NAME = L"PowerToys.MWB.Service";
+const static std::wstring_view USE_SERVICE_PROPERTY_NAME = L"UseService";
+
+class MouseWithoutBorders : public PowertoyModuleIface
+{
+ std::wstring app_name;
+ std::wstring app_key;
+
+private:
+ bool m_enabled = false;
+ bool run_in_service_mode = false;
+ HANDLE send_telemetry_event;
+ HANDLE m_hInvokeEvent;
+ PROCESS_INFORMATION p_info;
+
+ bool is_enabled_by_default() const override
+ {
+ return false;
+ }
+
+ bool is_process_running()
+ {
+ return WaitForSingleObject(p_info.hProcess, 0) == WAIT_TIMEOUT;
+ }
+
+ void launch_process()
+ {
+ Logger::trace(L"Launching PowerToys MouseWithoutBorders process");
+ const std::wstring application_path = L"modules\\MouseWithoutBorders\\PowerToys.MouseWithoutBorders.exe";
+ STARTUPINFO info = { sizeof(info) };
+ std::wstring full_command_path = application_path;
+ if (run_in_service_mode)
+ {
+ full_command_path += L" ";
+ full_command_path += USE_SERVICE_PROPERTY_NAME;
+ }
+
+ if (!CreateProcessW(application_path.c_str(), full_command_path.data(), nullptr, nullptr, true, {}, nullptr, nullptr, &info, &p_info))
+ {
+ DWORD error = GetLastError();
+ std::wstring message = L"PowerToys MouseWithoutBorders failed to start with error: ";
+ message += std::to_wstring(error);
+ Logger::error(message);
+ }
+
+ Trace::MouseWithoutBorders::Activate();
+ }
+
+ void unregister_service()
+ {
+ SC_HANDLE schSCManager = OpenSCManagerW(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
+
+ SC_HANDLE hService = OpenServiceW(schSCManager, SERVICE_NAME, SERVICE_STOP | DELETE);
+ if (!hService)
+ {
+ Logger::error("Failed to open MWB service");
+ return;
+ }
+
+ SERVICE_STATUS ss;
+ if (ControlService(hService, SERVICE_CONTROL_STOP, &ss))
+ {
+ Sleep(1000);
+ for (int i = 0; i < 5; ++i)
+ {
+ while (QueryServiceStatus(hService, &ss))
+ {
+ if (ss.dwCurrentState == SERVICE_STOP_PENDING)
+ {
+ Sleep(1000);
+ }
+ else
+ {
+ goto outer;
+ }
+ }
+ }
+ }
+
+ outer:
+ BOOL deleteResult = DeleteService(hService);
+ CloseServiceHandle(hService);
+
+ if (!deleteResult)
+ {
+ Logger::error("Failed to delete MWB service");
+ return;
+ }
+
+ Trace::MouseWithoutBorders::ToggleServiceRegistration(false);
+ }
+
+ void
+ register_service()
+ {
+ SC_HANDLE schSCManager = OpenSCManagerW(nullptr, SERVICES_ACTIVE_DATABASE, SC_MANAGER_ALL_ACCESS);
+ if (schSCManager == nullptr)
+ {
+ Logger::error(L"Couldn't open sc manager");
+ return;
+ }
+
+ const auto closeSCM = wil::scope_exit([&] {
+ CloseServiceHandle(schSCManager);
+ });
+
+ SC_HANDLE schService = OpenServiceW(schSCManager, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);
+
+ const auto closeService = wil::scope_exit([&] {
+ CloseServiceHandle(schService);
+ });
+
+ const auto servicePath = get_module_folderpath(g_hInst_MouseWithoutBorders) + L"/PowerToys.MouseWithoutBordersService.exe";
+
+ // Check that the service doesn't exist already and is not disabled
+ DWORD bytesNeeded;
+ LPQUERY_SERVICE_CONFIGW pServiceConfig = nullptr;
+ if (!QueryServiceConfigW(schService, nullptr, 0, &bytesNeeded))
+ {
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ {
+ pServiceConfig = static_cast(LocalAlloc(LMEM_FIXED, bytesNeeded));
+ if (!QueryServiceConfigW(schService, pServiceConfig, bytesNeeded, &bytesNeeded))
+ {
+ LocalFree(pServiceConfig);
+ pServiceConfig = nullptr;
+ CloseServiceHandle(schService);
+ }
+ }
+ }
+
+ bool alreadyRegistered = false;
+ if (pServiceConfig)
+ {
+ std::wstring_view existingServicePath{ pServiceConfig->lpBinaryPathName };
+ existingServicePath = existingServicePath.substr(1, existingServicePath.find(L'"', 1) - 1);
+ alreadyRegistered = std::filesystem::path{ existingServicePath } == servicePath;
+ LocalFree(pServiceConfig);
+
+ if (alreadyRegistered && pServiceConfig->dwStartType == SERVICE_DISABLED)
+ {
+ if (!ChangeServiceConfigW(schService,
+ SERVICE_NO_CHANGE,
+ SERVICE_DEMAND_START,
+ SERVICE_NO_CHANGE,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr))
+ {
+ const bool markedForDelete = GetLastError() == ERROR_SERVICE_MARKED_FOR_DELETE;
+ // We cannot remove the mark for deletion from the service.
+ if (markedForDelete)
+ {
+ alreadyRegistered = false;
+ CloseServiceHandle(schService);
+ }
+ }
+ }
+
+ if (alreadyRegistered)
+ {
+ SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;
+ if (!QueryServiceConfig2W(schService, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, reinterpret_cast(&delayedAutoStartInfo), sizeof(delayedAutoStartInfo), &bytesNeeded) || delayedAutoStartInfo.fDelayedAutostart)
+ {
+ alreadyRegistered = false;
+ // Wait until the service has been actually deleted so we can recreate it again
+ for (int i = 0; i < 10; ++i)
+ {
+ schService = OpenServiceW(schSCManager, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG);
+ if (schService)
+ {
+ CloseServiceHandle(schService);
+ Sleep(1000);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (alreadyRegistered)
+ {
+ return;
+ }
+
+ // Pass local app data of the current user to the service
+ PWSTR cLocalAppPath;
+ winrt::check_hresult(SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &cLocalAppPath));
+ CoTaskMemFree(cLocalAppPath);
+
+ std::wstring localAppPath{ cLocalAppPath };
+ std::wstring binaryWithArgsPath = L"\"";
+ binaryWithArgsPath += servicePath;
+ binaryWithArgsPath += L"\" ";
+ binaryWithArgsPath += escapeDoubleQuotes(localAppPath);
+
+ schService = CreateServiceW(
+ schSCManager,
+ SERVICE_NAME,
+ SERVICE_NAME,
+ SERVICE_ALL_ACCESS,
+ SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_DEMAND_START,
+ SERVICE_ERROR_NORMAL,
+ binaryWithArgsPath.c_str(),
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr,
+ nullptr);
+
+ if (schService == nullptr)
+ {
+ Logger::error(L"Failed to create service");
+ return;
+ }
+
+ // Set up the security descriptor to allow non-elevated users to start the service
+ PSECURITY_DESCRIPTOR pSD = nullptr;
+ ULONG szSD = 0;
+ std::wstring securityDescriptor = generateSecurityDescriptor(GetCurrentUserSid());
+
+ if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
+ securityDescriptor.c_str(),
+ SDDL_REVISION_1,
+ &pSD,
+ &szSD))
+ {
+ Logger::error(L"Failed to convert security descriptor string");
+ CloseServiceHandle(schService);
+ return;
+ }
+
+ if (!SetServiceObjectSecurity(schService, DACL_SECURITY_INFORMATION, pSD))
+ {
+ Logger::error("Failed to set service object security");
+ }
+
+ LocalFree(pSD);
+ CloseServiceHandle(schService);
+ }
+
+ void update_state_from_settings(const PowerToysSettings::PowerToyValues& values)
+ {
+ const bool new_run_in_service_mode = values.get_bool_value(USE_SERVICE_PROPERTY_NAME).value_or(false);
+
+ if (new_run_in_service_mode != run_in_service_mode)
+ {
+ run_in_service_mode = new_run_in_service_mode;
+
+ shutdown_processes();
+
+ if (new_run_in_service_mode)
+ {
+ register_service();
+ }
+ // Wait until Settings -> MWB IPC Shutdown() call is completed
+ else
+ {
+ const auto ps = getProcessHandlesByName(L"PowerToys.MouseWithoutBorders.exe", PROCESS_QUERY_LIMITED_INFORMATION);
+ for (const auto& p : ps)
+ {
+ DWORD status = STILL_ACTIVE;
+ do
+ {
+ GetExitCodeProcess(p.get(), &status);
+ } while (status == STILL_ACTIVE);
+ }
+
+ Sleep(1000);
+ }
+
+ if (m_enabled)
+ {
+ launch_process();
+ }
+
+ Trace::MouseWithoutBorders::ToggleServiceRegistration(new_run_in_service_mode);
+ }
+ }
+
+public:
+ MouseWithoutBorders()
+ {
+ app_name = L"MouseWithoutBorders";
+ app_key = app_name;
+ std::filesystem::path logFilePath(PTSettingsHelper::get_module_save_folder_location(app_key));
+ logFilePath.append(LogSettings::mouseWithoutBordersLogPath);
+ Logger::init(LogSettings::mouseWithoutBordersLoggerName, logFilePath.wstring(), PTSettingsHelper::get_log_settings_file_location());
+
+ try
+ {
+ PowerToysSettings::PowerToyValues values =
+ PowerToysSettings::PowerToyValues::load_from_settings_file(MODULE_NAME);
+ update_state_from_settings(values);
+ }
+ catch (std::exception&)
+ {
+ // Initial start/
+ }
+ };
+
+ // Return the configured status for the gpo policy for the module
+ virtual powertoys_gpo::gpo_rule_configured_t gpo_policy_enabled_configuration() override
+ {
+ return powertoys_gpo::getConfiguredMouseWithoutBordersEnabledValue();
+ }
+
+ void shutdown_process(HANDLE handle)
+ {
+ auto cb = [](HWND hwnd, LPARAM lParam) -> BOOL {
+ DWORD processId;
+ GetWindowThreadProcessId(hwnd, &processId);
+
+ if (processId == lParam)
+ {
+ PostMessageW(hwnd, WM_CLOSE, 0, 0);
+ return FALSE;
+ }
+
+ return TRUE;
+ };
+
+ DWORD processId = GetProcessId(handle);
+ EnumWindows(cb, processId);
+
+ DWORD waitResult = WaitForSingleObject(handle, 3000);
+ if (waitResult != WAIT_OBJECT_0)
+ {
+ TerminateProcess(handle, 0);
+ }
+ }
+
+ void shutdown_processes()
+ {
+ const auto services = getProcessHandlesByName(L"PowerToys.MouseWithoutBordersService.exe", PROCESS_TERMINATE);
+ for (const auto& svc : services)
+ TerminateProcess(svc.get(), 0);
+ wil::unique_process_handle s;
+
+ std::array processes_names = { L"PowerToys.MouseWithoutBorders.exe",
+ L"PowerToys.MouseWithoutBordersHelper.exe" };
+
+ for (const auto process : processes_names)
+ {
+ const auto apps = getProcessHandlesByName(process, PROCESS_TERMINATE);
+ for (const auto& app : apps)
+ shutdown_process(app.get());
+ }
+ }
+
+ virtual void destroy() override
+ {
+ shutdown_processes();
+ TerminateProcess(p_info.hProcess, 1);
+ delete this;
+ }
+
+ virtual const wchar_t* get_name() override
+ {
+ return MODULE_NAME;
+ }
+
+ virtual bool get_config(wchar_t* buffer, int* buffer_size) override
+ {
+ HINSTANCE hinstance = reinterpret_cast(&__ImageBase);
+
+ PowerToysSettings::Settings settings(hinstance, get_name());
+ settings.set_description(MODULE_DESC);
+
+ return settings.serialize_to_buffer(buffer, buffer_size);
+ }
+
+ virtual const wchar_t* get_key() override
+ {
+ return app_key.c_str();
+ }
+
+ virtual void set_config(const wchar_t* config) override
+ {
+ try
+ {
+ // Parse the input JSON string.
+ PowerToysSettings::PowerToyValues values =
+ PowerToysSettings::PowerToyValues::from_json_string(config, get_key());
+
+ update_state_from_settings(values);
+ // If you don't need to do any custom processing of the settings, proceed
+ // to persists the values.
+ values.save_to_settings_file();
+ }
+ catch (std::exception&)
+ {
+ // Improper JSON.
+ }
+ }
+
+ virtual void enable()
+ {
+ Trace::MouseWithoutBorders::Enable(true);
+ ResetEvent(send_telemetry_event);
+ ResetEvent(m_hInvokeEvent);
+
+ launch_process();
+
+ m_enabled = true;
+ };
+
+ virtual void disable()
+ {
+ if (m_enabled)
+ {
+ Trace::MouseWithoutBorders::Enable(false);
+ Logger::trace(L"Disabling MouseWithoutBorders...");
+ ResetEvent(send_telemetry_event);
+ ResetEvent(m_hInvokeEvent);
+
+ Logger::trace(L"Signaled exit event for PowerToys MouseWithoutBorders.");
+ TerminateProcess(p_info.hProcess, 1);
+
+ shutdown_processes();
+
+ CloseHandle(p_info.hProcess);
+ }
+
+ m_enabled = false;
+ }
+
+ virtual bool is_enabled() override
+ {
+ return m_enabled;
+ }
+
+ void launch_add_firewall_process()
+ {
+ Logger::trace(L"Starting Process to add firewall rule");
+
+ std::wstring executable_path = get_module_folderpath();
+ executable_path.append(L"\\modules\\MouseWithoutBorders\\PowerToys.MouseWithoutBorders.exe");
+
+ std::wstring executable_args = L"";
+ executable_args.append(L"/S /c \"");
+ executable_args.append(L"echo \"Deleting existing inbound firewall rules for PowerToys.MouseWithoutBorders.exe\"");
+ executable_args.append(L" & netsh advfirewall firewall delete rule dir=in name=all program=\"");
+ executable_args.append(executable_path);
+ executable_args.append(L"\" & echo \"Adding an inbound firewall rule for PowerToys.MouseWithoutBorders.exe\"");
+ executable_args.append(L" & netsh advfirewall firewall add rule name=\"PowerToys.MouseWithoutBorders\" dir=in action=allow program=\"");
+ executable_args.append(executable_path);
+ executable_args.append(L"\" enable=yes remoteip=LocalSubnet profile=any protocol=tcp & pause\"");
+
+ SHELLEXECUTEINFOW sei{ sizeof(sei) };
+ sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
+ sei.lpFile = L"cmd.exe";
+ sei.nShow = SW_SHOWNORMAL;
+ sei.lpParameters = executable_args.data();
+ sei.lpVerb = L"runas";
+
+ if (ShellExecuteExW(&sei))
+ {
+ Logger::trace("Successfully started the firewall rule adding process");
+ }
+ else
+ {
+ Logger::error(L"The firewall rule adding process failed to start. {}", get_last_error_or_default(GetLastError()));
+ }
+ }
+
+ virtual void call_custom_action(const wchar_t* action) override
+ {
+ try
+ {
+ PowerToysSettings::CustomActionObject action_object =
+ PowerToysSettings::CustomActionObject::from_json_string(action);
+
+ if (action_object.get_name() == L"add_firewall")
+ {
+ launch_add_firewall_process();
+ Trace::MouseWithoutBorders::AddFirewallRule();
+ }
+ else if (action_object.get_name() == L"uninstall_service")
+ {
+ unregister_service();
+ }
+ }
+ catch (std::exception&)
+ {
+ Logger::error(L"Failed to parse action. {}", action);
+ }
+ }
+};
+
+extern "C" __declspec(dllexport) PowertoyModuleIface* __cdecl powertoy_create()
+{
+ return new MouseWithoutBorders();
+}
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/generateSecurityDescriptor.h b/src/modules/MouseWithoutBorders/ModuleInterface/generateSecurityDescriptor.h
new file mode 100644
index 000000000000..f306b9aeb3b9
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/generateSecurityDescriptor.h
@@ -0,0 +1,10 @@
+#pragma once
+#include
+
+// Isolate this function for the magic strings it has.
+inline std::wstring generateSecurityDescriptor(std::wstring Sid) {
+ std::wstring securityDescriptor = L"D:(A;;CCLCSWRPWPDTLOCRRC;;;SY)(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;BA)(A;;CCLCSWLOCRRC;;;IU)(A;;CCLCSWLOCRRC;;;SU)(A;;CR;;;AU)(A;;CCLCSWRPWPDTLOCRRC;;;PU)(A;;RPWPDTLO;;;";
+ securityDescriptor += Sid;
+ securityDescriptor += L")S:(AU;FA;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;WD)";
+ return securityDescriptor;
+}
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/packages.config b/src/modules/MouseWithoutBorders/ModuleInterface/packages.config
new file mode 100644
index 000000000000..3d9798ef5e72
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/packages.config
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/pch.cpp b/src/modules/MouseWithoutBorders/ModuleInterface/pch.cpp
new file mode 100644
index 000000000000..1d9f38c57d63
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/pch.cpp
@@ -0,0 +1 @@
+#include "pch.h"
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/pch.h b/src/modules/MouseWithoutBorders/ModuleInterface/pch.h
new file mode 100644
index 000000000000..cb0737a69da5
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/pch.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/resource.h b/src/modules/MouseWithoutBorders/ModuleInterface/resource.h
new file mode 100644
index 000000000000..474acfc9de6f
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/resource.h
@@ -0,0 +1,21 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by MouseWithoutBorders.rc
+//
+#define IDS_MOUSE_WITHOUT_BORDERS_NAME 101
+
+
+#define FILE_DESCRIPTION "PowerToys MouseWithoutBorders Module"
+#define INTERNAL_NAME "PowerToys.MouseWithoutBordersModuleInterface"
+#define ORIGINAL_FILENAME "PowerToys.MouseWithoutBordersModuleInterface.dll"
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 102
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/trace.cpp b/src/modules/MouseWithoutBorders/ModuleInterface/trace.cpp
new file mode 100644
index 000000000000..fb2f631bc6c7
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/trace.cpp
@@ -0,0 +1,64 @@
+#include "pch.h"
+#include "trace.h"
+
+// Telemetry strings should not be localized.
+#define LoggingProviderKey "Microsoft.PowerToys"
+
+#define EventEnableMouseWithoutBordersKey "MouseWithoutBorders_EnableMouseWithoutBorders"
+#define EventEnabledKey "Enabled"
+
+TRACELOGGING_DEFINE_PROVIDER(
+ g_hProvider,
+ LoggingProviderKey,
+ // {38e8889b-9731-53f5-e901-e8a7c1753074}
+ (0x38e8889b, 0x9731, 0x53f5, 0xe9, 0x01, 0xe8, 0xa7, 0xc1, 0x75, 0x30, 0x74),
+ TraceLoggingOptionProjectTelemetry());
+
+void Trace::RegisterProvider() noexcept
+{
+ TraceLoggingRegister(g_hProvider);
+}
+
+void Trace::UnregisterProvider() noexcept
+{
+ TraceLoggingUnregister(g_hProvider);
+}
+
+void Trace::MouseWithoutBorders::Enable(bool enabled) noexcept
+{
+ TraceLoggingWrite(
+ g_hProvider,
+ EventEnableMouseWithoutBordersKey,
+ ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
+ TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
+ TraceLoggingBoolean(enabled, EventEnabledKey));
+}
+
+void Trace::MouseWithoutBorders::ToggleServiceRegistration(bool enabled) noexcept
+{
+ TraceLoggingWrite(
+ g_hProvider,
+ "MouseWithoutBorders_ToggleServiceRegistration",
+ ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
+ TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE),
+ TraceLoggingBoolean(enabled, EventEnabledKey));
+}
+
+void Trace::MouseWithoutBorders::Activate() noexcept
+{
+ TraceLoggingWrite(
+ g_hProvider,
+ "MouseWithoutBorders_Activate",
+ ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
+ TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
+}
+
+// Log that the user tried to activate the editor
+void Trace::MouseWithoutBorders::AddFirewallRule() noexcept
+{
+ TraceLoggingWrite(
+ g_hProvider,
+ "MouseWithoutBorders_AddFirewallRule",
+ ProjectTelemetryPrivacyDataTag(ProjectTelemetryTag_ProductAndServicePerformance),
+ TraceLoggingKeyword(PROJECT_KEYWORD_MEASURE));
+}
diff --git a/src/modules/MouseWithoutBorders/ModuleInterface/trace.h b/src/modules/MouseWithoutBorders/ModuleInterface/trace.h
new file mode 100644
index 000000000000..1f9099eaaea2
--- /dev/null
+++ b/src/modules/MouseWithoutBorders/ModuleInterface/trace.h
@@ -0,0 +1,17 @@
+#pragma once
+
+class Trace
+{
+public:
+ static void RegisterProvider() noexcept;
+ static void UnregisterProvider() noexcept;
+
+ class MouseWithoutBorders
+ {
+ public:
+ static void Enable(bool enabled) noexcept;
+ static void ToggleServiceRegistration(bool enabled) noexcept;
+ static void Activate() noexcept;
+ static void AddFirewallRule() noexcept;
+ };
+};
diff --git a/src/runner/main.cpp b/src/runner/main.cpp
index f32723684b24..d2799f84edc1 100644
--- a/src/runner/main.cpp
+++ b/src/runner/main.cpp
@@ -169,6 +169,7 @@ int runner(bool isProcessElevated, bool openSettings, std::string settingsWindow
L"modules/MeasureTool/PowerToys.MeasureToolModuleInterface.dll",
L"modules/Hosts/PowerToys.HostsModuleInterface.dll",
L"modules/Peek/PowerToys.Peek.dll",
+ L"modules/MouseWithoutBorders/PowerToys.MouseWithoutBordersModuleInterface.dll",
};
const auto VCM_PATH = L"modules/VideoConference/PowerToys.VideoConferenceModule.dll";
if (const auto mf = LoadLibraryA("mf.dll"))
diff --git a/src/settings-ui/Settings.UI.Library/EnabledModules.cs b/src/settings-ui/Settings.UI.Library/EnabledModules.cs
index dcf7cb05acb7..a64da60beb71 100644
--- a/src/settings-ui/Settings.UI.Library/EnabledModules.cs
+++ b/src/settings-ui/Settings.UI.Library/EnabledModules.cs
@@ -182,6 +182,22 @@ public bool Awake
}
}
+ private bool mouseWithoutBorders = true;
+
+ [JsonPropertyName("MouseWithoutBorders")]
+ public bool MouseWithoutBorders
+ {
+ get => mouseWithoutBorders;
+ set
+ {
+ if (mouseWithoutBorders != value)
+ {
+ LogTelemetryEvent(value);
+ mouseWithoutBorders = value;
+ }
+ }
+ }
+
private bool findMyMouse = true;
[JsonPropertyName("FindMyMouse")]
diff --git a/src/settings-ui/Settings.UI.Library/IntProperty.cs b/src/settings-ui/Settings.UI.Library/IntProperty.cs
index fc7a6376dadd..c36950568b5e 100644
--- a/src/settings-ui/Settings.UI.Library/IntProperty.cs
+++ b/src/settings-ui/Settings.UI.Library/IntProperty.cs
@@ -2,6 +2,7 @@
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
+using System;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -29,5 +30,15 @@ public override string ToString()
{
return JsonSerializer.Serialize(this);
}
+
+ public static implicit operator IntProperty(int v)
+ {
+ throw new NotImplementedException();
+ }
+
+ public static implicit operator IntProperty(uint v)
+ {
+ throw new NotImplementedException();
+ }
}
}
diff --git a/src/settings-ui/Settings.UI.Library/MouseWithoutBordersProperties.cs b/src/settings-ui/Settings.UI.Library/MouseWithoutBordersProperties.cs
new file mode 100644
index 000000000000..e2946fecd22a
--- /dev/null
+++ b/src/settings-ui/Settings.UI.Library/MouseWithoutBordersProperties.cs
@@ -0,0 +1,164 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.Json.Serialization;
+
+namespace Microsoft.PowerToys.Settings.UI.Library
+{
+#pragma warning disable SA1649 // File name should match first type name
+ public struct ConnectionRequest
+#pragma warning restore SA1649 // File name should match first type name
+ {
+ public string PCName;
+ public string SecurityKey;
+ }
+
+ public struct NewKeyGenerationRequest
+ {
+ }
+
+ public class MouseWithoutBordersProperties : ICloneable
+ {
+ public StringProperty SecurityKey { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool UseService { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool ShowOriginalUI { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool WrapMouse { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool ShareClipboard { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool TransferFile { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool HideMouseAtScreenEdge { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool DrawMouseCursor { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool ValidateRemoteMachineIP { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool SameSubnetOnly { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool BlockScreenSaverOnOtherMachines { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool MoveMouseRelatively { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool BlockMouseAtScreenCorners { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool ShowClipboardAndNetworkStatusMessages { get; set; }
+
+ public List MachineMatrixString { get; set; }
+
+ public StringProperty MachinePool { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool MatrixOneRow { get; set; }
+
+ public IntProperty EasyMouse { get; set; }
+
+ public IntProperty MachineID { get; set; }
+
+ public IntProperty LastX { get; set; }
+
+ public IntProperty LastY { get; set; }
+
+ public IntProperty PackageID { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool FirstRun { get; set; }
+
+ public IntProperty HotKeySwitchMachine { get; set; }
+
+ public IntProperty HotKeyToggleEasyMouse { get; set; }
+
+ public IntProperty HotKeyLockMachine { get; set; }
+
+ public IntProperty HotKeyReconnect { get; set; }
+
+ public IntProperty HotKeySwitch2AllPC { get; set; }
+
+ public IntProperty TCPPort { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool DrawMouseEx { get; set; }
+
+ public StringProperty Name2IP { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool UseVKMap { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool FirstCtrlShiftS { get; set; }
+
+ [JsonConverter(typeof(BoolPropertyJsonConverter))]
+ public bool StealFocusWhenSwitchingMachine { get; set; }
+
+ public StringProperty DeviceID { get; set; }
+
+ public MouseWithoutBordersProperties()
+ {
+ SecurityKey = new StringProperty(string.Empty);
+ WrapMouse = true;
+ ShareClipboard = true;
+ TransferFile = true;
+ HideMouseAtScreenEdge = true;
+ DrawMouseCursor = true;
+ ValidateRemoteMachineIP = false;
+ SameSubnetOnly = false;
+ BlockScreenSaverOnOtherMachines = true;
+ MoveMouseRelatively = false;
+ BlockMouseAtScreenCorners = false;
+ ShowClipboardAndNetworkStatusMessages = false;
+ EasyMouse = new IntProperty(1);
+ MachineMatrixString = new List();
+ DeviceID = new StringProperty(string.Empty);
+ ShowOriginalUI = false;
+ UseService = false;
+
+ HotKeySwitchMachine = new IntProperty(0x70); // VK.F1
+ HotKeyToggleEasyMouse = new IntProperty(0x45); // VK.E
+ HotKeyLockMachine = new IntProperty(0x4C); // VK.L
+ HotKeyReconnect = new IntProperty(0x52); // VK.R
+ HotKeySwitch2AllPC = new IntProperty(0); // Disabled
+
+ // These are internal, i.e. cannot be edited directly from UI
+ MachinePool = ":,:,:,:";
+ MatrixOneRow = true;
+ MachineID = new IntProperty(0);
+ LastX = new IntProperty(0);
+ LastY = new IntProperty(0);
+ PackageID = new IntProperty(0);
+ FirstRun = false;
+ TCPPort = new IntProperty(15100);
+ DrawMouseEx = true;
+ Name2IP = new StringProperty(string.Empty);
+ UseVKMap = false;
+ FirstCtrlShiftS = false;
+ StealFocusWhenSwitchingMachine = false;
+ }
+
+ public object Clone()
+ {
+ var clone = new MouseWithoutBordersProperties();
+ clone = this;
+ return clone;
+ }
+ }
+}
diff --git a/src/settings-ui/Settings.UI.Library/MouseWithoutBordersSettings.cs b/src/settings-ui/Settings.UI.Library/MouseWithoutBordersSettings.cs
new file mode 100644
index 000000000000..35b831e9beff
--- /dev/null
+++ b/src/settings-ui/Settings.UI.Library/MouseWithoutBordersSettings.cs
@@ -0,0 +1,55 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Text.Json;
+using System.Text.Json.Serialization;
+using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
+
+namespace Microsoft.PowerToys.Settings.UI.Library
+{
+ public class MouseWithoutBordersSettings : BasePTModuleSettings, ISettingsConfig
+ {
+ public const string ModuleName = "MouseWithoutBorders";
+
+ [JsonPropertyName("properties")]
+ public MouseWithoutBordersProperties Properties { get; set; }
+
+ public MouseWithoutBordersSettings()
+ {
+ Name = ModuleName;
+ Properties = new MouseWithoutBordersProperties();
+ Version = "1.0";
+ }
+
+ public string GetModuleName()
+ {
+ return Name;
+ }
+
+ // This can be utilized in the future if the settings.json file is to be modified/deleted.
+ public bool UpgradeSettingsConfiguration()
+ {
+ return false;
+ }
+
+ public virtual void Save(ISettingsUtils settingsUtils)
+ {
+ // Save settings to file
+ var options = new JsonSerializerOptions
+ {
+ WriteIndented = true,
+ MaxDepth = 0,
+ IncludeFields = true,
+ };
+
+ if (settingsUtils == null)
+ {
+ throw new ArgumentNullException(nameof(settingsUtils));
+ }
+
+ settingsUtils.SaveSettings(JsonSerializer.Serialize(this, options), ModuleName);
+ }
+ }
+}
diff --git a/src/settings-ui/Settings.UI.Library/SettingPath.cs b/src/settings-ui/Settings.UI.Library/SettingPath.cs
index 65a1ea124479..3768db997629 100644
--- a/src/settings-ui/Settings.UI.Library/SettingPath.cs
+++ b/src/settings-ui/Settings.UI.Library/SettingPath.cs
@@ -4,6 +4,7 @@
using System;
using System.IO.Abstractions;
+using Microsoft.PowerToys.Settings.UI.Library.Utilities;
namespace Microsoft.PowerToys.Settings.UI.Library
{
@@ -23,22 +24,17 @@ public SettingPath(IDirectory directory, IPath path)
public bool SettingsFolderExists(string powertoy)
{
- return _directory.Exists(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
+ return _directory.Exists(System.IO.Path.Combine(Helper.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
}
public void CreateSettingsFolder(string powertoy)
{
- _directory.CreateDirectory(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
+ _directory.CreateDirectory(System.IO.Path.Combine(Helper.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
}
public void DeleteSettings(string powertoy = "")
{
- _directory.Delete(System.IO.Path.Combine(LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
- }
-
- private static string LocalApplicationDataFolder()
- {
- return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ _directory.Delete(System.IO.Path.Combine(Helper.LocalApplicationDataFolder(), $"Microsoft\\PowerToys\\{powertoy}"));
}
///
@@ -50,12 +46,12 @@ public string GetSettingsPath(string powertoy, string fileName = DefaultFileName
if (string.IsNullOrWhiteSpace(powertoy))
{
return _path.Combine(
- LocalApplicationDataFolder(),
+ Helper.LocalApplicationDataFolder(),
$"Microsoft\\PowerToys\\{fileName}");
}
return _path.Combine(
- LocalApplicationDataFolder(),
+ Helper.LocalApplicationDataFolder(),
$"Microsoft\\PowerToys\\{powertoy}\\{fileName}");
}
}
diff --git a/src/settings-ui/Settings.UI.Library/SettingsUtils.cs b/src/settings-ui/Settings.UI.Library/SettingsUtils.cs
index a77f9e2c62f6..241705805914 100644
--- a/src/settings-ui/Settings.UI.Library/SettingsUtils.cs
+++ b/src/settings-ui/Settings.UI.Library/SettingsUtils.cs
@@ -150,7 +150,9 @@ private T GetFile(string powertoyFolderName = DefaultModuleName, string fileN
// This, while not totally ideal, does work around the problem by trimming the end.
// The file itself did write the content correctly but something is off with the actual end of the file, hence the 0x00 bug
var jsonSettingsString = _file.ReadAllText(_settingsPath.GetSettingsPath(powertoyFolderName, fileName)).Trim('\0');
- return JsonSerializer.Deserialize(jsonSettingsString);
+
+ var options = new JsonSerializerOptions { MaxDepth = 0, IncludeFields = true };
+ return JsonSerializer.Deserialize(jsonSettingsString, options);
}
// Save settings to a json file.
diff --git a/src/settings-ui/Settings.UI.Library/Utilities/Helper.cs b/src/settings-ui/Settings.UI.Library/Utilities/Helper.cs
index bd9d98e424fd..3ca22b9b39c2 100644
--- a/src/settings-ui/Settings.UI.Library/Utilities/Helper.cs
+++ b/src/settings-ui/Settings.UI.Library/Utilities/Helper.cs
@@ -7,6 +7,8 @@
using System.IO;
using System.IO.Abstractions;
using System.Linq;
+using System.Net.NetworkInformation;
+using System.Security.Principal;
using Microsoft.PowerToys.Settings.UI.Library.CustomAction;
namespace Microsoft.PowerToys.Settings.UI.Library.Utilities
@@ -15,6 +17,8 @@ public static class Helper
{
public static readonly IFileSystem FileSystem = new FileSystem();
+ public static string UserLocalAppDataPath { get; set; } = string.Empty;
+
public static bool AllowRunnerToForeground()
{
var result = false;
@@ -69,9 +73,20 @@ public static IFileSystemWatcher GetFileWatcher(string moduleName, string fileNa
return watcher;
}
- private static string LocalApplicationDataFolder()
+ public static string LocalApplicationDataFolder()
{
- return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
+ SecurityIdentifier currentUserSID = currentUser.User;
+
+ SecurityIdentifier localSystemSID = new SecurityIdentifier(WellKnownSidType.LocalSystemSid, null);
+ if (currentUserSID.Equals(localSystemSID) && UserLocalAppDataPath != string.Empty)
+ {
+ return UserLocalAppDataPath;
+ }
+ else
+ {
+ return Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ }
}
public static string GetPowerToysInstallationFolder()
diff --git a/src/settings-ui/Settings.UI.UnitTests/Settings.UI.UnitTests.csproj b/src/settings-ui/Settings.UI.UnitTests/Settings.UI.UnitTests.csproj
index 495d233decae..385bf0ab67a3 100644
--- a/src/settings-ui/Settings.UI.UnitTests/Settings.UI.UnitTests.csproj
+++ b/src/settings-ui/Settings.UI.UnitTests/Settings.UI.UnitTests.csproj
@@ -14,6 +14,13 @@
DEBUG;TRACE
+
+
+
+
+ VSTHRD002;VSTHRD110;VSTHRD100;VSTHRD200;VSTHRD101
+
+
..\..\..\x64\Release\SettingsTest\
diff --git a/src/settings-ui/Settings.UI/App.xaml.cs b/src/settings-ui/Settings.UI/App.xaml.cs
index ef58d823bda2..ec57d0cf1e37 100644
--- a/src/settings-ui/Settings.UI/App.xaml.cs
+++ b/src/settings-ui/Settings.UI/App.xaml.cs
@@ -359,6 +359,7 @@ public static Type GetPage(string settingWindow)
case "ImageResizer": return typeof(ImageResizerPage);
case "KBM": return typeof(KeyboardManagerPage);
case "MouseUtils": return typeof(MouseUtilsPage);
+ case "MouseWithoutBorders": return typeof(MouseWithoutBordersPage);
case "PowerRename": return typeof(PowerRenamePage);
case "QuickAccent": return typeof(PowerAccentPage);
case "FileExplorer": return typeof(PowerPreviewPage);
diff --git a/src/settings-ui/Settings.UI/Assets/FluentIcons/FluentIconsMouseWithoutBorders.png b/src/settings-ui/Settings.UI/Assets/FluentIcons/FluentIconsMouseWithoutBorders.png
new file mode 100644
index 000000000000..7e58dc94e4a7
Binary files /dev/null and b/src/settings-ui/Settings.UI/Assets/FluentIcons/FluentIconsMouseWithoutBorders.png differ
diff --git a/src/settings-ui/Settings.UI/Assets/Modules/MouseWithoutBorders.png b/src/settings-ui/Settings.UI/Assets/Modules/MouseWithoutBorders.png
new file mode 100644
index 000000000000..4261e4e16b10
Binary files /dev/null and b/src/settings-ui/Settings.UI/Assets/Modules/MouseWithoutBorders.png differ
diff --git a/src/settings-ui/Settings.UI/Assets/Modules/OOBE/MouseWithoutBorders.png b/src/settings-ui/Settings.UI/Assets/Modules/OOBE/MouseWithoutBorders.png
new file mode 100644
index 000000000000..578f55152ecf
Binary files /dev/null and b/src/settings-ui/Settings.UI/Assets/Modules/OOBE/MouseWithoutBorders.png differ
diff --git a/src/settings-ui/Settings.UI/Converters/NegativeBoolToVisibilityConverter.cs b/src/settings-ui/Settings.UI/Converters/NegativeBoolToVisibilityConverter.cs
new file mode 100644
index 000000000000..580c2507db0c
--- /dev/null
+++ b/src/settings-ui/Settings.UI/Converters/NegativeBoolToVisibilityConverter.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Globalization;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Data;
+
+namespace Microsoft.PowerToys.Settings.UI.Converters
+{
+ public class NegativeBoolToVisibilityConverter : IValueConverter
+ {
+ object IValueConverter.Convert(object value, Type targetType, object parameter, string language)
+ {
+ if ((bool)value)
+ {
+ return Visibility.Collapsed;
+ }
+
+ return Visibility.Visible;
+ }
+
+ object IValueConverter.ConvertBack(object value, Type targetType, object parameter, string language)
+ {
+ throw new NotImplementedException();
+ }
+ }
+}
diff --git a/src/settings-ui/Settings.UI/Helpers/AsyncCommand.cs b/src/settings-ui/Settings.UI/Helpers/AsyncCommand.cs
new file mode 100644
index 000000000000..4c9be4706084
--- /dev/null
+++ b/src/settings-ui/Settings.UI/Helpers/AsyncCommand.cs
@@ -0,0 +1,42 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+namespace Microsoft.PowerToys.Settings.UI.Helpers
+{
+ internal sealed class AsyncCommand : ICommand
+ {
+ private readonly Func _execute;
+ private readonly Func _canExecute;
+
+ public event EventHandler CanExecuteChanged;
+
+ public AsyncCommand(Func execute, Func canExecute = null)
+ {
+ _execute = execute;
+ _canExecute = canExecute;
+ }
+
+ public bool CanExecute(object parameter)
+ {
+ return _canExecute == null || _canExecute();
+ }
+
+ public async void Execute(object parameter)
+ {
+ await _execute();
+ }
+
+ public void RaiseCanExecuteChanged()
+ {
+ CanExecuteChanged?.Invoke(this, EventArgs.Empty);
+ }
+ }
+}
diff --git a/src/settings-ui/Settings.UI/Helpers/IndexedObservableCollection.cs b/src/settings-ui/Settings.UI/Helpers/IndexedObservableCollection.cs
new file mode 100644
index 000000000000..c0cdebcdc7c1
--- /dev/null
+++ b/src/settings-ui/Settings.UI/Helpers/IndexedObservableCollection.cs
@@ -0,0 +1,58 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Microsoft.PowerToys.Settings.UI.Helpers
+{
+#pragma warning disable SA1649 // File name should match first type name
+ public class IndexedItem
+#pragma warning restore SA1649 // File name should match first type name
+ {
+ public T Item { get; set; }
+
+ public int Index { get; set; }
+
+ public IndexedItem(T item, int index)
+ {
+ Item = item;
+ Index = index;
+ }
+ }
+
+#pragma warning disable SA1402 // File may only contain a single type
+ public class IndexedObservableCollection : ObservableCollection>
+#pragma warning restore SA1402 // File may only contain a single type
+ {
+ public IndexedObservableCollection(IEnumerable items)
+ {
+ int index = 0;
+ foreach (var item in items)
+ {
+ Add(new IndexedItem(item, index++));
+ }
+ }
+
+ public IEnumerable ToEnumerable()
+ {
+ return this.Select(x => x.Item);
+ }
+
+ public void Swap(int index1, int index2)
+ {
+ var temp = this[index1];
+ this[index1] = this[index2];
+ this[index2] = temp;
+
+ // Update the original index of the items
+ this[index1].Index = index1;
+ this[index2].Index = index2;
+ }
+ }
+}
diff --git a/src/settings-ui/Settings.UI/Helpers/Observable.cs b/src/settings-ui/Settings.UI/Helpers/Observable.cs
deleted file mode 100644
index 19c92553702b..000000000000
--- a/src/settings-ui/Settings.UI/Helpers/Observable.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) Microsoft Corporation
-// The Microsoft Corporation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.ComponentModel;
-using System.Runtime.CompilerServices;
-
-namespace Microsoft.PowerToys.Settings.UI.Helpers
-{
- public class Observable : INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler PropertyChanged;
-
- protected void Set(ref T storage, T value, [CallerMemberName] string propertyName = null)
- {
- if (Equals(storage, value))
- {
- return;
- }
-
- storage = value;
- OnPropertyChanged(propertyName);
- }
-
- protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
-}
diff --git a/src/settings-ui/Settings.UI/MainWindow.xaml.cs b/src/settings-ui/Settings.UI/MainWindow.xaml.cs
index c98f85baf211..896f95ed847e 100644
--- a/src/settings-ui/Settings.UI/MainWindow.xaml.cs
+++ b/src/settings-ui/Settings.UI/MainWindow.xaml.cs
@@ -125,6 +125,9 @@ public MainWindow(bool isDark, bool createHidden = false)
case "MousePointerCrosshairs":
needToUpdate = generalSettingsConfig.Enabled.MousePointerCrosshairs != isEnabled;
generalSettingsConfig.Enabled.MousePointerCrosshairs = isEnabled; break;
+ case "MouseWithoutBorders":
+ needToUpdate = generalSettingsConfig.Enabled.MouseWithoutBorders != isEnabled;
+ generalSettingsConfig.Enabled.MouseWithoutBorders = isEnabled; break;
case "PastePlain":
needToUpdate = generalSettingsConfig.Enabled.PastePlain != isEnabled;
generalSettingsConfig.Enabled.PastePlain = isEnabled; break;
diff --git a/src/settings-ui/Settings.UI/OOBE/Enums/PowerToysModules.cs b/src/settings-ui/Settings.UI/OOBE/Enums/PowerToysModules.cs
index d21d0a886468..669ee0a5e5ba 100644
--- a/src/settings-ui/Settings.UI/OOBE/Enums/PowerToysModules.cs
+++ b/src/settings-ui/Settings.UI/OOBE/Enums/PowerToysModules.cs
@@ -16,6 +16,7 @@ public enum PowerToysModules
ImageResizer,
KBM,
MouseUtils,
+ MouseWithoutBorders,
Peek,
PowerRename,
Run,
diff --git a/src/settings-ui/Settings.UI/OOBE/Views/OobeMouseWithoutBorders.xaml b/src/settings-ui/Settings.UI/OOBE/Views/OobeMouseWithoutBorders.xaml
new file mode 100644
index 000000000000..be04eae1f278
--- /dev/null
+++ b/src/settings-ui/Settings.UI/OOBE/Views/OobeMouseWithoutBorders.xaml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/settings-ui/Settings.UI/OOBE/Views/OobeMouseWithoutBorders.xaml.cs b/src/settings-ui/Settings.UI/OOBE/Views/OobeMouseWithoutBorders.xaml.cs
new file mode 100644
index 000000000000..243e871cdd60
--- /dev/null
+++ b/src/settings-ui/Settings.UI/OOBE/Views/OobeMouseWithoutBorders.xaml.cs
@@ -0,0 +1,47 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.PowerToys.Settings.UI.OOBE.Enums;
+using Microsoft.PowerToys.Settings.UI.OOBE.ViewModel;
+using Microsoft.PowerToys.Settings.UI.Views;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Navigation;
+
+namespace Microsoft.PowerToys.Settings.UI.OOBE.Views
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+ public sealed partial class OobeMouseWithoutBorders : Page
+ {
+ public OobePowerToysModule ViewModel { get; set; }
+
+ public OobeMouseWithoutBorders()
+ {
+ this.InitializeComponent();
+ ViewModel = new OobePowerToysModule(OobeShellPage.OobeShellHandler.Modules[(int)PowerToysModules.MouseWithoutBorders]);
+ DataContext = ViewModel;
+ }
+
+ private void SettingsLaunchButton_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
+ {
+ if (OobeShellPage.OpenMainWindowCallback != null)
+ {
+ OobeShellPage.OpenMainWindowCallback(typeof(MouseWithoutBordersPage));
+ }
+
+ ViewModel.LogOpeningSettingsEvent();
+ }
+
+ protected override void OnNavigatedTo(NavigationEventArgs e)
+ {
+ ViewModel.LogOpeningModuleEvent();
+ }
+
+ protected override void OnNavigatedFrom(NavigationEventArgs e)
+ {
+ ViewModel.LogClosingModuleEvent();
+ }
+ }
+}
diff --git a/src/settings-ui/Settings.UI/OOBE/Views/OobeShellPage.xaml b/src/settings-ui/Settings.UI/OOBE/Views/OobeShellPage.xaml
index 387785051f7a..26dae05314a3 100644
--- a/src/settings-ui/Settings.UI/OOBE/Views/OobeShellPage.xaml
+++ b/src/settings-ui/Settings.UI/OOBE/Views/OobeShellPage.xaml
@@ -68,6 +68,10 @@
x:Uid="Shell_MouseUtilities"
Icon="{ui:BitmapIcon Source=/Assets/FluentIcons/FluentIconsMouseUtils.png}"
Tag="MouseUtils" />
+
+
+
+
+ VSTHRD002;VSTHRD110;VSTHRD100;VSTHRD200;VSTHRD101
+
+
MSBuild:Compile
diff --git a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
index cd108c873822..06e9d7b853ec 100644
--- a/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
+++ b/src/settings-ui/Settings.UI/Strings/en-us/Resources.resw
@@ -216,6 +216,275 @@
Enable Screen Ruler
"Screen Ruler" is the name of the utility
+
+ Activation
+
+
+ Device layout
+
+
+ Drag and drop a machine to rearrange the order.
+
+
+ It is not possible to use drag and drop while running PowerToys elevated. As a workaround, please restart PowerToys without elevation to edit the device layout.
+
+
+ Encryption Key
+
+
+ Security key
+
+
+ The key must be auto generated in one machine by click on New Key, then typed in other machines
+
+
+ New key
+
+
+ Copy this PC name to the clipboard
+
+
+ Refresh connections
+
+
+ Reestablishes connections with other devices if you are experiencing issues.
+
+
+ The local machine's host name is:
+
+
+ Connect
+
+
+ Uninstall service
+
+
+ Removes the service from the computer. Needs to run as administrator.
+
+
+ Behavior
+
+
+ Troubleshooting
+
+
+ Add a firewall rule for Mouse Without Borders
+ "Mouse Without Borders" is a product name
+
+
+ Adding a firewall rule might help solve connection issues.
+
+
+ You need to run as administrator to modify this setting.
+
+
+ If PowerToys is installed as a user, uninstalling/upgrading may require the Mouse Without Borders service to be removed manually later.
+
+
+ Service
+
+
+ Enable Mouse Without Borders
+
+
+ Attribution
+ giving credit to the projects this utility was based on
+
+
+ Mouse Without Borders is a quick and easy way to move your cursor across multiple devices.
+ "Mouse Without Borders" is the name of the utility
+
+
+ Mouse Without Borders
+ "Mouse Without Borders" is the name of the utility
+
+
+ Use Service
+
+
+ Runs in service mode, that allows MWB to control remote machines when they're locked. Also allows control of system and administrator applications.
+
+
+ Devices in a single row
+
+
+ Sets whether the devices should are aligned on a single row. A two by two matrix is considered otherwise.
+
+
+ Wrap mouse
+
+
+ Move control back to the first machine when mouse moves past the last one.
+
+
+ Share clipboard
+
+
+ Transfer file
+
+
+ Hide mouse at the screen edge
+
+
+ Draw mouse cursor
+
+
+ Validate remote machine IP
+
+
+ Same subnet only
+
+
+ Block screen saver on other machines
+
+
+ Move mouse relatively
+
+
+ Block mouse at screen corners
+
+
+ Show clipboard and network status messages
+
+
+ Show the original Mouse Without Borders UI
+
+
+ This is accessible from the system tray and requires a restart.
+
+
+ If share clipboard stops working, Ctrl+Alt+Del then Esc may solve the problem.
+
+
+ If a file (<100MB) is copied, it will be transferred to the remote machine clipboard.
+
+
+ Hide the mouse cursor at the top edge of the screen when switching to other machine. This option also steals the focus from any full-screen app to ensure the keyboard input is redirected.
+
+
+ Mouse cursor may not be visible in Windows 10 and later versions of Windows when there is no physical mouse attached.
+
+
+ Reverse DNS lookup to validate machine IP Address.
+
+
+ Only connect to machines in the same intranet NNN.NNN.*.* (only works when both machines have IPv4 enabled)
+
+
+ Prevent screen saver from starting on other machines when user is actively working on this machine.
+
+
+ Use this option when remote machine's monitor settings are different, or remote machine has multiple monitors.
+
+
+ To avoid accident machine-switch at screen corners.
+
+
+ Show clipboard activities and network status in system tray notifications
+
+
+ Keyboard Shortcuts
+ keyboard is the hardware peripheral
+
+
+ Easy Mouse: Move between machines by moving the mouse pointer to the screen edges.
+
+
+ Can also be set to move only when pressing Shift or Ctrl.
+ Shift and Ctrl are the keyboard keys
+
+
+ Disabled
+
+
+ Enabled
+
+
+ Ctrl
+ This is the Ctrl keyboard key
+
+
+ Shift
+ This is the Shift keyboard key
+
+
+ Shortcut to toggle Easy Mouse. Ctrl+Alt+:
+ Ctrl and Alt are the keyboard keys
+
+
+ Only works if EasyMouse is set to Enabled or Disabled.
+
+
+ Disabled
+
+
+ Shortcut to switch between machines. Ctrl+Alt+:
+ Ctrl and Alt are the keyboard keys
+
+
+ Click on Ctrl+Alt+ the chosen option to switch between machines.
+ Ctrl and Alt are the keyboard keys
+
+
+ F1, F2, F3, F4
+ Don't localize. These are keyboard keys
+
+
+ 1, 2, 3, 4
+ Don't localize. These are keyboard keys
+
+
+ Disabled
+
+
+ Shortcut to press twice quickly to lock all machines. Ctrl+Alt+:
+ Ctrl and Alt are the keyboard keys
+
+
+ Click on Ctrl+Alt+ the chosen option twice quickly to lock all machines. Note: Only the machines which have the same shortcut configured will be locked.
+ Ctrl and Alt are the keyboard keys
+
+
+ Disabled
+
+
+ Shortcut to try reconnecting. Ctrl+Alt+:
+ Ctrl and Alt are the keyboard keys
+
+
+ Click on Ctrl+Alt+ the chosen option to reconnect.
+ Ctrl and Alt are the keyboard keys
+
+
+ Disabled
+
+
+ Shortcut to switch to multiple machine mode. Ctrl+Alt+:
+ Ctrl and Alt are the keyboard keys
+
+
+ Allows controlling all computers at once. Pressing Ctrl three times is also an option.
+ This is the Ctrl keyboard key
+
+
+ Disabled
+
+
+ Ctrl three times
+ This is the Ctrl keyboard key
+
Enable Video Conference Mute
@@ -364,6 +633,10 @@
Keyboard Manager
Product name: Navigation view item name for Keyboard Manager
+
+ Mouse Without Borders
+ Product name: Navigation view item name for Mouse Without Borders
+
Mouse utilities
Product name: Navigation view item name for Mouse utilities
@@ -1674,6 +1947,9 @@ Made with 💗 by Microsoft and the PowerToys community.
Keyboard Manager allows you to customize the keyboard to be more productive by remapping keys and creating your own keyboard shortcuts.
+
+ Mouse Without Borders enables using the mouse pointer, keyboard, clipboard and drag and drop between machines in the same local network.
+
PowerRename enables you to perform simple bulk renaming, searching and replacing file names.
@@ -1753,6 +2029,12 @@ From there, simply click on one of the supported files in the File Explorer and
Want to only have a shortcut work for a single application? Use the Target App field when creating the shortcut remapping.
+
+ Use the Settings screen on each machine to connect to the other machines using the same key. If a connection is not working, it may be necessary to add an exception to the Windows Firewall.
+
+
+ Use the service option in Settings to install a service enabling Mouse Without Borders to function even in the lock screen.
+
In File Explorer, right-click one or more selected files and select **PowerRename** from the context menu.
@@ -1812,6 +2094,10 @@ From there, simply click on one of the supported files in the File Explorer and
Keyboard Manager
Do not localize this string
+
+ Mouse Without Borders
+ Product name. Do not localize this string
+
PowerRename
Do not localize this string
diff --git a/src/settings-ui/Settings.UI/ViewModels/Flyout/AllAppsViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/Flyout/AllAppsViewModel.cs
index 80c12b1c3cc8..6fb1f95f6ef0 100644
--- a/src/settings-ui/Settings.UI/ViewModels/Flyout/AllAppsViewModel.cs
+++ b/src/settings-ui/Settings.UI/ViewModels/Flyout/AllAppsViewModel.cs
@@ -93,6 +93,11 @@ public AllAppsViewModel(ISettingsRepository settingsRepository,
FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("MouseUtils_MousePointerCrosshairs/Header"), IsEnabled = generalSettingsConfig.Enabled.MousePointerCrosshairs, Tag = "MousePointerCrosshairs", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsMouseCrosshairs.png", EnabledChangedCallback = EnabledChangedOnUI });
}
+ if ((gpo = GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled)
+ {
+ FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("MouseWithoutBorders/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.MouseWithoutBorders, Tag = "MouseWithoutBorders", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsMouseWithoutBorders.png", EnabledChangedCallback = EnabledChangedOnUI });
+ }
+
if ((gpo = GPOWrapper.GetConfiguredPastePlainEnabledValue()) != GpoRuleConfigured.Disabled && gpo != GpoRuleConfigured.Enabled)
{
FlyoutMenuItems.Add(new FlyoutMenuItem() { Label = resourceLoader.GetString("PastePlain/ModuleTitle"), IsEnabled = generalSettingsConfig.Enabled.PastePlain, Tag = "PastePlain", Icon = "ms-appx:///Assets/FluentIcons/FluentIconsPastePlain.png", EnabledChangedCallback = EnabledChangedOnUI });
@@ -170,6 +175,7 @@ private void ModuleEnabledChangedOnSettingsPage()
case "MouseHighlighter": item.IsEnabled = generalSettingsConfig.Enabled.MouseHighlighter; break;
case "MouseJump": item.IsEnabled = generalSettingsConfig.Enabled.MouseJump; break;
case "MousePointerCrosshairs": item.IsEnabled = generalSettingsConfig.Enabled.MousePointerCrosshairs; break;
+ case "MouseWithoutBorders": item.IsEnabled = generalSettingsConfig.Enabled.MouseWithoutBorders; break;
case "PastePlain": item.IsEnabled = generalSettingsConfig.Enabled.PastePlain; break;
case "Peek": item.IsEnabled = generalSettingsConfig.Enabled.Peek; break;
case "PowerRename": item.IsEnabled = generalSettingsConfig.Enabled.PowerRename; break;
diff --git a/src/settings-ui/Settings.UI/ViewModels/MouseWithoutBordersViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/MouseWithoutBordersViewModel.cs
new file mode 100644
index 000000000000..157115758fb0
--- /dev/null
+++ b/src/settings-ui/Settings.UI/ViewModels/MouseWithoutBordersViewModel.cs
@@ -0,0 +1,1108 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.IO.Pipes;
+using System.Linq;
+using System.Net;
+using System.Runtime.CompilerServices;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using global::PowerToys.GPOWrapper;
+using ManagedCommon;
+using Microsoft.PowerToys.Settings.UI.Helpers;
+using Microsoft.PowerToys.Settings.UI.Library;
+using Microsoft.PowerToys.Settings.UI.Library.Helpers;
+using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
+using Microsoft.PowerToys.Settings.UI.Library.ViewModels.Commands;
+using Microsoft.UI;
+using Microsoft.UI.Dispatching;
+using Microsoft.UI.Xaml.Media;
+using StreamJsonRpc;
+using Windows.ApplicationModel.DataTransfer;
+
+namespace Microsoft.PowerToys.Settings.UI.ViewModels
+{
+ public class MouseWithoutBordersViewModel : Observable, IDisposable
+ {
+ // These should be in the same order as the ComboBoxItems in MouseWithoutBordersPage.xaml switch machine shortcut options
+ private readonly int[] _switchBetweenMachineShortcutOptions =
+ {
+ 112,
+ 49,
+ 0,
+ };
+
+ private readonly object _machineMatrixStringLock = new();
+
+ private static readonly Dictionary StatusColors = new Dictionary()
+{
+ { SocketStatus.NA, new SolidColorBrush(ColorHelper.FromArgb(0x71, 0x71, 0x71, 0x71)) },
+ { SocketStatus.Resolving, new SolidColorBrush(Colors.Yellow) },
+ { SocketStatus.Connecting, new SolidColorBrush(Colors.Orange) },
+ { SocketStatus.Handshaking, new SolidColorBrush(Colors.Blue) },
+ { SocketStatus.Error, new SolidColorBrush(Colors.Red) },
+ { SocketStatus.ForceClosed, new SolidColorBrush(Colors.Purple) },
+ { SocketStatus.InvalidKey, new SolidColorBrush(Colors.Brown) },
+ { SocketStatus.Timeout, new SolidColorBrush(Colors.Pink) },
+ { SocketStatus.SendError, new SolidColorBrush(Colors.Maroon) },
+ { SocketStatus.Connected, new SolidColorBrush(Colors.Green) },
+};
+
+ private bool _connectFieldsVisible;
+
+ public bool IsElevated { get => GeneralSettingsConfig.IsElevated; }
+
+ public bool CanUninstallService { get => GeneralSettingsConfig.IsElevated && !UseService; }
+
+ public ButtonClickCommand AddFirewallRuleEventHandler => new ButtonClickCommand(AddFirewallRule);
+
+ public ButtonClickCommand UninstallServiceEventHandler => new ButtonClickCommand(UninstallService);
+
+ public bool ShowOriginalUI
+ {
+ get => Settings.Properties.ShowOriginalUI;
+
+ set
+ {
+ if (Settings.Properties.ShowOriginalUI != value)
+ {
+ Settings.Properties.ShowOriginalUI = value;
+ NotifyPropertyChanged(nameof(ShowOriginalUI));
+ }
+ }
+ }
+
+ public bool UseService
+ {
+ get => Settings.Properties.UseService;
+
+ set
+ {
+ var valueChanged = Settings.Properties.UseService != value;
+
+ // Set the UI property itself instantly
+ if (valueChanged)
+ {
+ Settings.Properties.UseService = value;
+ OnPropertyChanged(nameof(UseService));
+
+ // Must block here until the process exits
+ Task.Run(async () =>
+ {
+ await SubmitShutdownRequestAsync();
+
+ _uiDispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
+ {
+ Settings.Properties.UseService = value;
+ NotifyPropertyChanged(nameof(UseService));
+ });
+ });
+ }
+ }
+ }
+
+ public bool ConnectFieldsVisible
+ {
+ get => _connectFieldsVisible;
+
+ set
+ {
+ if (_connectFieldsVisible != value)
+ {
+ _connectFieldsVisible = value;
+ OnPropertyChanged(nameof(ConnectFieldsVisible));
+ }
+ }
+ }
+
+ private string _connectSecurityKey;
+
+ public string ConnectSecurityKey
+ {
+ get => _connectSecurityKey;
+
+ set
+ {
+ if (_connectSecurityKey != value)
+ {
+ _connectSecurityKey = value;
+ OnPropertyChanged(nameof(ConnectSecurityKey));
+ }
+ }
+ }
+
+ private string _connectPCName;
+
+ public string ConnectPCName
+ {
+ get => _connectPCName;
+
+ set
+ {
+ if (_connectPCName != value)
+ {
+ _connectPCName = value;
+ OnPropertyChanged(nameof(ConnectPCName));
+ }
+ }
+ }
+
+ private ISettingsUtils SettingsUtils { get; set; }
+
+ private GeneralSettings GeneralSettingsConfig { get; set; }
+
+ private GpoRuleConfigured _enabledGpoRuleConfiguration;
+ private bool _enabledStateIsGPOConfigured;
+ private bool _isEnabled;
+
+ public string MachineHostName
+ {
+ get
+ {
+ try
+ {
+ return Dns.GetHostName();
+ }
+ catch
+ {
+ return string.Empty;
+ }
+ }
+ }
+
+ public bool IsEnabledGpoConfigured
+ {
+ get => _enabledStateIsGPOConfigured;
+ }
+
+ private enum SocketStatus : int
+ {
+ NA = 0,
+ Resolving = 1,
+ Connecting = 2,
+ Handshaking = 3,
+ Error = 4,
+ ForceClosed = 5,
+ InvalidKey = 6,
+ Timeout = 7,
+ SendError = 8,
+ Connected = 9,
+ }
+
+ private interface ISettingsSyncHelper
+ {
+ [Newtonsoft.Json.JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)]
+ public struct MachineSocketState
+ {
+ // Disable false-positive warning due to IPC
+#pragma warning disable CS0649
+ [Newtonsoft.Json.JsonProperty]
+ public string Name;
+
+ [Newtonsoft.Json.JsonProperty]
+ public SocketStatus Status;
+#pragma warning restore CS0649
+ }
+
+ void Shutdown();
+
+ void Reconnect();
+
+ void GenerateNewKey();
+
+ void ConnectToMachine(string machineName, string securityKey);
+
+ Task RequestMachineSocketStateAsync();
+ }
+
+ private static CancellationTokenSource _cancellationTokenSource;
+
+ private static Task _machinePollingThreadTask;
+
+ private static VisualStudio.Threading.AsyncSemaphore _ipcSemaphore = new VisualStudio.Threading.AsyncSemaphore(1);
+
+ private sealed class SyncHelper : IDisposable
+ {
+ public SyncHelper(NamedPipeClientStream stream)
+ {
+ Stream = stream;
+ Endpoint = JsonRpc.Attach(Stream);
+ }
+
+ public NamedPipeClientStream Stream { get; }
+
+ public ISettingsSyncHelper Endpoint { get; private set; }
+
+ public void Dispose()
+ {
+ ((IDisposable)Endpoint).Dispose();
+ }
+ }
+
+ private static NamedPipeClientStream syncHelperStream;
+
+ private async Task GetSettingsSyncHelperAsync()
+ {
+ try
+ {
+ var recreateStream = false;
+ if (syncHelperStream == null)
+ {
+ recreateStream = true;
+ }
+ else
+ {
+ if (!syncHelperStream.IsConnected || !syncHelperStream.CanWrite)
+ {
+ await syncHelperStream.DisposeAsync();
+ recreateStream = true;
+ }
+ }
+
+ if (recreateStream)
+ {
+ syncHelperStream = new NamedPipeClientStream(".", "MouseWithoutBorders/SettingsSync", PipeDirection.InOut, PipeOptions.Asynchronous);
+ await syncHelperStream.ConnectAsync(10000);
+ }
+
+ return new SyncHelper(syncHelperStream);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError($"Couldn't create SettingsSync: {ex}");
+ return null;
+ }
+ }
+
+ public async Task SubmitShutdownRequestAsync()
+ {
+ using (await _ipcSemaphore.EnterAsync())
+ {
+ using (var syncHelper = await GetSettingsSyncHelperAsync())
+ {
+ syncHelper?.Endpoint?.Shutdown();
+ var task = syncHelper?.Stream.FlushAsync();
+ if (task != null)
+ {
+ await task;
+ }
+ }
+ }
+ }
+
+ public async Task SubmitReconnectRequestAsync()
+ {
+ using (await _ipcSemaphore.EnterAsync())
+ {
+ using (var syncHelper = await GetSettingsSyncHelperAsync())
+ {
+ syncHelper?.Endpoint?.Reconnect();
+ var task = syncHelper?.Stream.FlushAsync();
+ if (task != null)
+ {
+ await task;
+ }
+ }
+ }
+ }
+
+ public async Task SubmitNewKeyRequestAsync()
+ {
+ using (await _ipcSemaphore.EnterAsync())
+ {
+ using (var syncHelper = await GetSettingsSyncHelperAsync())
+ {
+ syncHelper?.Endpoint?.GenerateNewKey();
+ var task = syncHelper?.Stream.FlushAsync();
+ if (task != null)
+ {
+ await task;
+ }
+ }
+ }
+ }
+
+ public async Task SubmitConnectionRequestAsync(string pcName, string securityKey)
+ {
+ using (await _ipcSemaphore.EnterAsync())
+ {
+ using (var syncHelper = await GetSettingsSyncHelperAsync())
+ {
+ syncHelper?.Endpoint?.ConnectToMachine(pcName, securityKey);
+ var task = syncHelper?.Stream.FlushAsync();
+ if (task != null)
+ {
+ await task;
+ }
+ }
+ }
+ }
+
+ private async Task PollMachineSocketStateAsync()
+ {
+ using (await _ipcSemaphore.EnterAsync())
+ {
+ using (var syncHelper = await GetSettingsSyncHelperAsync())
+ {
+ var task = syncHelper?.Endpoint?.RequestMachineSocketStateAsync();
+ if (task != null)
+ {
+ return await task;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+ }
+
+ private MouseWithoutBordersSettings Settings { get; set; }
+
+ private DispatcherQueue _uiDispatcherQueue;
+
+ public MouseWithoutBordersViewModel(ISettingsUtils settingsUtils, ISettingsRepository settingsRepository, Func ipcMSGCallBackFunc, DispatcherQueue uiDispatcherQueue)
+ {
+ SettingsUtils = settingsUtils;
+
+ _uiDispatcherQueue = uiDispatcherQueue;
+
+ // To obtain the general settings configurations of PowerToys Settings.
+ if (settingsRepository == null)
+ {
+ throw new ArgumentNullException(nameof(settingsRepository));
+ }
+
+ GeneralSettingsConfig = settingsRepository.SettingsConfig;
+
+ InitializeEnabledValue();
+
+ // MouseWithoutBorders settings may be changed by the logic in the utility as machines connect. We need to get a fresh version everytime instead of using a repository.
+ MouseWithoutBordersSettings moduleSettings;
+ moduleSettings = SettingsUtils.GetSettingsOrDefault("MouseWithoutBorders");
+
+ LoadViewModelFromSettings(moduleSettings);
+
+ // set the callback functions value to handle outgoing IPC message.
+ SendConfigMSG = ipcMSGCallBackFunc;
+
+ _cancellationTokenSource?.Cancel();
+
+ _cancellationTokenSource = new CancellationTokenSource();
+
+ _machinePollingThreadTask = StartMachineStatusPollingThread(_machinePollingThreadTask, _cancellationTokenSource.Token);
+ }
+
+ private Task StartMachineStatusPollingThread(Task previousThreadTask, CancellationToken token)
+ {
+ return Task.Run(
+ async () =>
+ {
+ previousThreadTask?.Wait();
+
+ while (!token.IsCancellationRequested)
+ {
+ Dictionary states = null;
+ try
+ {
+ states = (await PollMachineSocketStateAsync())?.ToDictionary(s => s.Name, StringComparer.OrdinalIgnoreCase);
+ }
+ catch (Exception ex)
+ {
+ Logger.LogInfo($"Poll ISettingsSyncHelper.MachineSocketState error: {ex}");
+ continue;
+ }
+
+ if (states != null)
+ {
+ lock (_machineMatrixStringLock)
+ {
+ foreach (var machine in machineMatrixString)
+ {
+ if (states.TryGetValue(machine.Item.Name, out var state))
+ {
+ _uiDispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
+ {
+ try
+ {
+ machine.Item.StatusBrush = StatusColors[state.Status];
+ }
+ catch (Exception)
+ {
+ }
+ });
+ }
+ }
+ }
+ }
+
+ Thread.Sleep(500);
+ }
+ },
+ _cancellationTokenSource.Token);
+ }
+
+ private void InitializeEnabledValue()
+ {
+ _enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredMouseWithoutBordersEnabledValue();
+ if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
+ {
+ // Get the enabled state from GPO.
+ _enabledStateIsGPOConfigured = true;
+ _isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
+ }
+ else
+ {
+ _isEnabled = GeneralSettingsConfig.Enabled.MouseWithoutBorders;
+ }
+ }
+
+ private void LoadViewModelFromSettings(MouseWithoutBordersSettings moduleSettings)
+ {
+ if (moduleSettings == null)
+ {
+ throw new ArgumentNullException(nameof(moduleSettings));
+ }
+
+ Settings = moduleSettings;
+ /* TODO: Error handling */
+ _selectedSwitchBetweenMachineShortcutOptionsIndex = Array.IndexOf(_switchBetweenMachineShortcutOptions, moduleSettings.Properties.HotKeySwitchMachine.Value);
+ _easyMouseOptionIndex = (EasyMouseOption)moduleSettings.Properties.EasyMouse.Value;
+ _toggleEasyMouseShortcutIndex = ConvertMouseWithoutBordersHotKeyValueToIndex(moduleSettings.Properties.HotKeyToggleEasyMouse.Value);
+ _lockMachinesShortcutIndex = ConvertMouseWithoutBordersHotKeyValueToIndex(moduleSettings.Properties.HotKeyLockMachine.Value);
+ _reconnectShortcutIndex = ConvertMouseWithoutBordersHotKeyValueToIndex(moduleSettings.Properties.HotKeyReconnect.Value);
+ _switch2AllPcShortcutIndex = ConvertMouseWithoutBordersHotKeyValueToIndex(moduleSettings.Properties.HotKeySwitch2AllPC.Value, 1);
+ LoadMachineMatrixString();
+ }
+
+ // Loads the machine matrix, taking into account changes to the machine pool.
+ private void LoadMachineMatrixString()
+ {
+ List loadMachineMatrixString = Settings.Properties.MachineMatrixString ?? new List() { string.Empty, string.Empty, string.Empty, string.Empty };
+
+ if (loadMachineMatrixString.Count < 4)
+ {
+ // Current logic of MWB assumes there are always 4 slots. Any other configuration means data corruption here.
+ loadMachineMatrixString = new List() { string.Empty, string.Empty, string.Empty, string.Empty };
+ }
+
+ bool editedTheMatrix = false; // keep track of changes to the matrix because of changes to the available machine pool.
+
+ if (!string.IsNullOrEmpty(Settings.Properties.MachinePool?.Value))
+ {
+ List availableMachines = new List();
+
+ // Format of this field is "NAME1:ID1,NAME2:ID2,..."
+ // Load the available machines
+ foreach (string availableMachineIdPair in Settings.Properties.MachinePool.Value.Split(","))
+ {
+ string availableMachineName = availableMachineIdPair.Split(':')[0];
+ availableMachines.Add(availableMachineName);
+ }
+
+ // Start by removing the machines from the matrix that are no longer available to pick.
+ for (int i = 0; i < loadMachineMatrixString.Count; i++)
+ {
+ if (!availableMachines.Contains(loadMachineMatrixString[i]))
+ {
+ editedTheMatrix = true;
+ loadMachineMatrixString[i] = string.Empty;
+ }
+ }
+
+ // If an available machine is not in the matrix already, fill it in the first available spot.
+ foreach (string availableMachineName in availableMachines)
+ {
+ if (!loadMachineMatrixString.Contains(availableMachineName))
+ {
+ int availableIndex = loadMachineMatrixString.FindIndex(name => string.IsNullOrEmpty(name));
+ if (availableIndex >= 0)
+ {
+ loadMachineMatrixString[availableIndex] = availableMachineName;
+ editedTheMatrix = true;
+ }
+ }
+ }
+ }
+
+ // Dragging while elevated crashes on WinUI3: https://github.com/microsoft/microsoft-ui-xaml/issues/7690
+ machineMatrixString = new IndexedObservableCollection(loadMachineMatrixString.Select(name => new DeviceViewModel { Name = name, CanDragDrop = !IsElevated }));
+
+ if (editedTheMatrix)
+ {
+ // Set the property directly to save the new matrix right away with the new available machines.
+ MachineMatrixString = machineMatrixString;
+ }
+ }
+
+ public bool CanBeEnabled
+ {
+ get => !_enabledStateIsGPOConfigured;
+ }
+
+ public bool CanToggleUseService
+ {
+ get
+ {
+ return IsEnabled && !(!IsElevated && !UseService);
+ }
+ }
+
+ public bool IsEnabled
+ {
+ get => _isEnabled;
+ set
+ {
+ if (_enabledStateIsGPOConfigured)
+ {
+ // If it's GPO configured, shouldn't be able to change this state.
+ return;
+ }
+
+ if (_isEnabled != value)
+ {
+ _isEnabled = value;
+ GeneralSettingsConfig.Enabled.MouseWithoutBorders = value;
+ OnPropertyChanged(nameof(IsEnabled));
+
+ Task.Run(async () =>
+ {
+ if (!value)
+ {
+ try
+ {
+ await SubmitShutdownRequestAsync();
+ }
+ catch (Exception ex)
+ {
+ Logger.LogError($"Failed to shutdown MWB via SettingsSync: {ex}");
+ }
+ }
+
+ _uiDispatcherQueue.TryEnqueue(DispatcherQueuePriority.Normal, () =>
+ {
+ OutGoingGeneralSettings outgoing = new OutGoingGeneralSettings(GeneralSettingsConfig);
+ SendConfigMSG(outgoing.ToString());
+
+ NotifyPropertyChanged();
+
+ // Disable service mode if we're not elevated, because we cannot register service in that case
+ if (value == true && !IsElevated && UseService)
+ {
+ UseService = false;
+ }
+ });
+ });
+ }
+ }
+ }
+
+ public string SecurityKey
+ {
+ get => Settings.Properties.SecurityKey.Value;
+
+ set
+ {
+ if (value != Settings.Properties.SecurityKey.Value)
+ {
+ Settings.Properties.SecurityKey.Value = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool WrapMouse
+ {
+ get
+ {
+ return Settings.Properties.WrapMouse;
+ }
+
+ set
+ {
+ if (Settings.Properties.WrapMouse != value)
+ {
+ Settings.Properties.WrapMouse = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool MatrixOneRow
+ {
+ get
+ {
+ return Settings.Properties.MatrixOneRow;
+ }
+
+ set
+ {
+ if (Settings.Properties.MatrixOneRow != value)
+ {
+ Settings.Properties.MatrixOneRow = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool ShareClipboard
+ {
+ get
+ {
+ return Settings.Properties.ShareClipboard;
+ }
+
+ set
+ {
+ if (Settings.Properties.ShareClipboard != value)
+ {
+ Settings.Properties.ShareClipboard = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool TransferFile
+ {
+ get
+ {
+ return Settings.Properties.TransferFile;
+ }
+
+ set
+ {
+ if (Settings.Properties.TransferFile != value)
+ {
+ Settings.Properties.TransferFile = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool HideMouseAtScreenEdge
+ {
+ get
+ {
+ return Settings.Properties.HideMouseAtScreenEdge;
+ }
+
+ set
+ {
+ if (Settings.Properties.HideMouseAtScreenEdge != value)
+ {
+ Settings.Properties.HideMouseAtScreenEdge = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool DrawMouseCursor
+ {
+ get
+ {
+ return Settings.Properties.DrawMouseCursor;
+ }
+
+ set
+ {
+ if (Settings.Properties.DrawMouseCursor != value)
+ {
+ Settings.Properties.DrawMouseCursor = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool ValidateRemoteMachineIP
+ {
+ get
+ {
+ return Settings.Properties.ValidateRemoteMachineIP;
+ }
+
+ set
+ {
+ if (Settings.Properties.ValidateRemoteMachineIP != value)
+ {
+ Settings.Properties.ValidateRemoteMachineIP = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool SameSubnetOnly
+ {
+ get
+ {
+ return Settings.Properties.SameSubnetOnly;
+ }
+
+ set
+ {
+ if (Settings.Properties.SameSubnetOnly != value)
+ {
+ Settings.Properties.SameSubnetOnly = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool BlockScreenSaverOnOtherMachines
+ {
+ get
+ {
+ return Settings.Properties.BlockScreenSaverOnOtherMachines;
+ }
+
+ set
+ {
+ if (Settings.Properties.BlockScreenSaverOnOtherMachines != value)
+ {
+ Settings.Properties.BlockScreenSaverOnOtherMachines = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ // Should match EasyMouseOption enum from MouseWithoutBorders and the ComboBox in the MouseWithoutBordersView.cs
+ private enum EasyMouseOption
+ {
+ Disable = 0,
+ Enable = 1,
+ Ctrl = 2,
+ Shift = 3,
+ }
+
+ private EasyMouseOption _easyMouseOptionIndex;
+
+ public int EasyMouseOptionIndex
+ {
+ get
+ {
+ return (int)_easyMouseOptionIndex;
+ }
+
+ set
+ {
+ if (value != (int)_easyMouseOptionIndex)
+ {
+ _easyMouseOptionIndex = (EasyMouseOption)value;
+ Settings.Properties.EasyMouse.Value = value;
+ NotifyPropertyChanged(nameof(EasyMouseOptionIndex));
+ }
+ }
+ }
+
+ public int ConvertMouseWithoutBordersHotKeyValueToIndex(int value, int additionalOptions = 0)
+ {
+ if (value >= 0x41 && value <= 0x5A)
+ {
+ return value - 0x40 + additionalOptions; /* VK_A <= value <= VK_Z */
+ }
+
+ if (value <= additionalOptions)
+ {
+ return value;
+ }
+
+ return 0; /* Disabled */
+ }
+
+ public int ConvertMouseWithoutBordersHotKeyIndexToValue(int index, int additionalOptions = 0)
+ {
+ if (index >= additionalOptions + 1 && index <= additionalOptions + 26)
+ {
+ return index + 0x40 - additionalOptions; /* VK_A to VK_Z */
+ }
+
+ if (index <= additionalOptions)
+ {
+ return index;
+ }
+
+ return 0; /* Disabled */
+ }
+
+ private int _toggleEasyMouseShortcutIndex;
+
+ public int ToggleEasyMouseShortcutIndex
+ {
+ get
+ {
+ return _toggleEasyMouseShortcutIndex;
+ }
+
+ set
+ {
+ if (_toggleEasyMouseShortcutIndex != value)
+ {
+ _toggleEasyMouseShortcutIndex = value;
+ Settings.Properties.HotKeyToggleEasyMouse.Value = ConvertMouseWithoutBordersHotKeyIndexToValue(value);
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ private int _lockMachinesShortcutIndex;
+
+ public int LockMachinesShortcutIndex
+ {
+ get
+ {
+ return _lockMachinesShortcutIndex;
+ }
+
+ set
+ {
+ if (_lockMachinesShortcutIndex != value)
+ {
+ _lockMachinesShortcutIndex = value;
+ Settings.Properties.HotKeyLockMachine.Value = ConvertMouseWithoutBordersHotKeyIndexToValue(value);
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ private int _reconnectShortcutIndex;
+
+ public int ReconnectShortcutIndex
+ {
+ get
+ {
+ return _reconnectShortcutIndex;
+ }
+
+ set
+ {
+ if (_reconnectShortcutIndex != value)
+ {
+ _reconnectShortcutIndex = value;
+ Settings.Properties.HotKeyReconnect.Value = ConvertMouseWithoutBordersHotKeyIndexToValue(value);
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ private int _switch2AllPcShortcutIndex;
+
+ public int Switch2AllPcShortcutIndex
+ {
+ get
+ {
+ return _switch2AllPcShortcutIndex;
+ }
+
+ set
+ {
+ if (_switch2AllPcShortcutIndex != value)
+ {
+ _switch2AllPcShortcutIndex = value;
+ Settings.Properties.HotKeySwitch2AllPC.Value = ConvertMouseWithoutBordersHotKeyIndexToValue(value, 1);
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ private int _selectedSwitchBetweenMachineShortcutOptionsIndex;
+
+ public int SelectedSwitchBetweenMachineShortcutOptionsIndex
+ {
+ get
+ {
+ return _selectedSwitchBetweenMachineShortcutOptionsIndex;
+ }
+
+ set
+ {
+ if (_selectedSwitchBetweenMachineShortcutOptionsIndex != value)
+ {
+ _selectedSwitchBetweenMachineShortcutOptionsIndex = value;
+ Settings.Properties.HotKeySwitchMachine.Value = _switchBetweenMachineShortcutOptions[value];
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool MoveMouseRelatively
+ {
+ get
+ {
+ return Settings.Properties.MoveMouseRelatively;
+ }
+
+ set
+ {
+ if (Settings.Properties.MoveMouseRelatively != value)
+ {
+ Settings.Properties.MoveMouseRelatively = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool BlockMouseAtScreenCorners
+ {
+ get
+ {
+ return Settings.Properties.BlockMouseAtScreenCorners;
+ }
+
+ set
+ {
+ if (Settings.Properties.BlockMouseAtScreenCorners != value)
+ {
+ Settings.Properties.BlockMouseAtScreenCorners = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ private IndexedObservableCollection machineMatrixString;
+
+ public class DeviceViewModel : Observable
+ {
+ public string Name { get; set; }
+
+ public bool CanDragDrop { get; set; }
+
+ private Brush _statusBrush = StatusColors[SocketStatus.NA];
+
+ public Brush StatusBrush
+ {
+ get
+ {
+ return _statusBrush;
+ }
+
+ set
+ {
+ if (_statusBrush != value)
+ {
+ _statusBrush = value;
+ OnPropertyChanged(nameof(StatusBrush));
+ }
+ }
+ }
+ }
+
+ public IndexedObservableCollection MachineMatrixString
+ {
+ get
+ {
+ lock (_machineMatrixStringLock)
+ {
+ return machineMatrixString;
+ }
+ }
+
+ set
+ {
+ lock (_machineMatrixStringLock)
+ {
+ machineMatrixString = value;
+ }
+
+ Settings.Properties.MachineMatrixString = new List(value.ToEnumerable().Select(d => d.Name));
+ NotifyPropertyChanged();
+ }
+ }
+
+ public bool ShowClipboardAndNetworkStatusMessages
+ {
+ get
+ {
+ return Settings.Properties.ShowClipboardAndNetworkStatusMessages;
+ }
+
+ set
+ {
+ if (Settings.Properties.ShowClipboardAndNetworkStatusMessages != value)
+ {
+ Settings.Properties.ShowClipboardAndNetworkStatusMessages = value;
+ NotifyPropertyChanged();
+ }
+ }
+ }
+
+ public bool LoadUpdatedSettings()
+ {
+ try
+ {
+ LoadViewModelFromSettings(SettingsUtils.GetSettings("MouseWithoutBorders"));
+ return true;
+ }
+ catch (System.Exception ex)
+ {
+ Logger.LogError(ex.Message);
+ return false;
+ }
+ }
+
+ private void SendCustomAction(string actionName)
+ {
+ SendConfigMSG("{\"action\":{\"MouseWithoutBorders\":{\"action_name\":\"" + actionName + "\", \"value\":\"\"}}}");
+ }
+
+ public void AddFirewallRule()
+ {
+ SendCustomAction("add_firewall");
+ }
+
+ public void RefreshEnabledState()
+ {
+ InitializeEnabledValue();
+ OnPropertyChanged(nameof(IsEnabled));
+ }
+
+ private void NotifyModuleUpdatedSettings()
+ {
+ SendConfigMSG(
+ string.Format(
+ CultureInfo.InvariantCulture,
+ "{{ \"powertoys\": {{ \"{0}\": {1} }} }}",
+ MouseWithoutBordersSettings.ModuleName,
+ JsonSerializer.Serialize(Settings)));
+ }
+
+ public void NotifyUpdatedSettings()
+ {
+ OnPropertyChanged(null); // Notify all properties might have changed.
+ }
+
+ public void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
+ {
+ OnPropertyChanged(propertyName);
+ SettingsUtils.SaveSettings(Settings.ToJsonString(), MouseWithoutBordersSettings.ModuleName);
+
+ if (propertyName == nameof(UseService))
+ {
+ NotifyModuleUpdatedSettings();
+ }
+ }
+
+ private Func SendConfigMSG { get; }
+
+ public void CopyMachineNameToClipboard()
+ {
+ var data = new DataPackage();
+ data.SetText(Dns.GetHostName());
+ Clipboard.SetContent(data);
+ }
+
+ public void Dispose()
+ {
+ GC.SuppressFinalize(this);
+ }
+
+ internal void UninstallService()
+ {
+ SendCustomAction("uninstall_service");
+ }
+ }
+}
diff --git a/src/settings-ui/Settings.UI/ViewModels/ShellViewModel.cs b/src/settings-ui/Settings.UI/ViewModels/ShellViewModel.cs
index d21142b5daf0..7618fe1eedc7 100644
--- a/src/settings-ui/Settings.UI/ViewModels/ShellViewModel.cs
+++ b/src/settings-ui/Settings.UI/ViewModels/ShellViewModel.cs
@@ -10,7 +10,7 @@
using System.Threading.Tasks;
using System.Windows.Input;
using Microsoft.PowerToys.Settings.UI.Helpers;
-using Microsoft.PowerToys.Settings.UI.Library;
+using Microsoft.PowerToys.Settings.UI.Library.Helpers;
using Microsoft.PowerToys.Settings.UI.Services;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Input;
diff --git a/src/settings-ui/Settings.UI/Views/MouseWithoutBordersPage.xaml b/src/settings-ui/Settings.UI/Views/MouseWithoutBordersPage.xaml
new file mode 100644
index 000000000000..3b5e947e78b2
--- /dev/null
+++ b/src/settings-ui/Settings.UI/Views/MouseWithoutBordersPage.xaml
@@ -0,0 +1,443 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+ B
+ C
+ D
+ E
+ F
+ G
+ H
+ I
+ J
+ K
+ L
+ M
+ N
+ O
+ P
+ Q
+ R
+ S
+ T
+ U
+ V
+ W
+ X
+ Y
+ Z
+
+
+
+
+
+ A
+ B
+ C
+ D
+ E
+ F
+ G
+ H
+ I
+ J
+ K
+ L
+ M
+ N
+ O
+ P
+ Q
+ R
+ S
+ T
+ U
+ V
+ W
+ X
+ Y
+ Z
+
+
+
+
+
+ A
+ B
+ C
+ D
+ E
+ F
+ G
+ H
+ I
+ J
+ K
+ L
+ M
+ N
+ O
+ P
+ Q
+ R
+ S
+ T
+ U
+ V
+ W
+ X
+ Y
+ Z
+
+
+
+
+
+
+ A
+ B
+ C
+ D
+ E
+ F
+ G
+ H
+ I
+ J
+ K
+ L
+ M
+ N
+ O
+ P
+ Q
+ R
+ S
+ T
+ U
+ V
+ W
+ X
+ Y
+ Z
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/settings-ui/Settings.UI/Views/MouseWithoutBordersPage.xaml.cs b/src/settings-ui/Settings.UI/Views/MouseWithoutBordersPage.xaml.cs
new file mode 100644
index 000000000000..2670aa5eaddc
--- /dev/null
+++ b/src/settings-ui/Settings.UI/Views/MouseWithoutBordersPage.xaml.cs
@@ -0,0 +1,176 @@
+// Copyright (c) Microsoft Corporation
+// The Microsoft Corporation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.IO.Abstractions;
+using System.Net;
+using System.Threading.Tasks;
+using System.Windows.Input;
+using System.Xml.Linq;
+using CommunityToolkit.Labs.WinUI;
+using Microsoft.PowerToys.Settings.UI.Helpers;
+using Microsoft.PowerToys.Settings.UI.Library;
+using Microsoft.PowerToys.Settings.UI.Library.Utilities;
+using Microsoft.PowerToys.Settings.UI.ViewModels;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+using Windows.ApplicationModel.DataTransfer;
+using WinRT;
+using static Microsoft.PowerToys.Settings.UI.ViewModels.MouseWithoutBordersViewModel;
+
+namespace Microsoft.PowerToys.Settings.UI.Views
+{
+ public sealed partial class MouseWithoutBordersPage : Page, IRefreshablePage
+ {
+ private const string MouseWithoutBordersDragDropCheckString = "MWB Device Drag Drop";
+
+ private const string PowerToyName = "MouseWithoutBorders";
+
+ private MouseWithoutBordersViewModel ViewModel { get; set; }
+
+ private readonly IFileSystemWatcher watcher;
+
+ public MouseWithoutBordersPage()
+ {
+ var settingsUtils = new SettingsUtils();
+ ViewModel = new MouseWithoutBordersViewModel(
+ settingsUtils,
+ SettingsRepository.GetInstance(settingsUtils),
+ ShellPage.SendDefaultIPCMessage,
+ DispatcherQueue);
+
+ watcher = Helper.GetFileWatcher(
+ PowerToyName,
+ "settings.json",
+ OnConfigFileUpdate);
+
+ DataContext = ViewModel;
+ InitializeComponent();
+ }
+
+ private void OnConfigFileUpdate()
+ {
+ // Note: FileSystemWatcher raise notification multiple times for single update operation.
+ // Todo: Handle duplicate events either by somehow suppress them or re-read the configuration everytime since we will be updating the UI only if something is changed.
+ this.DispatcherQueue.TryEnqueue(() =>
+ {
+ if (ViewModel.LoadUpdatedSettings())
+ {
+ ViewModel.NotifyUpdatedSettings();
+ }
+ });
+ }
+
+ private static T GetChildOfType(DependencyObject depObj, string tag)
+ where T : FrameworkElement
+ {
+ if (depObj == null)
+ {
+ return null;
+ }
+
+ for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
+ {
+ var child = VisualTreeHelper.GetChild(depObj, i);
+
+ var result = (child as T) ?? GetChildOfType(child, tag);
+ if (result != null && (string)result.Tag == tag)
+ {
+ return result;
+ }
+ }
+
+ return null;
+ }
+
+ private int GetDeviceIndex(Border b)
+ {
+ return b.DataContext.As>().Index;
+ }
+
+ private void Device_DragStarting(UIElement sender, DragStartingEventArgs args)
+ {
+ args.Data.RequestedOperation = DataPackageOperation.Move;
+ args.Data.Properties.Add("check-usage", MouseWithoutBordersDragDropCheckString);
+ args.Data.Properties.Add("index", GetDeviceIndex((Border)sender));
+ }
+
+ private void Device_Drop(object sender, DragEventArgs e)
+ {
+ if (e.DataView.Properties.TryGetValue("check-usage", out object checkUsage))
+ {
+ // Guard against values dragged from somewhere else
+ if (!((string)checkUsage).Equals(MouseWithoutBordersDragDropCheckString, StringComparison.Ordinal))
+ {
+ return;
+ }
+ }
+ else
+ {
+ return;
+ }
+
+ if (!e.DataView.Properties.TryGetValue("index", out object boxIndex))
+ {
+ return;
+ }
+
+ var draggedDeviceIndex = (int)boxIndex;
+
+ if (draggedDeviceIndex < 0 || draggedDeviceIndex >= ViewModel.MachineMatrixString.Count)
+ {
+ return;
+ }
+
+ var targetDeviceIndex = GetDeviceIndex((Border)e.OriginalSource);
+
+ ViewModel.MachineMatrixString.Swap(draggedDeviceIndex, targetDeviceIndex);
+ var itemsControl = (ItemsControl)FindName("DevicesItemsControl");
+ var binding = itemsControl.GetBindingExpression(ItemsControl.ItemsSourceProperty);
+ binding.UpdateSource();
+ }
+
+ private void Device_DragOver(object sender, DragEventArgs e)
+ {
+ e.AcceptedOperation = DataPackageOperation.Move;
+ }
+
+ public ICommand ShowConnectFieldsCommand => new RelayCommand(ShowConnectFields);
+
+ public ICommand ConnectCommand => new AsyncCommand(Connect);
+
+ public ICommand GenerateNewKeyCommand => new AsyncCommand(ViewModel.SubmitNewKeyRequestAsync);
+
+ public ICommand CopyPCNameCommand => new RelayCommand(ViewModel.CopyMachineNameToClipboard);
+
+ public ICommand ReconnectCommand => new AsyncCommand(ViewModel.SubmitReconnectRequestAsync);
+
+ private void ShowConnectFields()
+ {
+ ViewModel.ConnectFieldsVisible = true;
+ }
+
+ private async Task Connect()
+ {
+ if (ConnectPCNameTextBox.Text.Length != 0 && ConnectSecurityKeyTextBox.Text.Length != 0)
+ {
+ string pcName = ConnectPCNameTextBox.Text;
+ string securityKey = ConnectSecurityKeyTextBox.Text.Trim();
+
+ await ViewModel.SubmitConnectionRequestAsync(pcName, securityKey);
+
+ ConnectPCNameTextBox.Text = string.Empty;
+ ConnectSecurityKeyTextBox.Text = string.Empty;
+ }
+ }
+
+ public void RefreshEnabledState()
+ {
+ ViewModel.RefreshEnabledState();
+ }
+ }
+}
diff --git a/src/settings-ui/Settings.UI/Views/ShellPage.xaml b/src/settings-ui/Settings.UI/Views/ShellPage.xaml
index 30453209345f..df9ee29d8d80 100644
--- a/src/settings-ui/Settings.UI/Views/ShellPage.xaml
+++ b/src/settings-ui/Settings.UI/Views/ShellPage.xaml
@@ -94,6 +94,11 @@
helpers:NavHelper.NavigateTo="views:MouseUtilsPage"
Icon="{ui:BitmapIcon Source=/Assets/FluentIcons/FluentIconsMouseUtils.png}" />
+
+
processes =
L"PowerToys.SvgPreviewHandler.exe",
L"PowerToys.SvgThumbnailProvider.exe",
L"PowerToys.RegistryPreview.exe",
+ L"PowerToys.MouseWithoutBorders.exe"
+ L"PowerToys.MouseWithoutBordersHelper.exe"
+ L"PowerToys.MouseWithoutBordersService.exe"
L"PowerToys.Peek.UI.exe"
};
diff --git a/tools/BugReportTool/BugReportTool/ReportGPOValues.cpp b/tools/BugReportTool/BugReportTool/ReportGPOValues.cpp
index e2828b8ce36b..40d6e7d2abe7 100644
--- a/tools/BugReportTool/BugReportTool/ReportGPOValues.cpp
+++ b/tools/BugReportTool/BugReportTool/ReportGPOValues.cpp
@@ -49,6 +49,7 @@ void ReportGPOValues(const std::filesystem::path& tmpDir)
report << "getConfiguredMouseHighlighterEnabledValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredMouseHighlighterEnabledValue()) << std::endl;
report << "getConfiguredMouseJumpEnabledValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredMouseJumpEnabledValue()) << std::endl;
report << "getConfiguredMousePointerCrosshairsEnabledValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredMousePointerCrosshairsEnabledValue()) << std::endl;
+ report << "getConfiguredMouseWithoutBordersEnabledValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredMouseWithoutBordersEnabledValue()) << std::endl;
report << "getConfiguredPastePlainEnabledValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredPastePlainEnabledValue()) << std::endl;
report << "getConfiguredPowerRenameEnabledValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredPowerRenameEnabledValue()) << std::endl;
report << "getConfiguredPowerLauncherEnabledValue: " << gpo_rule_configured_to_string(powertoys_gpo::getConfiguredPowerLauncherEnabledValue()) << std::endl;