Compare commits
246 commits
Author | SHA1 | Date | |
---|---|---|---|
|
ae8da16834 | ||
|
6745982d60 | ||
|
cd29b29282 | ||
|
3a473bdc10 | ||
|
3d2ed7395c | ||
|
3884c4446f | ||
|
11d0c30ddb | ||
|
f7eb0abe43 | ||
|
cad1ec393f | ||
|
4df563f1bb | ||
|
e8f06c1368 | ||
|
2c06fe1684 | ||
|
9e85ee5810 | ||
|
4998a104ea | ||
|
1fd82f35c8 | ||
|
e7b141e095 | ||
|
304c654e80 | ||
|
9661f8bd79 | ||
|
5d26d86e28 | ||
|
f05d569387 | ||
|
f66dc3afd8 | ||
|
5f666b20d1 | ||
|
2d695d11bf | ||
|
8da7d9b4bc | ||
|
f7a1f92343 | ||
|
8771c2edd7 | ||
|
f34fffa574 | ||
|
cce0f7f52d | ||
|
8c5d6475ad | ||
|
052cb05f53 | ||
|
40f8f5cefd | ||
|
7dc0cbee82 | ||
|
1a5d9442d2 | ||
|
d36bf0c56c | ||
|
9224d62191 | ||
|
e41caba220 | ||
|
769f35b681 | ||
|
2ba0a5395b | ||
|
e4be317e77 | ||
|
fb5f538b88 | ||
|
3b5813bb35 | ||
|
de1b815d57 | ||
|
62452f3e0b | ||
|
0adf762fa0 | ||
|
05a740a21f | ||
|
4330c95216 | ||
|
23b63d09ea | ||
|
6097ab4bc7 | ||
|
aacaefc205 | ||
|
557a3bbddb | ||
|
189611ad3a | ||
|
86926ffd27 | ||
|
10dd03498a | ||
|
3c585c1dab | ||
|
172cbdc35c | ||
|
5fc59d5bc5 | ||
|
8c710ab55c | ||
|
4f7479b0b7 | ||
|
c15ab870ac | ||
|
c719aee32f | ||
|
2cfa8ce92f | ||
|
83c228b6fe | ||
|
5d6c71d03a | ||
|
c58027bb9c | ||
|
62a03e4ed3 | ||
|
fe06972d58 | ||
|
b70db0aa53 | ||
|
2bfd021698 | ||
|
0e622b8021 | ||
|
5a794baf8b | ||
|
a5dd48becf | ||
|
13cd0ab8d5 | ||
|
52231e20ab | ||
|
362df4c720 | ||
|
5925950f24 | ||
|
c292fdd1b1 | ||
|
ecd57678e1 | ||
|
145769a886 | ||
|
b32fbee4d0 | ||
|
cfb1793dc6 | ||
|
2b288cb295 | ||
|
04e569fbcb | ||
|
3c6f053b00 | ||
|
bac953a9e4 | ||
|
ab1f69d06b | ||
|
44b17d4225 | ||
|
23fd9ba665 | ||
|
7d431a22f1 | ||
|
384154254a | ||
|
041ddcbb6d | ||
|
6764546824 | ||
|
453a4cb9e9 | ||
|
6feaa24d92 | ||
|
b03ddd4470 | ||
|
886182afc1 | ||
|
b519812fa5 | ||
|
cf4a966e28 | ||
|
9334f516a1 | ||
|
21e664b4c0 | ||
|
bc25a0ea01 | ||
|
d4742d6127 | ||
|
ddbbe88032 | ||
|
021205f255 | ||
|
a398bba08a | ||
|
e3b184b68d | ||
|
fffdf03c10 | ||
|
0d6940b6ec | ||
|
12e6522a78 | ||
|
9e63a2b853 | ||
|
b392ac84f9 | ||
|
573b453704 | ||
|
cabca12856 | ||
|
7f5f465362 | ||
|
cd328c2979 | ||
|
7dfd7f5616 | ||
|
3cb7f93cee | ||
|
e4571e4f34 | ||
|
4d6b24d8fc | ||
|
6910013026 | ||
|
0d5d0372ee | ||
|
b758b474cd | ||
|
3847a6eff0 | ||
|
94c7bd18c4 | ||
|
34c0dbd0cf | ||
|
1a13cf8b11 | ||
|
cea1088a7d | ||
|
8e33aab670 | ||
|
c7f0f29961 | ||
|
5296f7dff5 | ||
|
dfec7db6b7 | ||
|
80c43c2051 | ||
|
db3201ade2 | ||
|
efc2d0bb67 | ||
|
0d3d5c24f3 | ||
|
76118726a8 | ||
|
ee8603c5b6 | ||
|
9cb7fd2e90 | ||
|
382a427a47 | ||
|
c0e1af0c10 | ||
|
a40273567a | ||
|
c5c12dcad3 | ||
|
6cbfea8f69 | ||
|
cee860c2d4 | ||
|
a515bd6e6e | ||
|
23fd772152 | ||
|
b02d160872 | ||
|
b758dfed2d | ||
|
96caaa9cd8 | ||
|
5d15d4c042 | ||
|
580a0864e2 | ||
|
748d86ddc8 | ||
|
a98717ab4e | ||
|
3d38b70cf1 | ||
|
d39563b9b5 | ||
|
df594f6045 | ||
|
c8575c1b03 | ||
|
cc2fa3311c | ||
|
ea1b7baea6 | ||
|
346e5fdb36 | ||
|
bff39c71dc | ||
|
f23646e480 | ||
|
31e0ebc85e | ||
|
860034633a | ||
|
9d80f6c1b2 | ||
|
61133e14b5 | ||
|
6b2bbba706 | ||
|
2fd2ff129b | ||
|
cf5e26af87 | ||
|
a541eb0a6c | ||
|
c47246cc65 | ||
|
4fc6f7ad40 | ||
|
bcd23a31f2 | ||
|
2b0c470ce5 | ||
|
665aed45f7 | ||
|
ed3ee46735 | ||
|
e04dc2ee07 | ||
|
5d286a467d | ||
|
ebe7c5d33d | ||
|
08ef381f96 | ||
|
090fa0e3ad | ||
|
2763659b4c | ||
|
f6007a4b62 | ||
|
d22a183554 | ||
|
b575920805 | ||
|
2b73c3c2bc | ||
|
eea9165382 | ||
|
8d3816553b | ||
|
e6f11c354d | ||
|
1b4f62ee7d | ||
|
800b6afa15 | ||
|
452ef9017c | ||
|
1ef5e99d40 | ||
|
7fd80af8bf | ||
|
e8322d5a8a | ||
|
ef02d287d5 | ||
|
a1a3574f73 | ||
|
1e580843ff | ||
|
4cece1ab9c | ||
|
0a6c00c3a7 | ||
|
697e79b1ba | ||
|
7bd8511bb9 | ||
|
2a7a108748 | ||
|
3240042a68 | ||
|
ae75d66172 | ||
|
05dec2e6dd | ||
|
8b12f6e4a8 | ||
|
eade031052 | ||
|
b13bcf0b58 | ||
|
2d14ef2cb9 | ||
|
bed63a11f4 | ||
|
e7b52a035c | ||
|
4136e5d2a1 | ||
|
e99518f23b | ||
|
b1888cbf9b | ||
|
e5194d8660 | ||
|
ef6e0a6b37 | ||
|
451ecb9424 | ||
|
d3b1862113 | ||
|
f81735509a | ||
|
b8a03dd189 | ||
|
2b36e580b9 | ||
|
806fcd6bd2 | ||
|
185b34268c | ||
|
db6ca09f65 | ||
|
ff53cc352d | ||
|
5ecc8bdf1b | ||
|
a723695ff4 | ||
|
c6877b688f | ||
|
d1cf04ec3d | ||
|
8890db68e6 | ||
|
cf7a4b831a | ||
|
28a02c0a12 | ||
|
b782e9b034 | ||
|
63334fa67c | ||
|
5fc803757a | ||
|
958624db0a | ||
|
db2d8c5fb0 | ||
|
dfe5dbd16c | ||
|
8d68937a96 | ||
|
88e5a24441 | ||
|
a5221064eb | ||
|
74da136678 | ||
|
9c7c17a5b7 | ||
|
e166a3f89d | ||
|
2a95cebe6a | ||
|
d0ed7aa288 |
18
Help.md
|
@ -6,8 +6,9 @@
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| -gui=0 | Do not display the PersistentWindows icon on the System Tray. Effectively runs PersistentWindows as a service
|
| -gui=0 | Do not display the PersistentWindows icon on the System Tray. Effectively runs PersistentWindows as a service
|
||||||
| -splash=0 | No splash window at PersistentWindows startup
|
| -splash=0 | No splash window at PersistentWindows startup
|
||||||
| -legacy_icon | Switch to the original icon (as of 5.49 release)
|
| -legacy_icon | Switch to the original icon 
|
||||||
| -silent | No splash window, no balloon tip hint, no event logging
|
| -silent | No splash window, no balloon tip hint, no event logging
|
||||||
|
| -capture_floating_window=0 | Disable capture floating child window and dialog window position
|
||||||
| -ignore_process "notepad.exe;foo" | Avoid restoring windows for the processes notepad.exe and foo
|
| -ignore_process "notepad.exe;foo" | Avoid restoring windows for the processes notepad.exe and foo
|
||||||
| -debug_process "notepad.exe;foo" | Print the window positioning event logs in Event Viewer for the processes *notepad.exe* and *foo*
|
| -debug_process "notepad.exe;foo" | Print the window positioning event logs in Event Viewer for the processes *notepad.exe* and *foo*
|
||||||
| -foreground_background_dual_position=0 | Turn off dual position switching
|
| -foreground_background_dual_position=0 | Turn off dual position switching
|
||||||
|
@ -15,6 +16,7 @@
|
||||||
| -hotkey "Q" | register Alt + Q as the hotkey to (de)activate webpage commander window, default hotkey is "W" (Alt + W)
|
| -hotkey "Q" | register Alt + Q as the hotkey to (de)activate webpage commander window, default hotkey is "W" (Alt + W)
|
||||||
| -ctrl_minimize_to_tray=0 | Turn off ctrl minimize window to notification tray
|
| -ctrl_minimize_to_tray=0 | Turn off ctrl minimize window to notification tray
|
||||||
| -prompt_session_restore | Ask the user before restoring the window layout upon resuming the last session. This may help reduce the total restore time for remote desktop sessions on slow internet connections.
|
| -prompt_session_restore | Ask the user before restoring the window layout upon resuming the last session. This may help reduce the total restore time for remote desktop sessions on slow internet connections.
|
||||||
|
| -delay_restart 5 | Restart PersistentWindows in 5 seconds. This option should only be used in case normal start of PersistentWindows fails.
|
||||||
| -delay_auto_capture 1.0 | Adjust the lag between window move event and auto-capture to 1.0 second, the default lag is 3~4 seconds.
|
| -delay_auto_capture 1.0 | Adjust the lag between window move event and auto-capture to 1.0 second, the default lag is 3~4 seconds.
|
||||||
| *-delay_auto_restore 2.5* | Adjust the lag between monitor on/off event and auto-restore to 2.5 seconds (the default lag is 1 second). This is in case the restore is incomplete or the monitor fails to go to sleep due to the restore starting too early.
|
| *-delay_auto_restore 2.5* | Adjust the lag between monitor on/off event and auto-restore to 2.5 seconds (the default lag is 1 second). This is in case the restore is incomplete or the monitor fails to go to sleep due to the restore starting too early.
|
||||||
| -redraw_desktop | Redraw the whole desktop after a restore, in case some window workarea is not refreshed
|
| -redraw_desktop | Redraw the whole desktop after a restore, in case some window workarea is not refreshed
|
||||||
|
@ -22,13 +24,17 @@
|
||||||
| -fix_offscreen_window=0 | Turn off auto correction of off-screen windows
|
| -fix_offscreen_window=0 | Turn off auto correction of off-screen windows
|
||||||
| -fix_unminimized_window=0 | Turn off auto restore of unminimized windows. Use this switch to avoid undesirable window shifting during window activation, which comes with Event id 9999 : "restore minimized window ...." in event viewer.
|
| -fix_unminimized_window=0 | Turn off auto restore of unminimized windows. Use this switch to avoid undesirable window shifting during window activation, which comes with Event id 9999 : "restore minimized window ...." in event viewer.
|
||||||
|-auto_restore_new_display_session_from_db=0| Disable window restore from DB upon PC startup or switching display for the first time
|
|-auto_restore_new_display_session_from_db=0| Disable window restore from DB upon PC startup or switching display for the first time
|
||||||
|
|-auto_restore_existing_window_to_last_capture=1 | Turn on auto restore existing window from last capture upon PW start
|
||||||
|
|-auto_restore_new_window_to_last_capture=0 | Turn off auto restore new window to last killed position
|
||||||
|
|-pos_match_threshold 80 | Auto correct new window position to last killed position within range of 80 pixels, default is 40
|
||||||
| ‑auto_restore_missing_windows=1 | When restoring from disk, restore missing windows without prompting the user
|
| ‑auto_restore_missing_windows=1 | When restoring from disk, restore missing windows without prompting the user
|
||||||
| ‑auto_restore_missing_windows=2 | At startup, automatically restore missing windows from disk. The user will be prompted before restoring each missing window
|
| ‑auto_restore_missing_windows=2 | At startup, automatically restore missing windows from disk. The user will be prompted before restoring each missing window
|
||||||
| ‑auto_restore_missing_windows=3 | At startup, automatically restore missing windows from disk without prompting the user
|
| ‑auto_restore_missing_windows=3 | At startup, automatically restore missing windows from disk without prompting the user
|
||||||
| -invoke_multi_window_process_only_once=0 | Launch an application multiple times when multiple windows of the same process need to be restored from the database.
|
| -invoke_multi_window_process_only_once=0 | Launch an application multiple times when multiple windows of the same process need to be restored from the database.
|
||||||
| -check_upgrade=0 | Disable the PersistentWindows upgrade check
|
| -check_upgrade=0 | Disable the PersistentWindows upgrade check
|
||||||
| -auto_upgrade=1 | Upgrade PersistentWindows automatically without user interaction
|
| -auto_upgrade=1 | Upgrade PersistentWindows automatically without user interaction
|
||||||
|
| -dump_window_position_history=0 | Disable window position history dump
|
||||||
|
| -restore_snapshot "0" | restore snapshot 0 and exit. The range of snapshot id is [0-9a-z], as well as "~" or "`", the last two special ids represent the last auto restore. Note the window z-order can not be fully retored using this method, due to lack of capability to do multi-pass restore.
|
||||||
---
|
---
|
||||||
|
|
||||||
### Shortcuts to capture/restore snapshots
|
### Shortcuts to capture/restore snapshots
|
||||||
|
@ -54,7 +60,6 @@
|
||||||
|
|
||||||
* Dual Position Switching functionality:
|
* Dual Position Switching functionality:
|
||||||
* Click the desktop window to bring the foreground window to its previous background position and Z-order.
|
* Click the desktop window to bring the foreground window to its previous background position and Z-order.
|
||||||
* Shift + Click the desktop window to bring the foreground window to its *second* last background position. This is useful if the previous background position is mis-captured due to invoking start menu or other popups.
|
|
||||||
* Ctrl + Click the desktop window to bring the foreground window to its previous Z-order while keeping the current location and size.
|
* Ctrl + Click the desktop window to bring the foreground window to its previous Z-order while keeping the current location and size.
|
||||||
|
|
||||||
* To cancel Dual Position Switching:
|
* To cancel Dual Position Switching:
|
||||||
|
@ -110,7 +115,8 @@
|
||||||
| Alt + click commander window || send the mouse click to the underlying browser window
|
| Alt + click commander window || send the mouse click to the underlying browser window
|
||||||
|
|
||||||
### Other features
|
### Other features
|
||||||
* To replace the default app icon with your customized one:
|
* To replace the default app icons with customized one:
|
||||||
* Rename your .ico (or .png) file as `pwIcon.ico` (or `pwIcon.png`) and copy it to the PersistentWindows program folder, or alternatively to `C:/Users/<YOUR_ID>/AppData/Local/PersistentWindows/`.
|
* Rename customized .ico (or .png) file as `pwIcon.ico` (or `pwIcon.png`) and copy it to the PersistentWindows program folder, or alternatively to `C:/Users/<YOUR_ID>/AppData/Local/PersistentWindows/`.
|
||||||
* Copy another icon file to the same directory and rename it to `pwIconBusy.*`. This icon is displayed when PersistentWindows is busy restoring windows.
|
* Copy another ico/png file to the same directory and rename it to `pwIconBusy.*`. This icon is displayed when PersistentWindows is busy restoring windows.
|
||||||
|
* Copy yet another ico/png file to the same directory and rename it to `pwIconUpdate.*`. This icon is displayed when a new PersistentWindows release is available.
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Drawing" />
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Runtime.Serialization" />
|
||||||
<Reference Include="System.Windows.Forms" />
|
<Reference Include="System.Windows.Forms" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -93,21 +94,9 @@
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<EmbeddedResource Include="DbKeySelect.resx">
|
|
||||||
<DependentUpon>DbKeySelect.cs</DependentUpon>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Include="HotKeyWindow.resx">
|
|
||||||
<DependentUpon>HotKeyWindow.cs</DependentUpon>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Include="LayoutProfile.resx">
|
|
||||||
<DependentUpon>LayoutProfile.cs</DependentUpon>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Include="LaunchProcess.resx">
|
<EmbeddedResource Include="LaunchProcess.resx">
|
||||||
<DependentUpon>LaunchProcess.cs</DependentUpon>
|
<DependentUpon>LaunchProcess.cs</DependentUpon>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
<EmbeddedResource Include="NameDbKey.resx">
|
|
||||||
<DependentUpon>NameDbKey.cs</DependentUpon>
|
|
||||||
</EmbeddedResource>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<root>
|
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:choice maxOccurs="unbounded">
|
|
||||||
<xsd:element name="metadata">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="assembly">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:attribute name="alias" type="xsd:string" />
|
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="data">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="resheader">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:choice>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
<resheader name="resmimetype">
|
|
||||||
<value>text/microsoft-resx</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="version">
|
|
||||||
<value>2.0</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="reader">
|
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="writer">
|
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
</root>
|
|
|
@ -6,7 +6,6 @@ using System.Data;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
@ -21,25 +20,30 @@ namespace PersistentWindows.Common
|
||||||
private uint hotkey;
|
private uint hotkey;
|
||||||
|
|
||||||
public static IntPtr commanderWnd = IntPtr.Zero;
|
public static IntPtr commanderWnd = IntPtr.Zero;
|
||||||
|
public static bool invokedFromBrowser = false;
|
||||||
|
|
||||||
private static System.Timers.Timer aliveTimer;
|
private static System.Timers.Timer aliveTimer;
|
||||||
|
private static int callerAliveTimer = -1; //for tracing the starting source of alive timer
|
||||||
|
|
||||||
private System.Timers.Timer mouseScrollDelayTimer;
|
private System.Timers.Timer mouseScrollDelayTimer;
|
||||||
private bool init = true;
|
private bool init = true;
|
||||||
private bool active = false;
|
private bool active = false;
|
||||||
private static bool tiny = false;
|
private static bool tiny = false;
|
||||||
private static bool browserWindowActivated = false;
|
private static bool browserWindowActivated = false;
|
||||||
|
private static bool restoring = false;
|
||||||
private int origWidth;
|
private int origWidth;
|
||||||
private int origHeight;
|
private int origHeight;
|
||||||
private int mouseOffset = 0;
|
private int mouseOffset = 0; //mouse dithering to workaround mouse location mis-update issue in rdp session
|
||||||
private static POINT lastCursorPos;
|
private static POINT lastCursorPos;
|
||||||
private POINT lastWheelCursorPos;
|
private POINT lastWheelCursorPos;
|
||||||
private bool handCursor = false;
|
private bool handCursor = false;
|
||||||
|
private bool ibeamCursor = false;
|
||||||
private int titleHeight;
|
private int titleHeight;
|
||||||
private static int callerAliveTimer = -1; //for tracing the starting source of alive timer
|
|
||||||
private Color dfltBackColor;
|
private Color dfltBackColor;
|
||||||
private bool promptZkey = true;
|
private bool promptZkey = true;
|
||||||
private bool clickThrough = false;
|
private bool clickThrough = false;
|
||||||
private bool defocused = false;
|
private bool defocused = false;
|
||||||
|
private int totalWaitSecondsForWhiteColor = 0;
|
||||||
|
|
||||||
public HotKeyWindow(uint hkey)
|
public HotKeyWindow(uint hkey)
|
||||||
{
|
{
|
||||||
|
@ -203,6 +207,7 @@ namespace PersistentWindows.Common
|
||||||
Visible = false;
|
Visible = false;
|
||||||
IntPtr fgwnd = GetForegroundWindow();
|
IntPtr fgwnd = GetForegroundWindow();
|
||||||
User32.SetForegroundWindow(fgwnd);
|
User32.SetForegroundWindow(fgwnd);
|
||||||
|
FgSleep();
|
||||||
|
|
||||||
if (alt_key_pressed || clickThrough)
|
if (alt_key_pressed || clickThrough)
|
||||||
{
|
{
|
||||||
|
@ -273,7 +278,7 @@ namespace PersistentWindows.Common
|
||||||
StartAliveTimer(1);
|
StartAliveTimer(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsBrowserWindow(IntPtr hwnd)
|
private bool IsBrowserWindow(IntPtr hwnd)
|
||||||
{
|
{
|
||||||
return PersistentWindowProcessor.IsBrowserWindow(hwnd);
|
return PersistentWindowProcessor.IsBrowserWindow(hwnd);
|
||||||
}
|
}
|
||||||
|
@ -591,9 +596,16 @@ namespace PersistentWindows.Common
|
||||||
{
|
{
|
||||||
if (!from_menu)
|
if (!from_menu)
|
||||||
{
|
{
|
||||||
IntPtr fgwnd = GetForegroundWindow();
|
IntPtr fgwnd = GetForegroundWindow(strict : true);
|
||||||
if (!IsBrowserWindow(fgwnd))
|
if (fgwnd == commanderWnd)
|
||||||
|
fgwnd = GetForegroundWindow();
|
||||||
|
if (IsBrowserWindow(fgwnd))
|
||||||
{
|
{
|
||||||
|
invokedFromBrowser = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
invokedFromBrowser = false;
|
||||||
//forward hotkey
|
//forward hotkey
|
||||||
char c = Convert.ToChar(hotkey);
|
char c = Convert.ToChar(hotkey);
|
||||||
string cmd = $"%{c}";
|
string cmd = $"%{c}";
|
||||||
|
@ -629,13 +641,18 @@ namespace PersistentWindows.Common
|
||||||
active = false;
|
active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static void BrowserActivate(IntPtr hwnd, bool is_browser_window = true)
|
public static void BrowserActivate(IntPtr hwnd, bool is_browser_window = true, bool in_restore = false)
|
||||||
{
|
{
|
||||||
|
if (browserWindowActivated == is_browser_window)
|
||||||
|
return;
|
||||||
|
|
||||||
browserWindowActivated = is_browser_window;
|
browserWindowActivated = is_browser_window;
|
||||||
|
restoring = in_restore;
|
||||||
|
|
||||||
|
Console.WriteLine($"browser activated {hwnd.ToString("X")}");
|
||||||
|
|
||||||
if (!tiny && !User32.IsWindowVisible(commanderWnd))
|
if (!tiny && !User32.IsWindowVisible(commanderWnd))
|
||||||
return;
|
return;
|
||||||
|
@ -715,7 +732,7 @@ namespace PersistentWindows.Common
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsSimilarColor(IntPtr hwnd, int x, int y, int xsize, int ysize)
|
private bool IsSimilarColor(IntPtr hwnd, int x, int y, int xsize, int ysize, Color px)
|
||||||
{
|
{
|
||||||
using (Bitmap screenPixel = new Bitmap(xsize, ysize))
|
using (Bitmap screenPixel = new Bitmap(xsize, ysize))
|
||||||
{
|
{
|
||||||
|
@ -731,20 +748,16 @@ namespace PersistentWindows.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var p1 = screenPixel.GetPixel(0, 0);
|
Console.WriteLine($"pixel ({x}, {y}) {px}");
|
||||||
var p2 = screenPixel.GetPixel(xsize - 1, 0);
|
for (int i = 0; i < xsize; ++i)
|
||||||
Console.WriteLine($"pixel ({x}, {y}) {p1}");
|
|
||||||
for (int i = 1; i < xsize; ++i)
|
|
||||||
{
|
{
|
||||||
Color p = screenPixel.GetPixel(i, i);
|
Color p = screenPixel.GetPixel(i, i);
|
||||||
if (DiffColor(p, p1) > 10)
|
if (DiffColor(p, px) > 15)
|
||||||
return false;
|
return false;
|
||||||
p1 = p;
|
|
||||||
|
|
||||||
p = screenPixel.GetPixel(xsize - i - 1, i);
|
p = screenPixel.GetPixel(xsize - i - 1, i);
|
||||||
if (DiffColor(p, p2) > 10)
|
if (DiffColor(p, px) > 15)
|
||||||
return false;
|
return false;
|
||||||
p2 = p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -783,6 +796,37 @@ namespace PersistentWindows.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool IsSameColor(IntPtr hwnd, int x, int y, int xsize, int ysize, Color px)
|
||||||
|
{
|
||||||
|
using (Bitmap screenPixel = new Bitmap(xsize, ysize))
|
||||||
|
{
|
||||||
|
using (Graphics gdest = Graphics.FromImage(screenPixel))
|
||||||
|
{
|
||||||
|
using (Graphics gsrc = Graphics.FromHwnd(hwnd))
|
||||||
|
{
|
||||||
|
IntPtr hsrcdc = gsrc.GetHdc();
|
||||||
|
IntPtr hdc = gdest.GetHdc();
|
||||||
|
Gdi32.BitBlt(hdc, 0, 0, xsize, ysize, hsrcdc, x, y, (int)CopyPixelOperation.SourceCopy);
|
||||||
|
gdest.ReleaseHdc();
|
||||||
|
gsrc.ReleaseHdc();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine($"pixel ({x}, {y}) {px}");
|
||||||
|
for (int i = 0; i < xsize; ++i)
|
||||||
|
{
|
||||||
|
var p = screenPixel.GetPixel(i, i);
|
||||||
|
if (p.ToArgb() != px.ToArgb())
|
||||||
|
return false;
|
||||||
|
p = screenPixel.GetPixel(xsize - i - 1, i);
|
||||||
|
if (p.ToArgb() != px.ToArgb())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void AliveTimerCallBack(Object source, ElapsedEventArgs e)
|
private void AliveTimerCallBack(Object source, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
if (!active)
|
if (!active)
|
||||||
|
@ -793,12 +837,15 @@ namespace PersistentWindows.Common
|
||||||
IntPtr fgwnd = GetForegroundWindow();
|
IntPtr fgwnd = GetForegroundWindow();
|
||||||
if (!PersistentWindowProcessor.IsBrowserWindow(fgwnd))
|
if (!PersistentWindowProcessor.IsBrowserWindow(fgwnd))
|
||||||
{
|
{
|
||||||
if (browserWindowActivated)
|
if (browserWindowActivated || restoring)
|
||||||
{
|
|
||||||
StartAliveTimer(6, 1000);
|
StartAliveTimer(6, 1000);
|
||||||
return;
|
else
|
||||||
}
|
Visible = false;
|
||||||
Visible = false;
|
return;
|
||||||
|
}
|
||||||
|
else if (restoring)
|
||||||
|
{
|
||||||
|
StartAliveTimer(6, 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,7 +870,9 @@ namespace PersistentWindows.Common
|
||||||
}
|
}
|
||||||
else if (Math.Abs(cursorPos.X - lastCursorPos.X) > 3 || Math.Abs(cursorPos.Y - lastCursorPos.Y) > 3)
|
else if (Math.Abs(cursorPos.X - lastCursorPos.X) > 3 || Math.Abs(cursorPos.Y - lastCursorPos.Y) > 3)
|
||||||
{
|
{
|
||||||
|
ibeamCursor = false;
|
||||||
//mouse moving, continue monitor
|
//mouse moving, continue monitor
|
||||||
|
totalWaitSecondsForWhiteColor = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -831,39 +880,53 @@ namespace PersistentWindows.Common
|
||||||
if (hCursor == Cursors.Default.Handle)
|
if (hCursor == Cursors.Default.Handle)
|
||||||
{
|
{
|
||||||
handCursor = false;
|
handCursor = false;
|
||||||
if (!commanderWndUnderCursor && !IsSimilarColor(IntPtr.Zero, cursorPos.X - Width/2, cursorPos.Y - Height/2, 12, 12))
|
|
||||||
|
if (callerAliveTimer == 6)
|
||||||
{
|
{
|
||||||
// hide hotkey window to allow click through possible link
|
//browser activation
|
||||||
Visible = false;
|
;
|
||||||
clickThrough = true;
|
}
|
||||||
|
else if (!commanderWndUnderCursor && !IsUniColor(IntPtr.Zero, cursorPos.X - Width / 2, cursorPos.Y - Height / 2, 12, 12))
|
||||||
|
{
|
||||||
|
// shift commander window to allow click possible link
|
||||||
|
Left = cursorPos.X - 10;
|
||||||
|
Top = cursorPos.Y - 10;
|
||||||
|
totalWaitSecondsForWhiteColor = 0;
|
||||||
StartAliveTimer(11, 1000);
|
StartAliveTimer(11, 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if (!commanderWndUnderCursor && !IsSimilarColor(IntPtr.Zero, cursorPos.X - Width / 2, cursorPos.Y - Height / 2, 1, 1, Color.White))
|
||||||
if (!commanderWndUnderCursor && !IsUniColor(IntPtr.Zero, cursorPos.X - Width / 2, cursorPos.Y - Height / 2, 12, 12))
|
|
||||||
{
|
{
|
||||||
Left = cursorPos.X - 10;
|
// wait for possible menu selection within webpage
|
||||||
Top = cursorPos.Y - 10;
|
++totalWaitSecondsForWhiteColor;
|
||||||
StartAliveTimer(11, 1000);
|
if (Visible && totalWaitSecondsForWhiteColor < 3)
|
||||||
return;
|
{
|
||||||
|
StartAliveTimer(11, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (hCursor == Cursors.IBeam.Handle)
|
else if (hCursor == Cursors.IBeam.Handle)
|
||||||
{
|
{
|
||||||
|
ibeamCursor = true;
|
||||||
Visible = false;
|
Visible = false;
|
||||||
StartAliveTimer(11, 1000);
|
StartAliveTimer(11, 1000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (hCursor == Cursors.Cross.Handle || handCursor)
|
else if (hCursor == Cursors.Cross.Handle || handCursor)
|
||||||
{
|
{
|
||||||
|
ibeamCursor = false;
|
||||||
StartAliveTimer(7);
|
StartAliveTimer(7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totalWaitSecondsForWhiteColor = 0;
|
||||||
|
|
||||||
bool regain_focus = true;
|
bool regain_focus = true;
|
||||||
|
bool change_to_visible = false;
|
||||||
if (!Visible)
|
if (!Visible)
|
||||||
{
|
{
|
||||||
Visible = true;
|
change_to_visible = true;
|
||||||
TopMost = true;
|
TopMost = true;
|
||||||
if (defocused)
|
if (defocused)
|
||||||
{
|
{
|
||||||
|
@ -871,7 +934,7 @@ namespace PersistentWindows.Common
|
||||||
regain_focus = false;
|
regain_focus = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!handCursor)
|
else if (hCursor == Cursors.Default.Handle)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
if (!commanderWndUnderCursor)
|
if (!commanderWndUnderCursor)
|
||||||
|
@ -882,15 +945,29 @@ namespace PersistentWindows.Common
|
||||||
*/
|
*/
|
||||||
regain_focus = !commanderWndUnderCursor;
|
regain_focus = !commanderWndUnderCursor;
|
||||||
}
|
}
|
||||||
|
else if (!handCursor)
|
||||||
|
{
|
||||||
|
regain_focus = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ibeamCursor && hCursor == Cursors.Default.Handle)
|
||||||
|
//&& Math.Abs(cursorPos.X - lastCursorPos.X) < 3 && Math.Abs(cursorPos.Y - lastCursorPos.Y) < 3)
|
||||||
|
{
|
||||||
|
ibeamCursor = false;
|
||||||
|
StartAliveTimer(11, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// let tiny hotkey window follow cursor position
|
// let tiny hotkey window follow cursor position
|
||||||
ResetHotKeyVirtualDesktop();
|
ResetHotKeyVirtualDesktop();
|
||||||
|
ResetHotkeyWindowPos();
|
||||||
|
if (change_to_visible)
|
||||||
|
Visible = true;
|
||||||
if (regain_focus)
|
if (regain_focus)
|
||||||
{
|
{
|
||||||
User32.SetForegroundWindow(Handle);
|
User32.SetForegroundWindow(Handle);
|
||||||
User32.SetFocus(Handle);
|
User32.SetFocus(Handle);
|
||||||
}
|
}
|
||||||
ResetHotkeyWindowPos();
|
|
||||||
|
|
||||||
if (hCursor == Cursors.Default.Handle)
|
if (hCursor == Cursors.Default.Handle)
|
||||||
{
|
{
|
||||||
|
@ -903,6 +980,7 @@ namespace PersistentWindows.Common
|
||||||
// hand cursor shape
|
// hand cursor shape
|
||||||
if (!handCursor)
|
if (!handCursor)
|
||||||
{
|
{
|
||||||
|
ibeamCursor = false;
|
||||||
handCursor = true;
|
handCursor = true;
|
||||||
Left -= 10;
|
Left -= 10;
|
||||||
}
|
}
|
||||||
|
@ -1054,9 +1132,9 @@ namespace PersistentWindows.Common
|
||||||
User32.SetForegroundWindow(Handle);
|
User32.SetForegroundWindow(Handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IntPtr GetForegroundWindow()
|
public static IntPtr GetForegroundWindow(bool strict = false)
|
||||||
{
|
{
|
||||||
return PersistentWindowProcessor.GetForegroundWindow();
|
return PersistentWindowProcessor.GetForegroundWindow(strict);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FormSizeChanged(object sender, EventArgs e)
|
private void FormSizeChanged(object sender, EventArgs e)
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<root>
|
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:choice maxOccurs="unbounded">
|
|
||||||
<xsd:element name="metadata">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="assembly">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:attribute name="alias" type="xsd:string" />
|
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="data">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="resheader">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:choice>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
<resheader name="resmimetype">
|
|
||||||
<value>text/microsoft-resx</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="version">
|
|
||||||
<value>2.0</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="reader">
|
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="writer">
|
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
</root>
|
|
|
@ -1,120 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<root>
|
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:choice maxOccurs="unbounded">
|
|
||||||
<xsd:element name="metadata">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="assembly">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:attribute name="alias" type="xsd:string" />
|
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="data">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="resheader">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:choice>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
<resheader name="resmimetype">
|
|
||||||
<value>text/microsoft-resx</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="version">
|
|
||||||
<value>2.0</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="reader">
|
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="writer">
|
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
</root>
|
|
|
@ -1,7 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
using System.Text;
|
||||||
|
using System.Xml;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
using PersistentWindows.Common.WinApiBridge;
|
using PersistentWindows.Common.WinApiBridge;
|
||||||
using PersistentWindows.Common.Diagnostics;
|
|
||||||
|
|
||||||
namespace PersistentWindows.Common.Models
|
namespace PersistentWindows.Common.Models
|
||||||
{
|
{
|
||||||
|
@ -23,6 +26,8 @@ namespace PersistentWindows.Common.Models
|
||||||
public bool IsFullScreen { get; set; }
|
public bool IsFullScreen { get; set; }
|
||||||
public bool IsMinimized { get; set; }
|
public bool IsMinimized { get; set; }
|
||||||
public bool IsInvisible { get; set; }
|
public bool IsInvisible { get; set; }
|
||||||
|
public long Style { get; set; }
|
||||||
|
public long ExtStyle { get; set; }
|
||||||
|
|
||||||
// for restore window position to display session end time
|
// for restore window position to display session end time
|
||||||
public DateTime CaptureTime { get; set; }
|
public DateTime CaptureTime { get; set; }
|
||||||
|
@ -55,7 +60,15 @@ namespace PersistentWindows.Common.Models
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
//return string.Format("{0}.{1} {2}", ProcessId, HWnd.ToString("X8"), ProcessName);
|
//return string.Format("{0}.{1} {2}", ProcessId, HWnd.ToString("X8"), ProcessName);
|
||||||
return string.Format("{0}.{1:x8} {2}", ProcessId, HWnd.ToInt64(), ProcessName);
|
//return string.Format("process:{0:x4} hwnd:{1:x6} {2}", ProcessId, HWnd.ToInt64(), ProcessName);
|
||||||
|
DataContractSerializer dcs = new DataContractSerializer(typeof(ApplicationDisplayMetrics));
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
using (XmlWriter xw = XmlWriter.Create(sb))
|
||||||
|
{
|
||||||
|
dcs.WriteObject(xw, this);
|
||||||
|
}
|
||||||
|
string xml = sb.ToString();
|
||||||
|
return xml;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,120 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<root>
|
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:choice maxOccurs="unbounded">
|
|
||||||
<xsd:element name="metadata">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="assembly">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:attribute name="alias" type="xsd:string" />
|
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="data">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="resheader">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:choice>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
<resheader name="resmimetype">
|
|
||||||
<value>text/microsoft-resx</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="version">
|
|
||||||
<value>2.0</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="reader">
|
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="writer">
|
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
</root>
|
|
|
@ -41,6 +41,7 @@ namespace PersistentWindows.Common.WinApiBridge
|
||||||
EVENT_SYSTEM_IME_KEY_NOTIFICATION = 0x0029,
|
EVENT_SYSTEM_IME_KEY_NOTIFICATION = 0x0029,
|
||||||
EVENT_SYSTEM_END = 0x00FF,
|
EVENT_SYSTEM_END = 0x00FF,
|
||||||
|
|
||||||
|
EVENT_OBJECT_CREATE = 0x8000,
|
||||||
EVENT_OBJECT_DESTROY = 0x8001,
|
EVENT_OBJECT_DESTROY = 0x8001,
|
||||||
EVENT_OBJECT_REORDER = 0x8004,
|
EVENT_OBJECT_REORDER = 0x8004,
|
||||||
EVENT_OBJECT_LOCATIONCHANGE = 0x800B,
|
EVENT_OBJECT_LOCATIONCHANGE = 0x800B,
|
||||||
|
@ -623,6 +624,9 @@ namespace PersistentWindows.Common.WinApiBridge
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
public static extern bool CloseHandle(IntPtr hHandle);
|
public static extern bool CloseHandle(IntPtr hHandle);
|
||||||
|
|
||||||
|
[DllImport("kernel32")]
|
||||||
|
public static extern UInt64 GetTickCount64();
|
||||||
|
|
||||||
[DllImport("kernel32.dll", SetLastError = true)]
|
[DllImport("kernel32.dll", SetLastError = true)]
|
||||||
public static extern IntPtr OpenProcess(
|
public static extern IntPtr OpenProcess(
|
||||||
ProcessAccessFlags processAccess,
|
ProcessAccessFlags processAccess,
|
||||||
|
|
|
@ -28,6 +28,10 @@ namespace PersistentWindows.Common.WinApiBridge
|
||||||
X = x;
|
X = x;
|
||||||
Y = y;
|
Y = y;
|
||||||
}
|
}
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format($"({X}, {Y})");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
@ -57,5 +61,11 @@ namespace PersistentWindows.Common.WinApiBridge
|
||||||
{
|
{
|
||||||
return string.Format("({0}, {1}), {2} x {3}", Left, Top, Width, Height);
|
return string.Format("({0}, {1}), {2} x {3}", Left, Top, Width, Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int Diff(RECT r)
|
||||||
|
{
|
||||||
|
int diff = Math.Abs(Left - r.Left) + Math.Abs(Right - r.Right) + Math.Abs(Top - r.Top) + Math.Abs(Bottom - r.Bottom);
|
||||||
|
return diff / 4;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Windows.Forms;
|
using System.Windows.Forms;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
using PersistentWindows.Common;
|
using PersistentWindows.Common;
|
||||||
using PersistentWindows.Common.WinApiBridge;
|
using PersistentWindows.Common.WinApiBridge;
|
||||||
|
@ -10,6 +12,7 @@ namespace PersistentWindows.SystrayShell
|
||||||
{
|
{
|
||||||
public class HotKeyForm : Form
|
public class HotKeyForm : Form
|
||||||
{
|
{
|
||||||
|
static bool init = true;
|
||||||
static HotKeyWindow hkwin = null;
|
static HotKeyWindow hkwin = null;
|
||||||
static Thread messageLoop;
|
static Thread messageLoop;
|
||||||
|
|
||||||
|
@ -60,9 +63,42 @@ namespace PersistentWindows.SystrayShell
|
||||||
User32.KeyModifier modifier = (User32.KeyModifier)((int)m.LParam & 0xFFFF); // The modifier of the hotkey that was pressed.
|
User32.KeyModifier modifier = (User32.KeyModifier)((int)m.LParam & 0xFFFF); // The modifier of the hotkey that was pressed.
|
||||||
int id = m.WParam.ToInt32(); // The id of the hotkey that was pressed.
|
int id = m.WParam.ToInt32(); // The id of the hotkey that was pressed.
|
||||||
|
|
||||||
Program.HideRestoreTip(false); //hide icon
|
IntPtr fgWnd = PersistentWindowProcessor.GetForegroundWindow(strict : true);
|
||||||
Program.HideRestoreTip(); //show icon
|
|
||||||
hkwin.HotKeyPressed(from_menu : false);
|
hkwin.HotKeyPressed(from_menu : false);
|
||||||
|
if (PersistentWindowProcessor.IsBrowserWindow(fgWnd))
|
||||||
|
{
|
||||||
|
Program.HideRestoreTip(false); //hide icon
|
||||||
|
Program.HideRestoreTip(); //show icon
|
||||||
|
|
||||||
|
if (init)
|
||||||
|
{
|
||||||
|
init = false;
|
||||||
|
string webpage_commander_notification = Path.Combine(Program.AppdataFolder, "webpage_commander_notification");
|
||||||
|
if (File.Exists(webpage_commander_notification))
|
||||||
|
{
|
||||||
|
Program.systrayForm.notifyIconMain.ShowBalloonTip(8000, "webpage commander is invoked via hotkey", "Press the hotkey (Alt + W) again to revoke", ToolTipIcon.Info);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Create(webpage_commander_notification);
|
||||||
|
|
||||||
|
uint processId;
|
||||||
|
User32.GetWindowThreadProcessId(fgWnd, out processId);
|
||||||
|
string procPath = PersistentWindowProcessor.GetProcExePath(processId);
|
||||||
|
Process.Start(procPath, Program.ProjectUrl + "/blob/master/webpage_commander.md");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex.ToString());
|
||||||
|
Program.systrayForm.notifyIconMain.ShowBalloonTip(8000, "webpage commander is invoked via hotkey", "Press the hotkey (Alt + W) again to revoke", ToolTipIcon.Info);
|
||||||
|
Process.Start(Program.ProjectUrl + "/blob/master/webpage_commander.md");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (m.Msg == 0x0010 || m.Msg == 0x0002)
|
else if (m.Msg == 0x0010 || m.Msg == 0x0002)
|
||||||
|
|
|
@ -21,15 +21,21 @@ namespace PersistentWindows.SystrayShell
|
||||||
public static System.Drawing.Icon BusyIcon = null;
|
public static System.Drawing.Icon BusyIcon = null;
|
||||||
public static System.Drawing.Icon UpdateIcon = null;
|
public static System.Drawing.Icon UpdateIcon = null;
|
||||||
public static string AppdataFolder = null;
|
public static string AppdataFolder = null;
|
||||||
|
public static string DisableWebpageCommander = null;
|
||||||
|
public static string DisableUpgradeNotice = null;
|
||||||
public static string CmdArgs;
|
public static string CmdArgs;
|
||||||
public static bool Gui = true;
|
public static bool Gui = true;
|
||||||
public static bool hotkey_window = true;
|
public static bool hotkey_window = true;
|
||||||
public static uint hotkey = 'W'; //Alt + W
|
public static uint hotkey = 'W'; //Alt + W
|
||||||
|
public static string WaitPwFinish = @":wait_to_finish
|
||||||
|
timeout /t 2 /nobreak >nul
|
||||||
|
tasklist | find ""PersistentWindows"" >nul
|
||||||
|
if not errorlevel 1 goto wait_to_finish";
|
||||||
|
|
||||||
private const int MaxSnapshots = 38; // 0-9, a-z, ` and final one for undo
|
private const int MaxSnapshots = 38; // 0-9, a-z, ` and final one for undo
|
||||||
|
|
||||||
static PersistentWindowProcessor pwp = null;
|
public static PersistentWindowProcessor pwp = null;
|
||||||
static SystrayForm systrayForm = null;
|
public static SystrayForm systrayForm = null;
|
||||||
static bool silent = false; //suppress all balloon tip & sound prompt
|
static bool silent = false; //suppress all balloon tip & sound prompt
|
||||||
static bool notification = false; //pop balloon when auto restore
|
static bool notification = false; //pop balloon when auto restore
|
||||||
static int delay_manual_capture = 5000; //in millisecond
|
static int delay_manual_capture = 5000; //in millisecond
|
||||||
|
@ -50,9 +56,18 @@ namespace PersistentWindows.SystrayShell
|
||||||
|
|
||||||
pwp = new PersistentWindowProcessor();
|
pwp = new PersistentWindowProcessor();
|
||||||
|
|
||||||
|
var process = Process.GetCurrentProcess();
|
||||||
|
pwp.processPriority = process.PriorityClass;
|
||||||
|
process.PriorityClass = ProcessPriorityClass.High;
|
||||||
|
var timer = new System.Threading.Timer(state =>
|
||||||
|
{
|
||||||
|
process.PriorityClass = pwp.processPriority;
|
||||||
|
});
|
||||||
|
timer.Change(10000, System.Threading.Timeout.Infinite);
|
||||||
|
|
||||||
bool splash = true;
|
bool splash = true;
|
||||||
int delay_start = 0;
|
int delay_restart = 0;
|
||||||
bool relaunch = false;
|
int relaunch_delay = 0;
|
||||||
int delay_manual_capture = 0;
|
int delay_manual_capture = 0;
|
||||||
int delay_auto_capture = 0;
|
int delay_auto_capture = 0;
|
||||||
bool redirect_appdata = false; // use "." instead of appdata/local/PersistentWindows to store db file
|
bool redirect_appdata = false; // use "." instead of appdata/local/PersistentWindows to store db file
|
||||||
|
@ -68,13 +83,16 @@ namespace PersistentWindows.SystrayShell
|
||||||
bool offscreen_fix = true;
|
bool offscreen_fix = true;
|
||||||
bool fix_unminimized_window = true;
|
bool fix_unminimized_window = true;
|
||||||
bool enhanced_offscreen_fix = false;
|
bool enhanced_offscreen_fix = false;
|
||||||
|
bool set_pos_match_threshold = false;
|
||||||
bool auto_restore_missing_windows = false;
|
bool auto_restore_missing_windows = false;
|
||||||
bool auto_restore_from_db_at_startup = false;
|
bool auto_restore_from_db_at_startup = false;
|
||||||
|
bool auto_restore_last_capture_at_startup = false;
|
||||||
bool launch_once_per_process_id = true;
|
bool launch_once_per_process_id = true;
|
||||||
bool check_upgrade = true;
|
bool check_upgrade = true;
|
||||||
bool auto_upgrade = false;
|
bool auto_upgrade = false;
|
||||||
bool legacy_icon = false;
|
bool legacy_icon = false;
|
||||||
bool waiting_taskbar = false;
|
bool waiting_taskbar = false;
|
||||||
|
int restore_snapshot = -1;
|
||||||
|
|
||||||
foreach (var arg in args)
|
foreach (var arg in args)
|
||||||
{
|
{
|
||||||
|
@ -86,13 +104,12 @@ namespace PersistentWindows.SystrayShell
|
||||||
pwp.haltRestore = (Int32)(float.Parse(arg) * 1000);
|
pwp.haltRestore = (Int32)(float.Parse(arg) * 1000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (delay_start != 0)
|
else if (delay_restart != 0)
|
||||||
{
|
{
|
||||||
delay_start = 0;
|
delay_restart = 0;
|
||||||
if (!waiting_taskbar)
|
if (!waiting_taskbar)
|
||||||
{
|
{
|
||||||
Thread.Sleep((Int32)(float.Parse(arg) * 1000));
|
relaunch_delay = (Int32)(float.Parse(arg));
|
||||||
relaunch = true;
|
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -131,6 +148,17 @@ namespace PersistentWindows.SystrayShell
|
||||||
hotkey = arg[0];
|
hotkey = arg[0];
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
else if (restore_snapshot != -1)
|
||||||
|
{
|
||||||
|
restore_snapshot = SnapshotCharToId(arg[0]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (set_pos_match_threshold)
|
||||||
|
{
|
||||||
|
set_pos_match_threshold = false;
|
||||||
|
pwp.MaxDiffPos = int.Parse(arg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
switch(arg)
|
switch(arg)
|
||||||
{
|
{
|
||||||
|
@ -153,8 +181,11 @@ namespace PersistentWindows.SystrayShell
|
||||||
case "-enable_auto_restore_by_manual_capture":
|
case "-enable_auto_restore_by_manual_capture":
|
||||||
pwp.manualNormalSession = true;
|
pwp.manualNormalSession = true;
|
||||||
break;
|
break;
|
||||||
case "-delay_start":
|
case "-fast_restore=0":
|
||||||
delay_start = 1;
|
pwp.fastRestore = false;
|
||||||
|
break;
|
||||||
|
case "-delay_restart":
|
||||||
|
delay_restart = 1;
|
||||||
break;
|
break;
|
||||||
case "-wait_taskbar":
|
case "-wait_taskbar":
|
||||||
waiting_taskbar = true;
|
waiting_taskbar = true;
|
||||||
|
@ -165,6 +196,9 @@ namespace PersistentWindows.SystrayShell
|
||||||
case "-delay_auto_capture":
|
case "-delay_auto_capture":
|
||||||
delay_auto_capture = 1;
|
delay_auto_capture = 1;
|
||||||
break;
|
break;
|
||||||
|
case "-capture_floating_window=0":
|
||||||
|
pwp.captureFloatingWindow = false;
|
||||||
|
break;
|
||||||
case "-dpi_sensitive_call=1":
|
case "-dpi_sensitive_call=1":
|
||||||
User32.DpiSenstiveCall = true;
|
User32.DpiSenstiveCall = true;
|
||||||
break;
|
break;
|
||||||
|
@ -199,7 +233,10 @@ namespace PersistentWindows.SystrayShell
|
||||||
fix_unminimized_window = false;
|
fix_unminimized_window = false;
|
||||||
break;
|
break;
|
||||||
case "-fix_taskbar=0":
|
case "-fix_taskbar=0":
|
||||||
pwp.fixTaskBar = false;
|
pwp.fixTaskBar = 0;
|
||||||
|
break;
|
||||||
|
case "-fix_taskbar_no_game":
|
||||||
|
pwp.fixTaskBar = -1;
|
||||||
break;
|
break;
|
||||||
case "-foreground_background_dual_position=0":
|
case "-foreground_background_dual_position=0":
|
||||||
pwp.enableDualPosSwitch = false;
|
pwp.enableDualPosSwitch = false;
|
||||||
|
@ -239,6 +276,15 @@ namespace PersistentWindows.SystrayShell
|
||||||
case "-redraw_desktop":
|
case "-redraw_desktop":
|
||||||
redraw_desktop = true;
|
redraw_desktop = true;
|
||||||
break;
|
break;
|
||||||
|
case "-auto_restore_existing_window_to_last_capture=1":
|
||||||
|
auto_restore_last_capture_at_startup = true;
|
||||||
|
break;
|
||||||
|
case "-auto_restore_new_window_to_last_capture=0":
|
||||||
|
pwp.autoRestoreNewWindowToLastCapture = false;
|
||||||
|
break;
|
||||||
|
case "-pos_match_threshold":
|
||||||
|
set_pos_match_threshold = true;
|
||||||
|
break;
|
||||||
case "-auto_restore_missing_windows":
|
case "-auto_restore_missing_windows":
|
||||||
case "-auto_restore_missing_windows=1":
|
case "-auto_restore_missing_windows=1":
|
||||||
auto_restore_missing_windows = true;
|
auto_restore_missing_windows = true;
|
||||||
|
@ -251,7 +297,7 @@ namespace PersistentWindows.SystrayShell
|
||||||
auto_restore_missing_windows = true;
|
auto_restore_missing_windows = true;
|
||||||
break;
|
break;
|
||||||
case "-auto_restore_new_display_session_from_db=0":
|
case "-auto_restore_new_display_session_from_db=0":
|
||||||
pwp.autoRestoreLiveWindows = false;
|
pwp.autoRestoreLiveWindowsFromDb = false;
|
||||||
Log.Error("turn off auto restore db for new session");
|
Log.Error("turn off auto restore db for new session");
|
||||||
break;
|
break;
|
||||||
case "-invoke_multi_window_process_only_once=0":
|
case "-invoke_multi_window_process_only_once=0":
|
||||||
|
@ -263,9 +309,21 @@ namespace PersistentWindows.SystrayShell
|
||||||
case "-auto_upgrade=1":
|
case "-auto_upgrade=1":
|
||||||
auto_upgrade = true;
|
auto_upgrade = true;
|
||||||
break;
|
break;
|
||||||
|
case "-dump_window_position_history=0":
|
||||||
|
pwp.dumpHistoryData = false;
|
||||||
|
break;
|
||||||
|
case "-restore_snapshot":
|
||||||
|
restore_snapshot = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (restore_snapshot >= 0)
|
||||||
|
{
|
||||||
|
pwp.RestoreSnapshotCmd(restore_snapshot);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
string productName = System.Windows.Forms.Application.ProductName;
|
string productName = System.Windows.Forms.Application.ProductName;
|
||||||
string appDataFolder = redirect_appdata ? "." :
|
string appDataFolder = redirect_appdata ? "." :
|
||||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData),
|
||||||
|
@ -278,11 +336,18 @@ namespace PersistentWindows.SystrayShell
|
||||||
#endif
|
#endif
|
||||||
AppdataFolder = appDataFolder;
|
AppdataFolder = appDataFolder;
|
||||||
|
|
||||||
|
if (!Directory.Exists(appDataFolder))
|
||||||
|
Directory.CreateDirectory(appDataFolder);
|
||||||
|
|
||||||
|
DisableWebpageCommander = Path.Combine(AppdataFolder, "disable_webpage_commander");
|
||||||
|
DisableUpgradeNotice = Path.Combine(AppdataFolder, "disable_upgrade_notice");
|
||||||
|
|
||||||
// default icons
|
// default icons
|
||||||
IdleIcon = legacy_icon ? Properties.Resources.pwIcon2 : Properties.Resources.pwIcon;
|
var iconHandle = (legacy_icon ? Properties.Resources.pwIcon2: Properties.Resources.pwIcon).GetHicon();
|
||||||
var iconHandle = Properties.Resources.pwIconBusy.GetHicon();
|
IdleIcon = System.Drawing.Icon.FromHandle(iconHandle);
|
||||||
BusyIcon = legacy_icon ? Properties.Resources.pwIconBusy2 : System.Drawing.Icon.FromHandle(iconHandle);
|
iconHandle = (legacy_icon ? Properties.Resources.pwIconBusy2 : Properties.Resources.pwIconBusy).GetHicon();
|
||||||
iconHandle = Properties.Resources.pwIconUpdate.GetHicon();
|
BusyIcon = System.Drawing.Icon.FromHandle(iconHandle);
|
||||||
|
iconHandle = (legacy_icon ? Properties.Resources.pwIconUpdate2 : Properties.Resources.pwIconUpdate).GetHicon();
|
||||||
UpdateIcon = System.Drawing.Icon.FromHandle(iconHandle);
|
UpdateIcon = System.Drawing.Icon.FromHandle(iconHandle);
|
||||||
|
|
||||||
// customized icon/png
|
// customized icon/png
|
||||||
|
@ -291,38 +356,49 @@ namespace PersistentWindows.SystrayShell
|
||||||
if (i == 1)
|
if (i == 1)
|
||||||
iconFolder = AppDomain.CurrentDomain.BaseDirectory;
|
iconFolder = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
|
|
||||||
string icon_path = Path.Combine(iconFolder, "pwIcon.ico");
|
string ico_path = Path.Combine(iconFolder, "pwIcon.ico");
|
||||||
string icon_png_path = Path.Combine(iconFolder, "pwIcon.png");
|
string png_path = Path.Combine(iconFolder, "pwIcon.png");
|
||||||
if (File.Exists(icon_png_path))
|
if (File.Exists(png_path))
|
||||||
{
|
{
|
||||||
var bitmap = new System.Drawing.Bitmap(icon_png_path); // or get it from resource
|
var bitmap = new System.Drawing.Bitmap(png_path);
|
||||||
IdleIcon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());
|
IdleIcon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());
|
||||||
}
|
}
|
||||||
else if (File.Exists(icon_path))
|
else if (File.Exists(ico_path))
|
||||||
{
|
{
|
||||||
IdleIcon = new System.Drawing.Icon(icon_path);
|
IdleIcon = new System.Drawing.Icon(ico_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
icon_path = Path.Combine(iconFolder, "pwIconBusy.ico");
|
ico_path = Path.Combine(iconFolder, "pwIconBusy.ico");
|
||||||
icon_png_path = Path.Combine(iconFolder, "pwIconBusy.png");
|
png_path = Path.Combine(iconFolder, "pwIconBusy.png");
|
||||||
if (File.Exists(icon_png_path))
|
if (File.Exists(png_path))
|
||||||
{
|
{
|
||||||
var bitmap = new System.Drawing.Bitmap(icon_png_path);
|
var bitmap = new System.Drawing.Bitmap(png_path);
|
||||||
BusyIcon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());
|
BusyIcon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());
|
||||||
}
|
}
|
||||||
else if (File.Exists(icon_path))
|
else if (File.Exists(ico_path))
|
||||||
{
|
{
|
||||||
BusyIcon = new System.Drawing.Icon(icon_path);
|
BusyIcon = new System.Drawing.Icon(ico_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
ico_path = Path.Combine(iconFolder, "pwIconUpdate.ico");
|
||||||
|
png_path = Path.Combine(iconFolder, "pwIconUpdate.png");
|
||||||
|
if (File.Exists(png_path))
|
||||||
|
{
|
||||||
|
var bitmap = new System.Drawing.Bitmap(png_path);
|
||||||
|
UpdateIcon = System.Drawing.Icon.FromHandle(bitmap.GetHicon());
|
||||||
|
}
|
||||||
|
else if (File.Exists(ico_path))
|
||||||
|
{
|
||||||
|
UpdateIcon = new System.Drawing.Icon(ico_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
systrayForm = new SystrayForm();
|
systrayForm = new SystrayForm(check_upgrade);
|
||||||
systrayForm.enableUpgradeNotice = check_upgrade;
|
|
||||||
systrayForm.autoUpgrade = auto_upgrade;
|
systrayForm.autoUpgrade = auto_upgrade;
|
||||||
|
|
||||||
if (relaunch)
|
if (relaunch_delay > 0)
|
||||||
{
|
{
|
||||||
Restart(2);
|
Restart(relaunch_delay);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,10 +439,10 @@ namespace PersistentWindows.SystrayShell
|
||||||
if (ignore_process.Length > 0)
|
if (ignore_process.Length > 0)
|
||||||
pwp.SetIgnoreProcess(ignore_process);
|
pwp.SetIgnoreProcess(ignore_process);
|
||||||
|
|
||||||
if (hotkey_window)
|
if (!File.Exists(DisableWebpageCommander) && hotkey_window)
|
||||||
HotKeyForm.Start(hotkey);
|
HotKeyForm.Start(hotkey);
|
||||||
|
|
||||||
if (!pwp.Start(auto_restore_from_db_at_startup))
|
if (!pwp.Start(auto_restore_from_db_at_startup, auto_restore_last_capture_at_startup))
|
||||||
{
|
{
|
||||||
systrayForm.notifyIconMain.Visible = false;
|
systrayForm.notifyIconMain.Visible = false;
|
||||||
return;
|
return;
|
||||||
|
@ -401,17 +477,25 @@ namespace PersistentWindows.SystrayShell
|
||||||
Log.Error("taskbar not ready, restart PersistentWindows");
|
Log.Error("taskbar not ready, restart PersistentWindows");
|
||||||
}
|
}
|
||||||
|
|
||||||
Restart(10);
|
Restart(1);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Restart(int delay)
|
static public void Restart(int delay, bool hidden = true)
|
||||||
{
|
{
|
||||||
|
Process p = new Process();
|
||||||
string batFile = Path.Combine(AppdataFolder, $"pw_restart.bat");
|
string batFile = Path.Combine(AppdataFolder, $"pw_restart.bat");
|
||||||
string content = $"timeout /t {delay} /nobreak > NUL";
|
string content = WaitPwFinish;
|
||||||
|
content += $"\ntimeout /t {delay} /nobreak > NUL";
|
||||||
content += "\nstart \"\" /B \"" + Path.Combine(Application.StartupPath, Application.ProductName) + ".exe\" " + "-wait_taskbar " + Program.CmdArgs;
|
content += "\nstart \"\" /B \"" + Path.Combine(Application.StartupPath, Application.ProductName) + ".exe\" " + "-wait_taskbar " + Program.CmdArgs;
|
||||||
File.WriteAllText(batFile, content);
|
File.WriteAllText(batFile, content);
|
||||||
Process.Start(batFile);
|
p.StartInfo.FileName = batFile;
|
||||||
|
if (hidden)
|
||||||
|
{
|
||||||
|
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
|
||||||
|
p.StartInfo.UseShellExecute = true;
|
||||||
|
}
|
||||||
|
p.Start();
|
||||||
|
|
||||||
Log.Error("program restarted");
|
Log.Error("program restarted");
|
||||||
}
|
}
|
||||||
|
@ -426,7 +510,9 @@ namespace PersistentWindows.SystrayShell
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NotifyIcon ni = systrayForm.notifyIconMain;
|
NotifyIcon ni = systrayForm.notifyIconMain;
|
||||||
ni.Icon = BusyIcon;
|
if (!systrayForm.toggleIcon) {
|
||||||
|
ni.Icon = BusyIcon;
|
||||||
|
}
|
||||||
|
|
||||||
if (silent)
|
if (silent)
|
||||||
return;
|
return;
|
||||||
|
@ -451,7 +537,10 @@ namespace PersistentWindows.SystrayShell
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NotifyIcon ni = systrayForm.notifyIconMain;
|
NotifyIcon ni = systrayForm.notifyIconMain;
|
||||||
ni.Icon = IdleIcon;
|
if (!systrayForm.toggleIcon)
|
||||||
|
{
|
||||||
|
ni.Icon = IdleIcon;
|
||||||
|
}
|
||||||
|
|
||||||
if (Gui)
|
if (Gui)
|
||||||
{
|
{
|
||||||
|
@ -775,5 +864,14 @@ namespace PersistentWindows.SystrayShell
|
||||||
Log.Error(format, args);
|
Log.Error(format, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void WriteDataDump()
|
||||||
|
{
|
||||||
|
pwp.WriteDataDump();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Stop()
|
||||||
|
{
|
||||||
|
pwp.Stop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,5 +31,5 @@ using System.Runtime.InteropServices;
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
// by using the '*' as shown below:
|
// by using the '*' as shown below:
|
||||||
// [assembly: AssemblyVersion("1.0.*")]
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
[assembly: AssemblyVersion("5.56.*")]
|
[assembly: AssemblyVersion("5.65.*")]
|
||||||
|
|
||||||
|
|
|
@ -61,22 +61,22 @@ namespace PersistentWindows.SystrayShell.Properties {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static System.Drawing.Icon pwIcon {
|
internal static System.Drawing.Bitmap pwIcon {
|
||||||
get {
|
get {
|
||||||
object obj = ResourceManager.GetObject("pwIcon", resourceCulture);
|
object obj = ResourceManager.GetObject("pwIcon", resourceCulture);
|
||||||
return ((System.Drawing.Icon)(obj));
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static System.Drawing.Icon pwIcon2 {
|
internal static System.Drawing.Bitmap pwIcon2 {
|
||||||
get {
|
get {
|
||||||
object obj = ResourceManager.GetObject("pwIcon2", resourceCulture);
|
object obj = ResourceManager.GetObject("pwIcon2", resourceCulture);
|
||||||
return ((System.Drawing.Icon)(obj));
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,12 +91,12 @@ namespace PersistentWindows.SystrayShell.Properties {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static System.Drawing.Icon pwIconBusy2 {
|
internal static System.Drawing.Bitmap pwIconBusy2 {
|
||||||
get {
|
get {
|
||||||
object obj = ResourceManager.GetObject("pwIconBusy2", resourceCulture);
|
object obj = ResourceManager.GetObject("pwIconBusy2", resourceCulture);
|
||||||
return ((System.Drawing.Icon)(obj));
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,6 +110,16 @@ namespace PersistentWindows.SystrayShell.Properties {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
|
/// </summary>
|
||||||
|
internal static System.Drawing.Bitmap pwIconUpdate2 {
|
||||||
|
get {
|
||||||
|
object obj = ResourceManager.GetObject("pwIconUpdate2", resourceCulture);
|
||||||
|
return ((System.Drawing.Bitmap)(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
/// Looks up a localized resource of type System.Drawing.Bitmap.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -119,20 +119,23 @@
|
||||||
</resheader>
|
</resheader>
|
||||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
<data name="pwIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="pwIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\pwIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\pwIcon.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="pwIcon2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="pwIcon2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\pwIcon2.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\pwIcon2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="pwIconBusy" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="pwIconBusy" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\pwIconBusy.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\pwIconBusy.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="pwIconBusy2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="pwIconBusy2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\pwIconBusy2.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\pwIconBusy2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="pwIconUpdate" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="pwIconUpdate" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\pwIconUpdate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\pwIconUpdate.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="pwIconUpdate2" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>..\Resources\pwIconUpdate2.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
|
</data>
|
||||||
<data name="question" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
<data name="question" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
<value>..\Resources\question.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
<value>..\Resources\question.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 14 KiB |
|
@ -1,123 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<root>
|
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:choice maxOccurs="unbounded">
|
|
||||||
<xsd:element name="metadata">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="assembly">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:attribute name="alias" type="xsd:string" />
|
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="data">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="resheader">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:choice>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
<resheader name="resmimetype">
|
|
||||||
<value>text/microsoft-resx</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="version">
|
|
||||||
<value>2.0</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="reader">
|
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="writer">
|
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<metadata name="timer1.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>17, 17</value>
|
|
||||||
</metadata>
|
|
||||||
</root>
|
|
|
@ -168,10 +168,6 @@ namespace PersistentWindows.SystrayShell
|
||||||
// pause/resume upgrade notice
|
// pause/resume upgrade notice
|
||||||
//this.upgradeNoticeMenuItem.Text = "Disable upgrade notice";
|
//this.upgradeNoticeMenuItem.Text = "Disable upgrade notice";
|
||||||
this.upgradeNoticeMenuItem.Click += new System.EventHandler(this.PauseResumeUpgradeNotice);
|
this.upgradeNoticeMenuItem.Click += new System.EventHandler(this.PauseResumeUpgradeNotice);
|
||||||
if (this.enableUpgradeNotice)
|
|
||||||
this.upgradeNoticeMenuItem.Text = "Disable upgrade notice";
|
|
||||||
else
|
|
||||||
this.upgradeNoticeMenuItem.Text = "Enable upgrade notice";
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// exitToolStripMenuItem
|
// exitToolStripMenuItem
|
||||||
|
|
|
@ -17,16 +17,11 @@ namespace PersistentWindows.SystrayShell
|
||||||
{
|
{
|
||||||
private const int MaxSnapshots = 38; // 0-9, a-z, ` and final one for undo
|
private const int MaxSnapshots = 38; // 0-9, a-z, ` and final one for undo
|
||||||
|
|
||||||
public bool restoreToolStripMenuItemEnabled;
|
|
||||||
public bool restoreSnapshotMenuItemEnabled;
|
|
||||||
|
|
||||||
private bool pauseAutoRestore = false;
|
private bool pauseAutoRestore = false;
|
||||||
private bool toggleIcon = false;
|
public bool toggleIcon = false;
|
||||||
|
|
||||||
public bool enableUpgradeNotice = true;
|
|
||||||
private int skipUpgradeCounter = 0;
|
private int skipUpgradeCounter = 0;
|
||||||
private bool pauseUpgradeCounter = false;
|
private bool pauseUpgradeCounter = false;
|
||||||
private bool foundUpgrade = false;
|
|
||||||
|
|
||||||
public bool autoUpgrade = false;
|
public bool autoUpgrade = false;
|
||||||
|
|
||||||
|
@ -43,10 +38,25 @@ namespace PersistentWindows.SystrayShell
|
||||||
|
|
||||||
private Dictionary<string, bool> upgradeDownloaded = new Dictionary<string, bool>();
|
private Dictionary<string, bool> upgradeDownloaded = new Dictionary<string, bool>();
|
||||||
|
|
||||||
public SystrayForm()
|
public SystrayForm(bool enable_upgrade_notice)
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
if (File.Exists(Program.DisableUpgradeNotice))
|
||||||
|
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
|
||||||
|
else if (!enable_upgrade_notice)
|
||||||
|
{
|
||||||
|
File.Create(Program.DisableUpgradeNotice);
|
||||||
|
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
upgradeNoticeMenuItem.Text = "Disable upgrade notice";
|
||||||
|
|
||||||
|
if (File.Exists(Program.DisableWebpageCommander))
|
||||||
|
{
|
||||||
|
invokeWebCommander.Text = "Enable webpage commander";
|
||||||
|
}
|
||||||
|
|
||||||
clickDelayTimer = new System.Timers.Timer(1000);
|
clickDelayTimer = new System.Timers.Timer(1000);
|
||||||
clickDelayTimer.Elapsed += ClickTimerCallBack;
|
clickDelayTimer.Elapsed += ClickTimerCallBack;
|
||||||
clickDelayTimer.SynchronizingObject = this.contextMenuStripSysTray;
|
clickDelayTimer.SynchronizingObject = this.contextMenuStripSysTray;
|
||||||
|
@ -166,7 +176,6 @@ namespace PersistentWindows.SystrayShell
|
||||||
ctrlKeyPressed = 0;
|
ctrlKeyPressed = 0;
|
||||||
shiftKeyPressed = 0;
|
shiftKeyPressed = 0;
|
||||||
altKeyPressed = 0;
|
altKeyPressed = 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//private void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
|
//private void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
|
||||||
|
@ -177,7 +186,7 @@ namespace PersistentWindows.SystrayShell
|
||||||
else
|
else
|
||||||
restoreToolStripMenuItem.Image = Properties.Resources.question;
|
restoreToolStripMenuItem.Image = Properties.Resources.question;
|
||||||
|
|
||||||
if (checkUpgrade && enableUpgradeNotice)
|
if (checkUpgrade && upgradeNoticeMenuItem.Text.Contains("Disable"))
|
||||||
{
|
{
|
||||||
if (pauseUpgradeCounter)
|
if (pauseUpgradeCounter)
|
||||||
{
|
{
|
||||||
|
@ -239,10 +248,21 @@ namespace PersistentWindows.SystrayShell
|
||||||
|| current_major == latest_major && current_minor < latest_minor)
|
|| current_major == latest_major && current_minor < latest_minor)
|
||||||
{
|
{
|
||||||
notifyIconMain.ShowBalloonTip(5000, $"{Application.ProductName} {latestVersion} upgrade is available", "The upgrade notice can be disabled in menu", ToolTipIcon.Info);
|
notifyIconMain.ShowBalloonTip(5000, $"{Application.ProductName} {latestVersion} upgrade is available", "The upgrade notice can be disabled in menu", ToolTipIcon.Info);
|
||||||
foundUpgrade = true;
|
upgradeNoticeMenuItem.Text = $"Upgrade to {latestVersion}";
|
||||||
|
|
||||||
if (!upgradeDownloaded.ContainsKey(latestVersion))
|
if (!upgradeDownloaded.ContainsKey(latestVersion))
|
||||||
{
|
{
|
||||||
|
string url = Program.ProjectUrl + "/releases";
|
||||||
|
var os_version = Environment.OSVersion;
|
||||||
|
if (os_version.Version.Major < 10)
|
||||||
|
Process.Start(url);
|
||||||
|
else if (os_version.Version.Build < 22000)
|
||||||
|
Process.Start(url);
|
||||||
|
/* windows 11
|
||||||
|
else
|
||||||
|
Process.Start(new ProcessStartInfo(url));
|
||||||
|
*/
|
||||||
|
|
||||||
var src_file = $"{Program.ProjectUrl}/releases/download/{latestVersion}/{System.Windows.Forms.Application.ProductName}{latestVersion}.zip";
|
var src_file = $"{Program.ProjectUrl}/releases/download/{latestVersion}/{System.Windows.Forms.Application.ProductName}{latestVersion}.zip";
|
||||||
var dst_file = $"{Program.AppdataFolder}/upgrade.zip";
|
var dst_file = $"{Program.AppdataFolder}/upgrade.zip";
|
||||||
var dst_dir = Path.Combine($"{Program.AppdataFolder}", "upgrade");
|
var dst_dir = Path.Combine($"{Program.AppdataFolder}", "upgrade");
|
||||||
|
@ -256,7 +276,7 @@ namespace PersistentWindows.SystrayShell
|
||||||
upgradeDownloaded[latestVersion] = true;
|
upgradeDownloaded[latestVersion] = true;
|
||||||
|
|
||||||
string batFile = Path.Combine(Program.AppdataFolder, $"pw_upgrade.bat");
|
string batFile = Path.Combine(Program.AppdataFolder, $"pw_upgrade.bat");
|
||||||
string content = "timeout /t 5 /nobreak > NUL";
|
string content = Program.WaitPwFinish;
|
||||||
content += $"\ncopy /Y \"{dst_dir}\\*.*\" \"{install_dir}\"";
|
content += $"\ncopy /Y \"{dst_dir}\\*.*\" \"{install_dir}\"";
|
||||||
content += "\nstart \"\" /B \"" + Path.Combine(install_dir, Application.ProductName) + ".exe\" " + Program.CmdArgs;
|
content += "\nstart \"\" /B \"" + Path.Combine(install_dir, Application.ProductName) + ".exe\" " + Program.CmdArgs;
|
||||||
File.WriteAllText(batFile, content);
|
File.WriteAllText(batFile, content);
|
||||||
|
@ -264,10 +284,7 @@ namespace PersistentWindows.SystrayShell
|
||||||
if (autoUpgrade)
|
if (autoUpgrade)
|
||||||
Upgrade();
|
Upgrade();
|
||||||
else
|
else
|
||||||
{
|
|
||||||
upgradeNoticeMenuItem.Text = $"Upgrade to {latestVersion}";
|
|
||||||
notifyIconMain.Icon = Program.UpdateIcon;
|
notifyIconMain.Icon = Program.UpdateIcon;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -275,15 +292,24 @@ namespace PersistentWindows.SystrayShell
|
||||||
|
|
||||||
private void Exit()
|
private void Exit()
|
||||||
{
|
{
|
||||||
#if DEBUG
|
var process = Process.GetCurrentProcess();
|
||||||
|
process.PriorityClass = ProcessPriorityClass.High;
|
||||||
|
|
||||||
|
Program.WriteDataDump();
|
||||||
|
Log.Event("Session exit");
|
||||||
|
|
||||||
this.notifyIconMain.Visible = false;
|
this.notifyIconMain.Visible = false;
|
||||||
#endif
|
|
||||||
//this.notifyIconMain.Icon = null;
|
//this.notifyIconMain.Icon = null;
|
||||||
|
|
||||||
Log.Exit();
|
Log.Exit();
|
||||||
|
Program.Stop();
|
||||||
Application.Exit();
|
Application.Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Upgrade()
|
private void Upgrade()
|
||||||
{
|
{
|
||||||
|
Program.WriteDataDump();
|
||||||
|
|
||||||
string batFile = Path.Combine(Program.AppdataFolder, "pw_upgrade.bat");
|
string batFile = Path.Combine(Program.AppdataFolder, "pw_upgrade.bat");
|
||||||
Process.Start(batFile);
|
Process.Start(batFile);
|
||||||
Exit();
|
Exit();
|
||||||
|
@ -345,11 +371,21 @@ namespace PersistentWindows.SystrayShell
|
||||||
HotKeyForm.InvokeFromMenu();
|
HotKeyForm.InvokeFromMenu();
|
||||||
else if (this.invokeWebCommander.Text.Contains("Disable"))
|
else if (this.invokeWebCommander.Text.Contains("Disable"))
|
||||||
{
|
{
|
||||||
|
File.Create(Program.DisableWebpageCommander);
|
||||||
this.invokeWebCommander.Text = "Enable webpage commander";
|
this.invokeWebCommander.Text = "Enable webpage commander";
|
||||||
HotKeyForm.Stop();
|
HotKeyForm.Stop();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(Program.DisableWebpageCommander);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
this.invokeWebCommander.Text = "Disable webpage commander";
|
this.invokeWebCommander.Text = "Disable webpage commander";
|
||||||
HotKeyForm.Start(Program.hotkey);
|
HotKeyForm.Start(Program.hotkey);
|
||||||
}
|
}
|
||||||
|
@ -394,20 +430,27 @@ namespace PersistentWindows.SystrayShell
|
||||||
|
|
||||||
private void PauseResumeUpgradeNotice(Object sender, EventArgs e)
|
private void PauseResumeUpgradeNotice(Object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (foundUpgrade)
|
if (upgradeNoticeMenuItem.Text.Contains("Upgrade to"))
|
||||||
{
|
{
|
||||||
Upgrade();
|
Upgrade();
|
||||||
}
|
}
|
||||||
else if (enableUpgradeNotice)
|
else if (upgradeNoticeMenuItem.Text.Contains("Enable"))
|
||||||
{
|
{
|
||||||
enableUpgradeNotice = false;
|
|
||||||
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
enableUpgradeNotice = true;
|
|
||||||
upgradeNoticeMenuItem.Text = "Disable upgrade notice";
|
upgradeNoticeMenuItem.Text = "Disable upgrade notice";
|
||||||
CheckUpgradeSafe();
|
CheckUpgradeSafe();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.Delete(Program.DisableUpgradeNotice);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error(ex.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else //menu is "Disable upgrade notice"
|
||||||
|
{
|
||||||
|
File.Create(Program.DisableUpgradeNotice);
|
||||||
|
upgradeNoticeMenuItem.Text = "Enable upgrade notice";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,6 +461,9 @@ namespace PersistentWindows.SystrayShell
|
||||||
|
|
||||||
private void ExitToolStripMenuItemClickHandler(object sender, EventArgs e)
|
private void ExitToolStripMenuItemClickHandler(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
|
bool ctrl_key_pressed = (User32.GetKeyState(0x11) & 0x8000) != 0;
|
||||||
|
if (ctrl_key_pressed)
|
||||||
|
Program.Restart(2, hidden:false);
|
||||||
Exit();
|
Exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,127 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<root>
|
|
||||||
<!--
|
|
||||||
Microsoft ResX Schema
|
|
||||||
|
|
||||||
Version 2.0
|
|
||||||
|
|
||||||
The primary goals of this format is to allow a simple XML format
|
|
||||||
that is mostly human readable. The generation and parsing of the
|
|
||||||
various data types are done through the TypeConverter classes
|
|
||||||
associated with the data types.
|
|
||||||
|
|
||||||
Example:
|
|
||||||
|
|
||||||
... ado.net/XML headers & schema ...
|
|
||||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
|
||||||
<resheader name="version">2.0</resheader>
|
|
||||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
|
||||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
|
||||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
|
||||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
|
||||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
|
||||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
|
||||||
</data>
|
|
||||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
|
||||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
|
||||||
<comment>This is a comment</comment>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
There are any number of "resheader" rows that contain simple
|
|
||||||
name/value pairs.
|
|
||||||
|
|
||||||
Each data row contains a name, and value. The row also contains a
|
|
||||||
type or mimetype. Type corresponds to a .NET class that support
|
|
||||||
text/value conversion through the TypeConverter architecture.
|
|
||||||
Classes that don't support this are serialized and stored with the
|
|
||||||
mimetype set.
|
|
||||||
|
|
||||||
The mimetype is used for serialized objects, and tells the
|
|
||||||
ResXResourceReader how to depersist the object. This is currently not
|
|
||||||
extensible. For a given mimetype the value must be set accordingly:
|
|
||||||
|
|
||||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
|
||||||
that the ResXResourceWriter will generate, however the reader can
|
|
||||||
read any of the formats listed below.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.binary.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.soap.base64
|
|
||||||
value : The object must be serialized with
|
|
||||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
|
|
||||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
|
||||||
value : The object must be serialized into a byte array
|
|
||||||
: using a System.ComponentModel.TypeConverter
|
|
||||||
: and then encoded with base64 encoding.
|
|
||||||
-->
|
|
||||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
|
||||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
|
||||||
<xsd:element name="root" msdata:IsDataSet="true">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:choice maxOccurs="unbounded">
|
|
||||||
<xsd:element name="metadata">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="assembly">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:attribute name="alias" type="xsd:string" />
|
|
||||||
<xsd:attribute name="name" type="xsd:string" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="data">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
|
||||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
|
||||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
|
||||||
<xsd:attribute ref="xml:space" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element name="resheader">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
|
||||||
</xsd:sequence>
|
|
||||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:choice>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
<resheader name="resmimetype">
|
|
||||||
<value>text/microsoft-resx</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="version">
|
|
||||||
<value>2.0</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="reader">
|
|
||||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<resheader name="writer">
|
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
|
||||||
</resheader>
|
|
||||||
<metadata name="notifyIconMain.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>17, 17</value>
|
|
||||||
</metadata>
|
|
||||||
<metadata name="contextMenuStripSysTray.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
|
||||||
<value>150, 17</value>
|
|
||||||
</metadata>
|
|
||||||
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
|
|
||||||
</root>
|
|
|
@ -52,7 +52,9 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup />
|
<PropertyGroup />
|
||||||
<PropertyGroup />
|
<PropertyGroup />
|
||||||
<PropertyGroup />
|
<PropertyGroup>
|
||||||
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="System" />
|
||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
|
@ -84,19 +86,12 @@
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<EmbeddedResource Include="SplashForm.resx">
|
|
||||||
<DependentUpon>SplashForm.cs</DependentUpon>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Include="SystrayForm.resx">
|
|
||||||
<DependentUpon>SystrayForm.cs</DependentUpon>
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
</EmbeddedResource>
|
|
||||||
<EmbeddedResource Include="Properties\Resources.resx">
|
<EmbeddedResource Include="Properties\Resources.resx">
|
||||||
<Generator>ResXFileCodeGenerator</Generator>
|
<Generator>ResXFileCodeGenerator</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
|
<None Include="app.manifest" />
|
||||||
<None Include="Properties\Settings.settings">
|
<None Include="Properties\Settings.settings">
|
||||||
<Generator>SettingsSingleFileGenerator</Generator>
|
<Generator>SettingsSingleFileGenerator</Generator>
|
||||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||||
|
@ -131,12 +126,6 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="Resources\pwIconUpdate.png" />
|
<None Include="Resources\pwIconUpdate.png" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Resources\pwIcon2.ico" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Resources\pwIconBusy2.ico" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<PostBuildEvent>copy $(SolutionDir)*.bat $(TargetDir)
|
<PostBuildEvent>copy $(SolutionDir)*.bat $(TargetDir)
|
||||||
|
|
|
@ -28,16 +28,16 @@
|
||||||
and Windows will automatically select the most compatible environment. -->
|
and Windows will automatically select the most compatible environment. -->
|
||||||
|
|
||||||
<!-- Windows Vista -->
|
<!-- Windows Vista -->
|
||||||
<!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
|
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
|
||||||
|
|
||||||
<!-- Windows 7 -->
|
<!-- Windows 7 -->
|
||||||
<!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
|
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
|
||||||
|
|
||||||
<!-- Windows 8 -->
|
<!-- Windows 8 -->
|
||||||
<!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
|
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
|
||||||
|
|
||||||
<!-- Windows 8.1 -->
|
<!-- Windows 8.1 -->
|
||||||
<!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
|
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
|
||||||
|
|
||||||
<!-- Windows 10 -->
|
<!-- Windows 10 -->
|
||||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||||
|
|
11
README.md
|
@ -11,10 +11,11 @@ and restores back to its previous settings.
|
||||||
this tool and not have to worry about re-arranging when all is back to normal.
|
this tool and not have to worry about re-arranging when all is back to normal.
|
||||||
|
|
||||||
## Key Features
|
## Key Features
|
||||||
- Keeps track of window position changes, and automatically restores the desktop layout, including the taskbar position, to the last matching monitor setup.
|
- Auto restore: Keeps track of window position changes, and automatically restores the desktop layout, including the taskbar position, to the last matching monitor setup.
|
||||||
- Supports remote desktop sessions with multiple display configurations.
|
- Supports remote desktop sessions with multiple display configurations.
|
||||||
- Capture windows to disk: saves desktop layout capture to hard drive in liteDB format, so that closed windows can be restored after PC reboot, with virtual desktop observed.
|
- Capture windows to disk: manually saves desktop layout capture to hard drive in liteDB format, so that closed windows can be restored to corresponding virtual desktop after PC reboot.
|
||||||
- Capture snapshot to ram: saves desktop layout in memory using one char from [0-9a-z] as the name. The window Z-order is preserved in the snapshot.
|
- Capture snapshot: manually saves desktop layout to ram. The window Z-order is preserved in the snapshot. Up to 36 snapshots ([0-9a-z]) can be taken for each display configuration.
|
||||||
|
- Automatically persists the location history of all windows (alive and closed) to hard drive in xml format, so that manual-restore-point (aka snapshot) and auto-restore-point will continue to function smoothly upon app upgrade/restart, even after PC reboot.
|
||||||
- Webpage commander to improve the efficiency of web browsing for all major web browsers using one-letter commands like in vi editor.
|
- Webpage commander to improve the efficiency of web browsing for all major web browsers using one-letter commands like in vi editor.
|
||||||
- Efficient window switching between foreground and background dual positions.
|
- Efficient window switching between foreground and background dual positions.
|
||||||
- Pause/resume auto restore.
|
- Pause/resume auto restore.
|
||||||
|
@ -28,11 +29,11 @@ this tool and not have to worry about re-arranging when all is back to normal.
|
||||||
> Note: the program can be run from any directory, but the program saves its data in
|
> Note: the program can be run from any directory, but the program saves its data in
|
||||||
> *C:\Users\\[User]\AppData\Local\PersistentWindows*
|
> *C:\Users\\[User]\AppData\Local\PersistentWindows*
|
||||||
|
|
||||||
|
**For PersistentWindows to be able to restore windows with elevated privileges (for tools like Task Manager or Event Viewer), it needs to be run with Administrator privileges.**
|
||||||
|
|
||||||
### To set up PersistentWindows to automatically start at user login:
|
### To set up PersistentWindows to automatically start at user login:
|
||||||
This can be done by creating a task in **Task Scheduler**, or by adding a shortcut to the **Startup Folder** (shell:startup).
|
This can be done by creating a task in **Task Scheduler**, or by adding a shortcut to the **Startup Folder** (shell:startup).
|
||||||
|
|
||||||
For PersistentWindows to be able to restore windows with elevated privileges (for tools like Task Manager or Event Viewer), it needs to be run with Administrator privileges.
|
|
||||||
|
|
||||||
Choose **one** of the three options:
|
Choose **one** of the three options:
|
||||||
|
|
||||||
**Task Scheduler (Windows 10/11)**
|
**Task Scheduler (Windows 10/11)**
|
||||||
|
|
5
webpage_commander.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
|
||||||
|
### Webpage commander window is invoked via hotkey (Alt + W)
|
||||||
|
* If the invocation is unintentional, press the hotkey again to revoke webpage commander. The hotkey can be disabled via PW menu or command line.
|
||||||
|
* Webpage commander improves the efficiency of web browsing using single-letter command shortcut.
|
||||||
|
* Check out [Online Help](https://www.github.com/kangyu-california/PersistentWindows/blob/master/Help.md) for detailed instructions.
|