Compare commits

..

5 Commits

Author SHA1 Message Date
Michael Jolley
42bf5ad885 More refreshing 2025-12-01 10:20:10 -06:00
Michael Jolley
0b10a15a8a More service stuff 2025-11-25 15:15:31 -06:00
Michael Jolley
c755b8585a More service stuff 2025-11-24 22:48:27 -06:00
Michael Jolley
bfc1bcae6d More refreshing 2025-11-20 21:52:02 -06:00
Michael Jolley
c0f6a3f9f4 First commit of refresh 2025-11-20 17:28:05 -06:00
278 changed files with 3412 additions and 8337 deletions

View File

@@ -2,8 +2,8 @@ AAAAs
abcdefghjkmnpqrstuvxyz
abgr
ABlocked
ABORTIFHUNG
ABOUTBOX
ABORTIFHUNG
Abug
Acceleratorkeys
ACCEPTFILES
@@ -56,7 +56,6 @@ ANull
AOC
aocfnapldcnfbofgmbbllojgocaelgdd
AOklab
aot
APARTMENTTHREADED
APeriod
apicontract
@@ -98,8 +97,8 @@ ASSOCSTR
ASYNCWINDOWPLACEMENT
ASYNCWINDOWPOS
atl
ATRIOX
ATX
ATRIOX
aumid
authenticode
AUTOBUDDY
@@ -118,10 +117,10 @@ azman
azureaiinference
azureinference
azureopenai
backticks
bbwe
BCIE
bck
backticks
BESTEFFORT
bezelled
bhid
@@ -149,8 +148,8 @@ bmi
BNumber
BODGY
BOklab
BOOTSTRAPPERINSTALLFOLDER
Bootstrappers
BOOTSTRAPPERINSTALLFOLDER
BOTTOMALIGN
boxmodel
BPBF
@@ -177,16 +176,17 @@ BYPOSITION
CALCRECT
CALG
callbackptr
cabstr
calpwstr
caub
Cangjie
CANRENAME
Carlseibert
Canvascustomlayout
CAPTUREBLT
CAPTURECHANGED
CARETBLINKING
Carlseibert
CAtl
caub
CBN
cch
CCHDEVICENAME
@@ -206,9 +206,11 @@ changecursor
CHILDACTIVATE
CHILDWINDOW
CHOOSEFONT
CIBUILD
cidl
CIELCh
cim
claude
CImage
cla
CLASSDC
@@ -262,6 +264,7 @@ CONFIGW
CONFLICTINGMODIFIERKEY
CONFLICTINGMODIFIERSHORTCUT
CONOUT
coreclr
constexpr
contentdialog
contentfiles
@@ -273,7 +276,6 @@ copiedcolorrepresentation
coppied
copyable
COPYPEN
coreclr
COREWINDOW
Corpor
cotaskmem
@@ -282,18 +284,18 @@ countof
covrun
cpcontrols
cph
cppcoreguidelines
cplusplus
CPower
cppcoreguidelines
cpptools
cppvsdbg
cppwinrt
createdump
creativecommons
CREATEPROCESS
CREATESCHEDULEDTASK
CREATESTRUCT
CREATEWINDOWFAILED
creativecommons
CRECT
CRH
critsec
@@ -329,6 +331,7 @@ CYSCREEN
CYSMICON
CYVIRTUALSCREEN
Czechia
cziplib
Dac
dacl
DAffine
@@ -352,7 +355,9 @@ Deact
debugbreak
decryptor
Dedup
dfx
Deduplicator
Deeplink
DEFAULTBOOTSTRAPPERINSTALLFOLDER
DEFAULTCOLOR
DEFAULTFLAGS
@@ -399,6 +404,7 @@ DISPLAYFREQUENCY
displayname
DISPLAYORIENTATION
divyan
djwsxzxb
Dlg
DLGFRAME
DLGMODALFRAME
@@ -411,6 +417,7 @@ DONTVALIDATEPATH
dotnet
downsampled
downsampling
Downsampled
downscale
DPICHANGED
DPIs
@@ -524,6 +531,7 @@ EXTRINSICPROPERTIES
eyetracker
FANCYZONESDRAWLAYOUTTEST
FANCYZONESEDITOR
FNumber
FARPROC
fdx
fesf
@@ -555,8 +563,8 @@ FIXEDSYS
flac
flyouts
FMask
foundrylocal
fmtid
FNumber
FOF
FOFX
FOLDERID
@@ -567,7 +575,6 @@ FORCEMINIMIZE
FORMATDLGORD
formatetc
FORPARSING
foundrylocal
FRAMECHANGED
frm
FROMTOUCH
@@ -586,13 +593,13 @@ gdi
gdiplus
GDIPVER
GDISCALED
geolocator
GETCLIENTAREAANIMATION
GETCURSEL
GETDESKWALLPAPER
GETDLGCODE
GETDPISCALEDSIZE
getfilesiginforedist
geolocator
GETHOTKEY
GETICON
GETLBTEXT
@@ -603,12 +610,11 @@ GETSCREENSAVERRUNNING
GETSECKEY
GETSTICKYKEYS
GETTEXTLENGTH
GHND
GIFs
gitmodules
GHND
GMEM
GNumber
googleai
googlegemini
gpedit
gpo
GPOCA
@@ -625,6 +631,8 @@ GValue
gwl
GWLP
GWLSTYLE
googleai
googlegemini
hangeul
Hanzi
Hardlines
@@ -735,7 +743,9 @@ IDCANCEL
IDD
idk
idl
IIM
idlist
ifd
IDOK
IDOn
IDR
@@ -744,16 +754,15 @@ ietf
IEXPLORE
IFACEMETHOD
IFACEMETHODIMP
ifd
IGNOREUNKNOWN
IGo
iid
IIM
Iindex
Ijwhost
ILD
IMAGEHLP
IMAGERESIZERCONTEXTMENU
IPTC
IMAGERESIZEREXT
imageresizerinput
imageresizersettings
@@ -789,6 +798,7 @@ INSTALLFOLDERTOPREVIOUSINSTALLFOLDER
INSTALLLOCATION
INSTALLMESSAGE
INSTALLPROPERTY
installscopeperuser
INSTALLSTARTMENUSHORTCUT
INSTALLSTATE
Inste
@@ -801,7 +811,6 @@ invokecommand
ipcmanager
IPREVIEW
ipreviewhandlervisualssetfont
IPTC
irow
irprops
isbi
@@ -845,14 +854,15 @@ keyvault
KILLFOCUS
killrunner
kmph
ksa
kvp
Kybd
LARGEICON
lastcodeanalysissucceeded
LASTEXITCODE
LAYOUTRTL
lbl
LCh
lbl
lcid
LCIDTo
lcl
@@ -868,10 +878,10 @@ LExit
lhwnd
LIBFUZZER
LIBID
lightswitch
LIMITSIZE
LIMITTEXT
lindex
lightswitch
linkid
LINKOVERLAY
LINQTo
@@ -882,7 +892,6 @@ LLKH
llkhf
LMEM
LMENU
lng
LOADFROMFILE
LOBYTE
localappdata
@@ -892,14 +901,17 @@ LOCATIONCHANGE
LOCKTYPE
LOGFONT
LOGFONTW
LOGMSG
logon
lon
LOGMSG
LOGPIXELSX
LOGPIXELSY
lng
lon
longdate
LONGNAMES
lowlevel
lquadrant
LOWORD
lparam
LPBITMAPINFOHEADER
@@ -933,7 +945,6 @@ lpv
LPW
lpwcx
lpwndpl
lquadrant
LReader
LRESULT
LSTATUS
@@ -960,7 +971,6 @@ MAKELONG
MAKELPARAM
makepri
MAKEWPARAM
Malware
manifestdependency
MAPPEDTOSAMEKEY
MAPTOSAMESHORTCUT
@@ -983,8 +993,8 @@ MENUITEMINFO
MENUITEMINFOW
MERGECOPY
MERGEPAINT
metadatamatters
Metadatas
metadatamatters
metafile
mfc
Mgmt
@@ -1030,6 +1040,9 @@ mousepointer
mouseutils
MOVESIZEEND
MOVESIZESTART
muxx
muxxc
muxxh
MRM
MRT
mru
@@ -1058,14 +1071,10 @@ msrc
msstore
msvcp
MT
mstsc
MTND
MULTIPLEUSE
multizone
muxc
muxx
muxxc
muxxh
MVPs
mvvm
MVVMTK
@@ -1148,6 +1157,7 @@ nonstd
NOOWNERZORDER
NOPARENTNOTIFY
NOPREFIX
NPU
NOREDIRECTIONBITMAP
NOREDRAW
NOREMOVE
@@ -1176,7 +1186,6 @@ nowarn
NOZORDER
NPH
npmjs
NPU
NResize
NTAPI
ntdll
@@ -1201,17 +1210,15 @@ oldpath
oldtheme
oleaut
OLECHAR
ollama
onebranch
onnx
OOBEUI
openas
opencode
OPENFILENAME
openrdp
opensource
openxmlformats
ollama
Olllama
onnx
OPTIMIZEFORINVOKE
ORPHANEDDIALOGTITLE
@@ -1285,7 +1292,6 @@ pguid
phbm
phbmp
phicon
Photoshop
phwnd
pici
pidl
@@ -1308,6 +1314,7 @@ pnid
PNMLINK
Poc
Podcasts
Photoshop
POINTERID
POINTERUPDATE
Pokedex
@@ -1402,9 +1409,10 @@ pwsz
pwtd
QDC
qit
QNN
Qualcomm
QITAB
QITABENT
QNN
qoi
Quarternary
QUERYENDSESSION
@@ -1414,8 +1422,8 @@ quickaccent
QUNS
RAII
RAlt
randi
RAquadrant
randi
rasterization
Rasterize
RAWINPUTDEVICE
@@ -1425,8 +1433,6 @@ RAWPATH
rbhid
rclsid
RCZOOMIT
remotedesktop
rdp
RDW
READMODE
READOBJECTS
@@ -1444,7 +1450,9 @@ regfile
REGISTERCLASSFAILED
REGISTRYHEADER
REGISTRYPREVIEWEXT
registryroot
regkey
regroot
regsvr
REINSTALLMODE
releaseblog
@@ -1497,6 +1505,7 @@ rstringalpha
rstringdigit
rtb
RTLREADING
rtm
runas
rundll
rungameid
@@ -1553,8 +1562,8 @@ SETRULES
SETSCREENSAVEACTIVE
SETSTICKYKEYS
SETTEXT
SETTINGCHANGE
settingscard
SETTINGCHANGE
SETTINGSCHANGED
settingsheader
settingshotkeycontrol
@@ -1699,7 +1708,6 @@ stringtable
stringval
Strm
strret
STRSAFE
stscanf
sttngs
Stubless
@@ -1711,6 +1719,7 @@ sublang
SUBMODULEUPDATE
subresource
Superbar
suntimes
sut
svchost
SVGIn
@@ -1744,6 +1753,7 @@ SYSTEMMODAL
SYSTEMTIME
TARG
TARGETAPPHEADER
TARGETDIR
targetentrypoint
TARGETHEADER
targetver
@@ -1773,10 +1783,10 @@ textextractor
TEXTINCLUDE
tfopen
tgz
THEMECHANGED
themeresources
THH
THICKFRAME
THEMECHANGED
THISCOMPONENT
throughs
TILEDWINDOW
@@ -1873,6 +1883,7 @@ USEINSTALLERFORTEST
USESHOWWINDOW
USESTDHANDLES
USRDLL
utm
UType
uuidv
uwp
@@ -1945,11 +1956,11 @@ Wca
WCE
wcex
WClass
WCRAPI
wcsicmp
wcsncpy
wcsnicmp
WCT
WCRAPI
WDA
wdm
wdp
@@ -1977,7 +1988,6 @@ WINDOWPLACEMENT
WINDOWPOSCHANGED
WINDOWPOSCHANGING
WINDOWSBUILDNUMBER
windowsml
windowssearch
windowssettings
WINDOWSTYLES
@@ -1993,8 +2003,9 @@ Winhook
WINL
winlogon
winmd
winml
WINNT
windowsml
winml
winres
winrt
winsdk
@@ -2056,21 +2067,20 @@ WTSAT
Wubi
WUX
Wwanpp
xap
XAxis
XButton
xclip
xcopy
xap
XDeployment
xdf
XDimension
xdf
XDocument
XElement
xfd
XFile
XIncrement
XLoc
xmp
XNamespace
Xoshiro
XPels
@@ -2081,22 +2091,23 @@ xsi
XSpeed
XStr
xstyler
xmp
XTimer
XUP
XVIRTUALSCREEN
xxxxxx
YAxis
ycombinator
YDimension
YIncrement
YDimension
yinle
yinyue
YPels
YPos
YResolution
YSpeed
YStr
YTimer
YStr
YVIRTUALSCREEN
ZEROINIT
zonability

View File

@@ -21,6 +21,6 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v6
uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4

View File

@@ -27,7 +27,7 @@ jobs:
issue: ${{ fromJson(github.event.inputs.issue_numbers) }}
steps:
- name: Checkout
uses: actions/checkout@v6
uses: actions/checkout@v3
- name: Run GenAI Issue Deduplicator
uses: pelikhan/action-genai-issue-dedup@v0

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.PowerToys.Telemetry" version="2.0.4" />
<package id="Microsoft.PowerToys.Telemetry" version="2.0.3" />
</packages>

View File

@@ -69,7 +69,7 @@
This is present due to a bug in CsWinRT where WPF projects cause the analyzer to fail.
-->
<PackageVersion Include="Microsoft.Windows.CsWinRT" Version="2.2.0" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.6901" />
<PackageVersion Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.4948" />
<PackageVersion Include="Microsoft.WindowsAppSDK" Version="1.8.250907003" />
<PackageVersion Include="Microsoft.WindowsAppSDK.AI" Version="1.8.37" />
<PackageVersion Include="Microsoft.WindowsAppSDK.Runtime" Version="1.8.250907003" />

View File

@@ -834,10 +834,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LanguageModelProvider", "sr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.UI.ViewModels.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.UI.ViewModels.UnitTests\Microsoft.CmdPal.UI.ViewModels.UnitTests.csproj", "{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.RemoteDesktop", "src\modules\cmdpal\ext\Microsoft.CmdPal.Ext.RemoteDesktop\Microsoft.CmdPal.Ext.RemoteDesktop.csproj", "{2B3FB837-23DE-629F-82C6-42304E7083C9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.CmdPal.Ext.RemoteDesktop.UnitTests", "src\modules\cmdpal\Tests\Microsoft.CmdPal.Ext.RemoteDesktop.UnitTests\Microsoft.CmdPal.Ext.RemoteDesktop.UnitTests.csproj", "{DB34808A-FF91-D06E-A426-AFB5A8BD583B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
@@ -3040,22 +3036,6 @@ Global
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Release|ARM64.Build.0 = Release|ARM64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Release|x64.ActiveCfg = Release|x64
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C}.Release|x64.Build.0 = Release|x64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Debug|ARM64.ActiveCfg = Debug|ARM64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Debug|ARM64.Build.0 = Debug|ARM64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Debug|x64.ActiveCfg = Debug|x64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Debug|x64.Build.0 = Debug|x64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Release|ARM64.ActiveCfg = Release|ARM64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Release|ARM64.Build.0 = Release|ARM64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Release|x64.ActiveCfg = Release|x64
{2B3FB837-23DE-629F-82C6-42304E7083C9}.Release|x64.Build.0 = Release|x64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Debug|ARM64.ActiveCfg = Debug|ARM64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Debug|ARM64.Build.0 = Debug|ARM64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Debug|x64.ActiveCfg = Debug|x64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Debug|x64.Build.0 = Debug|x64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Release|ARM64.ActiveCfg = Release|ARM64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Release|ARM64.Build.0 = Release|ARM64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Release|x64.ActiveCfg = Release|x64
{DB34808A-FF91-D06E-A426-AFB5A8BD583B}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -3387,8 +3367,6 @@ Global
{4E0FCF69-B06B-D272-76BF-ED3A559B4EDA} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{45354F4F-1414-45CE-B600-51CD1209FD19} = {1AFB6476-670D-4E80-A464-657E01DFF482}
{A66E9270-5D93-EC9C-F06E-CE7295BB9A6C} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
{2B3FB837-23DE-629F-82C6-42304E7083C9} = {ECB8E0D1-7603-4E5C-AB10-D1E545E6F8E2}
{DB34808A-FF91-D06E-A426-AFB5A8BD583B} = {8EF25507-2575-4ADE-BF7E-D23376903AB8}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}

View File

@@ -53,17 +53,17 @@ Go to the [PowerToys GitHub releases][github-release-link], click Assets to reve
<!-- items that need to be updated release to release -->
[github-next-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.97%22
[github-current-release-work]: https://github.com/microsoft/PowerToys/issues?q=is%3Aissue+milestone%3A%22PowerToys+0.96%22
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysUserSetup-0.96.1-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysUserSetup-0.96.1-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysSetup-0.96.1-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.1/PowerToysSetup-0.96.1-arm64.exe
[ptUserX64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.0/PowerToysUserSetup-0.96.0-x64.exe
[ptUserArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.0/PowerToysUserSetup-0.96.0-arm64.exe
[ptMachineX64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.0/PowerToysSetup-0.96.0-x64.exe
[ptMachineArm64]: https://github.com/microsoft/PowerToys/releases/download/v0.96.0/PowerToysSetup-0.96.0-arm64.exe
| Description | Filename |
|----------------|----------|
| Per user - x64 | [PowerToysUserSetup-0.96.1-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.96.1-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.96.1-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.96.1-arm64.exe][ptMachineArm64] |
| Per user - x64 | [PowerToysUserSetup-0.96.0-x64.exe][ptUserX64] |
| Per user - ARM64 | [PowerToysUserSetup-0.96.0-arm64.exe][ptUserArm64] |
| Machine wide - x64 | [PowerToysSetup-0.96.0-x64.exe][ptMachineX64] |
| Machine wide - ARM64 | [PowerToysSetup-0.96.0-arm64.exe][ptMachineArm64] |
</details>

View File

@@ -33,12 +33,9 @@ The **Light Switch** module lets users automatically transition between light an
> **Note:** Using the shortcut overrides the current schedule until the next transition event.
* **LightSwitchService.cpp**
is the heart beat of the module. Controls ticking every minute and depending on user actions (manual override, settings changing, etc) triggers the state manager to perform the corresponding operation.
* **LightSwitchStateManager.cpp**
handles updating the state based on the signals sent by LightSwitchService.
* **LightSwitchService**
Reads settings and applies theming. Runs a check every minute to ensure the state is correct.
* **SettingsXAML/LightSwitch**
Provides the settings UI for configuring schedules, syncing location, and customizing shortcuts.

View File

@@ -64,7 +64,7 @@ public sealed class FoundryLocalModelProvider : ILanguageModelProvider
return new OpenAIClient(
new ApiKeyCredential("none"),
new OpenAIClientOptions { Endpoint = endpointUri, NetworkTimeout = TimeSpan.FromMinutes(5) })
new OpenAIClientOptions { Endpoint = endpointUri })
.GetChatClient(modelId)
.AsIChatClient();
}

View File

@@ -31,11 +31,6 @@ namespace ManagedCommon
/// </summary>
public static string CurrentVersionLogDirectoryPath { get; private set; }
/// <summary>
/// Gets the path to the current log file.
/// </summary>
public static string CurrentLogFile { get; private set; }
/// <summary>
/// Gets the path to the log directory for the app.
/// </summary>
@@ -60,9 +55,7 @@ namespace ManagedCommon
AppLogDirectoryPath = basePath;
CurrentVersionLogDirectoryPath = versionedPath;
var logFile = "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log";
var logFilePath = Path.Combine(versionedPath, logFile);
CurrentLogFile = logFilePath;
var logFilePath = Path.Combine(versionedPath, "Log_" + DateTime.Now.ToString(@"yyyy-MM-dd", CultureInfo.InvariantCulture) + ".log");
Trace.Listeners.Add(new TextWriterTraceListener(logFilePath));

View File

@@ -144,7 +144,7 @@ public sealed class AIServiceBatchIntegrationTests
switch (format)
{
case PasteFormats.CustomTextTransformation:
var transformResult = await services.CustomActionTransformService.TransformAsync(batchTestInput.Prompt, batchTestInput.Clipboard, null, CancellationToken.None, progress);
var transformResult = await services.CustomActionTransformService.TransformTextAsync(batchTestInput.Prompt, batchTestInput.Clipboard, CancellationToken.None, progress);
return DataPackageHelpers.CreateFromText(transformResult.Content ?? string.Empty);
case PasteFormats.KernelQuery:

View File

@@ -225,24 +225,6 @@ internal static class DataPackageHelpers
internal static async Task<string> GetHtmlContentAsync(this DataPackageView dataPackageView) =>
dataPackageView.Contains(StandardDataFormats.Html) ? await dataPackageView.GetHtmlFormatAsync() : string.Empty;
internal static async Task<byte[]> GetImageAsPngBytesAsync(this DataPackageView dataPackageView)
{
var bitmap = await dataPackageView.GetImageContentAsync();
if (bitmap == null)
{
return null;
}
using var pngStream = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, pngStream);
encoder.SetSoftwareBitmap(bitmap);
await encoder.FlushAsync();
using var memoryStream = new MemoryStream();
await pngStream.AsStreamForRead().CopyToAsync(memoryStream);
return memoryStream.ToArray();
}
internal static async Task<SoftwareBitmap> GetImageContentAsync(this DataPackageView dataPackageView)
{
using var stream = await dataPackageView.GetImageStreamAsync();

View File

@@ -166,8 +166,5 @@ namespace AdvancedPaste.Helpers
[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
internal static extern HResult AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string pszExtra, [Out] StringBuilder pszOut, [In][Out] ref uint pcchOut);
[DllImport("user32.dll", SetLastError = true)]
internal static extern uint GetClipboardSequenceNumber();
}
}

View File

@@ -46,7 +46,7 @@ public enum PasteFormats
CanPreview = true,
SupportedClipboardFormats = ClipboardFormat.Image,
IPCKey = AdvancedPasteAdditionalActions.PropertyNames.ImageToText,
KernelFunctionDescription = "Takes an image from the clipboard and extracts text using OCR. This function is intended only for explicit text extraction or OCR requests.")]
KernelFunctionDescription = "Takes an image in the clipboard and extracts all text from it using OCR.")]
ImageToText,
[PasteFormatMetadata(
@@ -118,8 +118,8 @@ public enum PasteFormats
IconGlyph = "\uE945",
RequiresAIService = true,
CanPreview = true,
SupportedClipboardFormats = ClipboardFormat.Text | ClipboardFormat.Image,
KernelFunctionDescription = "Takes user instructions and applies them to the current clipboard content (text or image). Use this function for image analysis, description, or transformation tasks beyond simple OCR.",
SupportedClipboardFormats = ClipboardFormat.Text,
KernelFunctionDescription = "Takes input instructions and transforms clipboard text (not TXT files) with these input instructions, putting the result back on the clipboard. This uses AI to accomplish the task.",
RequiresPrompt = true)]
CustomTextTransformation,
}

View File

@@ -215,6 +215,7 @@ public sealed class AdvancedAIKernelService : KernelServiceBase
return new OpenAIPromptExecutionSettings
{
FunctionChoiceBehavior = FunctionChoiceBehavior.Auto(),
Temperature = 0.01,
};
}
}

View File

@@ -40,15 +40,15 @@ namespace AdvancedPaste.Services.CustomActions
this.userSettings = userSettings;
}
public async Task<CustomActionTransformResult> TransformAsync(string prompt, string inputText, byte[] imageBytes, CancellationToken cancellationToken, IProgress<double> progress)
public async Task<CustomActionTransformResult> TransformTextAsync(string prompt, string inputText, CancellationToken cancellationToken, IProgress<double> progress)
{
var pasteConfig = userSettings?.PasteAIConfiguration;
var providerConfig = BuildProviderConfig(pasteConfig);
return await TransformAsync(prompt, inputText, imageBytes, providerConfig, cancellationToken, progress);
return await TransformAsync(prompt, inputText, providerConfig, cancellationToken, progress);
}
private async Task<CustomActionTransformResult> TransformAsync(string prompt, string inputText, byte[] imageBytes, PasteAIConfig providerConfig, CancellationToken cancellationToken, IProgress<double> progress)
private async Task<CustomActionTransformResult> TransformAsync(string prompt, string inputText, PasteAIConfig providerConfig, CancellationToken cancellationToken, IProgress<double> progress)
{
ArgumentNullException.ThrowIfNull(providerConfig);
@@ -57,9 +57,9 @@ namespace AdvancedPaste.Services.CustomActions
return new CustomActionTransformResult(string.Empty, AIServiceUsage.None);
}
if (string.IsNullOrWhiteSpace(inputText) && imageBytes is null)
if (string.IsNullOrWhiteSpace(inputText))
{
Logger.LogWarning("Clipboard has no usable data");
Logger.LogWarning("Clipboard has no usable text data");
return new CustomActionTransformResult(string.Empty, AIServiceUsage.None);
}
@@ -80,8 +80,6 @@ namespace AdvancedPaste.Services.CustomActions
{
Prompt = prompt,
InputText = inputText,
ImageBytes = imageBytes,
ImageMimeType = imageBytes != null ? "image/png" : null,
SystemPrompt = systemPrompt,
};

View File

@@ -146,7 +146,6 @@ public sealed class FoundryLocalPasteProvider : IPasteAIProvider
var options = new ChatOptions
{
ModelId = modelReference,
MaxOutputTokens = 2048,
};
if (!string.IsNullOrWhiteSpace(systemPrompt))

View File

@@ -12,6 +12,6 @@ namespace AdvancedPaste.Services.CustomActions
{
public interface ICustomActionTransformService
{
Task<CustomActionTransformResult> TransformAsync(string prompt, string inputText, byte[] imageBytes, CancellationToken cancellationToken, IProgress<double> progress);
Task<CustomActionTransformResult> TransformTextAsync(string prompt, string inputText, CancellationToken cancellationToken, IProgress<double> progress);
}
}

View File

@@ -12,10 +12,6 @@ namespace AdvancedPaste.Services.CustomActions
public string InputText { get; init; }
public byte[] ImageBytes { get; init; }
public string ImageMimeType { get; init; }
public string SystemPrompt { get; init; }
public AIServiceUsage Usage { get; set; } = AIServiceUsage.None;

View File

@@ -64,13 +64,21 @@ namespace AdvancedPaste.Services.CustomActions
var prompt = request.Prompt;
var inputText = request.InputText;
var imageBytes = request.ImageBytes;
if (string.IsNullOrWhiteSpace(prompt) || (string.IsNullOrWhiteSpace(inputText) && imageBytes is null))
if (string.IsNullOrWhiteSpace(prompt) || string.IsNullOrWhiteSpace(inputText))
{
throw new ArgumentException("Prompt and input content must be provided", nameof(request));
throw new ArgumentException("Prompt and input text must be provided", nameof(request));
}
var userMessageContent = $"""
User instructions:
{prompt}
Clipboard Content:
{inputText}
Output:
""";
var executionSettings = CreateExecutionSettings();
var kernel = CreateKernel();
var modelId = _config.Model;
@@ -94,32 +102,7 @@ namespace AdvancedPaste.Services.CustomActions
var chatHistory = new ChatHistory();
chatHistory.AddSystemMessage(systemPrompt);
if (imageBytes != null)
{
var collection = new ChatMessageContentItemCollection();
if (!string.IsNullOrWhiteSpace(inputText))
{
collection.Add(new TextContent($"Clipboard Content:\n{inputText}"));
}
collection.Add(new ImageContent(imageBytes, request.ImageMimeType ?? "image/png"));
collection.Add(new TextContent($"User instructions:\n{prompt}\n\nOutput:"));
chatHistory.AddUserMessage(collection);
}
else
{
var userMessageContent = $"""
User instructions:
{prompt}
Clipboard Content:
{inputText}
Output:
""";
chatHistory.AddUserMessage(userMessageContent);
}
chatHistory.AddUserMessage(userMessageContent);
var response = await chatService.GetChatMessageContentAsync(chatHistory, executionSettings, kernel, cancellationToken);
chatHistory.Add(response);
@@ -174,6 +157,8 @@ namespace AdvancedPaste.Services.CustomActions
{
AIServiceType.OpenAI or AIServiceType.AzureOpenAI => new OpenAIPromptExecutionSettings
{
Temperature = 0.01,
MaxTokens = 2000,
FunctionChoiceBehavior = null,
},
_ => new PromptExecutionSettings(),

View File

@@ -67,36 +67,12 @@ public abstract class KernelServiceBase(
LogResult(cacheUsed, isSavedQuery, kernel.GetOrAddActionChain(), usage);
var outputPackage = kernel.GetDataPackage();
var hasUsableData = await outputPackage.GetView().HasUsableDataAsync();
if (kernel.GetLastError() is Exception ex)
{
// If we have an error, but the AI provided a final text response, we can ignore the error (likely a tool failure that the AI handled).
// However, if we have usable data (e.g. from a successful tool call before the error?), we might want to keep it?
// In the case of ImageToText failure, outputPackage is empty (new DataPackage), hasUsableData is false.
// So we check if there is a valid response in the chat history.
var lastMessage = chatHistory.LastOrDefault();
bool hasAssistantResponse = lastMessage != null && lastMessage.Role == AuthorRole.Assistant && !string.IsNullOrEmpty(lastMessage.Content);
if (!hasAssistantResponse && !hasUsableData)
{
throw ex;
}
// If we have a response or data, we log the error but proceed.
Logger.LogWarning($"Kernel operation encountered an error but proceeded with available response/data: {ex.Message}");
throw ex;
}
if (!hasUsableData)
{
var lastMessage = chatHistory.LastOrDefault();
if (lastMessage != null && lastMessage.Role == AuthorRole.Assistant && !string.IsNullOrEmpty(lastMessage.Content))
{
outputPackage = DataPackageHelpers.CreateFromText(lastMessage.Content);
kernel.SetDataPackage(outputPackage);
}
}
var outputPackage = kernel.GetDataPackage();
if (!(await outputPackage.GetView().HasUsableDataAsync()))
{
@@ -172,21 +148,7 @@ public abstract class KernelServiceBase(
var systemPrompt = string.IsNullOrWhiteSpace(runtimeConfig.SystemPrompt) ? DefaultSystemPrompt : runtimeConfig.SystemPrompt;
chatHistory.AddSystemMessage(systemPrompt);
chatHistory.AddSystemMessage($"Available clipboard formats: {await kernel.GetDataFormatsAsync()}");
var imageBytes = await kernel.GetDataPackageView().GetImageAsPngBytesAsync();
if (imageBytes != null)
{
var collection = new ChatMessageContentItemCollection
{
new TextContent(prompt),
new ImageContent(imageBytes, "image/png"),
};
chatHistory.AddUserMessage(collection);
}
else
{
chatHistory.AddUserMessage(prompt);
}
chatHistory.AddUserMessage(prompt);
if (ShouldModerateAdvancedAI())
{
@@ -340,16 +302,8 @@ public abstract class KernelServiceBase(
new ActionChainItem(PasteFormats.CustomTextTransformation, Arguments: new() { { PromptParameterName, fixedPrompt } }),
async dataPackageView =>
{
var imageBytes = await dataPackageView.GetImageAsPngBytesAsync();
var input = await dataPackageView.GetTextOrHtmlTextAsync();
if (string.IsNullOrEmpty(input) && imageBytes == null)
{
// If we have no text and no image, try to get text via OCR or throw if nothing exists
input = await dataPackageView.GetClipboardTextOrThrowAsync(kernel.GetCancellationToken());
}
var result = await _customActionTransformService.TransformAsync(fixedPrompt, input, imageBytes, kernel.GetCancellationToken(), kernel.GetProgress());
var input = await dataPackageView.GetClipboardTextOrThrowAsync(kernel.GetCancellationToken());
var result = await _customActionTransformService.TransformTextAsync(fixedPrompt, input, kernel.GetCancellationToken(), kernel.GetProgress());
return DataPackageHelpers.CreateFromText(result?.Content ?? string.Empty);
});
@@ -359,22 +313,15 @@ public abstract class KernelServiceBase(
new ActionChainItem(format, Arguments: new() { { PromptParameterName, prompt } }),
async dataPackageView =>
{
var imageBytes = await dataPackageView.GetImageAsPngBytesAsync();
var input = await dataPackageView.GetTextOrHtmlTextAsync();
if (string.IsNullOrEmpty(input) && imageBytes == null)
{
input = await dataPackageView.GetClipboardTextOrThrowAsync(kernel.GetCancellationToken());
}
string output = await GetPromptBasedOutput(format, prompt, input, imageBytes, kernel.GetCancellationToken(), kernel.GetProgress());
var input = await dataPackageView.GetClipboardTextOrThrowAsync(kernel.GetCancellationToken());
string output = await GetPromptBasedOutput(format, prompt, input, kernel.GetCancellationToken(), kernel.GetProgress());
return DataPackageHelpers.CreateFromText(output);
});
private async Task<string> GetPromptBasedOutput(PasteFormats format, string prompt, string input, byte[] imageBytes, CancellationToken cancellationToken, IProgress<double> progress) =>
private async Task<string> GetPromptBasedOutput(PasteFormats format, string prompt, string input, CancellationToken cancellationToken, IProgress<double> progress) =>
format switch
{
PasteFormats.CustomTextTransformation => (await _customActionTransformService.TransformAsync(prompt, input, imageBytes, cancellationToken, progress))?.Content ?? string.Empty,
PasteFormats.CustomTextTransformation => (await _customActionTransformService.TransformTextAsync(prompt, input, cancellationToken, progress))?.Content ?? string.Empty,
_ => throw new ArgumentException($"Unsupported format {format} for prompt transform", nameof(format)),
};

View File

@@ -37,7 +37,7 @@ public sealed class PasteFormatExecutor(IKernelService kernelService, ICustomAct
pasteFormat.Format switch
{
PasteFormats.KernelQuery => await _kernelService.TransformClipboardAsync(pasteFormat.Prompt, clipboardData, pasteFormat.IsSavedQuery, cancellationToken, progress),
PasteFormats.CustomTextTransformation => DataPackageHelpers.CreateFromText((await _customActionTransformService.TransformAsync(pasteFormat.Prompt, await clipboardData.GetTextOrHtmlTextAsync(), await clipboardData.GetImageAsPngBytesAsync(), cancellationToken, progress))?.Content ?? string.Empty),
PasteFormats.CustomTextTransformation => DataPackageHelpers.CreateFromText((await _customActionTransformService.TransformTextAsync(pasteFormat.Prompt, await clipboardData.GetClipboardTextOrThrowAsync(cancellationToken), cancellationToken, progress))?.Content ?? string.Empty),
_ => await TransformHelpers.TransformAsync(format, clipboardData, cancellationToken, progress),
});
}

View File

@@ -45,7 +45,6 @@ namespace AdvancedPaste.ViewModels
private CancellationTokenSource _pasteActionCancellationTokenSource;
private string _currentClipboardHistoryId;
private uint _lastClipboardSequenceNumber;
private DateTimeOffset? _currentClipboardTimestamp;
private ClipboardFormat _lastClipboardFormats = ClipboardFormat.None;
private bool _clipboardHistoryUnavailableLogged;
@@ -456,7 +455,6 @@ namespace AdvancedPaste.ViewModels
{
ResetClipboardPreview();
_currentClipboardHistoryId = null;
_lastClipboardSequenceNumber = 0;
_currentClipboardTimestamp = null;
_lastClipboardFormats = ClipboardFormat.None;
return;
@@ -479,13 +477,6 @@ namespace AdvancedPaste.ViewModels
{
bool clipboardChanged = formatsChanged;
var currentSequenceNumber = NativeMethods.GetClipboardSequenceNumber();
if (_lastClipboardSequenceNumber != currentSequenceNumber)
{
clipboardChanged = true;
_lastClipboardSequenceNumber = currentSequenceNumber;
}
if (Clipboard.IsHistoryEnabled())
{
try

View File

@@ -0,0 +1,248 @@
// 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.
// <summary>
// Encrypt/decrypt implementation.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
using MouseWithoutBorders.Core;
namespace MouseWithoutBorders
{
internal partial class Common
{
#pragma warning disable SYSLIB0021
private static AesCryptoServiceProvider symAl;
#pragma warning restore SYSLIB0021
#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
internal static string myKey;
#pragma warning restore SA1307
private static uint magicNumber;
private static Random ran = new(); // Used for non encryption related functionality.
internal const int SymAlBlockSize = 16;
/// <summary>
/// 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
/// </summary>
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)
{
Logger.Log(e);
}
}
private static readonly ConcurrentDictionary<string, byte[]> LegalKeyDictionary = new(StringComparer.OrdinalIgnoreCase);
internal static byte[] GenLegalKey()
{
byte[] rv;
string myKey = Common.MyKey;
if (!LegalKeyDictionary.TryGetValue(myKey, out byte[] value))
{
Rfc2898DeriveBytes key = new(
myKey,
Common.GetBytesU(InitialIV),
50000,
HashAlgorithmName.SHA512);
rv = key.GetBytes(32);
_ = LegalKeyDictionary.AddOrUpdate(myKey, rv, (k, v) => rv);
}
else
{
rv = value;
}
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);
}
Logger.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;
}
}
}

View File

@@ -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.
// <summary>
// Package format/conversion.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
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;
}
}

View File

@@ -0,0 +1,33 @@
// 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 ManagedCommon;
using Microsoft.PowerToys.Telemetry;
using MouseWithoutBorders.Class;
using Logger = MouseWithoutBorders.Core.Logger;
namespace MouseWithoutBorders
{
internal class ShutdownWithPowerToys
{
public static void WaitForPowerToysRunner(ETWTrace etwTrace)
{
try
{
RunnerHelper.WaitForPowerToysRunnerExitFallback(() =>
{
etwTrace?.Dispose();
Common.MainForm.Quit(true, false);
});
}
catch (Exception e)
{
Logger.Log(e);
}
}
}
}

View File

@@ -0,0 +1,131 @@
// 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.
// <summary>
// Virtual key constants.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
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_MOUSEHWHEEL = 0x020E;
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,
}
}
}

View File

@@ -0,0 +1,363 @@
// 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;
// <summary>
// Screen/Desktop helper functions.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
using MouseWithoutBorders.Class;
using MouseWithoutBorders.Core;
using Thread = MouseWithoutBorders.Core.Thread;
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;
internal static void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
GetScreenConfig();
}
internal static readonly List<Point> 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);
Logger.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)
{
Logger.Log("GetDpiForMonitor is unsupported in Windows 7 and lower.");
}
catch (EntryPointNotFoundException)
{
Logger.Log("GetDpiForMonitor is unsupported in Windows 7 and lower.");
}
catch (Exception e)
{
Logger.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
{
Logger.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;
Logger.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 MachineStuff.desktopBounds, newDesktopBounds);
Interlocked.Exchange(ref MachineStuff.primaryScreenBounds, newPrimaryScreenBounds);
Logger.Log(string.Format(
CultureInfo.CurrentCulture,
"logon = {0} PrimaryScreenBounds = {1},{2},{3},{4} desktopBounds = {5},{6},{7},{8}",
Common.RunOnLogonDesktop,
MachineStuff.PrimaryScreenBounds.Left,
MachineStuff.PrimaryScreenBounds.Top,
MachineStuff.PrimaryScreenBounds.Right,
MachineStuff.PrimaryScreenBounds.Bottom,
MachineStuff.DesktopBounds.Left,
MachineStuff.DesktopBounds.Top,
MachineStuff.DesktopBounds.Right,
MachineStuff.DesktopBounds.Bottom));
Logger.Log("==================== GetScreenConfig ended");
}
catch (Exception e)
{
Logger.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)
{
Logger.LogDebug("*** Starting on active Desktop: " + desktopToRunMouseWithoutBordersOn);
Service.StartMouseWithoutBordersService(desktopToRunMouseWithoutBordersOn);
}
}
internal static void CheckForDesktopSwitchEvent(bool cleanupIfExit)
{
try
{
if (!IsMyDesktopActive() || Common.CurrentProcess.SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
{
Helper.RunDDHelper(true);
int waitCount = 20;
while (NativeMethods.WTSGetActiveConsoleSessionId() == 0xFFFFFFFF && waitCount > 0)
{
waitCount--;
Logger.LogDebug("The session is detached/attached.");
Thread.Sleep(500);
}
string myDesktop = GetMyDesktop();
activeDesktop = GetInputDesktop();
Logger.LogDebug("*** Active Desktop = " + activeDesktop);
Logger.LogDebug("*** My Desktop = " + myDesktop);
if (myDesktop.Equals(activeDesktop, StringComparison.OrdinalIgnoreCase))
{
Logger.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)
{
Logger.Log($"{nameof(CheckForDesktopSwitchEvent)}: {e}");
}
}
else
{
if (!myDesktop.Equals(activeDesktop, StringComparison.OrdinalIgnoreCase))
{
Logger.Log("*** Active Desktop <> My Desktop");
}
uint sid = NativeMethods.WTSGetActiveConsoleSessionId();
if (Process.GetProcessesByName(Common.BinaryName).Any(p => (uint)p.SessionId == sid))
{
Logger.Log("Found MouseWithoutBorders on the active session!");
}
else
{
Logger.Log("MouseWithoutBorders not found on the active session!");
StartMMService(null);
}
}
if (!myDesktop.Equals("winlogon", StringComparison.OrdinalIgnoreCase) &&
!myDesktop.Equals("default", StringComparison.OrdinalIgnoreCase))
{
Logger.LogDebug("*** Desktop inactive, exiting: " + myDesktop);
Setting.Values.LastX = JUST_GOT_BACK_FROM_SCREEN_SAVER;
if (cleanupIfExit)
{
InitAndCleanup.Cleanup();
}
Process.GetCurrentProcess().KillProcess();
}
}
}
catch (Exception e)
{
Logger.Log(e);
}
}
private static Point p;
internal static bool IsMyDesktopActive()
{
return NativeMethods.GetCursorPos(ref p);
}
}
}

View File

@@ -315,7 +315,7 @@ namespace MouseWithoutBorders
if (!acquireMutex)
{
Process[] ps = Process.GetProcessesByName(Common.BinaryName);
Logger.TelemetryLogTrace($"Balance: {socketMutexBalance}, Active: {WinAPI.IsMyDesktopActive()}, Sid/Console: {Process.GetCurrentProcess().SessionId}/{NativeMethods.WTSGetActiveConsoleSessionId()}, Desktop/Input: {WinAPI.GetMyDesktop()}/{WinAPI.GetInputDesktop()}, count: {ps?.Length}.", SeverityLevel.Warning);
Logger.TelemetryLogTrace($"Balance: {socketMutexBalance}, Active: {IsMyDesktopActive()}, Sid/Console: {Process.GetCurrentProcess().SessionId}/{NativeMethods.WTSGetActiveConsoleSessionId()}, Desktop/Input: {GetMyDesktop()}/{GetInputDesktop()}, count: {ps?.Length}.", SeverityLevel.Warning);
}
Logger.LogDebug("SOCKET MUTEX ENDED.");
@@ -358,7 +358,7 @@ namespace MouseWithoutBorders
Logger.TelemetryLogTrace($"[{actionName}] took more than {(long)timeout.TotalSeconds}, restarting the process.", SeverityLevel.Warning, true);
string desktop = WinAPI.GetMyDesktop();
string desktop = Common.GetMyDesktop();
MachineStuff.oneInstanceCheck?.Close();
_ = Process.Start(Application.ExecutablePath, desktop);
Logger.LogDebug($"Started on desktop {desktop}");
@@ -514,7 +514,7 @@ namespace MouseWithoutBorders
internal static void SendHeartBeat(bool initial = false)
{
SendPackage(ID.ALL, initial && Encryption.GeneratedKey ? PackageType.Heartbeat_ex : PackageType.Heartbeat);
SendPackage(ID.ALL, initial && Common.GeneratedKey ? PackageType.Heartbeat_ex : PackageType.Heartbeat);
}
private static long lastSendNextMachine;
@@ -550,7 +550,7 @@ namespace MouseWithoutBorders
internal static void SendAwakeBeat()
{
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && WinAPI.IsMyDesktopActive() &&
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && Common.IsMyDesktopActive() &&
Setting.Values.BlockScreenSaver && lastRealInputEventCount != Event.RealInputEventCount)
{
SendPackage(ID.ALL, PackageType.Awake);
@@ -568,7 +568,7 @@ namespace MouseWithoutBorders
{
if (lastInputEventCount == Event.InputEventCount)
{
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && WinAPI.IsMyDesktopActive())
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && Common.IsMyDesktopActive())
{
PokeMyself();
}
@@ -577,13 +577,13 @@ namespace MouseWithoutBorders
lastInputEventCount = Event.InputEventCount;
}
internal static void PokeMyself()
private static void PokeMyself()
{
int x, y = 0;
for (int i = 0; i < 10; i++)
{
x = Encryption.Ran.Next(-9, 10);
x = Ran.Next(-9, 10);
InputSimulation.MoveMouseRelative(x, y);
Thread.Sleep(50);
InputSimulation.MoveMouseRelative(-x, -y);
@@ -677,7 +677,7 @@ namespace MouseWithoutBorders
{
Common.MMSleep(0.2);
InputSimulation.SendKey(new KEYBDDATA() { wVk = (int)VK.SNAPSHOT });
InputSimulation.SendKey(new KEYBDDATA() { dwFlags = (int)WM.LLKHF.UP, wVk = (int)VK.SNAPSHOT });
InputSimulation.SendKey(new KEYBDDATA() { dwFlags = (int)Common.LLKHF.UP, wVk = (int)VK.SNAPSHOT });
Logger.LogDebug("PrepareScreenCapture: SNAPSHOT simulated.");
@@ -710,7 +710,7 @@ namespace MouseWithoutBorders
"\"" + Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe") +
"\"",
"\"" + file + "\"",
WinAPI.GetInputDesktop(),
GetInputDesktop(),
1);
// CreateNormalIntegrityProcess(Environment.ExpandEnvironmentVariables(@"%SystemRoot%\System32\Mspaint.exe") +
@@ -919,7 +919,7 @@ namespace MouseWithoutBorders
try
{
data.Id = Interlocked.Increment(ref Package.PackageID);
data.Id = Interlocked.Increment(ref PackageID);
bool updateClientSockets = false;
@@ -999,7 +999,7 @@ namespace MouseWithoutBorders
}
else
{
Package.PackageSent.Nil++;
PackageSent.Nil++;
}
}
@@ -1379,7 +1379,7 @@ namespace MouseWithoutBorders
if (string.IsNullOrEmpty(machine_Name))
{
machine_Name = "RANDOM" + Encryption.Ran.Next().ToString(CultureInfo.CurrentCulture);
machine_Name = "RANDOM" + Ran.Next().ToString(CultureInfo.CurrentCulture);
}
}
@@ -1533,13 +1533,13 @@ namespace MouseWithoutBorders
internal static void SendOrReceiveARandomDataBlockPerInitialIV(Stream st, bool send = true)
{
byte[] ranData = new byte[Encryption.SymAlBlockSize];
byte[] ranData = new byte[SymAlBlockSize];
try
{
if (send)
{
ranData = RandomNumberGenerator.GetBytes(Encryption.SymAlBlockSize);
ranData = RandomNumberGenerator.GetBytes(SymAlBlockSize);
st.Write(ranData, 0, ranData.Length);
}
else

View File

@@ -109,7 +109,7 @@ namespace MouseWithoutBorders.Class
// Install Mouse Hook
mouseHookProcedure = new NativeMethods.HookProc(MouseHookProc);
hMouseHook = NativeMethods.SetWindowsHookEx(
WM.WH_MOUSE_LL,
Common.WH_MOUSE_LL,
mouseHookProcedure,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[0]),
@@ -126,7 +126,7 @@ namespace MouseWithoutBorders.Class
// Install Keyboard Hook
keyboardHookProcedure = new NativeMethods.HookProc(KeyboardHookProc);
hKeyboardHook = NativeMethods.SetWindowsHookEx(
WM.WH_KEYBOARD_LL,
Common.WH_KEYBOARD_LL,
keyboardHookProcedure,
Marshal.GetHINSTANCE(
Assembly.GetExecutingAssembly().GetModules()[0]),
@@ -233,7 +233,7 @@ namespace MouseWithoutBorders.Class
if (nCode >= 0 && MouseEvent != null)
{
if (wParam == WM.WM_LBUTTONUP && SkipMouseUpCount > 0)
if (wParam == Common.WM_LBUTTONUP && SkipMouseUpCount > 0)
{
Logger.LogDebug($"{nameof(SkipMouseUpCount)}: {SkipMouseUpCount}.");
SkipMouseUpCount--;
@@ -241,7 +241,7 @@ namespace MouseWithoutBorders.Class
return rv;
}
if ((wParam == WM.WM_LBUTTONUP || wParam == WM.WM_LBUTTONDOWN) && SkipMouseUpDown)
if ((wParam == Common.WM_LBUTTONUP || wParam == Common.WM_LBUTTONDOWN) && SkipMouseUpDown)
{
rv = NativeMethods.CallNextHookEx(hMouseHook, nCode, wParam, lParam);
return rv;
@@ -370,7 +370,7 @@ namespace MouseWithoutBorders.Class
private bool ProcessKeyEx(int vkCode, int flags, KEYBDDATA hookCallbackKeybdData)
{
if ((flags & (int)WM.LLKHF.UP) == (int)WM.LLKHF.UP)
if ((flags & (int)Common.LLKHF.UP) == (int)Common.LLKHF.UP)
{
EasyMouseKeyDown = false;
@@ -553,7 +553,7 @@ namespace MouseWithoutBorders.Class
KeyboardEvent(hookCallbackKeybdData);
}
hookCallbackKeybdData.dwFlags |= (int)WM.LLKHF.UP;
hookCallbackKeybdData.dwFlags |= (int)Common.LLKHF.UP;
foreach (var code in codes)
{

View File

@@ -112,12 +112,12 @@ namespace MouseWithoutBorders.Class
uint scanCode = 0;
// http://msdn.microsoft.com/en-us/library/ms644967(VS.85).aspx
if ((kd.dwFlags & (int)WM.LLKHF.UP) == (int)WM.LLKHF.UP)
if ((kd.dwFlags & (int)Common.LLKHF.UP) == (int)Common.LLKHF.UP)
{
dwFlags = NativeMethods.KEYEVENTF.KEYUP;
}
if ((kd.dwFlags & (int)WM.LLKHF.EXTENDED) == (int)WM.LLKHF.EXTENDED)
if ((kd.dwFlags & (int)Common.LLKHF.EXTENDED) == (int)Common.LLKHF.EXTENDED)
{
dwFlags |= NativeMethods.KEYEVENTF.EXTENDEDKEY;
}
@@ -173,44 +173,44 @@ namespace MouseWithoutBorders.Class
mouse_input.mi.dy = (int)dy;
mouse_input.mi.mouseData = md.WheelDelta;
if (md.dwFlags != WM.WM_MOUSEMOVE)
if (md.dwFlags != Common.WM_MOUSEMOVE)
{
Logger.LogDebug($"InputSimulation.SendMouse: x = {md.X}, y = {md.Y}, WheelDelta = {md.WheelDelta}, dwFlags = {md.dwFlags}.");
}
switch (md.dwFlags)
{
case WM.WM_MOUSEMOVE:
case Common.WM_MOUSEMOVE:
mouse_input.mi.dwFlags |= (int)(NativeMethods.MOUSEEVENTF.MOVE | NativeMethods.MOUSEEVENTF.ABSOLUTE);
break;
case WM.WM_LBUTTONDOWN:
case Common.WM_LBUTTONDOWN:
mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.LEFTDOWN;
break;
case WM.WM_LBUTTONUP:
case Common.WM_LBUTTONUP:
mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.LEFTUP;
break;
case WM.WM_RBUTTONDOWN:
case Common.WM_RBUTTONDOWN:
mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.RIGHTDOWN;
break;
case WM.WM_RBUTTONUP:
case Common.WM_RBUTTONUP:
mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.RIGHTUP;
break;
case WM.WM_MBUTTONDOWN:
case Common.WM_MBUTTONDOWN:
mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.MIDDLEDOWN;
break;
case WM.WM_MBUTTONUP:
case Common.WM_MBUTTONUP:
mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.MIDDLEUP;
break;
case WM.WM_MOUSEWHEEL:
case Common.WM_MOUSEWHEEL:
mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.WHEEL;
break;
case WM.WM_MOUSEHWHEEL:
case Common.WM_MOUSEHWHEEL:
mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.HWHEEL;
break;
case WM.WM_XBUTTONUP:
case Common.WM_XBUTTONUP:
mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.XUP;
break;
case WM.WM_XBUTTONDOWN:
case Common.WM_XBUTTONDOWN:
mouse_input.mi.dwFlags |= (int)NativeMethods.MOUSEEVENTF.XDOWN;
break;
@@ -373,7 +373,7 @@ namespace MouseWithoutBorders.Class
{
eatKey = false;
if ((flags & (int)WM.LLKHF.UP) == (int)WM.LLKHF.UP)
if ((flags & (int)Common.LLKHF.UP) == (int)Common.LLKHF.UP)
{
switch ((VK)vkCode)
{

View File

@@ -143,7 +143,7 @@ namespace MouseWithoutBorders.Class
return;
}
string myDesktop = WinAPI.GetMyDesktop();
string myDesktop = Common.GetMyDesktop();
if (firstArg.Equals("winlogon", StringComparison.OrdinalIgnoreCase))
{
@@ -305,8 +305,8 @@ namespace MouseWithoutBorders.Class
MachineStuff.ClearComputerMatrix();
Setting.Values.MyKey = securityKey;
Encryption.MyKey = securityKey;
Encryption.MagicNumber = Encryption.Get24BitHash(Encryption.MyKey);
Common.MyKey = securityKey;
Common.MagicNumber = Common.Get24BitHash(Common.MyKey);
MachineStuff.MachineMatrix = new string[MachineStuff.MAX_MACHINE] { pcName.Trim().ToUpper(CultureInfo.CurrentCulture), Common.MachineName.Trim(), string.Empty, string.Empty };
string[] machines = MachineStuff.MachineMatrix;
@@ -328,8 +328,8 @@ namespace MouseWithoutBorders.Class
Setting.Values.EasyMouse = (int)EasyMouseOption.Enable;
MachineStuff.ClearComputerMatrix();
Setting.Values.MyKey = Encryption.MyKey = Encryption.CreateRandomKey();
Encryption.GeneratedKey = true;
Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
Common.GeneratedKey = true;
Setting.Values.PauseInstantSaving = false;
Setting.Values.SaveSettings();

View File

@@ -109,9 +109,9 @@ namespace MouseWithoutBorders.Class
var shouldReopenSockets = false;
if (Encryption.MyKey != _properties.SecurityKey.Value)
if (Common.MyKey != _properties.SecurityKey.Value)
{
Encryption.MyKey = _properties.SecurityKey.Value;
Common.MyKey = _properties.SecurityKey.Value;
shouldReopenSockets = true;
}
@@ -489,7 +489,7 @@ namespace MouseWithoutBorders.Class
}
else
{
string randomKey = Encryption.CreateDefaultKey();
string randomKey = Common.CreateDefaultKey();
_properties.SecurityKey.Value = randomKey;
return randomKey;
@@ -1055,7 +1055,7 @@ namespace MouseWithoutBorders.Class
if (machineId == 0)
{
var newMachineId = Encryption.Ran.Next();
var newMachineId = Common.Ran.Next();
_properties.MachineID.Value = newMachineId;
machineId = newMachineId;
if (!PauseInstantSaving)

View File

@@ -101,7 +101,7 @@ namespace MouseWithoutBorders.Class
{
if (encryptedStream == null && BackingSocket.Connected)
{
encryptedStream = Encryption.GetEncryptedStream(new NetworkStream(BackingSocket));
encryptedStream = Common.GetEncryptedStream(new NetworkStream(BackingSocket));
Common.SendOrReceiveARandomDataBlockPerInitialIV(encryptedStream);
}
@@ -115,7 +115,7 @@ namespace MouseWithoutBorders.Class
{
if (decryptedStream == null && BackingSocket.Connected)
{
decryptedStream = Encryption.GetDecryptedStream(new NetworkStream(BackingSocket));
decryptedStream = Common.GetDecryptedStream(new NetworkStream(BackingSocket));
Common.SendOrReceiveARandomDataBlockPerInitialIV(decryptedStream, false);
}
@@ -181,7 +181,7 @@ namespace MouseWithoutBorders.Class
Logger.LogDebug("SocketStuff started.");
bASE_PORT = port;
Encryption.Ran = new Random();
Common.Ran = new Random();
Logger.LogDebug("Validating session...");
@@ -221,11 +221,11 @@ namespace MouseWithoutBorders.Class
if (Setting.Values.IsMyKeyRandom)
{
Setting.Values.MyKey = Encryption.MyKey;
Setting.Values.MyKey = Common.MyKey;
}
Encryption.MagicNumber = Encryption.Get24BitHash(Encryption.MyKey);
Package.PackageID = Setting.Values.PackageID;
Common.MagicNumber = Common.Get24BitHash(Common.MyKey);
Common.PackageID = Setting.Values.PackageID;
TcpPort = bASE_PORT;
@@ -242,7 +242,7 @@ namespace MouseWithoutBorders.Class
Logger.TelemetryLogTrace($"{nameof(SocketStuff)}: {e.Message}", SeverityLevel.Warning);
}
WinAPI.GetScreenConfig();
Common.GetScreenConfig();
if (firstRun && Common.RunOnScrSaverDesktop)
{
@@ -305,7 +305,7 @@ namespace MouseWithoutBorders.Class
sleepSecs = 10;
// It is reasonable to give a try on restarting MwB processes in other sessions.
if (restartCount++ < 5 && WinAPI.IsMyDesktopActive() && !Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
if (restartCount++ < 5 && Common.IsMyDesktopActive() && !Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
{
Logger.TelemetryLogTrace("Restarting the service dues to WSAEADDRINUSE.", SeverityLevel.Warning);
Program.StartService();
@@ -361,7 +361,7 @@ namespace MouseWithoutBorders.Class
{
Setting.Values.LastX = Common.LastX;
Setting.Values.LastY = Common.LastY;
Setting.Values.PackageID = Package.PackageID;
Setting.Values.PackageID = Common.PackageID;
// Common.Log("Saving IP: " + Setting.Values.DesMachineID.ToString(CultureInfo.CurrentCulture));
Setting.Values.DesMachineID = (uint)Common.DesMachineID;
@@ -505,10 +505,10 @@ namespace MouseWithoutBorders.Class
throw new ExpectedSocketException(log);
}
bytes[3] = (byte)((Encryption.MagicNumber >> 24) & 0xFF);
bytes[2] = (byte)((Encryption.MagicNumber >> 16) & 0xFF);
bytes[3] = (byte)((Common.MagicNumber >> 24) & 0xFF);
bytes[2] = (byte)((Common.MagicNumber >> 16) & 0xFF);
bytes[1] = 0;
for (int i = 2; i < Package.PACKAGE_SIZE; i++)
for (int i = 2; i < Common.PACKAGE_SIZE; i++)
{
bytes[1] = (byte)(bytes[1] + bytes[i]);
}
@@ -535,13 +535,13 @@ namespace MouseWithoutBorders.Class
magic = (buf[3] << 24) + (buf[2] << 16);
if (magic != (Encryption.MagicNumber & 0xFFFF0000))
if (magic != (Common.MagicNumber & 0xFFFF0000))
{
Logger.Log("Magic number invalid!");
buf[0] = (byte)PackageType.Invalid;
}
for (int i = 2; i < Package.PACKAGE_SIZE; i++)
for (int i = 2; i < Common.PACKAGE_SIZE; i++)
{
checksum = (byte)(checksum + buf[i]);
}
@@ -557,7 +557,7 @@ namespace MouseWithoutBorders.Class
internal static DATA TcpReceiveData(TcpSk tcp, out int bytesReceived)
{
byte[] buf = new byte[Package.PACKAGE_SIZE_EX];
byte[] buf = new byte[Common.PACKAGE_SIZE_EX];
Stream decryptedStream = tcp.DecryptedStream;
if (tcp.BackingSocket == null || !tcp.BackingSocket.Connected || decryptedStream == null)
@@ -571,9 +571,9 @@ namespace MouseWithoutBorders.Class
try
{
bytesReceived = decryptedStream.ReadEx(buf, 0, Package.PACKAGE_SIZE);
bytesReceived = decryptedStream.ReadEx(buf, 0, Common.PACKAGE_SIZE);
if (bytesReceived != Package.PACKAGE_SIZE)
if (bytesReceived != Common.PACKAGE_SIZE)
{
buf[0] = bytesReceived == 0 ? (byte)PackageType.Error : (byte)PackageType.Invalid;
}
@@ -586,9 +586,9 @@ namespace MouseWithoutBorders.Class
if (package.IsBigPackage)
{
bytesReceived = decryptedStream.ReadEx(buf, Package.PACKAGE_SIZE, Package.PACKAGE_SIZE);
bytesReceived = decryptedStream.ReadEx(buf, Common.PACKAGE_SIZE, Common.PACKAGE_SIZE);
if (bytesReceived != Package.PACKAGE_SIZE)
if (bytesReceived != Common.PACKAGE_SIZE)
{
buf[0] = bytesReceived == 0 ? (byte)PackageType.Error : (byte)PackageType.Invalid;
}
@@ -614,28 +614,28 @@ namespace MouseWithoutBorders.Class
switch (type)
{
case PackageType.Keyboard:
Package.PackageSent.Keyboard++;
Common.PackageSent.Keyboard++;
break;
case PackageType.Mouse:
Package.PackageSent.Mouse++;
Common.PackageSent.Mouse++;
break;
case PackageType.Heartbeat:
case PackageType.Heartbeat_ex:
Package.PackageSent.Heartbeat++;
Common.PackageSent.Heartbeat++;
break;
case PackageType.Hello:
Package.PackageSent.Hello++;
Common.PackageSent.Hello++;
break;
case PackageType.ByeBye:
Package.PackageSent.ByeBye++;
Common.PackageSent.ByeBye++;
break;
case PackageType.Matrix:
Package.PackageSent.Matrix++;
Common.PackageSent.Matrix++;
break;
default:
@@ -643,11 +643,11 @@ namespace MouseWithoutBorders.Class
switch (subtype)
{
case (byte)PackageType.ClipboardText:
Package.PackageSent.ClipboardText++;
Common.PackageSent.ClipboardText++;
break;
case (byte)PackageType.ClipboardImage:
Package.PackageSent.ClipboardImage++;
Common.PackageSent.ClipboardImage++;
break;
default:
@@ -1266,7 +1266,7 @@ namespace MouseWithoutBorders.Class
string strIP = string.Empty;
ID remoteID = ID.NONE;
byte[] buf = RandomNumberGenerator.GetBytes(Package.PACKAGE_SIZE_EX);
byte[] buf = RandomNumberGenerator.GetBytes(Common.PACKAGE_SIZE_EX);
d = new DATA(buf);
TcpSk currentTcp = tcp;
@@ -1280,8 +1280,8 @@ namespace MouseWithoutBorders.Class
try
{
currentSocket.SendBufferSize = Package.PACKAGE_SIZE * 10000;
currentSocket.ReceiveBufferSize = Package.PACKAGE_SIZE * 10000;
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;
@@ -1829,7 +1829,7 @@ namespace MouseWithoutBorders.Class
}
while (rv > 0);
if ((rv = Package.PACKAGE_SIZE - (sentCount % Package.PACKAGE_SIZE)) > 0)
if ((rv = Common.PACKAGE_SIZE - (sentCount % Common.PACKAGE_SIZE)) > 0)
{
Array.Clear(buf, 0, buf.Length);
ecStream.Write(buf, 0, rv);
@@ -1900,7 +1900,7 @@ namespace MouseWithoutBorders.Class
}
while (rv > 0);
if ((rv = sentCount % Package.PACKAGE_SIZE) > 0)
if ((rv = sentCount % Common.PACKAGE_SIZE) > 0)
{
Array.Clear(buf, 0, buf.Length);
ecStream.Write(buf, 0, rv);
@@ -1984,7 +1984,7 @@ namespace MouseWithoutBorders.Class
if (tcp.MachineId == Setting.Values.MachineId)
{
tcp = null;
Setting.Values.MachineId = Encryption.Ran.Next();
Setting.Values.MachineId = Common.Ran.Next();
InitAndCleanup.UpdateMachineTimeAndID();
InitAndCleanup.PleaseReopenSocket = InitAndCleanup.REOPEN_WHEN_HOTKEY;

View File

@@ -70,7 +70,7 @@ namespace MouseWithoutBorders.Class
continue;
}
if (!WinAPI.IsMyDesktopActive())
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.");

View File

@@ -270,15 +270,15 @@ internal static class Clipboard
int index = 0;
int len;
DATA package = new();
byte[] buf = new byte[Package.PACKAGE_SIZE_EX];
int dataStart = Package.PACKAGE_SIZE_EX - DATA_SIZE;
byte[] buf = new byte[Common.PACKAGE_SIZE_EX];
int dataStart = Common.PACKAGE_SIZE_EX - DATA_SIZE;
while (true)
{
if ((index + DATA_SIZE) > l)
{
len = l - index;
Array.Clear(buf, 0, Package.PACKAGE_SIZE_EX);
Array.Clear(buf, 0, Common.PACKAGE_SIZE_EX);
}
else
{
@@ -315,7 +315,7 @@ internal static class Clipboard
}
MemoryStream m = new();
int dataStart = Package.PACKAGE_SIZE_EX - DATA_SIZE;
int dataStart = Common.PACKAGE_SIZE_EX - DATA_SIZE;
m.Write(data.Bytes, dataStart, DATA_SIZE);
int unexpectedCount = 0;
@@ -809,27 +809,27 @@ internal static class Clipboard
MachineName = Common.MachineName,
};
byte[] buf = new byte[Package.PACKAGE_SIZE_EX];
byte[] buf = new byte[Common.PACKAGE_SIZE_EX];
NetworkStream ns = new(s);
enStream = Encryption.GetEncryptedStream(ns);
enStream = Common.GetEncryptedStream(ns);
Common.SendOrReceiveARandomDataBlockPerInitialIV(enStream);
Logger.LogDebug($"{nameof(ShakeHand)}: Writing header package.");
enStream.Write(package.Bytes, 0, Package.PACKAGE_SIZE_EX);
enStream.Write(package.Bytes, 0, Common.PACKAGE_SIZE_EX);
Logger.LogDebug($"{nameof(ShakeHand)}: Sent: clientPush={clientPushData}, postAction={postAction}.");
deStream = Encryption.GetDecryptedStream(ns);
deStream = Common.GetDecryptedStream(ns);
Common.SendOrReceiveARandomDataBlockPerInitialIV(deStream, false);
Logger.LogDebug($"{nameof(ShakeHand)}: Reading header package.");
int bytesReceived = deStream.ReadEx(buf, 0, Package.PACKAGE_SIZE_EX);
int bytesReceived = deStream.ReadEx(buf, 0, Common.PACKAGE_SIZE_EX);
package.Bytes = buf;
string name = "Unknown";
if (bytesReceived == Package.PACKAGE_SIZE_EX)
if (bytesReceived == Common.PACKAGE_SIZE_EX)
{
if (package.Type is PackageType.Clipboard or PackageType.ClipboardPush)
{

View File

@@ -1,25 +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;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
// <summary>
// Package format/conversion.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
internal enum ClipboardPostAction : uint
{
Other = 0,
Desktop = 1,
Mspaint = 2,
}

View File

@@ -1,150 +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;
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.Core.DATA", Justification = "Dotnet port with style preservation")]
// <summary>
// Package format/conversion.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
// The beauty of "union" in C#
[StructLayout(LayoutKind.Explicit)]
internal sealed 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 ? Package.PACKAGE_SIZE_EX : Package.PACKAGE_SIZE];
Array.Copy(StructToBytes(this), buf, IsBigPackage ? Package.PACKAGE_SIZE_EX : Package.PACKAGE_SIZE);
return buf;
}
set
{
Debug.Assert(value.Length <= Package.PACKAGE_SIZE_EX, "Length > package size");
byte[] buf = new byte[Package.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[Package.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();
}
}

View File

@@ -67,20 +67,20 @@ internal static class DragDrop
return;
}
if (wParam == WM.WM_LBUTTONDOWN)
if (wParam == Common.WM_LBUTTONDOWN)
{
MouseDown = true;
DragMachine = MachineStuff.desMachineID;
MachineStuff.dropMachineID = ID.NONE;
Logger.LogDebug("DragDropStep01: MouseDown");
}
else if (wParam == WM.WM_LBUTTONUP)
else if (wParam == Common.WM_LBUTTONUP)
{
MouseDown = false;
Logger.LogDebug("DragDropStep01: MouseUp");
}
if (wParam == WM.WM_RBUTTONUP && IsDropping)
if (wParam == Common.WM_RBUTTONUP && IsDropping)
{
IsDropping = false;
Clipboard.LastIDWithClipboardData = ID.NONE;
@@ -252,7 +252,7 @@ internal static class DragDrop
internal static void DragDropStep09(int wParam)
{
if (wParam == WM.WM_MOUSEMOVE && IsDropping)
if (wParam == Common.WM_MOUSEMOVE && IsDropping)
{
// Show/Move form
Common.DoSomethingInUIThread(() =>
@@ -260,7 +260,7 @@ internal static class DragDrop
_ = NativeMethods.PostMessage(Common.MainForm.Handle, NativeMethods.WM_SHOW_DRAG_DROP, (IntPtr)0, (IntPtr)0);
});
}
else if (wParam == WM.WM_LBUTTONUP && (IsDropping || IsDragging))
else if (wParam == Common.WM_LBUTTONUP && (IsDropping || IsDragging))
{
if (IsDropping)
{

View File

@@ -1,245 +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;
using System.Collections.Concurrent;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading.Tasks;
// <summary>
// Encrypt/decrypt implementation.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
internal static class Encryption
{
#pragma warning disable SYSLIB0021
private static AesCryptoServiceProvider symAl;
#pragma warning restore SYSLIB0021
#pragma warning disable SA1307 // Accessible fields should begin with upper-case letter
internal static string myKey;
#pragma warning restore SA1307
private static uint magicNumber;
private static Random ran = new(); // Used for non encryption related functionality.
internal const int SymAlBlockSize = 16;
/// <summary>
/// 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
/// </summary>
private static readonly string InitialIV = ulong.MaxValue.ToString(CultureInfo.InvariantCulture);
internal static Random Ran
{
get => Encryption.ran ??= new Random();
set => Encryption.ran = value;
}
internal static uint MagicNumber
{
get => Encryption.magicNumber;
set => Encryption.magicNumber = value;
}
internal static string MyKey
{
get => Encryption.myKey;
set
{
if (Encryption.myKey != value)
{
Encryption.myKey = value;
_ = Task.Factory.StartNew(
() => Encryption.GenLegalKey(),
System.Threading.CancellationToken.None,
TaskCreationOptions.None,
TaskScheduler.Default); // Cache the key to improve UX.
}
}
}
private 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)
{
Logger.Log(e);
}
}
private static readonly ConcurrentDictionary<string, byte[]> LegalKeyDictionary = new(StringComparer.OrdinalIgnoreCase);
private static byte[] GenLegalKey()
{
byte[] rv;
string myKey = Encryption.MyKey;
if (!LegalKeyDictionary.TryGetValue(myKey, out byte[] value))
{
Rfc2898DeriveBytes key = new(
myKey,
Common.GetBytesU(InitialIV),
50000,
HashAlgorithmName.SHA512);
rv = key.GetBytes(32);
_ = LegalKeyDictionary.AddOrUpdate(myKey, rv, (k, v) => rv);
}
else
{
rv = value;
}
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 Common.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.PACKAGE_SIZE];
for (int i = 0; i < Package.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);
}
Logger.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;
internal 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;
}
}

View File

@@ -70,7 +70,7 @@ internal static class Event
// Check if easy mouse setting is enabled.
bool isEasyMouseEnabled = IsSwitchingByMouseEnabled();
if (isEasyMouseEnabled && Common.Sk != null && (Common.DesMachineID == Common.MachineID || !Setting.Values.MoveMouseRelatively) && e.dwFlags == WM.WM_MOUSEMOVE)
if (isEasyMouseEnabled && Common.Sk != null && (Common.DesMachineID == Common.MachineID || !Setting.Values.MoveMouseRelatively) && e.dwFlags == Common.WM_MOUSEMOVE)
{
Point p = MachineStuff.MoveToMyNeighbourIfNeeded(e.X, e.Y, MachineStuff.desMachineID);
@@ -115,7 +115,7 @@ internal static class Event
Common.SkSend(MousePackage, null, false);
if (MousePackage.Md.dwFlags is WM.WM_LBUTTONUP or WM.WM_RBUTTONUP)
if (MousePackage.Md.dwFlags is Common.WM_LBUTTONUP or Common.WM_RBUTTONUP)
{
Thread.Sleep(10);
}
@@ -265,7 +265,7 @@ internal static class Event
KeybdPackage.Kd = e;
KeybdPackage.DateTime = Common.GetTick();
Common.SkSend(KeybdPackage, null, false);
if (KeybdPackage.Kd.dwFlags is WM.WM_KEYUP or WM.WM_SYSKEYUP)
if (KeybdPackage.Kd.dwFlags is Common.WM_KEYUP or Common.WM_SYSKEYUP)
{
Thread.Sleep(10);
}

View File

@@ -290,7 +290,7 @@ internal static class Helper
return;
}
if (!WinAPI.IsMyDesktopActive())
if (!Common.IsMyDesktopActive())
{
return;
}
@@ -314,7 +314,7 @@ internal static class Helper
_ = Launch.CreateProcessInInputDesktopSession(
$"\"{Path.GetDirectoryName(Application.ExecutablePath)}\\{HelperProcessName}.exe\"",
string.Empty,
WinAPI.GetInputDesktop(),
Common.GetInputDesktop(),
0);
Clipboard.HasSwitchedMachineSinceLastCopy = true;
@@ -379,7 +379,7 @@ internal static class Helper
log += "=============================================================================================================================\r\n";
log += $"{Application.ProductName} version {Application.ProductVersion}\r\n";
log += $"{Setting.Values.Username}/{Encryption.GetDebugInfo(Encryption.MyKey)}\r\n";
log += $"{Setting.Values.Username}/{Common.GetDebugInfo(Common.MyKey)}\r\n";
log += $"{Common.MachineName}/{Common.MachineID}/{Common.DesMachineID}\r\n";
log += $"Id: {Setting.Values.DeviceId}\r\n";
log += $"Matrix: {string.Join(",", MachineStuff.MachineMatrix)}\r\n";

View File

@@ -1,19 +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.
// <summary>
// Package format/conversion.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
internal enum ID : uint
{
NONE = 0,
ALL = 255,
}

View File

@@ -89,23 +89,23 @@ internal static class InitAndCleanup
internal static void Init()
{
_ = Helper.GetUserName();
Encryption.GeneratedKey = true;
Common.GeneratedKey = true;
try
{
Encryption.MyKey = Setting.Values.MyKey;
Common.MyKey = Setting.Values.MyKey;
int tmp = Setting.Values.MyKeyDaysToExpire;
}
catch (FormatException e)
{
Encryption.KeyCorrupted = true;
Setting.Values.MyKey = Encryption.MyKey = Encryption.CreateRandomKey();
Common.KeyCorrupted = true;
Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
Logger.Log(e.Message);
}
catch (CryptographicException e)
{
Encryption.KeyCorrupted = true;
Setting.Values.MyKey = Encryption.MyKey = Encryption.CreateRandomKey();
Common.KeyCorrupted = true;
Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
Logger.Log(e.Message);
}
@@ -127,14 +127,14 @@ internal static class InitAndCleanup
bool dummy = Setting.Values.DrawMouseEx;
Common.Is64bitOS = IntPtr.Size == 8;
Common.tcpPort = Setting.Values.TcpPort;
WinAPI.GetScreenConfig();
Package.PackageSent = new PackageMonitor(0);
Package.PackageReceived = new PackageMonitor(0);
Common.GetScreenConfig();
Common.PackageSent = new PackageMonitor(0);
Common.PackageReceived = new PackageMonitor(0);
SetupMachineNameAndID();
Encryption.InitEncryption();
Common.InitEncryption();
CreateHelperThreads();
SystemEvents.DisplaySettingsChanged += new EventHandler(WinAPI.SystemEvents_DisplaySettingsChanged);
SystemEvents.DisplaySettingsChanged += new EventHandler(Common.SystemEvents_DisplaySettingsChanged);
NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
PleaseReopenSocket = 9;
@@ -220,7 +220,7 @@ internal static class InitAndCleanup
lastReleaseAllKeysCall = Common.GetTick();
KEYBDDATA kd;
kd.dwFlags = (int)WM.LLKHF.UP;
kd.dwFlags = (int)Common.LLKHF.UP;
VK[] keys = new VK[]
{
@@ -266,7 +266,7 @@ internal static class InitAndCleanup
true);
}
if (!WinAPI.IsMyDesktopActive())
if (!Common.IsMyDesktopActive())
{
PleaseReopenSocket = 0;
}

View File

@@ -1,25 +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.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
// <summary>
// Package format/conversion.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
[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;
}

View File

@@ -121,52 +121,52 @@ internal static class Logger
{
string log;
if (!lastPackageSent.Equals(Package.PackageSent))
if (!lastPackageSent.Equals(Common.PackageSent))
{
log = string.Format(
CultureInfo.CurrentCulture,
"SENT:" + HeaderSENT,
Package.PackageSent.Heartbeat,
Package.PackageSent.Keyboard,
Package.PackageSent.Mouse,
Package.PackageSent.Hello,
Package.PackageSent.Matrix,
Package.PackageSent.ClipboardText,
Package.PackageSent.ClipboardImage,
Package.PackageSent.ByeBye,
Package.PackageSent.Clipboard,
Package.PackageSent.ClipboardDragDrop,
Package.PackageSent.ClipboardDragDropEnd,
Package.PackageSent.ExplorerDragDrop,
Common.PackageSent.Heartbeat,
Common.PackageSent.Keyboard,
Common.PackageSent.Mouse,
Common.PackageSent.Hello,
Common.PackageSent.Matrix,
Common.PackageSent.ClipboardText,
Common.PackageSent.ClipboardImage,
Common.PackageSent.ByeBye,
Common.PackageSent.Clipboard,
Common.PackageSent.ClipboardDragDrop,
Common.PackageSent.ClipboardDragDropEnd,
Common.PackageSent.ExplorerDragDrop,
Event.inputEventCount,
Package.PackageSent.Nil);
Common.PackageSent.Nil);
Log(log);
lastPackageSent = Package.PackageSent; // Copy data
lastPackageSent = Common.PackageSent; // Copy data
}
if (!lastPackageReceived.Equals(Package.PackageReceived))
if (!lastPackageReceived.Equals(Common.PackageReceived))
{
log = string.Format(
CultureInfo.CurrentCulture,
"RECEIVED:" + HeaderRECEIVED,
Package.PackageReceived.Heartbeat,
Package.PackageReceived.Keyboard,
Package.PackageReceived.Mouse,
Package.PackageReceived.Hello,
Package.PackageReceived.Matrix,
Package.PackageReceived.ClipboardText,
Package.PackageReceived.ClipboardImage,
Package.PackageReceived.ByeBye,
Package.PackageReceived.Clipboard,
Package.PackageReceived.ClipboardDragDrop,
Package.PackageReceived.ClipboardDragDropEnd,
Package.PackageReceived.ExplorerDragDrop,
Common.PackageReceived.Heartbeat,
Common.PackageReceived.Keyboard,
Common.PackageReceived.Mouse,
Common.PackageReceived.Hello,
Common.PackageReceived.Matrix,
Common.PackageReceived.ClipboardText,
Common.PackageReceived.ClipboardImage,
Common.PackageReceived.ByeBye,
Common.PackageReceived.Clipboard,
Common.PackageReceived.ClipboardDragDrop,
Common.PackageReceived.ClipboardDragDropEnd,
Common.PackageReceived.ExplorerDragDrop,
Event.invalidPackageCount,
Package.PackageReceived.Nil,
Common.PackageReceived.Nil,
Receiver.processedPackageCount,
Receiver.skippedPackageCount);
Log(log);
lastPackageReceived = Package.PackageReceived;
lastPackageReceived = Common.PackageReceived;
}
}
@@ -209,9 +209,9 @@ internal static class Logger
"Private Mem: " + (Process.GetCurrentProcess().PrivateMemorySize64 / 1024).ToString(CultureInfo.CurrentCulture) + "KB",
sb.ToString());
if (!string.IsNullOrEmpty(Encryption.myKey))
if (!string.IsNullOrEmpty(Common.myKey))
{
log = log.Replace(Encryption.MyKey, Encryption.GetDebugInfo(Encryption.MyKey));
log = log.Replace(Common.MyKey, Common.GetDebugInfo(Common.MyKey));
}
log += Thread.DumpThreadsStack();
@@ -251,18 +251,14 @@ internal static class Logger
{
typeof(Clipboard),
typeof(DragDrop),
typeof(Encryption),
typeof(Event),
typeof(InitAndCleanup),
typeof(Helper),
typeof(Launch),
typeof(Logger),
typeof(MachineStuff),
typeof(Package),
typeof(Receiver),
typeof(Service),
typeof(WinAPI),
typeof(WM),
};
foreach (var staticType in staticTypes)
{
@@ -298,7 +294,7 @@ internal static class Logger
// strArr[3] = t.FullName;
strArr[4] = " = ";
strArr[5] = objName.Equals("myKey", StringComparison.OrdinalIgnoreCase)
? Encryption.GetDebugInfo(objString)
? Common.GetDebugInfo(objString)
: objName.Equals("lastClipboardObject", StringComparison.OrdinalIgnoreCase)
? string.Empty
: objString

View File

@@ -1,26 +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.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
// <summary>
// Package format/conversion.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
[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;
}

View File

@@ -221,9 +221,9 @@ internal static class MachineStuff
if (Setting.Values.BlockMouseAtCorners)
{
lock (WinAPI.SensitivePoints)
lock (Common.SensitivePoints)
{
foreach (Point p in WinAPI.SensitivePoints)
foreach (Point p in Common.SensitivePoints)
{
if (Math.Abs(p.X - x) < 100 && Math.Abs(p.Y - y) < 100)
{
@@ -793,8 +793,8 @@ internal static class MachineStuff
internal static void ShowSetupForm(bool reopenSockets = false)
{
Logger.LogDebug("========== BEGIN THE SETUP EXPERIENCE ==========", true);
Setting.Values.MyKey = Encryption.MyKey = Encryption.CreateRandomKey();
Encryption.GeneratedKey = true;
Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
Common.GeneratedKey = true;
if (Process.GetCurrentProcess().SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
{
@@ -1067,7 +1067,7 @@ internal static class MachineStuff
internal static void AssertOneInstancePerDesktopSession()
{
string eventName = $"Global\\{Application.ProductName}-{FrmAbout.AssemblyVersion}-{WinAPI.GetMyDesktop()}-{Common.CurrentProcess.SessionId}";
string eventName = $"Global\\{Application.ProductName}-{FrmAbout.AssemblyVersion}-{Common.GetMyDesktop()}-{Common.CurrentProcess.SessionId}";
oneInstanceCheck = new EventWaitHandle(false, EventResetMode.ManualReset, eventName, out bool created);
if (!created)

View File

@@ -1,23 +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.
// <summary>
// Package format/conversion.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
internal static class Package
{
internal const byte PACKAGE_SIZE = 32;
internal const byte PACKAGE_SIZE_EX = 64;
private const byte WP_PACKAGE_SIZE = 6;
internal static PackageMonitor PackageSent;
internal static PackageMonitor PackageReceived;
internal static int PackageID;
}

View File

@@ -1,38 +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.
// <summary>
// Package format/conversion.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
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;
}
}

View File

@@ -1,57 +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.
// <summary>
// Package format/conversion.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
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,
}

View File

@@ -93,7 +93,7 @@ internal static class Receiver
switch (package.Type)
{
case PackageType.Keyboard:
Package.PackageReceived.Keyboard++;
Common.PackageReceived.Keyboard++;
if (package.Des == Common.MachineID || package.Des == ID.ALL)
{
JustGotAKey = Common.GetTick();
@@ -102,7 +102,7 @@ internal static class Receiver
bool nonElevated = Common.RunWithNoAdminRight && false;
if (nonElevated && Setting.Values.OneWayControlMode)
{
if ((package.Kd.dwFlags & (int)WM.LLKHF.UP) == (int)WM.LLKHF.UP)
if ((package.Kd.dwFlags & (int)Common.LLKHF.UP) == (int)Common.LLKHF.UP)
{
Helper.ShowOneWayModeMessage();
}
@@ -116,7 +116,7 @@ internal static class Receiver
break;
case PackageType.Mouse:
Package.PackageReceived.Mouse++;
Common.PackageReceived.Mouse++;
if (package.Des == Common.MachineID || package.Des == ID.ALL)
{
@@ -127,16 +127,16 @@ internal static class Receiver
// NOTE(@yuyoyuppe): disabled to drop elevation requirement
bool nonElevated = Common.RunWithNoAdminRight && false;
if (nonElevated && Setting.Values.OneWayControlMode && package.Md.dwFlags != WM.WM_MOUSEMOVE)
if (nonElevated && Setting.Values.OneWayControlMode && package.Md.dwFlags != Common.WM_MOUSEMOVE)
{
if (!DragDrop.IsDropping)
{
if (package.Md.dwFlags is WM.WM_LBUTTONDOWN or WM.WM_RBUTTONDOWN)
if (package.Md.dwFlags is Common.WM_LBUTTONDOWN or Common.WM_RBUTTONDOWN)
{
Helper.ShowOneWayModeMessage();
}
}
else if (package.Md.dwFlags is WM.WM_LBUTTONUP or WM.WM_RBUTTONUP)
else if (package.Md.dwFlags is Common.WM_LBUTTONUP or Common.WM_RBUTTONUP)
{
DragDrop.IsDropping = false;
}
@@ -146,7 +146,7 @@ internal static class Receiver
if (Math.Abs(package.Md.X) >= Event.MOVE_MOUSE_RELATIVE && Math.Abs(package.Md.Y) >= Event.MOVE_MOUSE_RELATIVE)
{
if (package.Md.dwFlags == WM.WM_MOUSEMOVE)
if (package.Md.dwFlags == Common.WM_MOUSEMOVE)
{
InputSimulation.MoveMouseRelative(
package.Md.X < 0 ? package.Md.X + Event.MOVE_MOUSE_RELATIVE : package.Md.X - Event.MOVE_MOUSE_RELATIVE,
@@ -203,19 +203,19 @@ internal static class Receiver
break;
case PackageType.ExplorerDragDrop:
Package.PackageReceived.ExplorerDragDrop++;
Common.PackageReceived.ExplorerDragDrop++;
DragDrop.DragDropStep03(package);
break;
case PackageType.Heartbeat:
case PackageType.Heartbeat_ex:
Package.PackageReceived.Heartbeat++;
Common.PackageReceived.Heartbeat++;
Encryption.GeneratedKey = Encryption.GeneratedKey || package.Type == PackageType.Heartbeat_ex;
Common.GeneratedKey = Common.GeneratedKey || package.Type == PackageType.Heartbeat_ex;
if (Encryption.GeneratedKey)
if (Common.GeneratedKey)
{
Setting.Values.MyKey = Encryption.MyKey;
Setting.Values.MyKey = Common.MyKey;
Common.SendPackage(ID.ALL, PackageType.Heartbeat_ex_l2);
}
@@ -230,26 +230,26 @@ internal static class Receiver
break;
case PackageType.Heartbeat_ex_l2:
Encryption.GeneratedKey = true;
Setting.Values.MyKey = Encryption.MyKey;
Common.GeneratedKey = true;
Setting.Values.MyKey = Common.MyKey;
Common.SendPackage(ID.ALL, PackageType.Heartbeat_ex_l3);
break;
case PackageType.Heartbeat_ex_l3:
Encryption.GeneratedKey = true;
Setting.Values.MyKey = Encryption.MyKey;
Common.GeneratedKey = true;
Setting.Values.MyKey = Common.MyKey;
break;
case PackageType.Awake:
Package.PackageReceived.Heartbeat++;
Common.PackageReceived.Heartbeat++;
_ = MachineStuff.AddToMachinePool(package);
Common.HumanBeingDetected();
break;
case PackageType.Hello:
Package.PackageReceived.Hello++;
Common.PackageReceived.Hello++;
Common.SendHeartBeat();
string newMachine = MachineStuff.AddToMachinePool(package);
if (Setting.Values.MachineMatrixString == null)
@@ -262,16 +262,16 @@ internal static class Receiver
break;
case PackageType.Hi:
Package.PackageReceived.Hello++;
Common.PackageReceived.Hello++;
break;
case PackageType.ByeBye:
Package.PackageReceived.ByeBye++;
Common.PackageReceived.ByeBye++;
Common.ProcessByeByeMessage(package);
break;
case PackageType.Clipboard:
Package.PackageReceived.Clipboard++;
Common.PackageReceived.Clipboard++;
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
{
Clipboard.clipboardCopiedTime = Common.GetTick();
@@ -291,7 +291,7 @@ internal static class Receiver
break;
case PackageType.ClipboardCapture:
Package.PackageReceived.Clipboard++;
Common.PackageReceived.Clipboard++;
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
{
if (package.Des == Common.MachineID || package.Des == ID.ALL)
@@ -304,7 +304,7 @@ internal static class Receiver
break;
case PackageType.CaptureScreenCommand:
Package.PackageReceived.Clipboard++;
Common.PackageReceived.Clipboard++;
if (package.Des == Common.MachineID || package.Des == ID.ALL)
{
Common.SendImage(package.Src, Common.CaptureScreen());
@@ -313,7 +313,7 @@ internal static class Receiver
break;
case PackageType.ClipboardAsk:
Package.PackageReceived.ClipboardAsk++;
Common.PackageReceived.ClipboardAsk++;
if (package.Des == Common.MachineID)
{
@@ -344,17 +344,17 @@ internal static class Receiver
break;
case PackageType.ClipboardDragDrop:
Package.PackageReceived.ClipboardDragDrop++;
Common.PackageReceived.ClipboardDragDrop++;
DragDrop.DragDropStep08(package);
break;
case PackageType.ClipboardDragDropOperation:
Package.PackageReceived.ClipboardDragDrop++;
Common.PackageReceived.ClipboardDragDrop++;
DragDrop.DragDropStep08_2(package);
break;
case PackageType.ClipboardDragDropEnd:
Package.PackageReceived.ClipboardDragDropEnd++;
Common.PackageReceived.ClipboardDragDropEnd++;
DragDrop.DragDropStep12();
break;
@@ -363,11 +363,11 @@ internal static class Receiver
Clipboard.clipboardCopiedTime = 0;
if (package.Type == PackageType.ClipboardImage)
{
Package.PackageReceived.ClipboardImage++;
Common.PackageReceived.ClipboardImage++;
}
else
{
Package.PackageReceived.ClipboardText++;
Common.PackageReceived.ClipboardText++;
}
if (tcp != null)
@@ -390,7 +390,7 @@ internal static class Receiver
default:
if ((package.Type & PackageType.Matrix) == PackageType.Matrix)
{
Package.PackageReceived.Matrix++;
Common.PackageReceived.Matrix++;
MachineStuff.UpdateMachineMatrix(package);
break;
}

View File

@@ -1,29 +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;
using ManagedCommon;
using Microsoft.PowerToys.Telemetry;
namespace MouseWithoutBorders.Core;
internal static class ShutdownWithPowerToys
{
internal static void WaitForPowerToysRunner(ETWTrace etwTrace)
{
try
{
RunnerHelper.WaitForPowerToysRunnerExitFallback(() =>
{
etwTrace?.Dispose();
Common.MainForm.Quit(true, false);
});
}
catch (Exception e)
{
Logger.Log(e);
}
}
}

View File

@@ -1,88 +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.
// <summary>
// Virtual key constants.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
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,
}

View File

@@ -1,55 +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;
// <summary>
// Virtual key constants.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
internal partial class WM
{
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_MOUSEHWHEEL = 0x020E;
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,
}
}

View File

@@ -1,359 +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;
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;
using MouseWithoutBorders.Class;
// <summary>
// Screen/Desktop helper functions.
// </summary>
// <history>
// 2008 created by Truong Do (ductdo).
// 2009-... modified by Truong Do (TruongDo).
// 2023- Included in PowerToys.
// </history>
namespace MouseWithoutBorders.Core;
// Desktops, and GetScreenConfig routines
internal static class WinAPI
{
private static MyRectangle newDesktopBounds;
private static MyRectangle newPrimaryScreenBounds;
private static string activeDesktop;
private static string ActiveDesktop => WinAPI.activeDesktop;
internal static void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
{
GetScreenConfig();
}
internal static readonly List<Point> 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);
Logger.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)
{
Logger.Log("GetDpiForMonitor is unsupported in Windows 7 and lower.");
}
catch (EntryPointNotFoundException)
{
Logger.Log("GetDpiForMonitor is unsupported in Windows 7 and lower.");
}
catch (Exception e)
{
Logger.Log(e);
}
if (mi.rcMonitor.Left == 0 && mi.rcMonitor.Top == 0 && mi.rcMonitor.Right != 0 && mi.rcMonitor.Bottom != 0)
{
// Primary screen
_ = Interlocked.Exchange(ref Common.screenWidth, mi.rcMonitor.Right - mi.rcMonitor.Left);
_ = Interlocked.Exchange(ref Common.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
{
Logger.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;
Logger.Log(string.Format(
CultureInfo.CurrentCulture,
"logon = {0} PrimaryScreenBounds = {1},{2},{3},{4} desktopBounds = {5},{6},{7},{8}",
Common.RunOnLogonDesktop,
WinAPI.newPrimaryScreenBounds.Left,
WinAPI.newPrimaryScreenBounds.Top,
WinAPI.newPrimaryScreenBounds.Right,
WinAPI.newPrimaryScreenBounds.Bottom,
WinAPI.newDesktopBounds.Left,
WinAPI.newDesktopBounds.Top,
WinAPI.newDesktopBounds.Right,
WinAPI.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 MachineStuff.desktopBounds, newDesktopBounds);
Interlocked.Exchange(ref MachineStuff.primaryScreenBounds, newPrimaryScreenBounds);
Logger.Log(string.Format(
CultureInfo.CurrentCulture,
"logon = {0} PrimaryScreenBounds = {1},{2},{3},{4} desktopBounds = {5},{6},{7},{8}",
Common.RunOnLogonDesktop,
MachineStuff.PrimaryScreenBounds.Left,
MachineStuff.PrimaryScreenBounds.Top,
MachineStuff.PrimaryScreenBounds.Right,
MachineStuff.PrimaryScreenBounds.Bottom,
MachineStuff.DesktopBounds.Left,
MachineStuff.DesktopBounds.Top,
MachineStuff.DesktopBounds.Right,
MachineStuff.DesktopBounds.Bottom));
Logger.Log("==================== GetScreenConfig ended");
}
catch (Exception e)
{
Logger.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 Common.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 Common.GetString(arInputDesktop).Replace("\0", string.Empty);
}
return string.Empty;
}
private static void StartMMService(string desktopToRunMouseWithoutBordersOn)
{
if (!Common.RunWithNoAdminRight)
{
Logger.LogDebug("*** Starting on active Desktop: " + desktopToRunMouseWithoutBordersOn);
Service.StartMouseWithoutBordersService(desktopToRunMouseWithoutBordersOn);
}
}
internal static void CheckForDesktopSwitchEvent(bool cleanupIfExit)
{
try
{
if (!IsMyDesktopActive() || Common.CurrentProcess.SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
{
Helper.RunDDHelper(true);
int waitCount = 20;
while (NativeMethods.WTSGetActiveConsoleSessionId() == 0xFFFFFFFF && waitCount > 0)
{
waitCount--;
Logger.LogDebug("The session is detached/attached.");
Thread.Sleep(500);
}
string myDesktop = GetMyDesktop();
activeDesktop = GetInputDesktop();
Logger.LogDebug("*** Active Desktop = " + activeDesktop);
Logger.LogDebug("*** My Desktop = " + myDesktop);
if (myDesktop.Equals(activeDesktop, StringComparison.OrdinalIgnoreCase))
{
Logger.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)
{
Logger.Log($"{nameof(CheckForDesktopSwitchEvent)}: {e}");
}
}
else
{
if (!myDesktop.Equals(activeDesktop, StringComparison.OrdinalIgnoreCase))
{
Logger.Log("*** Active Desktop <> My Desktop");
}
uint sid = NativeMethods.WTSGetActiveConsoleSessionId();
if (Process.GetProcessesByName(Common.BinaryName).Any(p => (uint)p.SessionId == sid))
{
Logger.Log("Found MouseWithoutBorders on the active session!");
}
else
{
Logger.Log("MouseWithoutBorders not found on the active session!");
StartMMService(null);
}
}
if (!myDesktop.Equals("winlogon", StringComparison.OrdinalIgnoreCase) &&
!myDesktop.Equals("default", StringComparison.OrdinalIgnoreCase))
{
Logger.LogDebug("*** Desktop inactive, exiting: " + myDesktop);
Setting.Values.LastX = Common.JUST_GOT_BACK_FROM_SCREEN_SAVER;
if (cleanupIfExit)
{
InitAndCleanup.Cleanup();
}
Process.GetCurrentProcess().KillProcess();
}
}
}
catch (Exception e)
{
Logger.Log(e);
}
}
private static Point p;
internal static bool IsMyDesktopActive()
{
return NativeMethods.GetCursorPos(ref p);
}
}

View File

@@ -42,7 +42,7 @@ namespace MouseWithoutBorders
protected string GetSecureKey()
{
return Encryption.MyKey;
return Common.MyKey;
}
private void BackButton_Click(object sender, EventArgs e)

View File

@@ -89,8 +89,8 @@ namespace MouseWithoutBorders
{
if (GetSecureKey() != SecurityCodeField.Text)
{
Encryption.MyKey = Regex.Replace(SecurityCodeField.Text, @"\s+", string.Empty);
SecurityCode = Encryption.MyKey;
Common.MyKey = Regex.Replace(SecurityCodeField.Text, @"\s+", string.Empty);
SecurityCode = Common.MyKey;
}
MachineStuff.MachineMatrix = new string[MachineStuff.MAX_MACHINE] { ComputerNameField.Text.Trim().ToUpper(CultureInfo.CurrentCulture), Common.MachineName.Trim(), string.Empty, string.Empty };

View File

@@ -135,7 +135,7 @@ namespace MouseWithoutBorders
internal void UpdateKeyTextBox()
{
_ = Helper.GetUserName();
textBoxEnc.Text = Encryption.MyKey;
textBoxEnc.Text = Common.MyKey;
}
private void InitAll()
@@ -505,19 +505,19 @@ namespace MouseWithoutBorders
private bool UpdateKey(string newKey)
{
if (!Encryption.IsKeyValid(newKey, out string rv))
if (!Common.IsKeyValid(newKey, out string rv))
{
ShowKeyErrorMsg(rv);
return false;
}
if (!newKey.Equals(Encryption.MyKey, StringComparison.OrdinalIgnoreCase))
if (!newKey.Equals(Common.MyKey, StringComparison.OrdinalIgnoreCase))
{
Encryption.MyKey = newKey;
Encryption.GeneratedKey = false;
Common.MyKey = newKey;
Common.GeneratedKey = false;
}
Encryption.MagicNumber = Encryption.Get24BitHash(Encryption.MyKey);
Common.MagicNumber = Common.Get24BitHash(Common.MyKey);
return true;
}
@@ -1116,10 +1116,10 @@ namespace MouseWithoutBorders
if (MessageBox.Show(message, Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
{
Setting.Values.MyKey = Encryption.MyKey = Encryption.CreateRandomKey();
textBoxEnc.Text = Encryption.MyKey;
Setting.Values.MyKey = Common.MyKey = Common.CreateRandomKey();
textBoxEnc.Text = Common.MyKey;
checkBoxShowKey.Checked = true;
Encryption.GeneratedKey = 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);
}

View File

@@ -318,7 +318,7 @@ namespace MouseWithoutBorders
try
{
if (!WinAPI.IsMyDesktopActive() || Common.CurrentProcess.SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
if (!Common.IsMyDesktopActive() || Common.CurrentProcess.SessionId != NativeMethods.WTSGetActiveConsoleSessionId())
{
myDesktopNotActive = true;
@@ -348,7 +348,7 @@ namespace MouseWithoutBorders
Common.Hook?.ResetLastSwitchKeys();
});
WinAPI.CheckForDesktopSwitchEvent(true);
Common.CheckForDesktopSwitchEvent(true);
}
}
else
@@ -369,21 +369,21 @@ namespace MouseWithoutBorders
if (myDesktopNotActive)
{
myDesktopNotActive = false;
Encryption.MyKey = Setting.Values.MyKey;
Common.MyKey = Setting.Values.MyKey;
}
MachineStuff.UpdateMachinePoolStringSetting();
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && (Setting.Values.FirstRun || Encryption.KeyCorrupted))
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && (Setting.Values.FirstRun || Common.KeyCorrupted))
{
if (!shownSetupFormOneTime)
{
shownSetupFormOneTime = true;
MachineStuff.ShowMachineMatrix();
if (Encryption.KeyCorrupted && !Setting.Values.FirstRun)
if (Common.KeyCorrupted && !Setting.Values.FirstRun)
{
Encryption.KeyCorrupted = false;
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);
}
@@ -490,9 +490,9 @@ namespace MouseWithoutBorders
if (count == 600)
{
if (!Encryption.GeneratedKey)
if (!Common.GeneratedKey)
{
Encryption.MyKey = Setting.Values.MyKey;
Common.MyKey = Setting.Values.MyKey;
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop)
{
@@ -505,7 +505,7 @@ namespace MouseWithoutBorders
Common.ShowToolTip("The security key must be auto generated in one of the machines.", 10000);
}
}
else if (!Encryption.KeyCorrupted && !Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && !Setting.Values.FirstRun && Common.AtLeastOneSocketConnected())
else if (!Common.KeyCorrupted && !Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && !Setting.Values.FirstRun && Common.AtLeastOneSocketConnected())
{
int myKeyDaysToExpire = Setting.Values.MyKeyDaysToExpire;
@@ -531,7 +531,7 @@ namespace MouseWithoutBorders
#if SHOW_ON_WINLOGON
// if (Common.RunOnLogonDesktop) ShowMouseWithoutBordersUiOnWinLogonDesktop(false);
#endif
WinAPI.CheckForDesktopSwitchEvent(true);
Common.CheckForDesktopSwitchEvent(true);
MachineStuff.UpdateClientSockets("helperTimer_Tick"); // Sockets may be closed by the remote host when both machines switch desktop at the same time.
}
@@ -582,7 +582,7 @@ namespace MouseWithoutBorders
int rv = 0;
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && WinAPI.IsMyDesktopActive() && (rv = Helper.SendMessageToHelper(0x400, IntPtr.Zero, IntPtr.Zero)) <= 0)
if (!Common.RunOnLogonDesktop && !Common.RunOnScrSaverDesktop && Common.IsMyDesktopActive() && (rv = Helper.SendMessageToHelper(0x400, IntPtr.Zero, IntPtr.Zero)) <= 0)
{
Logger.TelemetryLogTrace($"{Helper.HELPER_FORM_TEXT} not found: {rv}", SeverityLevel.Warning);
}

View File

@@ -46,6 +46,79 @@ avgSendTime = 0
maxSendTime = 0
totalSendCount = 0
totalSendTime = 0
magicNumber = 0
ran = System.Random
--_impl = System.Random+XoshiroImpl
----_s0 = ????????????
----_s1 = ????????????
----_s2 = ????????????
----_s3 = ????????????
--<Shared>k__BackingField = System.Random+ThreadSafeRandom
InitialIV = ????????????
<GeneratedKey>k__BackingField = False
<KeyCorrupted>k__BackingField = False
LegalKeyDictionary = Concurrent.ConcurrentDictionary`2[System.String,System.Byte[]]
--_tables = Concurrent.ConcurrentDictionary`2+Tables[System.String,System.Byte[]]
----_comparer = Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer
----_buckets = Concurrent.ConcurrentDictionary`2+VolatileNode[System.String,System.Byte[]][]
------System.Collections.Concurrent.ConcurrentDictionary`2+VolatileNode[System.String,System.Byte[]][] = Concurrent.ConcurrentDictionary`2+VolatileNode[System.String,System.Byte[]][]: N/A
----_fastModBucketsMultiplier = 498560650640798693
----_locks = O[]
------System.Object[] = O[]: N/A
----_countPerLock = 32[]
------[0] = 0
------[1] = 0
------[2] = 0
------[3] = 0
------[4] = 0
------[5] = 0
------[6] = 0
------[7] = 0
--_budget = ????????????
--_growLockArray = True
--_comparerIsDefaultForClasses = False
PackageSent = MouseWithoutBorders.PackageMonitor
--Keyboard = 0
--Mouse = 0
--Heartbeat = 0
--ByeBye = 0
--Hello = 0
--Matrix = 0
--ClipboardText = 0
--ClipboardImage = 0
--Clipboard = 0
--ClipboardDragDrop = 0
--ClipboardDragDropEnd = 0
--ClipboardAsk = 0
--ExplorerDragDrop = 0
--Nil = 0
PackageReceived = MouseWithoutBorders.PackageMonitor
--Keyboard = 0
--Mouse = 0
--Heartbeat = 0
--ByeBye = 0
--Hello = 0
--Matrix = 0
--ClipboardText = 0
--ClipboardImage = 0
--Clipboard = 0
--ClipboardDragDrop = 0
--ClipboardDragDropEnd = 0
--ClipboardAsk = 0
--ExplorerDragDrop = 0
--Nil = 0
PackageID = 0
SensitivePoints = Generic.List`1[Point]
--_items = Point[]
----System.Drawing.Point[] = Point[]: N/A
--_size = 0
--_version = 0
--s_emptyArray = Point[]
----System.Drawing.Point[] = Point[]: N/A
p = {X=0,Y=0}
--x = 0
--y = 0
--Empty = {X=0,Y=0}
<IpcChannelCreated>k__BackingField = False
TOGGLE_ICONS_SIZE = 4
ICON_ONE = 0
@@ -55,6 +128,34 @@ ICON_BIG_CLIPBOARD = 3
ICON_ERROR = 4
JUST_GOT_BACK_FROM_SCREEN_SAVER = 9999
NETWORK_STREAM_BUF_SIZE = 1048576
SymAlBlockSize = 16
PW_LENGTH = 16
PACKAGE_SIZE = 32
PACKAGE_SIZE_EX = 64
WP_PACKAGE_SIZE = 6
KEYEVENTF_KEYDOWN = 1
KEYEVENTF_KEYUP = 2
WH_MOUSE = 7
WH_KEYBOARD = 2
WH_MOUSE_LL = 14
WH_KEYBOARD_LL = 13
WM_MOUSEMOVE = 512
WM_LBUTTONDOWN = 513
WM_RBUTTONDOWN = 516
WM_MBUTTONDOWN = 519
WM_XBUTTONDOWN = 523
WM_LBUTTONUP = 514
WM_RBUTTONUP = 517
WM_MBUTTONUP = 520
WM_XBUTTONUP = 524
WM_LBUTTONDBLCLK = 515
WM_RBUTTONDBLCLK = 518
WM_MBUTTONDBLCLK = 521
WM_MOUSEWHEEL = 522
WM_KEYDOWN = 256
WM_KEYUP = 257
WM_SYSKEYDOWN = 260
WM_SYSKEYUP = 261
[Clipboard]
===============
Comma = System.Char[]
@@ -92,51 +193,16 @@ dragDropStep05ExCalledByIpc = 0
isDropping = False
dragMachine = NONE
<MouseDown>k__BackingField = False
[Encryption]
===============
magicNumber = 0
ran = System.Random
--_impl = System.Random+XoshiroImpl
----_s0 = ????????????
----_s1 = ????????????
----_s2 = ????????????
----_s3 = ????????????
--<Shared>k__BackingField = System.Random+ThreadSafeRandom
InitialIV = ????????????
<GeneratedKey>k__BackingField = False
<KeyCorrupted>k__BackingField = False
LegalKeyDictionary = Concurrent.ConcurrentDictionary`2[System.String,System.Byte[]]
--_tables = Concurrent.ConcurrentDictionary`2+Tables[System.String,System.Byte[]]
----_comparer = Generic.NonRandomizedStringEqualityComparer+OrdinalIgnoreCaseComparer
----_buckets = Concurrent.ConcurrentDictionary`2+VolatileNode[System.String,System.Byte[]][]
------System.Collections.Concurrent.ConcurrentDictionary`2+VolatileNode[System.String,System.Byte[]][] = Concurrent.ConcurrentDictionary`2+VolatileNode[System.String,System.Byte[]][]: N/A
----_fastModBucketsMultiplier = 498560650640798693
----_locks = O[]
------System.Object[] = O[]: N/A
----_countPerLock = 32[]
------[0] = 0
------[1] = 0
------[2] = 0
------[3] = 0
------[4] = 0
------[5] = 0
------[6] = 0
------[7] = 0
--_budget = ????????????
--_growLockArray = True
--_comparerIsDefaultForClasses = False
SymAlBlockSize = 16
PW_LENGTH = 16
[Event]
===============
KeybdPackage = MouseWithoutBorders.Core.DATA
KeybdPackage = MouseWithoutBorders.DATA
--Type = 0
--Id = 0
--Src = NONE
--Des = NONE
--DateTime = 0
--Kd = MouseWithoutBorders.Core.KEYBDDATA
--Md = MouseWithoutBorders.Core.MOUSEDATA
--Kd = MouseWithoutBorders.KEYBDDATA
--Md = MouseWithoutBorders.MOUSEDATA
--Machine1 = NONE
--Machine2 = NONE
--Machine3 = NONE
@@ -146,14 +212,14 @@ KeybdPackage = MouseWithoutBorders.Core.DATA
--machineNameP2 = 0
--machineNameP3 = 0
--machineNameP4 = 0
MousePackage = MouseWithoutBorders.Core.DATA
MousePackage = MouseWithoutBorders.DATA
--Type = 0
--Id = 0
--Src = NONE
--Des = NONE
--DateTime = 0
--Kd = MouseWithoutBorders.Core.KEYBDDATA
--Md = MouseWithoutBorders.Core.MOUSEDATA
--Kd = MouseWithoutBorders.KEYBDDATA
--Md = MouseWithoutBorders.MOUSEDATA
--Machine1 = NONE
--Machine2 = NONE
--Machine3 = NONE
@@ -230,7 +296,7 @@ LogCounter = Concurrent.ConcurrentDictionary`2[System.String,32]
allLogsIndex = 0
lastHour = 0
exceptionCount = 0
lastPackageSent = MouseWithoutBorders.Core.PackageMonitor
lastPackageSent = MouseWithoutBorders.PackageMonitor
--Keyboard = 0
--Mouse = 0
--Heartbeat = 0
@@ -245,7 +311,7 @@ lastPackageSent = MouseWithoutBorders.Core.PackageMonitor
--ClipboardAsk = 0
--ExplorerDragDrop = 0
--Nil = 0
lastPackageReceived = MouseWithoutBorders.Core.PackageMonitor
lastPackageReceived = MouseWithoutBorders.PackageMonitor
--Keyboard = 0
--Mouse = 0
--Heartbeat = 0
@@ -300,42 +366,6 @@ MAX_SOCKET = 8
HEARTBEAT_TIMEOUT = 1500000
SKIP_PIXELS = 1
JUMP_PIXELS = 2
[Package]
===============
PackageSent = MouseWithoutBorders.Core.PackageMonitor
--Keyboard = 0
--Mouse = 0
--Heartbeat = 0
--ByeBye = 0
--Hello = 0
--Matrix = 0
--ClipboardText = 0
--ClipboardImage = 0
--Clipboard = 0
--ClipboardDragDrop = 0
--ClipboardDragDropEnd = 0
--ClipboardAsk = 0
--ExplorerDragDrop = 0
--Nil = 0
PackageReceived = MouseWithoutBorders.Core.PackageMonitor
--Keyboard = 0
--Mouse = 0
--Heartbeat = 0
--ByeBye = 0
--Hello = 0
--Matrix = 0
--ClipboardText = 0
--ClipboardImage = 0
--Clipboard = 0
--ClipboardDragDrop = 0
--ClipboardDragDropEnd = 0
--ClipboardAsk = 0
--ExplorerDragDrop = 0
--Nil = 0
PackageID = 0
PACKAGE_SIZE = 32
PACKAGE_SIZE_EX = 64
WP_PACKAGE_SIZE = 6
[Receiver]
===============
QUEUE_SIZE = 50
@@ -406,41 +436,3 @@ lastStartServiceTime = ????????????
--MinValue = 01/01/0001 00:00:00
--MaxValue = 31/12/9999 23:59:59
--UnixEpoch = 01/01/1970 00:00:00
[WinAPI]
===============
SensitivePoints = Generic.List`1[Point]
--_items = Point[]
----System.Drawing.Point[] = Point[]: N/A
--_size = 0
--_version = 0
--s_emptyArray = Point[]
----System.Drawing.Point[] = Point[]: N/A
p = {X=0,Y=0}
--x = 0
--y = 0
--Empty = {X=0,Y=0}
[WM]
===============
KEYEVENTF_KEYDOWN = 1
KEYEVENTF_KEYUP = 2
WH_MOUSE = 7
WH_KEYBOARD = 2
WH_MOUSE_LL = 14
WH_KEYBOARD_LL = 13
WM_MOUSEMOVE = 512
WM_LBUTTONDOWN = 513
WM_RBUTTONDOWN = 516
WM_MBUTTONDOWN = 519
WM_XBUTTONDOWN = 523
WM_LBUTTONUP = 514
WM_RBUTTONUP = 517
WM_MBUTTONUP = 520
WM_XBUTTONUP = 524
WM_LBUTTONDBLCLK = 515
WM_RBUTTONDBLCLK = 518
WM_MBUTTONDBLCLK = 521
WM_MOUSEWHEEL = 522
WM_KEYDOWN = 256
WM_KEYUP = 257
WM_SYSKEYDOWN = 260
WM_SYSKEYUP = 261

View File

@@ -350,7 +350,7 @@ namespace Awake.Core
TrayHelper.TimedIcon,
TrayIconAction.Update);
},
() => HandleTimerCompletion("timed"),
_ => HandleTimerCompletion("timed"),
_tokenSource.Token);
}

View File

@@ -1,62 +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;
namespace Microsoft.CmdPal.Core.Common;
public static class CoreLogger
{
public static void InitializeLogger(ILogger implementation)
{
_logger = implementation;
}
private static ILogger? _logger;
public static void LogError(string message, Exception ex, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogError(message, ex, memberName, sourceFilePath, sourceLineNumber);
}
public static void LogError(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogError(message, memberName, sourceFilePath, sourceLineNumber);
}
public static void LogWarning(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogWarning(message, memberName, sourceFilePath, sourceLineNumber);
}
public static void LogInfo(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogInfo(message, memberName, sourceFilePath, sourceLineNumber);
}
public static void LogDebug(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogDebug(message, memberName, sourceFilePath, sourceLineNumber);
}
public static void LogTrace([System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0)
{
_logger?.LogTrace(memberName, sourceFilePath, sourceLineNumber);
}
}
public interface ILogger
{
void LogError(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
void LogError(string message, Exception ex, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
void LogWarning(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
void LogInfo(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
void LogDebug(string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
void LogTrace([System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0);
}

View File

@@ -9,4 +9,8 @@
<PackageReference Include="Microsoft.Extensions.Hosting" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
</ItemGroup>
</Project>

View File

@@ -2,8 +2,6 @@
// 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.Collections.Generic;
using System.Threading.Tasks;
using Windows.Foundation;
namespace Microsoft.CmdPal.Core.Common.Services;
@@ -26,12 +24,4 @@ public interface IExtensionService
void EnableExtension(string extensionUniqueId);
void DisableExtension(string extensionUniqueId);
///// <summary>
///// Gets a boolean indicating whether the extension was disabled due to the corresponding Windows optional feature
///// being absent from the machine or in an unknown state.
///// </summary>
///// <param name="extension">The out of proc extension object</param>
///// <returns>True only if the extension was disabled. False otherwise.</returns>
// public Task<bool> DisableExtensionIfWindowsFeatureNotAvailable(IExtensionWrapper extension);
}

View File

@@ -23,12 +23,3 @@ public interface IRunHistoryService
/// <param name="item">The run history item to add.</param>
void AddRunHistoryItem(string item);
}
public interface ITelemetryService
{
void LogRunQuery(string query, int resultCount, ulong durationMs);
void LogRunCommand(string command, bool asAdmin, bool success);
void LogOpenUri(string uri, bool isWeb, bool success);
}

View File

@@ -0,0 +1,10 @@
// 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 Microsoft.CmdPal.Core.Common.Services.Telemetry;
public interface ITelemetryService
{
void WriteEvent(TelemetryEventBase telemetryEvent);
}

View File

@@ -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.
using Microsoft.PowerToys.Telemetry;
using Microsoft.PowerToys.Telemetry.Events;
namespace Microsoft.CmdPal.Core.Common.Services.Telemetry;
public abstract class TelemetryEventBase : EventBase, IEvent
{
// Overridden in derived classes
public abstract PartA_PrivTags PartA_PrivTags { get; }
}

View File

@@ -4,9 +4,9 @@
using System.Collections.ObjectModel;
using System.Diagnostics;
using Microsoft.CmdPal.Core.Common;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
using Windows.Foundation;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -14,6 +14,7 @@ namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class AppExtensionHost : IExtensionHost
{
private static readonly GlobalLogPageContext _globalLogPageContext = new();
private readonly ILogger _logger;
private static ulong _hostingHwnd;
@@ -27,6 +28,11 @@ public abstract partial class AppExtensionHost : IExtensionHost
public static void SetHostHwnd(ulong hostHwnd) => _hostingHwnd = hostHwnd;
public AppExtensionHost(ILogger logger)
{
_logger = logger;
}
public void DebugLog(string message)
{
#if DEBUG
@@ -60,7 +66,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
return Task.CompletedTask.AsAsyncAction();
}
CoreLogger.LogDebug(message.Message);
Log_DebugMessage(message.Message);
_ = Task.Run(() =>
{
@@ -96,7 +102,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
public void ProcessLogMessage(ILogMessage message)
{
var vm = new LogMessageViewModel(message, _globalLogPageContext);
var vm = new LogMessageViewModel(message, _globalLogPageContext, _logger);
vm.SafeInitializePropertiesSynchronous();
Task.Factory.StartNew(
@@ -127,7 +133,7 @@ public abstract partial class AppExtensionHost : IExtensionHost
return;
}
var vm = new StatusMessageViewModel(message, new(_globalLogPageContext));
var vm = new StatusMessageViewModel(message, new(_globalLogPageContext), _logger);
vm.SafeInitializePropertiesSynchronous();
Task.Factory.StartNew(
@@ -158,6 +164,11 @@ public abstract partial class AppExtensionHost : IExtensionHost
}
public abstract string? GetExtensionDisplayName();
public abstract AppExtensionHost GetHostForCommand(object? context, AppExtensionHost? currentHost);
[LoggerMessage(Level = LogLevel.Debug, Message = "{Message}")]
partial void Log_DebugMessage(string message);
}
public interface IAppHostService

View File

@@ -6,6 +6,7 @@ using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
using Windows.System;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -13,6 +14,8 @@ namespace Microsoft.CmdPal.Core.ViewModels;
public partial class CommandBarViewModel : ObservableObject,
IRecipient<UpdateCommandBarMessage>
{
private readonly ILogger _logger;
public ICommandBarContext? SelectedItem
{
get => field;
@@ -48,8 +51,9 @@ public partial class CommandBarViewModel : ObservableObject,
[ObservableProperty]
public partial PageViewModel? CurrentPage { get; set; }
public CommandBarViewModel()
public CommandBarViewModel(ILogger logger)
{
_logger = logger;
WeakReferenceMessenger.Default.Register<UpdateCommandBarMessage>(this);
}

View File

@@ -5,12 +5,12 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)]
public partial class CommandContextItemViewModel(ICommandContextItem contextItem, WeakReference<IPageContext> context) : CommandItemViewModel(new(contextItem), context), IContextItemViewModel
public partial class CommandContextItemViewModel(ICommandContextItem contextItem, WeakReference<IPageContext> context, ILogger logger) : CommandItemViewModel(new(contextItem), context, logger), IContextItemViewModel
{
private readonly KeyChord nullKeyChord = new(0, 0, 0);

View File

@@ -3,11 +3,11 @@
// See the LICENSE file in the project root for more information.
using System.Diagnostics.CodeAnalysis;
using Microsoft.CmdPal.Core.Common;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -86,11 +86,11 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
_errorIcon.InitializeProperties();
}
public CommandItemViewModel(ExtensionObject<ICommandItem> item, WeakReference<IPageContext> errorContext)
: base(errorContext)
public CommandItemViewModel(ExtensionObject<ICommandItem> item, WeakReference<IPageContext> errorContext, ILogger logger)
: base(errorContext, logger)
{
_commandItemModel = item;
Command = new(null, errorContext);
Command = new(null, errorContext, Logger);
}
public void FastInitializeProperties()
@@ -106,7 +106,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
return;
}
Command = new(model.Command, PageContext);
Command = new(model.Command, PageContext, Logger);
Command.FastInitializeProperties();
_itemTitle = model.Title;
@@ -184,7 +184,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
MoreCommands = more
.Select<IContextItem, IContextItemViewModel>(item =>
{
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext, Logger) : new SeparatorViewModel();
})
.ToList();
}
@@ -201,7 +201,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
if (!string.IsNullOrEmpty(model.Command?.Name))
{
_defaultCommandContextItemViewModel = new CommandContextItemViewModel(new CommandContextItem(model.Command!), PageContext)
_defaultCommandContextItemViewModel = new CommandContextItemViewModel(new CommandContextItem(model.Command!), PageContext, Logger)
{
_itemTitle = Name,
Subtitle = Subtitle,
@@ -231,8 +231,8 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
}
catch (Exception ex)
{
CoreLogger.LogError("error fast initializing CommandItemViewModel", ex);
Command = new(null, PageContext);
Log_ErrorFastInitializingCommandItemViewModel(Logger, ex);
Command = new(null, PageContext, Logger);
_itemTitle = "Error";
Subtitle = "Item failed to load";
MoreCommands = [];
@@ -253,7 +253,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
catch (Exception ex)
{
Initialized |= InitializedState.Error;
CoreLogger.LogError("error slow initializing CommandItemViewModel", ex);
Log_ErrorSlowInitializingCommandItemViewModel(Logger, ex);
}
return false;
@@ -268,8 +268,8 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
}
catch (Exception ex)
{
CoreLogger.LogError("error initializing CommandItemViewModel", ex);
Command = new(null, PageContext);
Log_ErrorSlowInitializingCommandItemViewModel(Logger, ex);
Command = new(null, PageContext, Logger);
_itemTitle = "Error";
Subtitle = "Item failed to load";
MoreCommands = [];
@@ -304,7 +304,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
{
case nameof(Command):
Command.PropertyChanged -= Command_PropertyChanged;
Command = new(model.Command, PageContext);
Command = new(model.Command, PageContext, Logger);
Command.InitializeProperties();
Command.PropertyChanged += Command_PropertyChanged;
@@ -351,7 +351,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
var newContextMenu = more
.Select<IContextItem, IContextItemViewModel>(item =>
{
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext) : new SeparatorViewModel();
return item is ICommandContextItem contextItem ? new CommandContextItemViewModel(contextItem, PageContext, Logger) : new SeparatorViewModel();
})
.ToList();
lock (MoreCommands)
@@ -464,6 +464,15 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
base.SafeCleanup();
Initialized |= InitializedState.CleanedUp;
}
[LoggerMessage(level: LogLevel.Error, message: "error fast initializing CommandItemViewModel")]
static partial void Log_ErrorFastInitializingCommandItemViewModel(ILogger logger, Exception ex);
[LoggerMessage(level: LogLevel.Error, message: "error slow initializing CommandItemViewModel")]
static partial void Log_ErrorSlowInitializingCommandItemViewModel(ILogger logger, Exception ex);
[LoggerMessage(level: LogLevel.Error, message: "error initializing CommandItemViewModel")]
static partial void Log_ErrorInitializingCommandItemViewModel(ILogger logger, Exception ex);
}
[Flags]

View File

@@ -4,6 +4,7 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -38,8 +39,8 @@ public partial class CommandViewModel : ExtensionObjectViewModel
public IReadOnlyDictionary<string, ExtensionObject<object>>? Properties => _properties?.AsReadOnly();
public CommandViewModel(ICommand? command, WeakReference<IPageContext> pageContext)
: base(pageContext)
public CommandViewModel(ICommand? command, WeakReference<IPageContext> pageContext, ILogger logger)
: base(pageContext, logger)
{
Model = new(command);
Icon = new(null);

View File

@@ -4,13 +4,14 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class ConfirmResultViewModel(IConfirmationArgs _args, WeakReference<IPageContext> context) :
ExtensionObjectViewModel(context)
public partial class ConfirmResultViewModel(IConfirmationArgs? args, WeakReference<IPageContext> context, ILogger logger)
: ExtensionObjectViewModel(context, logger)
{
public ExtensionObject<IConfirmationArgs> Model { get; } = new(_args);
public ExtensionObject<IConfirmationArgs> Model { get; private set; } = new(args);
// Remember - "observable" properties from the model (via PropChanged)
// cannot be marked [ObservableProperty]
@@ -20,7 +21,7 @@ public partial class ConfirmResultViewModel(IConfirmationArgs _args, WeakReferen
public bool IsPrimaryCommandCritical { get; private set; }
public CommandViewModel PrimaryCommand { get; private set; } = new(null, context);
public CommandViewModel PrimaryCommand { get; private set; } = new(null, context, logger);
public override void InitializeProperties()
{
@@ -33,7 +34,7 @@ public partial class ConfirmResultViewModel(IConfirmationArgs _args, WeakReferen
Title = model.Title;
Description = model.Description;
IsPrimaryCommandCritical = model.IsPrimaryCommandCritical;
PrimaryCommand = new(model.PrimaryCommand, PageContext);
PrimaryCommand = new(model.PrimaryCommand, PageContext, Logger);
PrimaryCommand.InitializeProperties();
UpdateProperty(nameof(Title));

View File

@@ -11,12 +11,14 @@ using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
{
private readonly ExtensionObject<IContentPage> _model;
private readonly ILogger _logger;
[ObservableProperty]
public partial ObservableCollection<ContentViewModel> Content { get; set; } = [];
@@ -47,10 +49,11 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
// Remember - "observable" properties from the model (via PropChanged)
// cannot be marked [ObservableProperty]
public ContentPageViewModel(IContentPage model, TaskScheduler scheduler, AppExtensionHost host)
: base(model, scheduler, host)
public ContentPageViewModel(IContentPage model, AppExtensionHost host, ILogger logger)
: base(model, host, logger)
{
_model = new(model);
_logger = logger;
}
// TODO: Does this need to hop to a _different_ thread, so that we don't block the extension while we're fetching?
@@ -115,7 +118,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
{
if (item is ICommandContextItem contextItem)
{
return new CommandContextItemViewModel(contextItem, PageContext);
return new CommandContextItemViewModel(contextItem, PageContext, _logger);
}
else
{
@@ -135,7 +138,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
var extensionDetails = model.Details;
if (extensionDetails is not null)
{
Details = new(extensionDetails, PageContext);
Details = new(extensionDetails, PageContext, _logger);
Details.InitializeProperties();
}
@@ -174,7 +177,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
{
if (item is ICommandContextItem contextItem)
{
return new CommandContextItemViewModel(contextItem, PageContext) as IContextItemViewModel;
return new CommandContextItemViewModel(contextItem, PageContext, _logger) as IContextItemViewModel;
}
else
{
@@ -216,7 +219,7 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
break;
case nameof(Details):
var extensionDetails = model.Details;
Details = extensionDetails is not null ? new(extensionDetails, PageContext) : null;
Details = extensionDetails is not null ? new(extensionDetails, PageContext, _logger) : null;
UpdateDetails();
break;
}

View File

@@ -2,10 +2,12 @@
// 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.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class ContentViewModel(WeakReference<IPageContext> context) :
ExtensionObjectViewModel(context)
public abstract partial class ContentViewModel(WeakReference<IPageContext> context, ILogger logger) :
ExtensionObjectViewModel(context, logger)
{
public bool OnlyControlOnPage { get; internal set; }
}

View File

@@ -5,7 +5,6 @@
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using Microsoft.CmdPal.Core.Common;
using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
@@ -138,11 +137,7 @@ public partial class ContextMenuViewModel : ObservableObject,
if (item is CommandContextItemViewModel cmd && cmd.HasRequestedShortcut)
{
var key = cmd.RequestedShortcut ?? new KeyChord(0, 0, 0);
var added = result.TryAdd(key, cmd);
if (!added)
{
CoreLogger.LogWarning($"Ignoring duplicate keyboard shortcut {KeyChordHelpers.FormatForDebug(key)} on command '{cmd.Title ?? cmd.Name ?? "(unknown)"}'");
}
_ = result.TryAdd(key, cmd);
}
}

View File

@@ -4,19 +4,26 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class DetailsCommandsViewModel(
IDetailsElement _detailsElement,
WeakReference<IPageContext> context) : DetailsElementViewModel(_detailsElement, context)
public partial class DetailsCommandsViewModel : DetailsElementViewModel
{
private readonly ILogger _logger;
public List<CommandViewModel> Commands { get; private set; } = [];
public bool HasCommands => Commands.Count > 0;
private readonly ExtensionObject<IDetailsCommands> _dataModel =
new(_detailsElement.Data as IDetailsCommands);
private readonly ExtensionObject<IDetailsCommands> _dataModel;
public DetailsCommandsViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context, ILogger logger)
: base(_detailsElement, context, logger)
{
_logger = logger;
_dataModel = new(_detailsElement.Data as IDetailsCommands);
}
public override void InitializeProperties()
{
@@ -31,7 +38,7 @@ public partial class DetailsCommandsViewModel(
.Commands?
.Select(c =>
{
var vm = new CommandViewModel(c, PageContext);
var vm = new CommandViewModel(c, PageContext, _logger);
vm.InitializeProperties();
return vm;
})

View File

@@ -2,11 +2,10 @@
// 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.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class DetailsDataViewModel(IPageContext context) : ExtensionObjectViewModel(context)
public abstract partial class DetailsDataViewModel(IPageContext context, ILogger logger) : ExtensionObjectViewModel(context, logger)
{
}

View File

@@ -4,10 +4,11 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class DetailsElementViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context) : ExtensionObjectViewModel(context)
public abstract partial class DetailsElementViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context, ILogger logger) : ExtensionObjectViewModel(context, logger)
{
private readonly ExtensionObject<IDetailsElement> _model = new(_detailsElement);

View File

@@ -6,12 +6,12 @@ using CommunityToolkit.Mvvm.Input;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class DetailsLinkViewModel(
IDetailsElement _detailsElement,
WeakReference<IPageContext> context) : DetailsElementViewModel(_detailsElement, context)
public partial class DetailsLinkViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context, ILogger logger)
: DetailsElementViewModel(_detailsElement, context, logger)
{
private static readonly string[] _initProperties = [
nameof(Text),

View File

@@ -4,12 +4,13 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class DetailsSeparatorViewModel(
IDetailsElement _detailsElement,
WeakReference<IPageContext> context) : DetailsElementViewModel(_detailsElement, context)
WeakReference<IPageContext> context, ILogger logger) : DetailsElementViewModel(_detailsElement, context, logger)
{
private readonly ExtensionObject<IDetailsSeparator> _dataModel =
new(_detailsElement.Data as IDetailsSeparator);

View File

@@ -4,19 +4,25 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class DetailsTagsViewModel(
IDetailsElement _detailsElement,
WeakReference<IPageContext> context) : DetailsElementViewModel(_detailsElement, context)
public partial class DetailsTagsViewModel : DetailsElementViewModel
{
public List<TagViewModel> Tags { get; private set; } = [];
public bool HasTags => Tags.Count > 0;
private readonly ExtensionObject<IDetailsTags> _dataModel =
new(_detailsElement.Data as IDetailsTags);
private readonly ExtensionObject<IDetailsTags> _dataModel;
private readonly ILogger _logger;
public DetailsTagsViewModel(IDetailsElement _detailsElement, WeakReference<IPageContext> context, ILogger logger)
: base(_detailsElement, context, logger)
{
_logger = logger;
_dataModel = new(_detailsElement.Data as IDetailsTags);
}
public override void InitializeProperties()
{
@@ -31,7 +37,7 @@ public partial class DetailsTagsViewModel(
.Tags?
.Select(t =>
{
var vm = new TagViewModel(t, PageContext);
var vm = new TagViewModel(t, PageContext, _logger);
vm.InitializeProperties();
return vm;
})

View File

@@ -4,10 +4,11 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class DetailsViewModel(IDetails _details, WeakReference<IPageContext> context) : ExtensionObjectViewModel(context)
public partial class DetailsViewModel(IDetails _details, WeakReference<IPageContext> context, ILogger logger) : ExtensionObjectViewModel(context, logger)
{
private readonly ExtensionObject<IDetails> _detailsModel = new(_details);
@@ -47,10 +48,10 @@ public partial class DetailsViewModel(IDetails _details, WeakReference<IPageCont
{
DetailsElementViewModel? vm = element.Data switch
{
IDetailsSeparator => new DetailsSeparatorViewModel(element, this.PageContext),
IDetailsLink => new DetailsLinkViewModel(element, this.PageContext),
IDetailsCommands => new DetailsCommandsViewModel(element, this.PageContext),
IDetailsTags => new DetailsTagsViewModel(element, this.PageContext),
IDetailsSeparator => new DetailsSeparatorViewModel(element, this.PageContext, Logger),
IDetailsLink => new DetailsLinkViewModel(element, this.PageContext, Logger),
IDetailsCommands => new DetailsCommandsViewModel(element, this.PageContext, Logger),
IDetailsTags => new DetailsTagsViewModel(element, this.PageContext, Logger),
_ => null,
};
if (vm is not null)

View File

@@ -3,23 +3,29 @@
// See the LICENSE file in the project root for more information.
using CommunityToolkit.Mvvm.ComponentModel;
using Microsoft.CmdPal.Core.Common;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public abstract partial class ExtensionObjectViewModel : ObservableObject
{
private readonly ILogger _logger;
public ILogger Logger => _logger;
public WeakReference<IPageContext> PageContext { get; set; }
internal ExtensionObjectViewModel(IPageContext? context)
internal ExtensionObjectViewModel(IPageContext? context, ILogger logger)
{
var realContext = context ?? (this is IPageContext c ? c : throw new ArgumentException("You need to pass in an IErrorContext"));
_logger = logger;
PageContext = new(realContext);
}
internal ExtensionObjectViewModel(WeakReference<IPageContext> context)
internal ExtensionObjectViewModel(WeakReference<IPageContext> context, ILogger logger)
{
PageContext = context;
_logger = logger;
}
public async virtual Task InitializePropertiesAsync()
@@ -114,7 +120,10 @@ public abstract partial class ExtensionObjectViewModel : ObservableObject
}
catch (Exception ex)
{
CoreLogger.LogDebug(ex.ToString());
Log_CleanupException(ex);
}
}
[LoggerMessage(Level = LogLevel.Debug)]
partial void Log_CleanupException(Exception exception);
}

View File

@@ -4,6 +4,7 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -23,8 +24,8 @@ public partial class FilterItemViewModel : ExtensionObjectViewModel, IFilterItem
public bool IsInErrorState => Initialized.HasFlag(InitializedState.Error);
public FilterItemViewModel(IFilter filter, WeakReference<IPageContext> context)
: base(context)
public FilterItemViewModel(IFilter filter, WeakReference<IPageContext> context, ILogger logger)
: base(context, logger)
{
_model = new(filter);
}

View File

@@ -2,10 +2,9 @@
// 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.Collections.Generic;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -21,8 +20,8 @@ public partial class FiltersViewModel : ExtensionObjectViewModel
public bool ShouldShowFilters => Filters.Length > 0;
public FiltersViewModel(ExtensionObject<IFilters> filters, WeakReference<IPageContext> context)
: base(context)
public FiltersViewModel(ExtensionObject<IFilters> filters, WeakReference<IPageContext> context, ILogger logger)
: base(context, logger)
{
_filtersModel = filters;
}
@@ -71,7 +70,7 @@ public partial class FiltersViewModel : ExtensionObjectViewModel
{
if (filter is IFilter filterItem)
{
var filterItemViewModel = new FilterItemViewModel(filterItem, PageContext);
var filterItemViewModel = new FilterItemViewModel(filterItem, PageContext, Logger);
filterItemViewModel.InitializeProperties();
if (firstFilterItem is null)

View File

@@ -11,15 +11,15 @@ public class GalleryGridPropertiesViewModel : IGridPropertiesViewModel
{
private readonly ExtensionObject<IGalleryGridLayout> _model;
public bool ShowTitle { get; private set; }
public bool ShowSubtitle { get; private set; }
public GalleryGridPropertiesViewModel(IGalleryGridLayout galleryGridLayout)
{
_model = new(galleryGridLayout);
}
public bool ShowTitle { get; set; }
public bool ShowSubtitle { get; set; }
public void InitializeProperties()
{
var model = _model.Unsafe;

View File

@@ -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.
using Microsoft.CmdPal.Core.ViewModels.Messages;
namespace Microsoft.CmdPal.Core.ViewModels;
// Represents everything the command bar needs to know about to show command
// buttons at the bottom.
//
// This is implemented by both ListItemViewModel and ContentPageViewModel,
// the two things with sub-commands.
public interface ICommandBarContext : IContextMenuContext
{
public string SecondaryCommandName { get; }
public CommandItemViewModel? PrimaryCommand { get; }
public CommandItemViewModel? SecondaryCommand { get; }
}

View File

@@ -6,9 +6,5 @@ namespace Microsoft.CmdPal.Core.ViewModels;
public interface IGridPropertiesViewModel
{
bool ShowTitle { get; }
bool ShowSubtitle { get; }
void InitializeProperties();
}

View File

@@ -0,0 +1,12 @@
// 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 Microsoft.CmdPal.Core.ViewModels;
public interface IPageContext
{
void ShowException(Exception ex, string? extensionHint = null);
TaskScheduler Scheduler { get; }
}

View File

@@ -0,0 +1,19 @@
// 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.CommandPalette.Extensions;
namespace Microsoft.CmdPal.Core.ViewModels;
public interface IPageViewModelFactoryService
{
/// <summary>
/// Creates a new instance of the page view model for the given page type.
/// </summary>
/// <param name="page">The page for which to create the view model.</param>
/// <param name="nested">Indicates whether the page is not the top-level page.</param>
/// <param name="host">The command palette host that will host the page (for status messages)</param>
/// <returns>A new instance of the page view model.</returns>
PageViewModel? TryCreatePageViewModel(IPage page, bool nested, AppExtensionHost host);
}

View File

@@ -7,9 +7,11 @@ using Microsoft.CmdPal.Core.ViewModels.Commands;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
// Fix for CS9107: Do not capture 'logger' in the primary constructor; use a regular constructor instead.
public partial class ListItemViewModel : CommandItemViewModel
{
public new ExtensionObject<IListItem> Model { get; }
@@ -31,38 +33,13 @@ public partial class ListItemViewModel : CommandItemViewModel
public string AccessibleName { get; private set; } = string.Empty;
public bool ShowTitle { get; private set; }
private readonly ILogger _logger;
public bool ShowSubtitle { get; private set; }
public bool LayoutShowsTitle
public ListItemViewModel(IListItem model, WeakReference<IPageContext> context, ILogger logger)
: base(new(model), context, logger)
{
get;
set
{
if (SetProperty(ref field, value))
{
UpdateShowsTitle();
}
}
}
public bool LayoutShowsSubtitle
{
get;
set
{
if (SetProperty(ref field, value))
{
UpdateShowsSubtitle();
}
}
}
public ListItemViewModel(IListItem model, WeakReference<IPageContext> context)
: base(new(model), context)
{
Model = new ExtensionObject<IListItem>(model);
Model = new(model);
_logger = logger;
}
public override void InitializeProperties()
@@ -102,7 +79,7 @@ public partial class ListItemViewModel : CommandItemViewModel
var extensionDetails = model.Details;
if (extensionDetails is not null)
{
Details = new(extensionDetails, PageContext);
Details = new(extensionDetails, PageContext, Logger);
Details.InitializeProperties();
UpdateProperty(nameof(Details));
UpdateProperty(nameof(HasDetails));
@@ -126,43 +103,33 @@ public partial class ListItemViewModel : CommandItemViewModel
switch (propertyName)
{
case nameof(model.Tags):
case nameof(Tags):
UpdateTags(model.Tags);
break;
case nameof(model.TextToSuggest):
TextToSuggest = model.TextToSuggest ?? string.Empty;
UpdateProperty(nameof(TextToSuggest));
case nameof(TextToSuggest):
this.TextToSuggest = model.TextToSuggest ?? string.Empty;
break;
case nameof(model.Section):
Section = model.Section ?? string.Empty;
UpdateProperty(nameof(Section));
case nameof(Section):
this.Section = model.Section ?? string.Empty;
break;
case nameof(model.Details):
case nameof(Details):
var extensionDetails = model.Details;
Details = extensionDetails is not null ? new(extensionDetails, PageContext) : null;
Details = extensionDetails is not null ? new(extensionDetails, PageContext, Logger) : null;
Details?.InitializeProperties();
UpdateProperty(nameof(Details));
UpdateProperty(nameof(HasDetails));
UpdateShowDetailsCommand();
break;
case nameof(model.MoreCommands):
UpdateProperty(nameof(MoreCommands));
case nameof(MoreCommands):
AddShowDetailsCommands();
break;
case nameof(model.Title):
UpdateProperty(nameof(Title));
UpdateShowsTitle();
case nameof(Title):
case nameof(Subtitle):
UpdateAccessibleName();
break;
case nameof(model.Subtitle):
UpdateProperty(nameof(Subtitle));
UpdateShowsSubtitle();
UpdateAccessibleName();
break;
default:
UpdateProperty(propertyName);
break;
}
UpdateProperty(propertyName);
}
// TODO: Do we want filters to match descriptions and other properties? Tags, etc... Yes?
@@ -189,7 +156,7 @@ public partial class ListItemViewModel : CommandItemViewModel
// Create the view model for the show details command
var showDetailsCommand = new ShowDetailsCommand(Details);
var showDetailsContextItem = new CommandContextItem(showDetailsCommand);
var showDetailsContextItemViewModel = new CommandContextItemViewModel(showDetailsContextItem, PageContext);
var showDetailsContextItemViewModel = new CommandContextItemViewModel(showDetailsContextItem, PageContext, _logger);
showDetailsContextItemViewModel.SlowInitializeProperties();
MoreCommands.Add(showDetailsContextItemViewModel);
}
@@ -223,7 +190,7 @@ public partial class ListItemViewModel : CommandItemViewModel
// Create the view model for the show details command
var showDetailsCommand = new ShowDetailsCommand(Details);
var showDetailsContextItem = new CommandContextItem(showDetailsCommand);
var showDetailsContextItemViewModel = new CommandContextItemViewModel(showDetailsContextItem, PageContext);
var showDetailsContextItemViewModel = new CommandContextItemViewModel(showDetailsContextItem, PageContext, _logger);
showDetailsContextItemViewModel.SlowInitializeProperties();
MoreCommands.Add(showDetailsContextItemViewModel);
@@ -236,7 +203,7 @@ public partial class ListItemViewModel : CommandItemViewModel
{
var newTags = newTagsFromModel?.Select(t =>
{
var vm = new TagViewModel(t, PageContext);
var vm = new TagViewModel(t, PageContext, Logger);
vm.InitializeProperties();
return vm;
})
@@ -249,32 +216,11 @@ public partial class ListItemViewModel : CommandItemViewModel
// many COM exception issues.
Tags = [.. newTags];
// We're already in UI thread, so just raise the events
OnPropertyChanged(nameof(Tags));
OnPropertyChanged(nameof(HasTags));
UpdateProperty(nameof(Tags));
UpdateProperty(nameof(HasTags));
});
}
private void UpdateShowsTitle()
{
var oldShowTitle = ShowTitle;
ShowTitle = LayoutShowsTitle;
if (oldShowTitle != ShowTitle)
{
UpdateProperty(nameof(ShowTitle));
}
}
private void UpdateShowsSubtitle()
{
var oldShowSubtitle = ShowSubtitle;
ShowSubtitle = LayoutShowsSubtitle && !string.IsNullOrWhiteSpace(Subtitle);
if (oldShowSubtitle != ShowSubtitle)
{
UpdateProperty(nameof(ShowSubtitle));
}
}
protected override void UnsafeCleanup()
{
base.UnsafeCleanup();

View File

@@ -11,6 +11,7 @@ using Microsoft.CmdPal.Core.ViewModels.Messages;
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.CommandPalette.Extensions.Toolkit;
using Microsoft.Extensions.Logging;
using Windows.Foundation;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -19,12 +20,14 @@ public partial class ListViewModel : PageViewModel, IDisposable
{
// private readonly HashSet<ListItemViewModel> _itemCache = [];
private readonly TaskFactory filterTaskFactory = new(new ConcurrentExclusiveSchedulerPair().ExclusiveScheduler);
private readonly ILogger _logger;
// TODO: Do we want a base "ItemsPageViewModel" for anything that's going to have items?
// Observable from MVVM Toolkit will auto create public properties that use INotifyPropertyChange change
// https://learn.microsoft.com/dotnet/communitytoolkit/mvvm/observablegroupedcollections for grouping support
public ObservableCollection<ListItemViewModel> FilteredItems { get; } = [];
[ObservableProperty]
public partial ObservableCollection<ListItemViewModel> FilteredItems { get; set; } = [];
public FiltersViewModel? Filters { get; set; }
@@ -89,11 +92,12 @@ public partial class ListViewModel : PageViewModel, IDisposable
}
}
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host)
: base(model, scheduler, host)
public ListViewModel(IListPage model, TaskScheduler scheduler, AppExtensionHost host, ILogger logger)
: base(model, host, logger)
{
_model = new(model);
EmptyContent = new(new(null), PageContext);
EmptyContent = new(new(null), PageContext, logger);
_logger = logger;
}
private void FiltersPropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
@@ -223,8 +227,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
// TODO we can probably further optimize this by also keeping a
// HashSet of every ExtensionObject we currently have, and only
// building new viewmodels for the ones we haven't already built.
var showsTitle = GridProperties?.ShowTitle ?? true;
var showsSubtitle = GridProperties?.ShowSubtitle ?? true;
foreach (var item in newItems)
{
// Check for cancellation during item processing
@@ -233,13 +235,11 @@ public partial class ListViewModel : PageViewModel, IDisposable
return;
}
ListItemViewModel viewModel = new(item, new(this));
ListItemViewModel viewModel = new(item, new(this), _logger);
// If an item fails to load, silently ignore it.
if (viewModel.SafeFastInit())
{
viewModel.LayoutShowsTitle = showsTitle;
viewModel.LayoutShowsSubtitle = showsSubtitle;
newViewModels.Add(viewModel);
}
}
@@ -586,7 +586,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
GridProperties = LoadGridPropertiesViewModel(model.GridProperties);
GridProperties?.InitializeProperties();
UpdateProperty(nameof(GridProperties));
ApplyLayoutToItems();
ShowDetails = model.ShowDetails;
UpdateProperty(nameof(ShowDetails));
@@ -598,11 +597,11 @@ public partial class ListViewModel : PageViewModel, IDisposable
UpdateProperty(nameof(SearchText));
UpdateProperty(nameof(InitialSearchText));
EmptyContent = new(new(model.EmptyContent), PageContext);
EmptyContent = new(new(model.EmptyContent), PageContext, _logger);
EmptyContent.SlowInitializeProperties();
Filters?.PropertyChanged -= FiltersPropertyChanged;
Filters = new(new(model.Filters), PageContext);
Filters = new(new(model.Filters), PageContext, _logger);
Filters?.PropertyChanged += FiltersPropertyChanged;
Filters?.InitializeProperties();
@@ -612,15 +611,22 @@ public partial class ListViewModel : PageViewModel, IDisposable
model.ItemsChanged += Model_ItemsChanged;
}
private static IGridPropertiesViewModel? LoadGridPropertiesViewModel(IGridProperties? gridProperties)
private IGridPropertiesViewModel? LoadGridPropertiesViewModel(IGridProperties? gridProperties)
{
return gridProperties switch
if (gridProperties is IMediumGridLayout mediumGridLayout)
{
IMediumGridLayout mediumGridLayout => new MediumGridPropertiesViewModel(mediumGridLayout),
IGalleryGridLayout galleryGridLayout => new GalleryGridPropertiesViewModel(galleryGridLayout),
ISmallGridLayout smallGridLayout => new SmallGridPropertiesViewModel(smallGridLayout),
_ => null,
};
return new MediumGridPropertiesViewModel(mediumGridLayout);
}
else if (gridProperties is IGalleryGridLayout galleryGridLayout)
{
return new GalleryGridPropertiesViewModel(galleryGridLayout);
}
else if (gridProperties is ISmallGridLayout smallGridLayout)
{
return new SmallGridPropertiesViewModel(smallGridLayout);
}
return null;
}
public void LoadMoreIfNeeded()
@@ -682,7 +688,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
GridProperties = LoadGridPropertiesViewModel(model.GridProperties);
GridProperties?.InitializeProperties();
UpdateProperty(nameof(IsGridView));
ApplyLayoutToItems();
break;
case nameof(ShowDetails):
ShowDetails = model.ShowDetails;
@@ -694,12 +699,12 @@ public partial class ListViewModel : PageViewModel, IDisposable
SearchText = model.SearchText;
break;
case nameof(EmptyContent):
EmptyContent = new(new(model.EmptyContent), PageContext);
EmptyContent = new(new(model.EmptyContent), PageContext, _logger);
EmptyContent.SlowInitializeProperties();
break;
case nameof(Filters):
Filters?.PropertyChanged -= FiltersPropertyChanged;
Filters = new(new(model.Filters), PageContext);
Filters = new(new(model.Filters), PageContext, _logger);
Filters?.PropertyChanged += FiltersPropertyChanged;
Filters?.InitializeProperties();
break;
@@ -728,21 +733,6 @@ public partial class ListViewModel : PageViewModel, IDisposable
});
}
private void ApplyLayoutToItems()
{
lock (_listLock)
{
var showsTitle = GridProperties?.ShowTitle ?? true;
var showsSubtitle = GridProperties?.ShowSubtitle ?? true;
foreach (var item in Items)
{
item.LayoutShowsTitle = showsTitle;
item.LayoutShowsSubtitle = showsSubtitle;
}
}
}
public void Dispose()
{
GC.SuppressFinalize(this);
@@ -764,7 +754,7 @@ public partial class ListViewModel : PageViewModel, IDisposable
base.UnsafeCleanup();
EmptyContent?.SafeCleanup();
EmptyContent = new(new(null), PageContext); // necessary?
EmptyContent = new(new(null), PageContext, _logger); // necessary?
_cancellationTokenSource?.Cancel();
filterCancellationTokenSource?.Cancel();

View File

@@ -3,13 +3,14 @@
// See the LICENSE file in the project root for more information.
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
public partial class LoadingPageViewModel : PageViewModel
{
public LoadingPageViewModel(IPage? model, TaskScheduler scheduler, AppExtensionHost host)
: base(model, scheduler, host)
public LoadingPageViewModel(IPage? model, AppExtensionHost host, ILogger logger)
: base(model, host, logger)
{
ModelIsLoading = true;
IsInitialized = false;

View File

@@ -4,6 +4,7 @@
using Microsoft.CmdPal.Core.ViewModels.Models;
using Microsoft.CommandPalette.Extensions;
using Microsoft.Extensions.Logging;
namespace Microsoft.CmdPal.Core.ViewModels;
@@ -13,8 +14,8 @@ public partial class LogMessageViewModel : ExtensionObjectViewModel
public string Message { get; private set; } = string.Empty;
public LogMessageViewModel(ILogMessage message, IPageContext context)
: base(context)
public LogMessageViewModel(ILogMessage message, IPageContext context, ILogger logger)
: base(context, logger)
{
_model = new(message);
}

View File

@@ -11,15 +11,13 @@ public class MediumGridPropertiesViewModel : IGridPropertiesViewModel
{
private readonly ExtensionObject<IMediumGridLayout> _model;
public bool ShowTitle { get; private set; }
public bool ShowSubtitle => false;
public MediumGridPropertiesViewModel(IMediumGridLayout mediumGridLayout)
{
_model = new(mediumGridLayout);
}
public bool ShowTitle { get; set; }
public void InitializeProperties()
{
var model = _model.Unsafe;

View File

@@ -7,6 +7,4 @@ namespace Microsoft.CmdPal.Core.ViewModels.Messages;
/// <summary>
/// Used to perform a list item's secondary command when the user presses ctrl+enter in the search box
/// </summary>
public record ActivateSecondaryCommandMessage
{
}
public record ActivateSecondaryCommandMessage;

View File

@@ -7,6 +7,4 @@ namespace Microsoft.CmdPal.Core.ViewModels.Messages;
/// <summary>
/// Used to perform a list item's command when the user presses enter in the search box
/// </summary>
public record ActivateSelectedListItemMessage
{
}
public record ActivateSelectedListItemMessage;

View File

@@ -4,6 +4,4 @@
namespace Microsoft.CmdPal.Core.ViewModels.Messages;
public record ClearSearchMessage()
{
}
public record ClearSearchMessage();

Some files were not shown because too many files have changed in this diff Show More