Browse Source

Merge pull request #65 from BookerLiu/2.5.13

Booker 3 years ago
parent
commit
ab5529f1e8
40 changed files with 3192 additions and 447 deletions
  1. 62 55
      App.config
  2. 4 1
      App.xaml.cs
  3. 7 1
      Constant/Constants.cs
  4. 18 0
      Constant/RunTimeStatus.cs
  5. 15 0
      Constant/WidthTypeEnum.cs
  6. 14 10
      Control/UserControls/Config/MotionControl.xaml.cs
  7. 16 2
      Control/UserControls/Config/OtherControl.xaml
  8. 76 0
      Control/UserControls/Config/OtherControl.xaml.cs
  9. 51 27
      Control/UserControls/PannelCard/LeftCardControl.xaml.cs
  10. 137 56
      Control/UserControls/PannelCard/RightCardControl.xaml
  11. 335 101
      Control/UserControls/PannelCard/RightCardControl.xaml.cs
  12. 2 1
      Control/Windows/PixelColorPickerWindow.xaml
  13. 25 4
      Control/Windows/PixelColorPickerWindow.xaml.cs
  14. 2 3
      Control/Windows/ToDoWindow.xaml.cs
  15. 40 0
      Converts/GetWidthByWWConvert.cs
  16. 35 5
      GeekDesk.csproj
  17. BIN
      Logo.ico
  18. 69 69
      MainWindow.xaml
  19. 68 22
      MainWindow.xaml.cs
  20. 71 27
      MyThread/MouseHookThread.cs
  21. 22 17
      MyThread/RelativePathThread.cs
  22. 39 0
      Plugins/ShowSeconds/Common/Constants.cs
  23. 32 0
      Plugins/ShowSeconds/SecondsWindow.xaml
  24. 312 0
      Plugins/ShowSeconds/SecondsWindow.xaml.cs
  25. 25 0
      Plugins/ShowSeconds/ViewModel/SecondsDataContext.cs
  26. 2 2
      Properties/AssemblyInfo.cs
  27. BIN
      Resource/Image/TitleLogo.png
  28. 2 2
      Task/ToDoTask.cs
  29. 3 3
      Update.json
  30. 7 38
      Util/CommonCode.cs
  31. 22 1
      Util/FileUtil.cs
  32. 227 0
      Util/HideWindowUtil.cs
  33. 1 0
      Util/ListBoxDragDropManager.cs
  34. 131 0
      Util/MessageUtil.cs
  35. 156 0
      Util/MouseHook.cs
  36. 156 0
      Util/ScreenUtil.cs
  37. 75 0
      Util/ScrollUtil.cs
  38. 837 0
      Util/UserActivityHook.cs
  39. 17 0
      ViewModel/AppConfig.cs
  40. 79 0
      app.manifest

+ 62 - 55
App.config

@@ -2,9 +2,16 @@
 <configuration>
 	<configSections>
 		<section name="SystemIcons" type="System.Configuration.DictionarySectionHandler" />
+		<section name="ShowSecondsSettings" type="System.Configuration.DictionarySectionHandler" />
 		<section name="SystemBGs" type="System.Collections.ObjectModel.ObservableCollection" />
 		<section name="GradientBGParam" type="GeekDesk.ViewModel.GradientBGParam" />
 	</configSections>
+	<ShowSecondsSettings>
+		<add key="Version" value="1.0.01" />
+		<add key="LProportion" value="0.82" />
+		<add key="TProportion" value="0.03" />
+		<add key="DelayTime" value="1500" />
+	</ShowSecondsSettings>
 	<SystemIcons>
 		<add key="Calculator" value="计算器" />
 		<add key="Computer" value="此电脑" />
@@ -21,59 +28,59 @@
 	<SystemBGs>
 		<GradientBGParam Color1="#FCCF31" Color2="#F55555" Name="诸神黄昏" />
 	</SystemBGs>
-  <startup>
-    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
-  </startup>
-  <runtime>
-    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
-		<probing privatePath="lib" />
-      <dependentAssembly>
-        <assemblyIdentity name="CommonServiceLocator" publicKeyToken="489b6accfaf20ef0" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-2.0.6.0" newVersion="2.0.6.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
-      </dependentAssembly>
-      <dependentAssembly>
-        <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
-        <bindingRedirect oldVersion="0.0.0.0-2.1.1.0" newVersion="2.1.1.0" />
-      </dependentAssembly>
-    </assemblyBinding>
-  </runtime>
-  <appSettings>
-      <add key="Version" value="2.5.11" />
-      <add key="GitHubUrl" value="https://github.com/BookerLiu/GeekDesk" />
-      <add key="GiteeUrl" value="https://gitee.com/BookerLiu/GeekDesk/tree/master" />
-      <add key="GitHubUpdateUrl" value="https://raw.githubusercontent.com/BookerLiu/GeekDesk/master/Update.json" />
-      <add key="GiteeUpdateUrl" value="https://gitee.com/BookerLiu/GeekDesk/raw/master/Update.json" />
-	  <!--<add key="GiteeUpdateUrl" value="file:///D:/WorkSpace/workspace-VS/GeekDesk/Update.json" />-->
-	  <add key="ClientSettingsProvider.ServiceUri" value="" />
-	  <add key="CustomIconTeachUrl" value="https://mp.weixin.qq.com/s/LxoHAekho9HBVl4FRw_Law" />
-	  <add key="ShowPublicWeChat" value="Y"/>
-  </appSettings>
-  <system.web>
-    <membership defaultProvider="ClientAuthenticationMembershipProvider">
-      <providers>
-        <add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" />
-      </providers>
-    </membership>
-    <roleManager defaultProvider="ClientRoleProvider" enabled="true">
-      <providers>
-        <add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" />
-      </providers>
-    </roleManager>
-  </system.web>
+	<startup>
+		<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
+	</startup>
+	<runtime>
+		<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+			<probing privatePath="lib" />
+			<dependentAssembly>
+				<assemblyIdentity name="CommonServiceLocator" publicKeyToken="489b6accfaf20ef0" culture="neutral" />
+				<bindingRedirect oldVersion="0.0.0.0-2.0.6.0" newVersion="2.0.6.0" />
+			</dependentAssembly>
+			<dependentAssembly>
+				<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+				<bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0" />
+			</dependentAssembly>
+			<dependentAssembly>
+				<assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+				<bindingRedirect oldVersion="0.0.0.0-4.2.0.1" newVersion="4.2.0.1" />
+			</dependentAssembly>
+			<dependentAssembly>
+				<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+				<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
+			</dependentAssembly>
+			<dependentAssembly>
+				<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+				<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
+			</dependentAssembly>
+			<dependentAssembly>
+				<assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+				<bindingRedirect oldVersion="0.0.0.0-2.1.1.0" newVersion="2.1.1.0" />
+			</dependentAssembly>
+		</assemblyBinding>
+	</runtime>
+	<appSettings>
+		<add key="Version" value="2.5.13" />
+		<add key="GitHubUrl" value="https://github.com/BookerLiu/GeekDesk" />
+		<add key="GiteeUrl" value="https://gitee.com/BookerLiu/GeekDesk/tree/master" />
+		<add key="GitHubUpdateUrl" value="https://raw.githubusercontent.com/BookerLiu/GeekDesk/master/Update.json" />
+		<add key="GiteeUpdateUrl" value="https://gitee.com/BookerLiu/GeekDesk/raw/master/Update.json" />
+		<!--<add key="GiteeUpdateUrl" value="file:///D:/WorkSpace/workspace-VS/GeekDesk/Update.json" />-->
+		<add key="ClientSettingsProvider.ServiceUri" value="" />
+		<add key="CustomIconTeachUrl" value="https://mp.weixin.qq.com/s/LxoHAekho9HBVl4FRw_Law" />
+		<add key="ShowPublicWeChat" value="Y" />
+	</appSettings>
+	<system.web>
+		<membership defaultProvider="ClientAuthenticationMembershipProvider">
+			<providers>
+				<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" />
+			</providers>
+		</membership>
+		<roleManager defaultProvider="ClientRoleProvider" enabled="true">
+			<providers>
+				<add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" />
+			</providers>
+		</roleManager>
+	</system.web>
 </configuration>

+ 4 - 1
App.xaml.cs

@@ -24,7 +24,6 @@ namespace GeekDesk
 
         private void App_Startup(object sender, StartupEventArgs e)
         {
-
             mutex = new System.Threading.Mutex(true, Constants.MY_NAME, out bool ret);
             if (!ret)
             {
@@ -32,6 +31,10 @@ namespace GeekDesk
                 mutex = new System.Threading.Mutex(true, Constants.MY_NAME, out ret);
                 if (!ret)
                 {
+                    MessageUtil.SendMsgByWName(
+                        "GeekDesk_Main_" + Constants.MY_UUID,
+                        "ShowApp"
+                        );
                     Environment.Exit(0);
                 }
             }

+ 7 - 1
Constant/Constants.cs

@@ -13,7 +13,7 @@ namespace GeekDesk.Constant
 
         public static string MY_NAME = DEV ? "GeekDesk-D" : "GeekDesk";
 
-
+        public static string MY_UUID = "8400A17AEEF7C029";
         /// <summary>
         /// app数据文件路径
         /// </summary>
@@ -30,6 +30,12 @@ namespace GeekDesk.Constant
 
         public static string ERROR_FILE_PATH = APP_DIR + "logs\\error.log"; // 错误日志
 
+        /// <summary>
+        /// 插件文件夹
+        /// </summary>
+        public static string PLUGINS_PATH = APP_DIR + "plugins\\";
+
+
         public static int SHADOW_WIDTH = 20;
 
         //系统图标

+ 18 - 0
Constant/RunTimeStatus.cs

@@ -40,5 +40,23 @@
         /// </summary>
         public static bool IS_MENU_EDIT = false;
 
+
+        /// <summary>
+        /// 图标card 鼠标滚轮是否正在工作  
+        /// 用来控制popup的显示 否则低性能机器会造成卡顿
+        /// </summary>
+        public static bool ICONLIST_MOUSE_WHEEL = false;
+        /// <summary>
+        /// 控制多少毫秒后 关闭(ICONLIST_MOUSE_WHEEL)鼠标滚轮运行状态
+        /// </summary>
+        public static int MOUSE_WHEEL_WAIT_MS = 100;
+        /// <summary>
+        /// 与关闭popup 配合使用, 避免线程结束后不显示popup
+        /// </summary>
+        public static bool MOUSE_ENTER_ICON = false;
+        /// <summary>
+        /// 控制每次刷新搜索结果 鼠标移动后显示popup
+        /// </summary>
+        public static int MOUSE_MOVE_COUNT = 0;
     }
 }

+ 15 - 0
Constant/WidthTypeEnum.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GeekDesk.Constant
+{
+    public enum WidthTypeEnum
+    {
+        LEFT_CARD = 0,  //左侧托盘宽度
+        RIGHT_CARD = 1, //右侧托盘宽度
+        RIGHT_CARD_HALF = 2 //右侧托盘宽度的一半
+    }
+}

+ 14 - 10
Control/UserControls/Config/MotionControl.xaml.cs

@@ -47,7 +47,7 @@ namespace GeekDesk.Control.UserControls.Config
 
                 if (!CheckIsEnable(hkType)) return;
 
-                
+
                 if (prevKeyTemp == Key.None || prevKeyTemp != downKey)
                 {
                     if (hotkeyFinished)
@@ -315,14 +315,17 @@ namespace GeekDesk.Control.UserControls.Config
         /// <param name="e"></param>
         private void MouseMiddle_Changed(object sender, RoutedEventArgs e)
         {
-            if (appConfig.MouseMiddleShow)
-            {
-                MouseHookThread.MiddleHook();
-            }
-            else
-            {
-                MouseHookThread.Dispose();
-            }
+            //if (appConfig.MouseMiddleShow)
+            //{
+            //    MouseHookThread.MiddleHook();
+            //}
+            //else
+            //{
+            //    MouseHookThread.DisposeMiddle();
+            //}
+
+            MouseHookThread.Dispose();
+            MouseHookThread.Hook();
         }
 
         /// <summary>
@@ -339,7 +342,8 @@ namespace GeekDesk.Control.UserControls.Config
                     if (true == appConfig.EnableAppHotKey)
                     {
                         MainWindow.RegisterHotKey(false);
-                    } else
+                    }
+                    else
                     {
                         if (MainWindow.hotKeyId != -1)
                         {

+ 16 - 2
Control/UserControls/Config/OtherControl.xaml

@@ -5,7 +5,7 @@
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:cvt="clr-namespace:GeekDesk.Converts"
              xmlns:local="clr-namespace:GeekDesk.Control.UserControls.PannelCard"
-             xmlns:hc="https://handyorg.github.io/handycontrol"
+             xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:viewmodel="clr-namespace:GeekDesk.ViewModel" d:DataContext="{d:DesignInstance Type=viewmodel:AppConfig}"
              mc:Ignorable="d" 
              Background="Transparent"
              d:DesignHeight="400" d:DesignWidth="500"
@@ -41,6 +41,20 @@
                         </CheckBox.Background>
                     </CheckBox>
                 </hc:UniformSpacingPanel>
+                <TextBlock Text="插件"  Margin="0,20,0,0"/>
+                <hc:UniformSpacingPanel Spacing="10" Margin="20,6,0,0">
+                    <CheckBox  Content="时钟显秒" Click="ShowSeconds_Click" IsChecked="{Binding SecondsWindow}" 
+                           hc:Poptip.HitMode="None"
+                           hc:Poptip.IsOpen="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}"
+                           hc:Poptip.Content="仅Win11有效" 
+                           hc:Poptip.Placement="TopLeft">
+                        <CheckBox.Background>
+                            <LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
+                                <GradientStop Color="#FF9EA3A6"/>
+                            </LinearGradientBrush>
+                        </CheckBox.Background>
+                    </CheckBox>
+                </hc:UniformSpacingPanel>
                 <TextBlock Text="排序方式"  Margin="0,25,0,0"/>
 
                 <hc:UniformSpacingPanel Spacing="10" Margin="20,8,0,0">
@@ -93,7 +107,7 @@
                              Foreground="Black"
                              IsChecked="{Binding UpdateType, Mode=TwoWay, Converter={StaticResource UpdateTypeConvert}, ConverterParameter=2}"/>
                 </hc:UniformSpacingPanel>
-                
+
                 <TextBlock Text="其它"  Margin="0,25,0,0"/>
                 <hc:UniformSpacingPanel Spacing="10" Margin="20,8,0,0">
                     <Button Content="备份数据" 

+ 76 - 0
Control/UserControls/Config/OtherControl.xaml.cs

@@ -1,6 +1,12 @@
 using GeekDesk.Constant;
+using GeekDesk.MyThread;
 using GeekDesk.Util;
 using GeekDesk.ViewModel;
+using ShowSeconds;
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Management;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
@@ -112,5 +118,75 @@ namespace GeekDesk.Control.UserControls.Config
         {
             CommonCode.BakAppData();
         }
+
+        private void ShowSeconds_Click(object sender, RoutedEventArgs e)
+        {
+            if (MainWindow.appData.AppConfig.SecondsWindow == true)
+            {
+                //StartSecondsWindow();
+                SecondsWindow.ShowWindow();
+            }
+            else
+            {
+                SecondsWindow.CloseWindow();
+                //StopSecondsWindow();
+            }
+        }
+
+        public static void StopSecondsWindow()
+        {
+            if (MessageUtil.CheckWindowIsRuning("ShowSeconds_Main_" + Constants.MY_UUID))
+            {
+                MessageUtil.SendMsgByWName(
+                    "ShowSeconds_Main_" + Constants.MY_UUID,
+                    "Shutdown"
+                    );
+            }
+        }
+
+        public static void StartSecondsWindow()
+        {
+            try
+            {
+                using (var objOS = new ManagementObjectSearcher("SELECT * FROM Win32_OperatingSystem"))
+                {
+                    foreach (ManagementObject objMgmt in objOS.Get())
+                    {
+                        if (objMgmt.Properties["Caption"].Value != null)
+                        {
+                            string caption = objMgmt.Properties["Caption"].Value.ToString(); ;
+                            LogUtil.WriteLog("获取的系统版本号为:" + caption);
+                            if (caption.Contains("Windows 11"))
+                            {
+                                //找到ShowSeconds插件
+                                FileInfo fi = FileUtil.GetFileByNameWithDir("ShowSeconds.exe", Constants.PLUGINS_PATH);
+                                if (fi == null)
+                                {
+                                    HandyControl.Controls.MessageBox.Show("未安装程序插件:ShowSeconds");
+                                }
+                                else
+                                {
+                                    //检查是否在运行
+                                    if (!MessageUtil.CheckWindowIsRuning("ShowSeconds_Main_" + Constants.MY_UUID))
+                                    {
+                                        using (Process p = new Process())
+                                        {
+                                            p.StartInfo.FileName = fi.FullName;
+                                            p.StartInfo.WorkingDirectory = fi.FullName.Substring(0, fi.FullName.LastIndexOf("\\"));
+                                            p.Start();
+                                        }
+                                    }
+                                }
+
+                            }
+                        }
+                    }
+                }
+            }
+            catch (Exception ex) { }
+        }
+
+
+
     }
 }

+ 51 - 27
Control/UserControls/PannelCard/LeftCardControl.xaml.cs

@@ -161,13 +161,18 @@ namespace GeekDesk.Control.UserControls.PannelCard
 
         private void Lbi_Selected(object sender, RoutedEventArgs e)
         {
-            ListBoxItem lbi = sender as ListBoxItem;
+            try
+            {
+                ListBoxItem lbi = sender as ListBoxItem;
 
-            SolidColorBrush fontColor = new SolidColorBrush(Colors.Black);
+                SolidColorBrush fontColor = new SolidColorBrush(Colors.Black);
+
+                lbi.MouseLeave -= Lbi_MouseLeave;
+                lbi.Background = bac;
+                lbi.Foreground = fontColor;
+            }
+            catch { }
 
-            lbi.MouseLeave -= Lbi_MouseLeave;
-            lbi.Background = bac;
-            lbi.Foreground = fontColor;
         }
 
         private void Lbi_MouseLeave(object sender, MouseEventArgs e)
@@ -339,6 +344,7 @@ namespace GeekDesk.Control.UserControls.PannelCard
                 }
             }
             MainWindow.mainWindow.RightCard.WrapUFG.Visibility = Visibility.Visible;
+            //App.DoEvents();
         }
 
 
@@ -421,32 +427,47 @@ namespace GeekDesk.Control.UserControls.PannelCard
         private void Menu_MouseWheel(object sender, MouseWheelEventArgs e)
         {
             if (RunTimeStatus.IS_MENU_EDIT) return;
+
+            ScrollViewer scrollViewer = ScrollUtil.FindSimpleVisualChild<ScrollViewer>(MenuListBox);
             if (e.Delta < 0)
             {
-                int index = MenuListBox.SelectedIndex;
-                if (index < MenuListBox.Items.Count - 1)
+                //判断是否到了最底部
+                if (ScrollUtil.IsBootomScrollView(scrollViewer))
                 {
-                    index ++;
-                } else
-                {
-                    index = 0;
+                    int index = MenuListBox.SelectedIndex;
+                    if (index < MenuListBox.Items.Count - 1)
+                    {
+                        index++;
+                    }
+                    else
+                    {
+                        index = 0;
+                    }
+                    MenuListBox.SelectedIndex = index;
                 }
-                MenuListBox.SelectedIndex = index;
-            } else if (e.Delta > 0)
+            }
+            else if (e.Delta > 0)
             {
-                int index = MenuListBox.SelectedIndex;
-                if (index > 0)
-                {
-                    index --;
-                }
-                else
+                if (ScrollUtil.IsTopScrollView(scrollViewer))
                 {
-                    index = MenuListBox.Items.Count - 1;
+                    int index = MenuListBox.SelectedIndex;
+                    if (index > 0)
+                    {
+                        index--;
+                    }
+                    else
+                    {
+                        index = MenuListBox.Items.Count - 1;
+                    }
+                    MenuListBox.SelectedIndex = index;
                 }
-                MenuListBox.SelectedIndex = index;
             }
+
+            //滚动到选中项
+            MenuListBox.ScrollIntoView(MenuListBox.SelectedItem);
+
         }
-       
+
 
         private void Menu_PreviewDragLeave(object sender, DragEventArgs e)
         {
@@ -489,14 +510,15 @@ namespace GeekDesk.Control.UserControls.PannelCard
                 MainWindow.mainWindow.RightCard.PDDialog.Visibility = Visibility.Visible;
                 //单独设置焦点
                 MainWindow.mainWindow.RightCard.PDDialog.SetFocus();
-            } else
+            }
+            else
             {
                 if (string.IsNullOrEmpty(appData.AppConfig.MenuPassword))
                 {
                     MainWindow.mainWindow.RightCard.PDDialog.menuInfo = menuInfo;
                     MainWindow.mainWindow.RightCard.PDDialog.Title.Text = "设置新密码";
                     MainWindow.mainWindow.RightCard.PDDialog.type = PasswordType.CREATE;
-                    RunTimeStatus.SHOW_MENU_PASSWORDBOX = true;                    
+                    RunTimeStatus.SHOW_MENU_PASSWORDBOX = true;
                     MainWindow.mainWindow.RightCard.PDDialog.Visibility = Visibility.Visible;
                 }
                 else
@@ -534,7 +556,8 @@ namespace GeekDesk.Control.UserControls.PannelCard
             if (string.IsNullOrEmpty(appData.AppConfig.MenuPassword))
             {
                 AlterPW1.Visibility = Visibility.Collapsed;
-            } else
+            }
+            else
             {
                 AlterPW1.Visibility = Visibility.Visible;
             }
@@ -545,7 +568,7 @@ namespace GeekDesk.Control.UserControls.PannelCard
             ListBoxItem lbi = sender as ListBoxItem;
             MenuInfo info = lbi.DataContext as MenuInfo;
 
-            ItemCollection ics =  lbi.ContextMenu.Items;
+            ItemCollection ics = lbi.ContextMenu.Items;
 
             foreach (object obj in ics)
             {
@@ -567,7 +590,8 @@ namespace GeekDesk.Control.UserControls.PannelCard
                     if (info.IsEncrypt)
                     {
                         mi.Header = "取消加密此列表";
-                    } else
+                    }
+                    else
                     {
                         mi.Header = "加密此列表";
                     }

+ 137 - 56
Control/UserControls/PannelCard/RightCardControl.xaml

@@ -6,9 +6,11 @@
              xmlns:temp="clr-namespace:GeekDesk.ViewModel.Temp"
              xmlns:hc="https://handyorg.github.io/handycontrol"
              xmlns:cvt="clr-namespace:GeekDesk.Converts"
+              xmlns:cst="clr-namespace:GeekDesk.Constant"
              xmlns:DraggAnimatedPanel="clr-namespace:DraggAnimatedPanel"
              xmlns:xf="clr-namespace:XamlFlair;assembly=XamlFlair.WPF"
-             xmlns:ot="clr-namespace:GeekDesk.Control.Other"
+             xmlns:ot="clr-namespace:GeekDesk.Control.Other" 
+             xmlns:viewmodel="clr-namespace:GeekDesk.ViewModel" d:DataContext="{d:DesignInstance Type=viewmodel:AppData}"
              mc:Ignorable="d" 
              d:DesignHeight="450" d:DesignWidth="800"
              >
@@ -58,6 +60,25 @@
             </Setter>
         </Style>
 
+        <Style x:Key="MyPoptipStyle" TargetType="Border">
+            <Setter Property="HorizontalAlignment" Value="Center"/>
+            <Setter Property="VerticalAlignment" Value="Center"/>
+            <Setter Property="BorderThickness" Value="1"/>
+            <Setter Property="Background" Value="White"/>
+            <Setter Property="BorderBrush" Value="{DynamicResource BorderBrush}"/>
+            <Setter Property="CornerRadius" Value="{StaticResource DefaultCornerRadius}"/>
+            <Setter Property="Padding" Value="{StaticResource DefaultControlPadding}"/>
+            <!--<Setter Property="Template">
+                <Setter.Value>
+                    <ControlTemplate TargetType="hc:Poptip">
+                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="{Binding Path=(hc:BorderElement.CornerRadius),RelativeSource={RelativeSource TemplatedParent}}">
+                            <ContentPresenter Margin="{TemplateBinding Padding}" ContentTemplateSelector="{TemplateBinding ContentTemplateSelector}" ContentStringFormat="{TemplateBinding ContentStringFormat}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
+                        </Border>
+                    </ControlTemplate>
+                </Setter.Value>
+            </Setter>-->
+        </Style>
+
         <Storyboard x:Key="Custom1Transition1" x:Shared="False">
             <DoubleAnimation From="50" To="0" Duration="0:0:0.4" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
                 <DoubleAnimation.EasingFunction>
@@ -82,11 +103,23 @@
         </Storyboard>
 
         <cvt:OpcityConvert x:Key="OpcityConvert"/>
-        <cvt:SearchResWidth x:Key="SearchResWidth"/>
+        <cvt:GetWidthByWWConvert x:Key="GetWidthByWWConvert"/>
         <temp:SearchIconList x:Key="SearchIconList"/>
     </UserControl.Resources>
     <!--右侧栏-->
     <Grid>
+        <Popup Name="MyPoptip" FlowDirection="LeftToRight" 
+               PopupAnimation="None" Placement="Mouse"
+               IsOpen="False"
+               AllowsTransparency="True"
+               >
+            <Grid Background="Transparent">
+                <Border Style="{StaticResource MyPoptipStyle}">
+                    <TextBlock Name="MyPoptipContent" HorizontalAlignment="Center" VerticalAlignment="Center" TextAlignment="Left" Text="Test" FontSize="13"/>
+                </Border>
+            </Grid>
+        </Popup>
+
         <hc:Card AllowDrop="True" 
                  x:Name="WrapCard"
                  Visibility="Visible"
@@ -96,6 +129,7 @@
                  Margin="5,0,5,5" Grid.ColumnSpan="2"
                  PreviewMouseRightButtonDown="WrapCard_PreviewMouseRightButtonDown"
                  hc:Dialog.Token="RightWrapCardDialog"
+                 MouseWheel="IconListBox_MouseWheel"
                  >
             <hc:Card.Background>
                 <SolidColorBrush Color="AliceBlue"  hc:GeometryEffect.GeometryEffect="20" Opacity="{Binding AppConfig.CardOpacity, Mode=TwoWay, Converter={StaticResource OpcityConvert}}"/>
@@ -118,7 +152,9 @@
                                        IsVisibleChanged="PDDialog_IsVisibleChanged"
                                        Margin="0,-100,0,0"/>
                     <StackPanel Panel.ZIndex="1" Margin="0,-10,-0,0"/>
+
                     <WrapPanel Orientation="Horizontal" 
+                               Margin="10"
                             VirtualizingPanel.VirtualizationMode="Recycling"  
                             VirtualizingPanel.IsVirtualizing="True" 
                             VirtualizingPanel.IsContainerVirtualizable="True"
@@ -126,12 +162,30 @@
                         <UniformGrid x:Name="WrapUFG" xf:Animations.Primary="{xf:Animate BasedOn={StaticResource FadeInAndGrowHorizontally}, Event=Visibility}">
                             <!--<hc:TransitioningContentControl TransitionStoryboard="{StaticResource Custom3Transition3}">-->
                             <ListBox x:Name="IconListBox" 
-                                ItemsSource="{Binding AppConfig.SelectedMenuIcons, Mode=OneWay}" 
-                                BorderThickness="0"
-                                Padding="0,10,0,0"
-                                >
+                                         ItemsSource="{Binding AppConfig.SelectedMenuIcons, Mode=OneWay}" 
+                                         BorderThickness="0"
+                                         Padding="0,10,0,0"
+                                         ScrollViewer.CanContentScroll ="False"
+                                         >
+                                <ListBox.Template>
+                                    <ControlTemplate TargetType="ListBox">
+                                        <hc:ScrollViewer x:Name="WrapScroll"
+                                                         Orientation="Vertical" 
+                                                         HorizontalScrollBarVisibility="Hidden" 
+                                                         VerticalScrollBarVisibility="Auto" 
+                                                         IsInertiaEnabled="True"
+                                                         CanContentScroll="True"
+                                                         PreviewMouseWheel="IconListBox_MouseWheel"
+                                                         >
+                                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderBrush}">
+                                                <ItemsPresenter/>
+
+                                            </Border>
+                                        </hc:ScrollViewer>
+                                    </ControlTemplate>
+                                </ListBox.Template>
                                 <ListBox.Background>
-                                    <SolidColorBrush Opacity="0"/>
+                                    <SolidColorBrush Color="#00FFFFFF"  />
                                 </ListBox.Background>
                                 <ListBox.ItemsPanel>
                                     <ItemsPanelTemplate>
@@ -140,7 +194,12 @@
                                                         ItemsHeight="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.AppConfig.ImgPanelHeight, Mode=OneWay}"
                                                         HorizontalAlignment="Center" 
                                                         SwapCommand="{Binding SwapCommand, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}"/>-->
-                                        <WrapPanel />
+
+                                        <WrapPanel Background="#00FFFFFF"
+                                                Width="{Binding AppConfig.WindowWidth, Mode=OneWay, 
+                                                Converter={StaticResource GetWidthByWWConvert}, 
+                                                ConverterParameter={x:Static cst:WidthTypeEnum.RIGHT_CARD}}"
+                                                />
                                     </ItemsPanelTemplate>
                                 </ListBox.ItemsPanel>
 
@@ -166,17 +225,16 @@
                                     <DataTemplate>
 
                                         <hc:SimpleStackPanel Tag="{Binding}"
-                                                    Height="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.AppConfig.ImgPanelHeight, Mode=OneWay}" 
-                                                    Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.AppConfig.ImgPanelWidth, Mode=OneWay}"
-                                                    HorizontalAlignment="Center"
-                                                    hc:Poptip.Content="{Binding Content}"
-                                                    hc:Poptip.Placement="BottomLeft"
-                                                    Background="#00FFFFFF"
-                                                    MouseEnter="StackPanel_MouseEnter"
-                                                    MouseLeave="StackPanel_MouseLeave"
-                                                    MouseLeftButtonDown="Icon_MouseLeftButtonDown"
-                                                    MouseLeftButtonUp="Icon_MouseLeftButtonUp"
-                                                    >
+                                                                 Height="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.AppConfig.ImgPanelHeight, Mode=OneWay}" 
+                                                                 Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.AppConfig.ImgPanelWidth, Mode=OneWay}"
+                                                                 HorizontalAlignment="Center"
+                                                                 Background="#00FFFFFF"
+                                                                 MouseEnter="MenuIcon_MouseEnter"
+                                                                 MouseLeave="MenuIcon_MouseLeave"
+                                                                 MouseMove="MenuIcon_MouseMove"        
+                                                                 MouseLeftButtonDown="Icon_MouseLeftButtonDown"
+                                                                 MouseLeftButtonUp="Icon_MouseLeftButtonUp"
+                                                                 >
                                             <!--<StackPanel Background="#00FFFFFF"
                                             MouseEnter="CursorPanel_MouseEnter"
                                             MouseLeave="CursorPanel_MouseLeave"
@@ -202,6 +260,7 @@
                             <!--</hc:TransitioningContentControl>-->
                         </UniformGrid>
                     </WrapPanel>
+
                 </Grid>
             </hc:DialogContainer>
         </hc:Card>
@@ -223,49 +282,68 @@
             </hc:Card.BorderBrush>
             <Grid>
                 <WrapPanel Orientation="Horizontal" VirtualizingPanel.VirtualizationMode="Recycling"  
-                   VirtualizingPanel.IsVirtualizing="True"  
-                   VirtualizingPanel.IsContainerVirtualizable="True"
-                   >
+                           VirtualizingPanel.IsVirtualizing="True"  
+                           VirtualizingPanel.IsContainerVirtualizable="True"
+                           Margin="10"
+                           >
                     <UniformGrid x:Name="VerticalUFG" xf:Animations.Primary="{xf:Animate BasedOn={StaticResource FadeIn}, OffsetY= -10, Event=Visibility}">
                         <!--<hc:TransitioningContentControl TransitionMode="Left2RightWithFade">-->
-                            <ListBox ItemsSource="{Binding Source={StaticResource SearchIconList},Path=IconList}" 
+                        <ListBox ItemsSource="{Binding Source={StaticResource SearchIconList},Path=IconList}" 
                                      BorderThickness="0"
                                      Padding="0,10,0,0"
                                      x:Name="SearchListBox"
                                      SelectionChanged="SearchListBox_SelectionChanged"
                                      >
-                                <ListBox.Background>
-                                    <SolidColorBrush Opacity="0"/>
-                                </ListBox.Background>
+                            <ListBox.Template>
+                                <ControlTemplate TargetType="ListBox">
+                                    <hc:ScrollViewer Orientation="Vertical" 
+                                                     HorizontalScrollBarVisibility="Hidden" 
+                                                     VerticalScrollBarVisibility="Auto" 
+                                                     IsInertiaEnabled="True"
+                                                     CanContentScroll="True"
+                                                     PreviewMouseWheel="VerticalIconList_PreviewMouseWheel"
+                                                     >
+                                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderBrush}">
+                                            <ItemsPresenter/>
+                                        </Border>
+                                    </hc:ScrollViewer>
+                                </ControlTemplate>
+                            </ListBox.Template>
 
-                                <ListBox.Resources>
-                                    <ContextMenu x:Key="IconDialog" Width="200">
-                                        <MenuItem Header="管理员方式运行" Click="IconAdminStart" Tag="{Binding}"/>
-                                        <MenuItem Header="打开文件所在位置" Click="ShowInExplore" Tag="{Binding}"/>
-                                        <MenuItem Header="添加URL项目" Click="AddUrlIcon"/>
-                                        <MenuItem Header="添加系统项目" Click="AddSystemIcon"/>
-                                        <MenuItem Header="资源管理器菜单" Click="SystemContextMenu" Tag="{Binding}"/>
-                                        <MenuItem Header="属性" Click="PropertyConfig" Tag="{Binding}"/>
-                                    </ContextMenu>
-                                </ListBox.Resources>
+                            <ListBox.Background>
+                                <SolidColorBrush Opacity="0"/>
+                            </ListBox.Background>
 
-                                <ListBox.ItemContainerStyle>
-                                    <Style TargetType="ListBoxItem" BasedOn="{StaticResource SearchListBoxItemStyle}">
-                                        <Setter Property="ContextMenu" Value="{StaticResource IconDialog}"/>
-                                    </Style>
-                                </ListBox.ItemContainerStyle>
+                            <ListBox.Resources>
+                                <ContextMenu x:Key="IconDialog" Width="200">
+                                    <MenuItem Header="管理员方式运行" Click="IconAdminStart" Tag="{Binding}"/>
+                                    <MenuItem Header="打开文件所在位置" Click="ShowInExplore" Tag="{Binding}"/>
+                                    <MenuItem Header="添加URL项目" Click="AddUrlIcon"/>
+                                    <MenuItem Header="添加系统项目" Click="AddSystemIcon"/>
+                                    <MenuItem Header="资源管理器菜单" Click="SystemContextMenu" Tag="{Binding}"/>
+                                    <MenuItem Header="属性" Click="PropertyConfig" Tag="{Binding}"/>
+                                </ContextMenu>
+                            </ListBox.Resources>
 
-                                <ListBox.ItemsPanel>
-                                    <ItemsPanelTemplate>
-                                        <StackPanel Background="#00FFFFFF"
-                                            Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.AppConfig.MenuCardWidth, Mode=OneWay, Converter={StaticResource SearchResWidth}, ConverterParameter=1}"
+                            <ListBox.ItemContainerStyle>
+                                <Style TargetType="ListBoxItem" BasedOn="{StaticResource SearchListBoxItemStyle}">
+                                    <Setter Property="ContextMenu" Value="{StaticResource IconDialog}"/>
+                                </Style>
+                            </ListBox.ItemContainerStyle>
+
+                            <ListBox.ItemsPanel>
+                                <ItemsPanelTemplate>
+                                    <StackPanel Background="#00FFFFFF"
+                                           Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.AppConfig.WindowWidth, Mode=OneWay, 
+                                                Converter={StaticResource GetWidthByWWConvert}, 
+                                                ConverterParameter={x:Static cst:WidthTypeEnum.RIGHT_CARD}}"
                                             />
-                                    </ItemsPanelTemplate>
-                                </ListBox.ItemsPanel>
+                                </ItemsPanelTemplate>
+                            </ListBox.ItemsPanel>
 
-                                <ListBox.ItemTemplate>
-                                    <DataTemplate>
-                                        <Border CornerRadius="8">
+                            <ListBox.ItemTemplate>
+                                <DataTemplate>
+                                    <Border CornerRadius="8">
                                         <Border.Style>
                                             <Style TargetType="Border">
                                                 <Setter Property="VerticalAlignment" Value="Center"/>
@@ -283,16 +361,19 @@
                                         </Border.Style>
                                         <WrapPanel Tag="{Binding}"
                                                    Height="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.AppConfig.ImageHeight, Mode=OneWay}" 
-                                                   Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.AppConfig.MenuCardWidth, Mode=OneWay, Converter={StaticResource SearchResWidth}, ConverterParameter=2}" 
+                                                   Width="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type Window}},Path=DataContext.AppConfig.WindowWidth, Mode=OneWay, 
+                                                        Converter={StaticResource GetWidthByWWConvert}, 
+                                                        ConverterParameter={x:Static cst:WidthTypeEnum.RIGHT_CARD_HALF}}" 
                                                    HorizontalAlignment="Left"
                                                    VerticalAlignment="Center"
                                                    hc:Poptip.HitMode="None"
-                                                   hc:Poptip.IsOpen="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}"
-                                                   hc:Poptip.Content="{Binding Content}"
                                                    hc:Poptip.Placement="BottomLeft"
                                                    Background="#00FFFFFF"
+                                                   MouseEnter="SearchIcon_MouseEnter"
+                                                   MouseLeave="SearchIcon_MouseLeave"
                                                    MouseLeftButtonDown="Icon_MouseLeftButtonDown"
                                                    MouseLeftButtonUp="Icon_MouseLeftButtonUp"
+                                                   MouseMove="SearchIcon_MouseMove"
                                                    Margin="25,10,0,10"
                                                    >
                                             <Image Style="{StaticResource ImageStyle}"  RenderOptions.BitmapScalingMode="HighQuality"/>
@@ -308,9 +389,9 @@
                                                Text="{Binding Name}"/>
                                         </WrapPanel>
                                     </Border>
-                                    </DataTemplate>
-                                </ListBox.ItemTemplate>
-                            </ListBox>
+                                </DataTemplate>
+                            </ListBox.ItemTemplate>
+                        </ListBox>
 
                         <!--</hc:TransitioningContentControl>-->
                     </UniformGrid>

+ 335 - 101
Control/UserControls/PannelCard/RightCardControl.xaml.cs

@@ -9,6 +9,7 @@ using System;
 using System.Collections.ObjectModel;
 using System.Diagnostics;
 using System.IO;
+using System.Reflection;
 using System.Threading;
 using System.Windows;
 using System.Windows.Controls;
@@ -34,7 +35,7 @@ namespace GeekDesk.Control.UserControls.PannelCard
         {
             InitializeComponent();
             this.Loaded += RightCardControl_Loaded;
-            
+
         }
 
         private void RightCardControl_Loaded(object sender, RoutedEventArgs e)
@@ -174,123 +175,130 @@ namespace GeekDesk.Control.UserControls.PannelCard
 
         private void StartIconApp(IconInfo icon, IconStartType type, bool useRelativePath = false)
         {
-            
+
             try
             {
-                using (Process p = new Process())
+                Process p = new Process();
+                //using ()
+                //{
+                p.StartInfo.UseShellExecute = false;
+                p.StartInfo.RedirectStandardInput = true;
+                p.StartInfo.RedirectStandardOutput = true;
+                p.StartInfo.RedirectStandardError = true;
+                p.StartInfo.CreateNoWindow = true;
+
+                string startArg = icon.StartArg;
+
+                if (startArg != null && Constants.SYSTEM_ICONS.ContainsKey(startArg))
+                {
+                    StartSystemApp(startArg, type);
+                }
+                else
                 {
-                    string startArg = icon.StartArg;
-                    
-                    if (startArg != null && Constants.SYSTEM_ICONS.ContainsKey(startArg))
+                    string path;
+                    if (useRelativePath)
                     {
-                        StartSystemApp(startArg, type);
+                        string fullPath = Path.Combine(Constants.APP_DIR, icon.RelativePath);
+                        path = Path.GetFullPath(fullPath);
                     }
                     else
                     {
-                        string path;
-                        if (useRelativePath)
-                        {
-                            string fullPath = Path.Combine(Constants.APP_DIR, icon.RelativePath);
-                            path = Path.GetFullPath(fullPath);
-                        } else
-                        {
-                            path = icon.Path;
-                        }
-                        p.StartInfo.FileName = path;
-                        if (!StringUtil.IsEmpty(startArg))
-                        {
-                            p.StartInfo.Arguments = startArg;
-                        }
-                        if (icon.IconType == IconType.OTHER)
+                        path = icon.Path;
+                    }
+                    p.StartInfo.FileName = path;
+                    if (!StringUtil.IsEmpty(startArg))
+                    {
+                        p.StartInfo.Arguments = startArg;
+                    }
+                    if (icon.IconType == IconType.OTHER)
+                    {
+                        if (!File.Exists(path) && !Directory.Exists(path))
                         {
-                            if (!File.Exists(path) && !Directory.Exists(path))
+                            //如果没有使用相对路径  那么使用相对路径启动一次
+                            if (!useRelativePath)
                             {
-                                //如果没有使用相对路径  那么使用相对路径启动一次
-                                if (!useRelativePath)
-                                {
-                                    StartIconApp(icon, type, true);
-                                    return;
-                                } else
-                                {
-                                    HandyControl.Controls.Growl.WarningGlobal("程序启动失败(文件路径不存在或已删除)!");
-                                    return;
-                                }
+                                StartIconApp(icon, type, true);
+                                return;
                             }
-                            p.StartInfo.WorkingDirectory = path.Substring(0, path.LastIndexOf("\\"));
-                            switch (type)
+                            else
                             {
-                                case IconStartType.ADMIN_STARTUP:
-                                    //p.StartInfo.Arguments = "1";//启动参数
-                                    p.StartInfo.Verb = "runas";
-                                    //p.StartInfo.CreateNoWindow = false; //设置显示窗口
-                                    p.StartInfo.UseShellExecute = true;//不使用操作系统外壳程序启动进程
-                                    //p.StartInfo.ErrorDialog = false;
-                                    if (appData.AppConfig.AppHideType == AppHideType.START_EXE && !RunTimeStatus.LOCK_APP_PANEL)
+                                HandyControl.Controls.Growl.WarningGlobal("程序启动失败(文件路径不存在或已删除)!");
+                                return;
+                            }
+                        }
+                        p.StartInfo.WorkingDirectory = path.Substring(0, path.LastIndexOf("\\"));
+                        switch (type)
+                        {
+                            case IconStartType.ADMIN_STARTUP:
+                                p.StartInfo.Verb = "runas";
+                                if (appData.AppConfig.AppHideType == AppHideType.START_EXE && !RunTimeStatus.LOCK_APP_PANEL)
+                                {
+                                    //如果开启了贴边隐藏 则窗体不贴边才隐藏窗口
+                                    if (appData.AppConfig.MarginHide)
                                     {
-                                        //如果开启了贴边隐藏 则窗体不贴边才隐藏窗口
-                                        if (appData.AppConfig.MarginHide)
-                                        {
-                                            if (!MarginHide.IsMargin())
-                                            {
-                                                MainWindow.HideApp();
-                                            }
-                                        }
-                                        else
+                                        if (!MarginHide.IsMargin())
                                         {
                                             MainWindow.HideApp();
                                         }
-
                                     }
-                                    break;// c#好像不能case穿透
-                                case IconStartType.DEFAULT_STARTUP:
-                                    if (appData.AppConfig.AppHideType == AppHideType.START_EXE && !RunTimeStatus.LOCK_APP_PANEL)
+                                    else
                                     {
-                                        //如果开启了贴边隐藏 则窗体不贴边才隐藏窗口
-                                        if (appData.AppConfig.MarginHide)
-                                        {
-                                            if (!MarginHide.IsMargin())
-                                            {
-                                                MainWindow.HideApp();
-                                            }
-                                        }
-                                        else
+                                        MainWindow.HideApp();
+                                    }
+
+                                }
+                                break;// c#好像不能case穿透
+                            case IconStartType.DEFAULT_STARTUP:
+                                if (appData.AppConfig.AppHideType == AppHideType.START_EXE && !RunTimeStatus.LOCK_APP_PANEL)
+                                {
+                                    //如果开启了贴边隐藏 则窗体不贴边才隐藏窗口
+                                    if (appData.AppConfig.MarginHide)
+                                    {
+                                        if (!MarginHide.IsMargin())
                                         {
                                             MainWindow.HideApp();
                                         }
                                     }
-                                    break;
-                                case IconStartType.SHOW_IN_EXPLORE:
-                                    p.StartInfo.FileName = "Explorer.exe";
-                                    p.StartInfo.Arguments = "/e,/select," + icon.Path;
-                                    break;
-                            }
-                        }
-                        else
-                        {
-                            if (appData.AppConfig.AppHideType == AppHideType.START_EXE && !RunTimeStatus.LOCK_APP_PANEL)
-                            {
-                                //如果开启了贴边隐藏 则窗体不贴边才隐藏窗口
-                                if (appData.AppConfig.MarginHide)
-                                {
-                                    if (!MarginHide.IS_HIDE)
+                                    else
                                     {
                                         MainWindow.HideApp();
                                     }
                                 }
-                                else
+                                break;
+                            case IconStartType.SHOW_IN_EXPLORE:
+                                p.StartInfo.FileName = "Explorer.exe";
+                                p.StartInfo.Arguments = "/e,/select," + icon.Path;
+                                break;
+                        }
+                    }
+                    else
+                    {
+                        if (appData.AppConfig.AppHideType == AppHideType.START_EXE && !RunTimeStatus.LOCK_APP_PANEL)
+                        {
+                            //如果开启了贴边隐藏 则窗体不贴边才隐藏窗口
+                            if (appData.AppConfig.MarginHide)
+                            {
+                                if (!MarginHide.IS_HIDE)
                                 {
                                     MainWindow.HideApp();
                                 }
                             }
-                        }
-                        p.Start();
-                        if (useRelativePath)
-                        {
-                            //如果使用相对路径启动成功 那么重新设置程序绝对路径
-                            icon.Path = path;
+                            else
+                            {
+                                MainWindow.HideApp();
+                            }
                         }
                     }
+                    p.Start();
+                    p.Close();
+                    p.Dispose();
+                    if (useRelativePath)
+                    {
+                        //如果使用相对路径启动成功 那么重新设置程序绝对路径
+                        icon.Path = path;
+                    }
                 }
+                //}
                 icon.Count++;
 
                 //隐藏搜索框
@@ -453,38 +461,55 @@ namespace GeekDesk.Control.UserControls.PannelCard
             }
         }
 
-        private void StackPanel_MouseEnter(object sender, MouseEventArgs e)
+        private void MenuIcon_MouseEnter(object sender, MouseEventArgs e)
         {
+            RunTimeStatus.MOUSE_ENTER_ICON = true;
+            if (!RunTimeStatus.ICONLIST_MOUSE_WHEEL)
+            {
+                ThreadPool.QueueUserWorkItem(state =>
+                {
+                    this.Dispatcher.BeginInvoke(new Action(() =>
+                    {
+                        IconInfo info = (sender as Panel).Tag as IconInfo;
+                        MyPoptipContent.Text = info.Content;
+                        MyPoptip.VerticalOffset = 30;
+                        Thread.Sleep(50);
+                        if (!RunTimeStatus.ICONLIST_MOUSE_WHEEL)
+                        {
+                            MyPoptip.IsOpen = true;
+                        }
+                    }));
+                });
+            }
+
+
 
             double width = appData.AppConfig.ImageWidth;
             double height = appData.AppConfig.ImageHeight;
             width += width * 0.15;
             height += height * 0.15;
-            Thread t = new Thread(() =>
+
+            ThreadPool.QueueUserWorkItem(state =>
             {
                 this.Dispatcher.BeginInvoke(new Action(() =>
                 {
                     ImgStoryBoard(sender, (int)width, (int)height, 1, true);
                 }));
             });
-            t.IsBackground = true;
-            t.Start();
-
         }
 
-        private void StackPanel_MouseLeave(object sender, MouseEventArgs e)
+        private void MenuIcon_MouseLeave(object sender, MouseEventArgs e)
         {
+            RunTimeStatus.MOUSE_ENTER_ICON = false;
+            MyPoptip.IsOpen = false;
 
-            Thread t = new Thread(() =>
-            {
-            this.Dispatcher.BeginInvoke(new Action(() =>
+            ThreadPool.QueueUserWorkItem(state =>
             {
-                ImgStoryBoard(sender, appData.AppConfig.ImageWidth, appData.AppConfig.ImageHeight, 260);
-            }));
+                this.Dispatcher.BeginInvoke(new Action(() =>
+                {
+                    ImgStoryBoard(sender, appData.AppConfig.ImageWidth, appData.AppConfig.ImageHeight, 260);
+                }));
             });
-            t.IsBackground = true;
-            t.Start();
-
         }
 
 
@@ -750,7 +775,8 @@ namespace GeekDesk.Control.UserControls.PannelCard
             if (RunTimeStatus.LOCK_APP_PANEL)
             {
                 CardLockCM.Header = "解锁主面板";
-            } else
+            }
+            else
             {
                 CardLockCM.Header = "锁定主面板";
             }
@@ -758,6 +784,10 @@ namespace GeekDesk.Control.UserControls.PannelCard
 
         public void SearchListBoxIndexAdd()
         {
+            //控制移动后 鼠标即使在图标上也不显示popup
+            RunTimeStatus.MOUSE_MOVE_COUNT = 0;
+            MyPoptip.IsOpen = false;
+
             if (SearchListBox.Items.Count > 0)
             {
                 if (SearchListBox.SelectedIndex < SearchListBox.Items.Count - 1)
@@ -769,6 +799,10 @@ namespace GeekDesk.Control.UserControls.PannelCard
 
         public void SearchListBoxIndexSub()
         {
+            //控制移动后 鼠标即使在图标上也不显示popup
+            RunTimeStatus.MOUSE_MOVE_COUNT = 0;
+            MyPoptip.IsOpen = false;
+
             if (SearchListBox.Items.Count > 0)
             {
                 if (SearchListBox.SelectedIndex > 0)
@@ -818,5 +852,205 @@ namespace GeekDesk.Control.UserControls.PannelCard
                 MainWindow.mainWindow.Focus();
             }
         }
+
+        /// <summary>
+        /// 菜单结果icon 列表鼠标滚轮预处理时间  
+        /// 主要使用自定义popup解决卡顿问题解决卡顿问题
+        /// 以及滚动条收尾切换菜单
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void IconListBox_MouseWheel(object sender, MouseWheelEventArgs e)
+        {
+
+            //控制在滚动时不显示popup 否则会在低GPU性能机器上造成卡顿
+            MyPoptip.IsOpen = false;
+            if (RunTimeStatus.ICONLIST_MOUSE_WHEEL)
+            {
+                RunTimeStatus.MOUSE_WHEEL_WAIT_MS = 500;
+            }
+            else
+            {
+                RunTimeStatus.ICONLIST_MOUSE_WHEEL = true;
+
+                new Thread(() =>
+                {
+                    while (RunTimeStatus.MOUSE_WHEEL_WAIT_MS > 0)
+                    {
+                        Thread.Sleep(1);
+                        RunTimeStatus.MOUSE_WHEEL_WAIT_MS -= 1;
+                    }
+                    if (RunTimeStatus.MOUSE_ENTER_ICON)
+                    {
+                        this.Dispatcher.BeginInvoke(new Action(() =>
+                        {
+                            MyPoptip.IsOpen = true;
+                        }));
+                    }
+                    RunTimeStatus.MOUSE_WHEEL_WAIT_MS = 100;
+                    RunTimeStatus.ICONLIST_MOUSE_WHEEL = false;
+                }).Start();
+            }
+
+            //修改菜单时不切换菜单
+            if (RunTimeStatus.IS_MENU_EDIT) return;
+
+
+            //切换菜单
+            System.Windows.Controls.ScrollViewer scrollViewer = sender as System.Windows.Controls.ScrollViewer;
+            if (scrollViewer == null)
+            {
+                //在card 上获取的事件
+                scrollViewer = ScrollUtil.FindSimpleVisualChild<System.Windows.Controls.ScrollViewer>(IconListBox);
+            }
+            if (e.Delta < 0)
+            {
+                int index = MainWindow.mainWindow.LeftCard.MenuListBox.SelectedIndex;
+                if (ScrollUtil.IsBootomScrollView(scrollViewer))
+                {
+                    if (index < MainWindow.mainWindow.LeftCard.MenuListBox.Items.Count - 1)
+                    {
+                        index++;
+                    }
+                    else
+                    {
+                        index = 0;
+                    }
+                    MainWindow.mainWindow.LeftCard.MenuListBox.SelectedIndex = index;
+                    scrollViewer.ScrollToVerticalOffset(0);
+                }
+            }
+            else if (e.Delta > 0)
+            {
+                if (ScrollUtil.IsTopScrollView(scrollViewer))
+                {
+                    int index = MainWindow.mainWindow.LeftCard.MenuListBox.SelectedIndex;
+                    if (index > 0)
+                    {
+                        index--;
+                    }
+                    else
+                    {
+                        index = MainWindow.mainWindow.LeftCard.MenuListBox.Items.Count - 1;
+                    }
+                    MainWindow.mainWindow.LeftCard.MenuListBox.SelectedIndex = index;
+                    scrollViewer.ScrollToVerticalOffset(0);
+                }
+            }
+
+
+        }
+
+        /// <summary>
+        /// 搜索结果icon 列表鼠标滚轮预处理时间  
+        /// 主要使用自定义popup解决卡顿问题解决卡顿问题
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void VerticalIconList_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
+        {
+            //控制在滚动时不显示popup 否则会在低GPU性能机器上造成卡顿
+            MyPoptip.IsOpen = false;
+            if (RunTimeStatus.ICONLIST_MOUSE_WHEEL)
+            {
+                RunTimeStatus.MOUSE_WHEEL_WAIT_MS = 500;
+            }
+            else
+            {
+                RunTimeStatus.ICONLIST_MOUSE_WHEEL = true;
+
+                new Thread(() =>
+                {
+                    while (RunTimeStatus.MOUSE_WHEEL_WAIT_MS > 0)
+                    {
+                        Thread.Sleep(1);
+                        RunTimeStatus.MOUSE_WHEEL_WAIT_MS -= 1;
+                    }
+                    if (RunTimeStatus.MOUSE_ENTER_ICON)
+                    {
+                        this.Dispatcher.BeginInvoke(new Action(() =>
+                        {
+                            MyPoptip.IsOpen = true;
+                        }));
+                    }
+                    RunTimeStatus.MOUSE_WHEEL_WAIT_MS = 100;
+                    RunTimeStatus.ICONLIST_MOUSE_WHEEL = false;
+                }).Start();
+            }
+        }
+
+        /// <summary>
+        /// 查询结果 ICON 鼠标进入事件
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void SearchIcon_MouseEnter(object sender, MouseEventArgs e)
+        {
+
+            //显示popup
+            RunTimeStatus.MOUSE_ENTER_ICON = true;
+            if (!RunTimeStatus.ICONLIST_MOUSE_WHEEL)
+            {
+                new Thread(() =>
+                {
+                    this.Dispatcher.BeginInvoke(new Action(() =>
+                    {
+                        IconInfo info = (sender as Panel).Tag as IconInfo;
+                        MyPoptipContent.Text = info.Content;
+                        MyPoptip.VerticalOffset = 30;
+                        Thread.Sleep(100);
+                        if (!RunTimeStatus.ICONLIST_MOUSE_WHEEL && RunTimeStatus.MOUSE_MOVE_COUNT > 1)
+                        {
+                            MyPoptip.IsOpen = true;
+                        }
+                    }));
+                }).Start();
+            }
+        }
+
+        /// <summary>
+        /// 查询结果ICON鼠标离开事件
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void SearchIcon_MouseLeave(object sender, MouseEventArgs e)
+        {
+            RunTimeStatus.MOUSE_ENTER_ICON = false;
+            MyPoptip.IsOpen = false;
+        }
+
+        /// <summary>
+        /// 查询结果ICON鼠标移动事件
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void SearchIcon_MouseMove(object sender, MouseEventArgs e)
+        {
+            //控制首次刷新搜索结果后, 鼠标首次移动后显示popup
+            RunTimeStatus.MOUSE_MOVE_COUNT++;
+
+            //防止移动后不刷新popup content
+            IconInfo info = (sender as Panel).Tag as IconInfo;
+            MyPoptipContent.Text = info.Content;
+            MyPoptip.VerticalOffset = 30;
+
+            if (RunTimeStatus.MOUSE_MOVE_COUNT > 1 && !RunTimeStatus.ICONLIST_MOUSE_WHEEL)
+            {
+                MyPoptip.IsOpen = true;
+            }
+        }
+
+        /// <summary>
+        /// menu结果ICON鼠标移动事件
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void MenuIcon_MouseMove(object sender, MouseEventArgs e)
+        {
+            //防止移动后不刷新popup content
+            IconInfo info = (sender as Panel).Tag as IconInfo;
+            MyPoptipContent.Text = info.Content;
+            MyPoptip.VerticalOffset = 30;
+        }
     }
 }

+ 2 - 1
Control/Windows/PixelColorPickerWindow.xaml

@@ -8,6 +8,7 @@
     Background="Black"
     PreviewMouseMove="Window_PreviewMouseMove"
     MouseLeftButtonDown="Window_MouseLeftButtonDown"
+    MouseRightButtonDown="Window_MouseRightButtonDown"
     MouseWheel="Window_MouseWheel"
     >
     <Window.Resources>
@@ -21,7 +22,7 @@
     </Window.Resources>
     <Grid>
         <Image x:Name="DesktopBG" RenderOptions.BitmapScalingMode="HighQuality"/>
-        
+
         <Canvas HorizontalAlignment="Left" VerticalAlignment="Top" Background="Transparent">
             <Canvas x:Name="ColorCanvas" 
                         Width="185"

+ 25 - 4
Control/Windows/PixelColorPickerWindow.xaml.cs

@@ -39,7 +39,12 @@ namespace GeekDesk.Control.Windows
         {
             InitializeComponent();
             this.colorPicker = colorPicker;
-            SetProcessDPIAware();
+
+            try
+            {
+                SetProcessDPIAware();
+            }
+            catch (Exception e) { }
             ColorPickerWindow_Init();
         }
 
@@ -58,9 +63,12 @@ namespace GeekDesk.Control.Windows
             DesktopBG.Height = this.Height;
             this.Topmost = true;
 
+            //获取缩放比例
+            double scale = ScreenUtil.GetScreenScalingFactor();
+
             bgBitmap = new System.Drawing.Bitmap(
-                    Screen.AllScreens[0].Bounds.Width,
-                    Screen.AllScreens[0].Bounds.Height,
+                    (int)(Width * scale),
+                    (int)(Height * scale),
                     System.Drawing.Imaging.PixelFormat.Format32bppArgb
                 );
 
@@ -80,6 +88,7 @@ namespace GeekDesk.Control.Windows
                                         Int32Rect.Empty,
                                         BitmapSizeOptions.FromEmptyOptions()
                                     );
+
             DesktopBG.Source = bs;
             VisualBrush b = (VisualBrush)PixelBG.Fill;
             b.Visual = DesktopBG;
@@ -122,7 +131,7 @@ namespace GeekDesk.Control.Windows
                 mi.Invoke(colorPicker, new object[] { null, null });
             }
         }
-   
+
         private void Window_PreviewMouseMove(object sender, MouseEventArgs e)
         {
             SetPixelAbout(e);
@@ -199,5 +208,17 @@ namespace GeekDesk.Control.Windows
             SetPixelAbout(e);
         }
 
+        /// <summary>
+        /// 右键按下
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void Window_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
+        {
+            Mouse.OverrideCursor = null;
+            GlobalColorPickerWindow.ShowOrHide();
+            //关闭
+            this.Close();
+        }
     }
 }

+ 2 - 3
Control/Windows/ToDoWindow.xaml.cs

@@ -69,7 +69,8 @@ namespace GeekDesk.Control.Windows
                     {
                         backlog.NoData.Visibility = Visibility.Collapsed;
                         backlog.BacklogList.Visibility = Visibility.Visible;
-                    } else
+                    }
+                    else
                     {
                         backlog.NoData.Visibility = Visibility.Visible;
                         backlog.BacklogList.Visibility = Visibility.Collapsed;
@@ -110,9 +111,7 @@ namespace GeekDesk.Control.Windows
 
 
         private static System.Windows.Window window = null;
-#pragma warning disable CS0108 // “ToDoWindow.Show()”隐藏继承的成员“Window.Show()”。如果是有意隐藏,请使用关键字 new。
         public static void Show()
-#pragma warning restore CS0108 // “ToDoWindow.Show()”隐藏继承的成员“Window.Show()”。如果是有意隐藏,请使用关键字 new。
         {
             if (window == null || !window.Activate())
             {

+ 40 - 0
Converts/GetWidthByWWConvert.cs

@@ -0,0 +1,40 @@
+using GeekDesk.Constant;
+using GeekDesk.ViewModel;
+using System;
+using System.Globalization;
+using System.Windows.Data;
+
+namespace GeekDesk.Converts
+{
+    /// <summary>
+    /// 根据主窗口width 和传入类型  获取其它宽度
+    /// </summary>
+    class GetWidthByWWConvert : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            WidthTypeEnum type = (WidthTypeEnum)parameter;
+
+            AppConfig config = MainWindow.appData.AppConfig;
+
+            if (WidthTypeEnum.LEFT_CARD == type)
+            {
+                return config.MenuCardWidth;
+            }
+            else if (WidthTypeEnum.RIGHT_CARD == type)
+            {
+                return config.WindowWidth - config.MenuCardWidth;
+            } else if (WidthTypeEnum.RIGHT_CARD_HALF == type)
+            {
+                return (config.WindowWidth - config.MenuCardWidth) / 2;
+            }
+
+            return config.WindowWidth;
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return null;
+        }
+    }
+}

+ 35 - 5
GeekDesk.csproj

@@ -18,6 +18,9 @@
     <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
     <Deterministic>true</Deterministic>
     <TargetFrameworkProfile />
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
     <PublishUrl>publish\</PublishUrl>
     <Install>true</Install>
     <InstallFrom>Disk</InstallFrom>
@@ -30,11 +33,8 @@
     <MapFileExtensions>true</MapFileExtensions>
     <ApplicationRevision>0</ApplicationRevision>
     <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
-    <IsWebBootstrapper>false</IsWebBootstrapper>
     <UseApplicationTrust>false</UseApplicationTrust>
     <BootstrapperEnabled>true</BootstrapperEnabled>
-    <NuGetPackageImportStamp>
-    </NuGetPackageImportStamp>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
     <PlatformTarget>AnyCPU</PlatformTarget>
@@ -49,7 +49,7 @@
     <Prefer32Bit>false</Prefer32Bit>
   </PropertyGroup>
   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <PlatformTarget>x64</PlatformTarget>
+    <PlatformTarget>AnyCPU</PlatformTarget>
     <DebugType>pdbonly</DebugType>
     <Optimize>true</Optimize>
     <OutputPath>bin\Release\</OutputPath>
@@ -67,7 +67,7 @@
     <SignManifests>false</SignManifests>
   </PropertyGroup>
   <PropertyGroup>
-    <ApplicationIcon>Taskbar.ico</ApplicationIcon>
+    <ApplicationIcon>Logo.ico</ApplicationIcon>
   </PropertyGroup>
   <PropertyGroup>
     <TargetZone>LocalIntranet</TargetZone>
@@ -75,6 +75,9 @@
   <PropertyGroup>
     <GenerateManifests>false</GenerateManifests>
   </PropertyGroup>
+  <PropertyGroup>
+    <ApplicationManifest>app.manifest</ApplicationManifest>
+  </PropertyGroup>
   <ItemGroup>
     <Reference Include="CommonServiceLocator, Version=2.0.6.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0, processorArchitecture=MSIL">
       <HintPath>packages\CommonServiceLocator.2.0.6\lib\net45\CommonServiceLocator.dll</HintPath>
@@ -113,6 +116,7 @@
     <Reference Include="System.Drawing.Common, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
       <HintPath>packages\System.Drawing.Common.6.0.0-preview.6.21352.12\lib\net461\System.Drawing.Common.dll</HintPath>
     </Reference>
+    <Reference Include="System.Management" />
     <Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
       <HintPath>packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
     </Reference>
@@ -170,6 +174,7 @@
     <Compile Include="Constant\TodoTaskExecType.cs" />
     <Compile Include="Constant\BGStyle.cs" />
     <Compile Include="Constant\UpdateType.cs" />
+    <Compile Include="Constant\WidthTypeEnum.cs" />
     <Compile Include="Control\Other\GlobalMsgNotification.xaml.cs">
       <DependentUpon>GlobalMsgNotification.xaml</DependentUpon>
     </Compile>
@@ -247,6 +252,7 @@
     </Compile>
     <Compile Include="Converts\CountGreZero2BoolConvert.cs" />
     <Compile Include="Converts\Count2VisibleConvert.cs" />
+    <Compile Include="Converts\GetWidthByWWConvert.cs" />
     <Compile Include="Converts\SearchTypeConvert.cs" />
     <Compile Include="Converts\StringAppendConvert.cs" />
     <Compile Include="Converts\DoubleToGridLength.cs" />
@@ -265,6 +271,11 @@
     <Compile Include="Converts\HideTypeConvert.cs" />
     <Compile Include="Interface\IWindowCommon.cs" />
     <Compile Include="MyThread\RelativePathThread.cs" />
+    <Compile Include="Plugins\ShowSeconds\Common\Constants.cs" />
+    <Compile Include="Plugins\ShowSeconds\SecondsWindow.xaml.cs">
+      <DependentUpon>SecondsWindow.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Plugins\ShowSeconds\ViewModel\SecondsDataContext.cs" />
     <Compile Include="Task\ShowSecondTask.cs" />
     <Compile Include="Task\ToDoTask.cs" />
     <Compile Include="MyThread\MouseHookThread.cs" />
@@ -274,11 +285,15 @@
     <Compile Include="Util\BGSettingUtil.cs" />
     <Compile Include="Util\BlurGlassUtil.cs" />
     <Compile Include="Util\ColorUtil.cs" />
+    <Compile Include="Util\DefaultIcons.cs" />
     <Compile Include="Util\DragAdorner.cs" />
     <Compile Include="Util\GlobalHotKey.cs" />
     <Compile Include="Util\CommonCode.cs" />
     <Compile Include="Util\FileIcon.cs" />
     <Compile Include="Util\FileUtil.cs" />
+    <Compile Include="Util\HideWindowUtil.cs" />
+    <Compile Include="Util\IconHelper.cs" />
+    <Compile Include="Util\IconUtil.cs" />
     <Compile Include="Util\KeyUtil.cs" />
     <Compile Include="Util\ListBoxDragDropManager.cs" />
     <Compile Include="Util\LogUtil.cs" />
@@ -287,13 +302,20 @@
     <Compile Include="Util\ImageUtil.cs" />
     <Compile Include="Converts\MenuWidthConvert.cs" />
     <Compile Include="Util\MD5Util.cs" />
+    <Compile Include="Util\MessageUtil.cs" />
+    <Compile Include="Util\MouseHook.cs" />
     <Compile Include="Util\MouseUtil.cs" />
+    <Compile Include="Util\NativeMethods.cs" />
     <Compile Include="Util\RegisterUtil.cs" />
     <Compile Include="Util\RelayCommand.cs" />
+    <Compile Include="Util\ScreenUtil.cs" />
+    <Compile Include="Util\ScrollUtil.cs" />
     <Compile Include="Util\ShellContextMenu.cs" />
     <Compile Include="Util\ShowWindowFollowMouse.cs" />
     <Compile Include="Util\StringUtil.cs" />
     <Compile Include="Util\SvgToGeometry.cs" />
+    <Compile Include="Util\UserActivityHook.cs" />
+    <Compile Include="Util\WindowsThumbnailProvider.cs" />
     <Compile Include="ViewModel\AppConfig.cs" />
     <Compile Include="ViewModel\AppData.cs" />
     <Compile Include="ViewModel\GradientBGParam.cs" />
@@ -416,6 +438,10 @@
       <DependentUpon>MainWindow.xaml</DependentUpon>
       <SubType>Code</SubType>
     </Compile>
+    <Page Include="Plugins\ShowSeconds\SecondsWindow.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
     <Page Include="Resource\Dictionary\Geometry.xaml">
       <SubType>Designer</SubType>
       <Generator>MSBuild:Compile</Generator>
@@ -449,6 +475,7 @@
       <LastGenOutput>Resources.Designer.cs</LastGenOutput>
     </EmbeddedResource>
     <Resource Include="Resource\Iconfont\iconfont.json" />
+    <None Include="app.manifest" />
     <None Include="Properties\app.manifest" />
     <None Include="Update.json" />
     <None Include="packages.config" />
@@ -517,6 +544,9 @@
       <Install>false</Install>
     </BootstrapperPackage>
   </ItemGroup>
+  <ItemGroup>
+    <Resource Include="Logo.ico" />
+  </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
   <ProjectExtensions>
     <VisualStudio>

BIN
Logo.ico


+ 69 - 69
MainWindow.xaml

@@ -12,7 +12,7 @@
         x:Name="AppWindow"
         xmlns:hc="https://handyorg.github.io/handycontrol" xmlns:viewmodel="clr-namespace:GeekDesk.ViewModel" 
         d:DataContext="{d:DesignInstance Type=viewmodel:AppData}"
-        Title="GeekDesk" 
+        Title="GeekDesk_Main_8400A17AEEF7C029" 
         MinWidth="600"
         MinHeight="400"
         WindowStyle="None"
@@ -29,7 +29,7 @@
         GotFocus="Window_GotFocus"
         Loaded="Window_Loaded"          
         >
-    
+
     <Window.Resources>
         <RoutedUICommand x:Key="SearchHotKeyDown" Text="SearchHotKeyDown"/>
 
@@ -39,11 +39,11 @@
         <cvt:DoubleToGridLength x:Key="DoubleToGridLength"/>
         <cvt:ReverseBoolConvert x:Key="ReverseBoolConvert"/>
     </Window.Resources>
-    
+
     <WindowChrome.WindowChrome>
         <WindowChrome CaptionHeight="0" CornerRadius="30" ResizeBorderThickness="15"/>
     </WindowChrome.WindowChrome>
-    
+
     <Window.InputBindings>
         <KeyBinding Gesture="Ctrl+F" Key="F"  Command="{StaticResource SearchHotKeyDown}"/>
     </Window.InputBindings>
@@ -68,35 +68,35 @@
             <DropShadowEffect BlurRadius="30" Direction="-90" Color="Gray"
                               RenderingBias="Quality" ShadowDepth="2"/>
         </Border.Effect>
-            <hc:DialogContainer Focusable="True">
-                <Grid>
-                    <Grid.RowDefinitions>
-                        <RowDefinition Height="40" MouseMove="DragMove"></RowDefinition>
-                        <RowDefinition Height="*"></RowDefinition>
-                    </Grid.RowDefinitions>
-                    <Grid.ColumnDefinitions>
-                        <ColumnDefinition x:Name="LeftColumn" MinWidth="80" Width="{Binding AppConfig.MenuCardWidth, Mode=TwoWay, Converter={StaticResource DoubleToGridLength}}" MaxWidth="200"></ColumnDefinition>
-                        <ColumnDefinition x:Name="RightColumn" Width="*"></ColumnDefinition>
-                    </Grid.ColumnDefinitions>
-
-                    <CheckBox x:Name="ShowBox" Visibility="Hidden" Panel.ZIndex="2"/>
-                    <CheckBox x:Name="HideBox" Visibility="Hidden" Panel.ZIndex="2"/>
-
-                    <StackPanel HorizontalAlignment="Right" Panel.ZIndex="99" hc:Growl.GrowlParent="False" hc:Growl.Token="MainWindowGrowl" Grid.Column="1" Grid.Row="1"/>
-
-                    <DockPanel Grid.Row="0" Grid.Column="0" MouseMove="DragMove">
-                        <DockPanel.Background>
-                            <SolidColorBrush Opacity="0.01"/>
-                        </DockPanel.Background>
-                        <Image Visibility="{Binding AppConfig.TitleLogoVisible}" Source="/Resource/Image/TitleLogo.png" Margin="10,0,0,0" Width="94" Height="30" HorizontalAlignment="Left"/>
-                    </DockPanel>
-
-                    <DockPanel Grid.Row="0" Grid.Column="2" MouseMove="DragMove">
-                        <DockPanel.Background>
-                            <SolidColorBrush Opacity="0.01"/>
-                        </DockPanel.Background>
-                        <hc:UniformSpacingPanel Grid.ColumnSpan="4" HorizontalAlignment="Right" VerticalAlignment="Center">
-                            <Button Background="Transparent"
+        <hc:DialogContainer Focusable="True">
+            <Grid>
+                <Grid.RowDefinitions>
+                    <RowDefinition Height="40" MouseMove="DragMove"></RowDefinition>
+                    <RowDefinition Height="*"></RowDefinition>
+                </Grid.RowDefinitions>
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition x:Name="LeftColumn" MinWidth="80" Width="{Binding AppConfig.MenuCardWidth, Mode=TwoWay, Converter={StaticResource DoubleToGridLength}}" MaxWidth="200"></ColumnDefinition>
+                    <ColumnDefinition x:Name="RightColumn" Width="*"></ColumnDefinition>
+                </Grid.ColumnDefinitions>
+
+                <CheckBox x:Name="ShowBox" Visibility="Hidden" Panel.ZIndex="2"/>
+                <CheckBox x:Name="HideBox" Visibility="Hidden" Panel.ZIndex="2"/>
+
+                <StackPanel HorizontalAlignment="Right" Panel.ZIndex="99" hc:Growl.GrowlParent="False" hc:Growl.Token="MainWindowGrowl" Grid.Column="1" Grid.Row="1"/>
+
+                <DockPanel Grid.Row="0" Grid.Column="0" MouseMove="DragMove">
+                    <DockPanel.Background>
+                        <SolidColorBrush Opacity="0.01"/>
+                    </DockPanel.Background>
+                    <Image Visibility="{Binding AppConfig.TitleLogoVisible}" Source="/Resource/Image/TitleLogo.png" RenderOptions.BitmapScalingMode="HighQuality" Margin="10,0,0,0" Width="200" Height="30" HorizontalAlignment="Left"/>
+                </DockPanel>
+
+                <DockPanel Grid.Row="0" Grid.Column="2" MouseMove="DragMove">
+                    <DockPanel.Background>
+                        <SolidColorBrush Opacity="0.01"/>
+                    </DockPanel.Background>
+                    <hc:UniformSpacingPanel Grid.ColumnSpan="4" HorizontalAlignment="Right" VerticalAlignment="Center">
+                        <Button Background="Transparent"
                                     BorderThickness="0"
                                     hc:IconElement.Geometry="M917.930667 512c0-57.6 36.181333-106.496 86.869333-125.952a505.429333 505.429333 0 0 0-55.210667-133.461333A134.826667 134.826667 0 0 1 771.413333 74.410667 507.733333 507.733333 0 0 0 637.952 19.2 135.168 135.168 0 0 1 512 106.069333 134.912 134.912 0 0 1 386.048 19.2 505.429333 505.429333 0 0 0 252.586667 74.410667c22.186667 49.749333 13.141333 109.824-27.562667 150.528a135.168 135.168 0 0 1-150.528 27.648 502.016 502.016 0 0 0-55.296 133.461333c50.688 19.626667 86.869333 68.437333 86.869333 125.952 0 57.6-36.181333 106.496-86.869333 125.952 12.117333 47.530667 30.72 92.330667 55.210667 133.461333a134.826667 134.826667 0 0 1 178.090666 178.176 507.733333 507.733333 0 0 0 133.546667 55.210667A135.168 135.168 0 0 1 512 917.930667c57.6 0 106.496 36.181333 125.952 86.869333a505.429333 505.429333 0 0 0 133.461333-55.210667 134.912 134.912 0 0 1 27.562667-150.528 135.168 135.168 0 0 1 150.528-27.648 502.016 502.016 0 0 0 55.296-133.461333A134.912 134.912 0 0 1 917.930667 512zM512 647.338667a135.338667 135.338667 0 1 1 0.085333-270.762667A135.338667 135.338667 0 0 1 512 647.338667z"
                                     hc:IconElement.Height="18"
@@ -108,14 +108,14 @@
                                     x:Name="SettingButton"
                                     FocusVisualStyle="{x:Null}"
                                     >
-                                    <Button.ContextMenu>
-                                        <ContextMenu x:Name="SettingMenus" Width="130">
-                                            <MenuItem Header="设置" Click="ConfigMenuClick"/>
-                                            <MenuItem Header="待办" Click="BacklogMenuClick"/>
-                                        </ContextMenu>
-                                    </Button.ContextMenu>
-                            </Button>
-                            <Button Background="Transparent" 
+                            <Button.ContextMenu>
+                                <ContextMenu x:Name="SettingMenus" Width="130">
+                                    <MenuItem Header="设置" Click="ConfigMenuClick"/>
+                                    <MenuItem Header="待办" Click="BacklogMenuClick"/>
+                                </ContextMenu>
+                            </Button.ContextMenu>
+                        </Button>
+                        <Button Background="Transparent" 
                                     BorderThickness="0"
                                     hc:IconElement.Geometry="M828.770654 148.714771C641.293737-20.89959 354.184117-19.590868 168.245698 152.630946c-212.062907 196.418185-212.062907 522.329912 0 718.748098 185.93842 172.221815 473.048039 173.520546 660.524956 3.916176 219.435707-198.536117 219.435707-528.054322 0-726.580449z m-121.880976 569.643707c-11.708566 11.708566-30.680039 11.708566-42.388605 0L502.729054 556.586459c-0.659356-0.659356-1.728312-0.659356-2.397659 0L338.609327 718.318517c-11.708566 11.708566-30.680039 11.708566-42.388605 0l-0.039961-0.039961c-11.708566-11.708566-11.708566-30.680039 0-42.388605l161.732059-161.732058c0.659356-0.659356 0.659356-1.728312 0-2.397659L296.1408 350.008195c-11.708566-11.708566-11.708566-30.680039 0-42.388605l0.039961-0.039961c11.708566-11.708566 30.680039-11.708566 42.388605 0l161.772019 161.77202c0.659356 0.659356 1.728312 0.659356 2.397659 0L664.551024 307.539668c11.708566-11.708566 30.680039-11.708566 42.388605 0l0.039961 0.039961c11.708566 11.708566 11.708566 30.680039 0 42.388605L545.15762 511.770224c-0.659356 0.659356-0.659356 1.728312 0 2.397659L706.919649 675.939902c11.708566 11.708566 11.708566 30.680039 0 42.388605l-0.029971 0.029971z" 
                                     hc:IconElement.Height="18"
@@ -125,17 +125,17 @@
                                     PreviewMouseLeftButtonDown="AppButton_PreviewMouseLeftButtonDown"
                                     FocusVisualStyle="{x:Null}"
                                     />
-                        </hc:UniformSpacingPanel>
-                    </DockPanel>
+                    </hc:UniformSpacingPanel>
+                </DockPanel>
 
 
-                    <uc:LeftCardControl x:Name="LeftCard" Grid.Row="1" Grid.Column="0"/>
+                <uc:LeftCardControl x:Name="LeftCard" Grid.Row="1" Grid.Column="0"/>
 
-                    <!--分割线-->
-                    <GridSplitter Opacity="0" Grid.Row="1" Grid.Column="0" Width="1"  VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
+                <!--分割线-->
+                <GridSplitter Opacity="0" Grid.Row="1" Grid.Column="0" Width="1"  VerticalAlignment="Stretch" HorizontalAlignment="Right"/>
 
-                    <!--搜索输入框-->
-                    <TextBox Panel.ZIndex="2" Grid.Row="0" Grid.Column="1" 
+                <!--搜索输入框-->
+                <TextBox Panel.ZIndex="2" Grid.Row="0" Grid.Column="1" 
                              x:Name="SearchBox"
                              Width="0"
                              Margin="-100,5,0,0"
@@ -146,28 +146,28 @@
                              />
 
 
-                    <hc:NotifyIcon Icon="/Taskbar.ico" Click="NotifyIcon_Click" x:Name="BarIcon"
+                <hc:NotifyIcon Icon="/Logo.ico" Click="NotifyIcon_Click" x:Name="BarIcon"
                             Visibility="{Binding AppConfig.ShowBarIcon, Mode=TwoWay, Converter={StaticResource Boolean2VisibilityConverter}}">
-                        <hc:NotifyIcon.ContextMenu>
-                            <ContextMenu Width="130" x:Name="TaskbarContextMenu">
-                                <MenuItem Header="打开面板" Click="ShowApp"/>
-                                <MenuItem Header="拾色器" Click="ColorPicker"/>
-                                <MenuItem Header="备份" Click="BakDataFile"/>
-                                <MenuItem Header="隐藏图标" Click="CloseBarIcon"/>
-                                <MenuItem Header="待办"  Click="BacklogMenuClick"/>
-                                <MenuItem Header="程序目录"  Click="OpenThisDir"/>
-                                <MenuItem Header="设置"  Click="ConfigApp"/>
-                                <MenuItem Header="重启"  Click="ReStartApp"/>
-                                <MenuItem Header="退出" Click="ExitApp"/>
-                            </ContextMenu>
-                        </hc:NotifyIcon.ContextMenu>
-                    </hc:NotifyIcon>
-
-                    <uc:RightCardControl x:Name="RightCard" Grid.Row="1" Grid.Column="1"/>
-
-                    <StackPanel hc:Growl.GrowlParent="True" VerticalAlignment="Top" Margin="0,10,10,0"/>
-                </Grid>
-            </hc:DialogContainer>
+                    <hc:NotifyIcon.ContextMenu>
+                        <ContextMenu Width="130" x:Name="TaskbarContextMenu">
+                            <MenuItem Header="打开面板" Click="ShowApp"/>
+                            <MenuItem Header="拾色器" Click="ColorPicker"/>
+                            <MenuItem Header="备份" Click="BakDataFile"/>
+                            <MenuItem Header="隐藏图标" Click="CloseBarIcon"/>
+                            <MenuItem Header="待办"  Click="BacklogMenuClick"/>
+                            <MenuItem Header="程序目录"  Click="OpenThisDir"/>
+                            <MenuItem Header="设置"  Click="ConfigApp"/>
+                            <MenuItem Header="重启"  Click="ReStartApp"/>
+                            <MenuItem Header="退出" Click="ExitApp"/>
+                        </ContextMenu>
+                    </hc:NotifyIcon.ContextMenu>
+                </hc:NotifyIcon>
+
+                <uc:RightCardControl x:Name="RightCard" Grid.Row="1" Grid.Column="1"/>
+
+                <StackPanel hc:Growl.GrowlParent="True" VerticalAlignment="Top" Margin="0,10,10,0"/>
+            </Grid>
+        </hc:DialogContainer>
     </Border>
 
 </Window>

+ 68 - 22
MainWindow.xaml.cs

@@ -10,6 +10,7 @@ using GeekDesk.ViewModel;
 using GeekDesk.ViewModel.Temp;
 using Microsoft.Win32;
 using NPinyin;
+using ShowSeconds;
 using System;
 using System.Collections.ObjectModel;
 using System.Diagnostics;
@@ -61,7 +62,7 @@ namespace GeekDesk
 
         }
 
-       
+
 
 
         /// <summary>
@@ -94,9 +95,9 @@ namespace GeekDesk
         /// <param name="e"></param>
         private void SearchBox_TextChanged(object sender, TextChangedEventArgs e)
         {
-             if (!RunTimeStatus.SEARCH_BOX_SHOW 
-                && appData.AppConfig.SearchType != SearchType.KEY_DOWN
-                )
+            if (!RunTimeStatus.SEARCH_BOX_SHOW
+               && appData.AppConfig.SearchType != SearchType.KEY_DOWN
+               )
             {
                 SearchBox.TextChanged -= SearchBox_TextChanged;
                 SearchBox.Clear();
@@ -106,6 +107,11 @@ namespace GeekDesk
 
             if (!RunTimeStatus.SEARCH_BOX_SHOW) ShowSearchBox();
 
+            //刷新搜索后 鼠标移动次数置为0
+            RunTimeStatus.MOUSE_MOVE_COUNT = 0;
+            //隐藏popup
+            RightCard.MyPoptip.IsOpen = false;
+
             string inputText = SearchBox.Text.ToLower();
             RightCard.VerticalUFG.Visibility = Visibility.Collapsed;
             if (!string.IsNullOrEmpty(inputText))
@@ -168,7 +174,6 @@ namespace GeekDesk
             this.Height = appData.AppConfig.WindowHeight;
         }
 
-
         /// <summary>
         /// 窗口加载完毕 执行方法
         /// </summary>
@@ -185,7 +190,6 @@ namespace GeekDesk
             {
                 ShowApp();
             }
-            //ShowSecondTask.SHowSecond();
             //给任务栏图标一个名字
             BarIcon.Text = Constants.MY_NAME;
 
@@ -210,12 +214,19 @@ namespace GeekDesk
                 RegisterUtil.SetSelfStarting(appData.AppConfig.SelfStartUp, Constants.MY_NAME);
             }
 
-            //注册鼠标中键监听事件
+            //注册鼠标监听事件
             if (appData.AppConfig.MouseMiddleShow)
             {
-                MouseHookThread.MiddleHook();
+                MouseHookThread.Hook();
             }
 
+            //显秒插件
+            if (appData.AppConfig.SecondsWindow == true)
+            {
+                SecondsWindow.ShowWindow();
+            }
+
+
             //更新线程开启  检测更新
             UpdateThread.Update();
 
@@ -224,6 +235,8 @@ namespace GeekDesk
 
             //毛玻璃  暂时未解决阴影问题
             //BlurGlassUtil.EnableBlur(this);
+
+            MessageUtil.ChangeWindowMessageFilter(MessageUtil.WM_COPYDATA, 1);
         }
 
         /// <summary>
@@ -253,7 +266,8 @@ namespace GeekDesk
                     {
                         HandyControl.Controls.Growl.Success("GeekDesk快捷键注册成功(" + appData.AppConfig.HotkeyStr + ")!", "HotKeyGrowl");
                     }
-                } else
+                }
+                else
                 {
                 }
             }
@@ -296,7 +310,7 @@ namespace GeekDesk
                         HandyControl.Controls.Growl.Success("新建待办任务快捷键注册成功(" + appData.AppConfig.ToDoHotkeyStr + ")!", "HotKeyGrowl");
                     }
                 }
-                
+
             }
             catch (Exception)
             {
@@ -452,6 +466,11 @@ namespace GeekDesk
             else
             {
                 appData.AppConfig.IsShow = null;
+                //防止永远不显示界面
+                if (mainWindow.Opacity < 1)
+                {
+                    mainWindow.Opacity = 1;
+                }
             }
 
 
@@ -461,7 +480,8 @@ namespace GeekDesk
             if (RunTimeStatus.SHOW_MENU_PASSWORDBOX)
             {
                 mainWindow.RightCard.PDDialog.SetFocus();
-            } else
+            }
+            else
             {
                 Keyboard.Focus(mainWindow.SearchBox);
             }
@@ -478,7 +498,7 @@ namespace GeekDesk
                 appData.AppConfig.IsShow = null;
                 HideAppVis();
             }
-            
+
         }
 
         private static void HideAppVis()
@@ -492,7 +512,7 @@ namespace GeekDesk
             mainWindow.Visibility = Visibility.Collapsed;
             //if (!MarginHide.IS_HIDE)
             //{
-               
+
             //}
             //else
             //{
@@ -663,7 +683,7 @@ namespace GeekDesk
         /// <param name="e"></param>
         private void ExitApp(object sender, RoutedEventArgs e)
         {
-            if (appData.AppConfig.MouseMiddleShow)
+            if (appData.AppConfig.MouseMiddleShow || appData.AppConfig.SecondsWindow == true)
             {
                 MouseHookThread.Dispose();
             }
@@ -676,7 +696,7 @@ namespace GeekDesk
         /// <param name="e"></param>
         private void ReStartApp(object sender, RoutedEventArgs e)
         {
-            if (appData.AppConfig.MouseMiddleShow)
+            if (appData.AppConfig.MouseMiddleShow || appData.AppConfig.SecondsWindow == true)
             {
                 MouseHookThread.Dispose();
             }
@@ -709,8 +729,8 @@ namespace GeekDesk
                 HideApp();
             }
 
-            if (RunTimeStatus.SEARCH_BOX_SHOW && (e.Key == Key.Up 
-                || e.Key == Key.Down 
+            if (RunTimeStatus.SEARCH_BOX_SHOW && (e.Key == Key.Up
+                || e.Key == Key.Down
                 || e.Key == Key.Tab
                 || e.Key == Key.Enter
                 ))
@@ -718,14 +738,16 @@ namespace GeekDesk
                 if (e.Key == Key.Down || e.Key == Key.Tab)
                 {
                     RightCard.SearchListBoxIndexAdd();
-                } else if (e.Key == Key.Up)
+                }
+                else if (e.Key == Key.Up)
                 {
                     RightCard.SearchListBoxIndexSub();
-                } else if (e.Key == Key.Enter)
+                }
+                else if (e.Key == Key.Enter)
                 {
                     RightCard.StartupSelectionItem();
                 }
-            } 
+            }
         }
 
 
@@ -779,9 +801,9 @@ namespace GeekDesk
                     //必须在其它文本框没有工作的时候才给搜索框焦点
                     Keyboard.Focus(SearchBox);
                 }
-                
+
             }
-            
+
         }
 
         private void AppWindow_Deactivated(object sender, EventArgs e)
@@ -838,6 +860,30 @@ namespace GeekDesk
             }
         }
 
+        protected override void OnSourceInitialized(EventArgs e)
+        {
+            base.OnSourceInitialized(e);
+            HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
+            if (hwndSource != null)
+            {
+                IntPtr handle = hwndSource.Handle;
+                hwndSource.AddHook(new HwndSourceHook(WndProc));
+            }
+        }
+
+        IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
+        {
+            if (msg == MessageUtil.WM_COPYDATA)
+            {
+                MessageUtil.CopyDataStruct cds = (MessageUtil.CopyDataStruct)System.Runtime.InteropServices.Marshal.PtrToStructure(lParam, typeof(MessageUtil.CopyDataStruct));
+                if ("ShowApp".Equals(cds.msg))
+                {
+                    ShowApp();
+                }
+            }
+            return hwnd;
+        }
+
 
 
     }

+ 71 - 27
MyThread/MouseHookThread.cs

@@ -1,7 +1,11 @@
 using GeekDesk.Control.UserControls.Config;
+using GeekDesk.Control.Windows;
+using GeekDesk.Util;
 using GeekDesk.ViewModel;
 using Gma.System.MouseKeyHook;
 using System;
+using System.Drawing;
+using System.Threading;
 using System.Windows;
 using System.Windows.Threading;
 
@@ -9,28 +13,38 @@ namespace GeekDesk.MyThread
 {
     public class MouseHookThread
     {
-        private static AppConfig appConfig = MainWindow.appData.AppConfig;
-        private static IKeyboardMouseEvents m_GlobalHook = Hook.GlobalEvents();
-        private static Dispatcher dispatcher;
+        private static readonly AppConfig appConfig = MainWindow.appData.AppConfig;
+        public static Dispatcher dispatcher;
+        private static UserActivityHook hook;
 
-
-
-        public static void MiddleHook()
+        public static void Hook()
         {
-            //使用dispatcher来单独监听UI线程  防止程序卡顿
+            //使用dispatcher来单独监听UI线程 防止程序卡顿
             dispatcher = DispatcherBuild.Build();
-            m_GlobalHook = Hook.GlobalEvents();
-            dispatcher.BeginInvoke((Action)(() =>
+            dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
             {
-                m_GlobalHook.MouseUpExt += M_GlobalHook_MouseUpExt;
+                hook = new UserActivityHook();
+
+                if (appConfig.MouseMiddleShow)
+                {
+                    hook.OnMouseWheelUp += OnMouseWheelUp;
+                }
+
+                hook.Start(true, false);
             }));
         }
 
-        public static void Dispose()
+        private static void OnMouseLeftDown(object sender, System.Windows.Forms.MouseEventArgs e)
         {
-            m_GlobalHook.MouseUpExt -= M_GlobalHook_MouseUpExt;
-            m_GlobalHook.Dispose();
-            dispatcher.InvokeShutdown();
+        }
+
+        private static void OnMouseLeftUp(object sender, System.Windows.Forms.MouseEventArgs e)
+        {
+        }
+
+        private static void OnMouseWheelUp(object sender, System.Windows.Forms.MouseEventArgs e)
+        {
+            MouseWheelShowApp(sender, e);
         }
 
         /// <summary>
@@ -38,26 +52,56 @@ namespace GeekDesk.MyThread
         /// </summary>
         /// <param name="sender"></param>
         /// <param name="e"></param>
-        private static void M_GlobalHook_MouseUpExt(object sender, System.Windows.Forms.MouseEventArgs e)
+        private static void MouseWheelShowApp(object sender, System.Windows.Forms.MouseEventArgs e)
+        {
+            //中键打开App
+            if (appConfig.MouseMiddleShow && MotionControl.hotkeyFinished)
+            {
+                App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
+                {
+                    if (MainWindow.mainWindow.Visibility == Visibility.Collapsed || MainWindow.mainWindow.Opacity == 0)
+                    {
+                        MainWindow.ShowApp();
+                    }
+                    else
+                    {
+                        MainWindow.HideApp();
+                    }
+                }));
+            }
+        }
+
+
+        public static void Dispose()
         {
-            if (appConfig.MouseMiddleShow && e.Button == System.Windows.Forms.MouseButtons.Middle)
+            try
             {
-                if (MotionControl.hotkeyFinished)
+                if (hook != null)
                 {
-                    App.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render, new Action(() =>
+                    if (hook.MouseWheelUpEnable())
+                    {
+                        hook.OnMouseWheelUp -= OnMouseWheelUp;
+                    }
+                    if (hook.MouseLeftDownEnable())
+                    {
+                        hook.OnMouseLeftDown -= OnMouseLeftDown;
+                    }
+                    if (hook.MouseLeftUpEnable())
                     {
-                        if (MainWindow.mainWindow.Visibility == Visibility.Collapsed || MainWindow.mainWindow.Opacity == 0)
-                        {
-                            MainWindow.ShowApp();
-                        }
-                        else
-                        {
-                            MainWindow.HideApp();
-                        }
-                    }));
+                        hook.OnMouseLeftUp -= OnMouseLeftUp;
+                    }
+                    hook.Stop();
+                    dispatcher.InvokeShutdown();
+                    hook = null;
+                    dispatcher = null;
                 }
             }
+            catch (Exception ex)
+            {
+                LogUtil.WriteErrorLog(ex, "关闭hook出错");
+            }
         }
 
+
     }
 }

+ 22 - 17
MyThread/RelativePathThread.cs

@@ -2,13 +2,9 @@
 using GeekDesk.Util;
 using GeekDesk.ViewModel;
 using System;
-using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.IO;
-using System.Linq;
-using System.Text;
 using System.Threading;
-using System.Threading.Tasks;
 
 namespace GeekDesk.MyThread
 {
@@ -18,24 +14,33 @@ namespace GeekDesk.MyThread
         {
             new Thread(() =>
             {
-                ObservableCollection<MenuInfo> menuList = MainWindow.appData.MenuList;
-
-                string myExePath = Constants.APP_DIR + "GeekDesk.exe";
-                foreach (MenuInfo mi in menuList)
+                try
                 {
-                    ObservableCollection<IconInfo> iconList = mi.IconList;
-                    foreach (IconInfo icon in iconList)
+                    ObservableCollection<MenuInfo> menuList = MainWindow.appData.MenuList;
+
+                    string myExePath = Constants.APP_DIR + "GeekDesk.exe";
+                    foreach (MenuInfo mi in menuList)
                     {
-                        string relativePath = FileUtil.MakeRelativePath(myExePath, icon.Path);
-                        if (File.Exists(icon.Path) 
-                            && !string.IsNullOrEmpty(relativePath) 
-                            && !relativePath.Equals(icon.Path)) {
-                            icon.RelativePath_NoWrite = relativePath;
+                        ObservableCollection<IconInfo> iconList = mi.IconList;
+                        foreach (IconInfo icon in iconList)
+                        {
+                            if (icon == null) continue;
+                            string relativePath = FileUtil.MakeRelativePath(myExePath, icon.Path);
+                            if (File.Exists(icon.Path)
+                                && !string.IsNullOrEmpty(relativePath)
+                                && !relativePath.Equals(icon.Path))
+                            {
+                                icon.RelativePath_NoWrite = relativePath;
+                            }
                         }
                     }
+                    CommonCode.SaveAppData(MainWindow.appData, Constants.DATA_FILE_PATH);
+                    CommonCode.SaveAppData(MainWindow.appData, Constants.DATA_FILE_BAK_PATH);
+                }
+                catch (Exception ex)
+                {
+                    LogUtil.WriteErrorLog(ex, "init相对路径出错!");
                 }
-                CommonCode.SaveAppData(MainWindow.appData, Constants.DATA_FILE_PATH);
-                CommonCode.SaveAppData(MainWindow.appData, Constants.DATA_FILE_BAK_PATH);
             }).Start();
         }
     }

+ 39 - 0
Plugins/ShowSeconds/Common/Constants.cs

@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace ShowSeconds.Common
+{
+    public class Constants
+    {
+        public readonly static string MY_UUID = "8400A17AEEF7C029";
+
+        //dark theam
+        public readonly static System.Windows.Media.SolidColorBrush darkBG
+            = new System.Windows.Media.SolidColorBrush
+            {
+                Color = System.Windows.Media.Color.FromRgb(46, 50, 54),
+                Opacity = 0.8
+            };
+        public readonly static System.Windows.Media.SolidColorBrush darkFont
+            = new System.Windows.Media.SolidColorBrush
+            {
+                Color = System.Windows.Media.Color.FromRgb(255, 255, 255)
+            };
+
+        //light theam
+        public readonly static System.Windows.Media.SolidColorBrush lightBG
+            = new System.Windows.Media.SolidColorBrush
+            {
+                Color = System.Windows.Media.Color.FromRgb(236, 244, 251),
+                Opacity = 1
+            };
+        public readonly static System.Windows.Media.SolidColorBrush lightFont
+            = new System.Windows.Media.SolidColorBrush
+            {
+                Color = System.Windows.Media.Color.FromRgb(65, 63, 61),
+            };
+    }
+}

+ 32 - 0
Plugins/ShowSeconds/SecondsWindow.xaml

@@ -0,0 +1,32 @@
+<Window x:Class="ShowSeconds.SecondsWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+           xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+           xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+           xmlns:hc="https://handyorg.github.io/handycontrol"
+            xmlns:xf="clr-namespace:XamlFlair;assembly=XamlFlair.WPF"
+           Height="90" 
+           Width="160" 
+           WindowStyle="None"
+           Title=""
+           AllowsTransparency="True"
+           Background="Transparent" ShowInTaskbar="False"
+           Focusable="True"
+        Loaded="Window_Loaded"
+            >
+
+    <Grid Margin="20">
+        <Grid.Effect>
+            <DropShadowEffect BlurRadius="20" Direction="-90" Color="Gray"
+                              RenderingBias="Quality" ShadowDepth="2"/>
+        </Grid.Effect>
+        <Border x:Name="BGBorder" CornerRadius="8" xf:Animations.Primary="{xf:Animate BasedOn={StaticResource FadeInAndSlideFromRight}, Event=Visibility, Delay=0}">
+            <TextBlock x:Name="SecondsText" HorizontalAlignment="Center"
+                       VerticalAlignment="Center"
+                       FontSize="25"
+                       FontWeight="Bold"
+                       Foreground="White"
+                       Text="{Binding Seconds}"/>
+        </Border>
+    </Grid>
+</Window>

+ 312 - 0
Plugins/ShowSeconds/SecondsWindow.xaml.cs

@@ -0,0 +1,312 @@
+using GeekDesk.Util;
+using Gma.System.MouseKeyHook;
+using ShowSeconds.Common;
+using GeekDesk.Util;
+using ShowSeconds.ViewModel;
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Drawing;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Timers;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Windows.Threading;
+using GeekDesk.MyThread;
+using GeekDesk;
+using System.Collections;
+
+namespace ShowSeconds
+{
+    /// <summary>
+    /// Interaction logic for MainWindow.xaml
+    /// </summary>
+    public partial class SecondsWindow : Window
+    {
+
+        private System.Drawing.Color beforeColor;
+        private System.Drawing.Color topBeforeColor;
+
+        private bool expandClock = true; //是否展开时钟
+        private System.Windows.Forms.Timer timer;
+
+        private static double lProportion = 0.82;
+        private static double tProportion = 0.03;
+        private static int sleepTime = 1000;
+        public SecondsWindow()
+        {
+            SecondsDataContext dc = new SecondsDataContext
+            {
+                Seconds = (DateTime.Now.Hour).ToString() + ":" +
+                        FormatMS(DateTime.Now.Minute) + ":" +
+                        FormatMS(DateTime.Now.Second)
+            };
+            InitializeComponent();
+            SolidColorBrush scb = new SolidColorBrush(System.Windows.Media.Color.FromArgb(255, 47, 52, 44))
+            {
+                Opacity = 0.8
+            };
+
+
+            try
+            {
+
+                Hashtable settings = (Hashtable)ConfigurationManager.GetSection("ShowSecondsSettings");
+
+                lProportion = Convert.ToDouble(settings["LProportion"]);
+                tProportion = Convert.ToDouble(settings["TProportion"]);
+                sleepTime = Convert.ToInt32(settings["DelayTime"]);
+            }
+            catch (Exception ex)
+            {
+                lProportion = 0.82;
+                tProportion = 0.03;
+                sleepTime = 1000;
+            }
+
+            BGBorder.Background = scb;
+            this.DataContext = dc;
+            this.Topmost = true;
+            BGBorder.Visibility = Visibility.Collapsed;
+            this.Show();
+        }
+
+
+        private void Window_Loaded(object sender, RoutedEventArgs e)
+        {
+            timer = new System.Windows.Forms.Timer();
+            timer.Interval = 1000;
+            timer.Tick += Timer_Tick;
+
+            Dispatcher secondsDP = DispatcherBuild.Build();
+            IKeyboardMouseEvents secondsHook = Hook.GlobalEvents();
+            secondsDP.Invoke((Action)(() =>
+            {
+                secondsHook.MouseDownExt += SecondsBakColorFun;
+                secondsHook.MouseUpExt += SecondsHookSetFuc;
+            }));
+
+            HideWindowUtil.HideAltTab(this);
+        }
+
+        private void Timer_Tick(object sender, EventArgs e)
+        {
+            string str = (DateTime.Now.Hour).ToString() + ":" +
+                        FormatMS(DateTime.Now.Minute) + ":" +
+                        FormatMS(DateTime.Now.Second);
+            SecondsDataContext dc = this.DataContext as SecondsDataContext;
+            dc.Seconds = str;
+        }
+
+
+
+        private static string FormatMS(int ms)
+        {
+            if (ms < 10)
+            {
+                return "0" + ms;
+            }
+            else
+            {
+                return ms.ToString();
+            }
+        }
+
+        private void SecondsHookSetFuc(object sender, MouseEventExtArgs e)
+        {
+            if (e.Button == System.Windows.Forms.MouseButtons.Left)
+            {
+                if (ScreenUtil.IsPrimaryFullScreen()) return;
+
+                App.Current.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Render, new Action(() =>
+                {
+                    int x = e.X;
+                    int y = e.Y;
+                    double w = 1920;
+                    double h = 1080;
+                    double width = SystemParameters.PrimaryScreenWidth;
+                    double height = SystemParameters.PrimaryScreenHeight;
+                    if (x > 1843 / w * width
+                        && x < 1907 / w * width
+                        && y > 1037 / h * height
+                        && y < 1074 / h * height)
+                    {
+
+                        System.Drawing.Color c;
+                        int count = sleepTime;
+                        do
+                        {
+                            c = GetBottomBeforeColor();
+                            if (c.A != beforeColor.A
+                            || c.R != beforeColor.R
+                            || c.G != beforeColor.G
+                            || c.B != beforeColor.B)
+                            {
+                                break;
+                            }
+                            Thread.Sleep(50);
+                            count -= 50;
+                        } while (count > 0);
+
+                        if (c.A != beforeColor.A
+                            || c.R != beforeColor.R
+                            || c.G != beforeColor.G
+                            || c.B != beforeColor.B)
+                        {
+                            //判断是否展开时钟
+                            System.Drawing.Color ct = GetTopBeforeColor();
+                            if (ct.A != topBeforeColor.A
+                            || ct.R != topBeforeColor.R
+                            || ct.G != topBeforeColor.G
+                            || ct.B != topBeforeColor.B)
+                            {
+                                expandClock = true;
+                            }
+                            else
+                            {
+                                expandClock = false;
+                            }
+
+                            if (!BGBorder.IsVisible)
+                            {
+
+                                System.Drawing.Color theamColor = GetColor(1919, 1079);
+                                if (CalculateLight(theamColor) > 255 / 2)
+                                {
+                                    //light
+                                    BGBorder.Background = new SolidColorBrush(System.Windows.Media.Color.FromArgb(theamColor.A, theamColor.R, theamColor.G, theamColor.B));
+                                    SecondsText.Foreground = Constants.lightFont;
+                                }
+                                else
+                                {
+                                    // dark
+                                    //BGBorder.Background = new SolidColorBrush(System.Windows.Media.Color.FromArgb(theamColor.A, theamColor.R, theamColor.G, theamColor.B));
+                                    BGBorder.Background = Constants.darkBG;
+                                    SecondsText.Foreground = Constants.darkFont;
+                                }
+
+                                SecondsDataContext dc = this.DataContext as SecondsDataContext;
+                                dc.Seconds = (DateTime.Now.Hour).ToString() + ":" +
+                                   FormatMS(DateTime.Now.Minute) + ":" +
+                                   FormatMS(DateTime.Now.Second);
+
+                                int sx = (int)(SystemParameters.PrimaryScreenWidth * lProportion);
+                                int sMarginBottom = (int)(SystemParameters.WorkArea.Height * tProportion);
+                                Left = sx - Width;
+                                Top = SystemParameters.WorkArea.Height - Height;
+                                BGBorder.Visibility = Visibility.Visible;
+                                timer.Start();
+                            }
+                            else
+                            {
+                                BGBorder.Visibility= Visibility.Collapsed;
+                                timer.Stop();
+                            }
+                        }
+                    }
+                    else if (true)
+                    {
+                        if ((expandClock && (x < 1574 / w * width
+                              || x > 1906 / w * width
+                              || y < 598 / h * height
+                              || y > 1020 / h * height)
+                              )
+                              || !expandClock && (x < 1574 / w * width
+                              || x > 1906 / w * width
+                              || y < 950 / h * height
+                              || y > 1020 / h * height)
+                              )
+                        {
+                            BGBorder.Visibility = Visibility.Collapsed;
+                            timer.Stop();
+                        }
+                    }
+                }));
+            }
+        }
+
+
+        private static System.Windows.Window window = null;
+        public static void ShowWindow()
+        {
+            try
+            {
+                if (window == null || !window.Activate())
+                {
+                    window = new SecondsWindow();
+                }
+            } catch (Exception e)
+            {
+                LogUtil.WriteErrorLog(e, "打开显秒窗口异常!");
+            }
+            
+        }
+
+        public static void CloseWindow()
+        {
+            try
+            {
+                window.Close();
+            } catch (Exception e)
+            {
+                LogUtil.WriteErrorLog(e, "关闭显秒窗口异常!");
+            }
+        }
+
+        private void SecondsBakColorFun(object sender, MouseEventExtArgs e)
+        {
+            if (e.Button == System.Windows.Forms.MouseButtons.Left)
+            {
+                beforeColor = GetBottomBeforeColor();
+                topBeforeColor = GetTopBeforeColor();
+            }
+        }
+
+        private static System.Drawing.Color GetBottomBeforeColor()
+        {
+            return GetColor(1760, 985);
+        }
+
+        private static System.Drawing.Color GetTopBeforeColor()
+        {
+            return GetColor(1751, 693);
+        }
+
+        private static System.Drawing.Color GetColor(int w2, int h2)
+        {
+            double w = 1920;
+            double h = 1080;
+            double width = SystemParameters.PrimaryScreenWidth;
+            double height = SystemParameters.PrimaryScreenHeight;
+            System.Drawing.Point p = new System.Drawing.Point((int)(w2 / w * width), (int)(h2 / h * height));
+            return ScreenUtil.GetColorAt(p);
+        }
+
+
+        private static int CalculateLight(System.Drawing.Color color)
+        {
+            int[] colorArr = new int[] { color.R, color.G, color.B };
+
+            int max = 0;
+            int min = 255;
+            foreach (int i in colorArr)
+            {
+                max = Math.Max(max, i);
+                min = Math.Min(min, i);
+            }
+            int avg = (max + min) / 2;
+            return avg;
+        }
+
+    }
+}

+ 25 - 0
Plugins/ShowSeconds/ViewModel/SecondsDataContext.cs

@@ -0,0 +1,25 @@
+using System.ComponentModel;
+
+
+namespace ShowSeconds.ViewModel
+{
+    public class SecondsDataContext : INotifyPropertyChanged
+    {
+        private string seconds;
+        public string Seconds
+        {
+            set
+            {
+                seconds = value;
+                OnPropertyChanged("Seconds");
+            }
+            get { return seconds; }
+        }
+
+        public event PropertyChangedEventHandler PropertyChanged;
+        private void OnPropertyChanged(string propertyName)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+}

+ 2 - 2
Properties/AssemblyInfo.cs

@@ -49,5 +49,5 @@ using System.Windows;
 //可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
 //通过使用 "*",如下所示:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.5.1.0")]
-[assembly: AssemblyFileVersion("2.5.1.0")]
+[assembly: AssemblyVersion("2.5.1.3")]
+[assembly: AssemblyFileVersion("2.5.1.3")]

BIN
Resource/Image/TitleLogo.png


+ 2 - 2
Task/ToDoTask.cs

@@ -46,7 +46,7 @@ namespace GeekDesk.Task
                         }
                     }
                 }
-                ClearMemory();
+                //ClearMemory();
             }));
         }
 
@@ -60,7 +60,7 @@ namespace GeekDesk.Task
             if (Environment.OSVersion.Platform == PlatformID.Win32NT)
             {
                 SetProcessWorkingSetSize(System.Diagnostics.Process.GetCurrentProcess().Handle, -1, -1);
-            } 
+            }
         }
 
         #region 内存回收

+ 3 - 3
Update.json

@@ -1,9 +1,9 @@
 {
 	"title": "GeekDesk版本更新",
-	"subTitle": "V2.5.11",
+	"subTitle": "V2.5.13",
 	"msgTitle": "本次更新内容如下",
-	"msg": "['依旧耗费了我大量精力开发,希望大家去给我点个免费的Star', '这个版本有一些优化点, 大家可以自行探索, 另外征集新Logo的设计, 要求美观并能体现\\'极客\\'风格','本次重新打包了程序文件(文件目录更清爽了,注意,这次不要使用覆盖升级(2.5.10可覆盖)), 可以将旧版本根目录下的Data文件复制到新版本根目录, 然后使用新版本启动','修复了2.5.10版本部分相对路径创建导致启动崩溃的bug','增加可拖动图标到其它菜单的功能,取消了拖动时的动画','增加了列表展开动画的开关','增加了数据备份功能','优化大部分动画','优化搜索功能(达到了可只用键盘或只用鼠标启动所需目标)','增加了相对路径(实验性,可能有bug)','增加列表加密功能(实验性,可能有bug)','其它已知问题修复']",
+	"msg": "['求Star,求Star', '集成Win11显秒插件', '崩溃问题修复', '现在在右侧栏(快捷图标区域)也可以鼠标滚轮切换菜单了', '缩放屏幕截图问题修复(感谢@1062406901提的PR)', '更改一下Logo', '其它已知问题修复']",
 	"githubUrl": "https://github.com/BookerLiu/GeekDesk/releases",
 	"giteeUrl": "https://gitee.com/BookerLiu/GeekDesk/releases",
-	"version": "2.5.11"
+	"version": "2.5.13"
 }

+ 7 - 38
Util/CommonCode.cs

@@ -44,7 +44,7 @@ namespace GeekDesk.Util
                         BinaryFormatter bf = new BinaryFormatter();
                         appData = bf.Deserialize(fs) as AppData;
                     }
-                } 
+                }
                 catch
                 {
                     if (File.Exists(Constants.DATA_FILE_BAK_PATH))
@@ -69,20 +69,22 @@ namespace GeekDesk.Util
                             GlobalMsgNotification gm = new GlobalMsgNotification(msg);
                             HandyControl.Controls.Notification ntf = HandyControl.Controls.Notification.Show(gm, ShowAnimation.Fade, true);
                             gm.ntf = ntf;
-                        } catch 
+                        }
+                        catch
                         {
                             MessageBox.Show("不幸的是, GeekDesk当前的数据文件已经损坏\n如果你有备份, 请将备份文件重命名为:Data 然后将Data覆盖到GeekDesk的根目录即可!");
                             Application.Current.Shutdown();
                             return null;
                         }
-                        
-                    } else
+
+                    }
+                    else
                     {
                         MessageBox.Show("不幸的是, GeekDesk当前的数据文件已经损坏\n如果你有备份, 请将备份文件重命名为:Data 然后将Data覆盖到GeekDesk的根目录即可!");
                         Application.Current.Shutdown();
                         return null;
                     }
-                    
+
                 }
             }
             return appData;
@@ -144,25 +146,6 @@ namespace GeekDesk.Util
 
 
 
-        /// <summary>
-        /// 判断当前屏幕(鼠标最后活动屏幕)是否有全屏化应用
-        /// </summary>
-        /// <returns></returns>
-        public static bool IsPrimaryFullScreen()
-        {
-            RECT rect = new RECT();
-            GetWindowRect(new HandleRef(null, GetForegroundWindow()), ref rect);
-
-            int windowHeight = rect.bottom - rect.top;
-            int screenHeight = (int)SystemParameters.PrimaryScreenHeight;
-
-            if (windowHeight >= screenHeight)
-            {
-                return true;
-            }
-            return false;
-        }
-
         /// <summary>
         /// 根据路径获取文件图标等信息
         /// </summary>
@@ -263,20 +246,6 @@ namespace GeekDesk.Util
         }
 
 
-        [StructLayout(LayoutKind.Sequential)]
-        private struct RECT
-        {
-            public int left;
-            public int top;
-            public int right;
-            public int bottom;
-        }
-
-        [DllImport("user32.dll")]
-        private static extern bool GetWindowRect(HandleRef hWnd, [In, Out] ref RECT rect);
-
-        [DllImport("user32.dll")]
-        private static extern IntPtr GetForegroundWindow();
 
 
 

+ 22 - 1
Util/FileUtil.cs

@@ -172,12 +172,33 @@ namespace GeekDesk.Util
                         .ToString()
                         .Replace('/', Path.DirectorySeparatorChar)
                     );
-            } catch (Exception ex)
+            }
+            catch (Exception ex)
             {
                 LogUtil.WriteErrorLog(ex, "建立相对路径出错:fromPath:" + fromPath + ",toPath:" + toPath);
             }
             return relativePath;
         }
 
+
+        public static FileInfo GetFileByNameWithDir(string name, string dir)
+        {
+            DirectoryInfo d = new DirectoryInfo(dir);
+            FileInfo[] files = d.GetFiles();//文件
+            foreach (FileInfo fi in files)
+            {
+                if (fi.Name.Equals(name))
+                {
+                    return fi;
+                }
+            }
+            DirectoryInfo[] directs = d.GetDirectories();
+            foreach (DirectoryInfo direct in directs)
+            {
+                return GetFileByNameWithDir(name, direct.FullName);
+            }
+            return null;
+        }
+
     }
 }

+ 227 - 0
Util/HideWindowUtil.cs

@@ -0,0 +1,227 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Interop;
+
+namespace GeekDesk.Util
+{
+    public class HideWindowUtil
+    {
+
+        public enum GetWindowLongFields
+        {
+            // ...
+            GWL_EXSTYLE = (-20),
+            // ...
+        }
+
+        public static void HideAltTab(Window window)
+        {
+            try
+            {
+                WindowInteropHelper wndHelper = new WindowInteropHelper(window);
+                int exStyle = (int)HideWindowUtil.GetWindowLong(wndHelper.Handle, (int)HideWindowUtil.GetWindowLongFields.GWL_EXSTYLE);
+                exStyle |= (int)HideWindowUtil.ExtendedWindowStyles.WS_EX_TOOLWINDOW;
+                HideWindowUtil.SetWindowLong(wndHelper.Handle, (int)HideWindowUtil.GetWindowLongFields.GWL_EXSTYLE, (IntPtr)exStyle);
+            } catch (Exception e)
+            {
+
+            }
+        }
+
+
+        [DllImport("user32.dll")]
+        public static extern IntPtr GetWindowLong(IntPtr hWnd, int nIndex);
+
+        public static IntPtr SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong)
+        {
+            int error = 0;
+            IntPtr result = IntPtr.Zero;
+            // Win32 SetWindowLong doesn't clear error on success
+            SetLastError(0);
+
+            if (IntPtr.Size == 4)
+            {
+                // use SetWindowLong
+                Int32 tempResult = IntSetWindowLong(hWnd, nIndex, IntPtrToInt32(dwNewLong));
+                error = Marshal.GetLastWin32Error();
+                result = new IntPtr(tempResult);
+            }
+            else
+            {
+                // use SetWindowLongPtr
+                result = IntSetWindowLongPtr(hWnd, nIndex, dwNewLong);
+                error = Marshal.GetLastWin32Error();
+            }
+
+            if ((result == IntPtr.Zero) && (error != 0))
+            {
+                throw new System.ComponentModel.Win32Exception(error);
+            }
+
+            return result;
+        }
+
+        [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)]
+        private static extern IntPtr IntSetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
+
+        [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)]
+        private static extern Int32 IntSetWindowLong(IntPtr hWnd, int nIndex, Int32 dwNewLong);
+
+        private static int IntPtrToInt32(IntPtr intPtr)
+        {
+            return unchecked((int)intPtr.ToInt64());
+        }
+
+        [DllImport("kernel32.dll", EntryPoint = "SetLastError")]
+        public static extern void SetLastError(int dwErrorCode);
+        /// <summary>
+        /// 扩展的窗口风格
+        /// </summary>
+        /// 代码:[Extended Window Styles (Windows)](https://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx )
+        /// code from [Extended Window Styles (Windows)](https://msdn.microsoft.com/en-us/library/windows/desktop/ff700543(v=vs.85).aspx )
+        [Flags]
+        public enum ExtendedWindowStyles : long
+        {
+            /// <summary>
+            /// The window accepts drag-drop files
+            /// </summary>
+            WS_EX_ACCEPTFILES = 0x00000010L,
+
+            /// <summary>
+            /// Forces a top-level window onto the taskbar when the window is visible
+            /// </summary>
+            WS_EX_APPWINDOW = 0x00040000L,
+
+            /// <summary>
+            /// The window has a border with a sunken edge.
+            /// </summary>
+            WS_EX_CLIENTEDGE = 0x00000200L,
+
+            /// <summary>
+            /// Paints all descendants of a window in bottom-to-top painting order using double-buffering. For more information, see Remarks. This cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC.Windows 2000:  This style is not supported.
+            /// </summary>
+            WS_EX_COMPOSITED = 0x02000000L,
+
+            /// <summary>
+            /// The title bar of the window includes a question mark. When the user clicks the question mark, the cursor changes to a question mark with a pointer. If the user then clicks a child window, the child receives a WM_HELP message. The child window should pass the message to the parent window procedure, which should call the WinHelp function using the HELP_WM_HELP command. The Help application displays a pop-up window that typically contains help for the child window.WS_EX_CONTEXTHELP cannot be used with the WS_MAXIMIZEBOX or WS_MINIMIZEBOX styles.
+            /// </summary>
+            WS_EX_CONTEXTHELP = 0x00000400L,
+
+            /// <summary>
+            /// The window itself contains child windows that should take part in dialog box navigation. If this style is specified, the dialog manager recurses into children of this window when performing navigation operations such as handling the TAB key, an arrow key, or a keyboard mnemonic.
+            /// </summary>
+            WS_EX_CONTROLPARENT = 0x00010000L,
+
+            /// <summary>
+            /// The window has a double border; the window can, optionally, be created with a title bar by specifying the WS_CAPTION style in the dwStyle parameter.
+            /// </summary>
+            WS_EX_DLGMODALFRAME = 0x00000001L,
+
+            /// <summary>
+            /// The window is a layered window. This style cannot be used if the window has a class style of either CS_OWNDC or CS_CLASSDC.Windows 8:  The WS_EX_LAYERED style is supported for top-level windows and child windows. Previous Windows versions support WS_EX_LAYERED only for top-level windows.
+            /// </summary>
+            WS_EX_LAYERED = 0x00080000,
+
+            /// <summary>
+            /// If the shell language is Hebrew, Arabic, or another language that supports reading order alignment, the horizontal origin of the window is on the right edge. Increasing horizontal values advance to the left.
+            /// </summary>
+            WS_EX_LAYOUTRTL = 0x00400000L,
+
+            /// <summary>
+            /// The window has generic left-aligned properties. This is the default.
+            /// </summary>
+            WS_EX_LEFT = 0x00000000L,
+
+            /// <summary>
+            /// If the shell language is Hebrew, Arabic, or another language that supports reading order alignment, the vertical scroll bar (if present) is to the left of the client area. For other languages, the style is ignored.
+            /// </summary>
+            WS_EX_LEFTSCROLLBAR = 0x00004000L,
+
+            /// <summary>
+            /// The window text is displayed using left-to-right reading-order properties. This is the default.
+            /// </summary>
+            WS_EX_LTRREADING = 0x00000000L,
+
+            /// <summary>
+            /// The window is a MDI child window.
+            /// </summary>
+            WS_EX_MDICHILD = 0x00000040L,
+
+            /// <summary>
+            /// A top-level window created with this style does not become the foreground window when the user clicks it. The system does not bring this window to the foreground when the user minimizes or closes the foreground window.To activate the window, use the SetActiveWindow or SetForegroundWindow function.The window does not appear on the taskbar by default. To force the window to appear on the taskbar, use the WS_EX_APPWINDOW style.
+            /// </summary>
+            WS_EX_NOACTIVATE = 0x08000000L,
+
+            /// <summary>
+            /// The window does not pass its window layout to its child windows.
+            /// </summary>
+            WS_EX_NOINHERITLAYOUT = 0x00100000L,
+
+            /// <summary>
+            /// The child window created with this style does not send the WM_PARENTNOTIFY message to its parent window when it is created or destroyed.
+            /// </summary>
+            WS_EX_NOPARENTNOTIFY = 0x00000004L,
+
+            /// <summary>
+            /// The window does not render to a redirection surface. This is for windows that do not have visible content or that use mechanisms other than surfaces to provide their visual.
+            /// </summary>
+            WS_EX_NOREDIRECTIONBITMAP = 0x00200000L,
+
+            /// <summary>
+            /// The window is an overlapped window.
+            /// </summary>
+            WS_EX_OVERLAPPEDWINDOW = (WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE),
+
+            /// <summary>
+            /// The window is palette window, which is a modeless dialog box that presents an array of commands.
+            /// </summary>
+            WS_EX_PALETTEWINDOW = (WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST),
+
+            /// <summary>
+            /// The window has generic "right-aligned" properties. This depends on the window class. This style has an effect only if the shell language is Hebrew, Arabic, or another language that supports reading-order alignment; otherwise, the style is ignored.Using the WS_EX_RIGHT style for static or edit controls has the same effect as using the SS_RIGHT or ES_RIGHT style, respectively. Using this style with button controls has the same effect as using BS_RIGHT and BS_RIGHTBUTTON styles.
+            /// </summary>
+            WS_EX_RIGHT = 0x00001000L,
+
+            /// <summary>
+            /// The vertical scroll bar (if present) is to the right of the client area. This is the default.
+            /// </summary>
+            WS_EX_RIGHTSCROLLBAR = 0x00000000L,
+
+            /// <summary>
+            /// If the shell language is Hebrew, Arabic, or another language that supports reading-order alignment, the window text is displayed using right-to-left reading-order properties. For other languages, the style is ignored.
+            /// </summary>
+            WS_EX_RTLREADING = 0x00002000L,
+
+            /// <summary>
+            /// The window has a three-dimensional border style intended to be used for items that do not accept user input.
+            /// </summary>
+            WS_EX_STATICEDGE = 0x00020000L,
+
+            /// <summary>
+            /// The window is intended to be used as a floating toolbar. A tool window has a title bar that is shorter than a normal title bar, and the window title is drawn using a smaller font. A tool window does not appear in the taskbar or in the dialog that appears when the user presses ALT+TAB. If a tool window has a system menu, its icon is not displayed on the title bar. However, you can display the system menu by right-clicking or by typing ALT+SPACE.
+            /// </summary>
+            WS_EX_TOOLWINDOW = 0x00000080L,
+
+            /// <summary>
+            /// The window should be placed above all non-topmost windows and should stay above them, even when the window is deactivated. To add or remove this style, use the SetWindowPos function.
+            /// </summary>
+            WS_EX_TOPMOST = 0x00000008L,
+
+            /// <summary>
+            /// The window should not be painted until siblings beneath the window (that were created by the same thread) have been painted. The window appears transparent because the bits of underlying sibling windows have already been painted.To achieve transparency without these restrictions, use the SetWindowRgn function.
+            /// </summary>
+            WS_EX_TRANSPARENT = 0x00000020L,
+
+            /// <summary>
+            /// The window has a border with a raised edge
+            /// </summary>
+            WS_EX_WINDOWEDGE = 0x00000100L
+        }
+
+    }
+}

+ 1 - 0
Util/ListBoxDragDropManager.cs

@@ -490,6 +490,7 @@ namespace GeekDesk.Util
 					return false;
 
 				ListBoxItem item = this.GetListBoxItem( this.indexToSelect );
+				if (item == null) return false;
 				Rect bounds = VisualTreeHelper.GetDescendantBounds( item );
 				Point ptInItem = this.listBox.TranslatePoint( this.ptMouseDown, item );
 

+ 131 - 0
Util/MessageUtil.cs

@@ -0,0 +1,131 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace GeekDesk.Util
+{
+    public class MessageUtil
+    {
+
+        public const int WM_COPYDATA = 0x004A;
+        public static bool SendMsgByPName(string processName, string msg)
+        {
+            try
+            {
+                Process[] processArr = Process.GetProcessesByName(processName);
+                if (processArr != null && processArr.Length > 0)
+                {
+                    foreach (Process process in processArr)
+                    {
+                        IntPtr windowHandle = process.MainWindowHandle;
+                        // 发送消息
+                        CopyDataStruct cds = new CopyDataStruct(IntPtr.Zero, msg);
+                        SendMessage(
+                            windowHandle,
+                            WM_COPYDATA,
+                            0, ref cds);
+                    }
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            } catch (Exception e)
+            {
+                LogUtil.WriteErrorLog(e, processName + "P发送消息失败!");
+                return false;
+            }
+        }
+
+        public static bool SendMsgByWName(string windowName, string msg)
+        {
+            try
+            {
+                IntPtr hwnd = FindWindow(null, windowName);
+                if (hwnd != IntPtr.Zero)
+                {
+                    // 发送消息
+                    CopyDataStruct cds = new CopyDataStruct(IntPtr.Zero, msg);
+                    SendMessage(
+                        hwnd,
+                        WM_COPYDATA,
+                        0, ref cds);
+                } else
+                {
+                    return false;
+                }
+                return true;
+            }
+            catch (Exception e)
+            {
+                LogUtil.WriteErrorLog(e, windowName + "W发送消息失败!");
+                return false;
+            }
+        }
+
+
+        public static bool CheckProcessIsRuning(string processName)
+        {
+            try
+            {
+                Process[] processArr = Process.GetProcessesByName(processName);
+                return (processArr != null && processArr.Length > 0);
+            }
+            catch (Exception e)
+            {
+                LogUtil.WriteErrorLog(e, processName + "检查进程名失败!");
+                return false;
+            }
+        }
+
+        public static bool CheckWindowIsRuning(string windowName)
+        {
+            try
+            {
+                IntPtr hwnd = FindWindow(null, windowName);
+                return (hwnd != IntPtr.Zero);
+            } catch(Exception)
+            {
+                return false;
+            }
+            
+        }
+
+
+        [DllImport("User32.dll", EntryPoint = "FindWindow")]
+        public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
+
+        [DllImport("User32.dll", EntryPoint = "SendMessage")]
+        private static extern int SendMessage(
+                        IntPtr hWnd,                //目标窗体句柄
+                        int Msg,                   //WM_COPYDATA
+                        int wParam,                //自定义数值
+                        ref CopyDataStruct lParam  //传递消息的结构体,
+                        );
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct CopyDataStruct
+        {
+            public CopyDataStruct(IntPtr custom, string msg)
+            {
+                this.custom = custom;
+                this.msg = msg;
+                this.msgLength = msg.Length + 1;
+            }
+            public IntPtr custom;//用户定义数据  
+            public int msgLength;//字符串长度
+            [MarshalAs(UnmanagedType.LPStr)]
+            public string msg;//字符串
+        }
+
+
+        [DllImport("user32")]
+        public static extern bool ChangeWindowMessageFilter(uint msg, int flags);
+
+    }
+}

+ 156 - 0
Util/MouseHook.cs

@@ -0,0 +1,156 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+
+namespace GeekDesk.Util
+{
+    public class MouseHook
+    {
+
+        private Point point;
+        private Point Point
+        {
+            get { return point; }
+            set
+            {
+                if (point != value)
+                {
+                    point = value;
+                    if (MouseMoveEvent != null)
+                    {
+                        var e = new MouseEventArgs(MouseButtons.None, 0, point.X, point.Y, 0);
+                        MouseMoveEvent(this, e);
+                    }
+                }
+            }
+        }
+        private int hHook;
+        private const int WM_MOUSEMOVE = 0x200;
+        private const int WM_LBUTTONDOWN = 0x201;
+        private const int WM_RBUTTONDOWN = 0x204;
+        private const int WM_MBUTTONDOWN = 0x207;
+        private const int WM_LBUTTONUP = 0x202;
+        private const int WM_RBUTTONUP = 0x205;
+        private const int WM_MBUTTONUP = 0x208;
+        private const int WM_LBUTTONDBLCLK = 0x203;
+        private const int WM_RBUTTONDBLCLK = 0x206;
+        private const int WM_MBUTTONDBLCLK = 0x209;
+        public const int WH_MOUSE_LL = 14;
+        public Win32Api.HookProc hProc;
+        public MouseHook()
+        {
+            this.Point = new Point();
+        }
+        public int SetHook()
+        {
+            hProc = new Win32Api.HookProc(MouseHookProc);
+            hHook = Win32Api.SetWindowsHookEx(WH_MOUSE_LL, hProc, IntPtr.Zero, 0);
+            return hHook;
+        }
+        public void UnHook()
+        {
+            Win32Api.UnhookWindowsHookEx(hHook);
+        }
+        private int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
+        {
+            Win32Api.MouseHookStruct MyMouseHookStruct = (Win32Api.MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(Win32Api.MouseHookStruct));
+            if (nCode < 0)
+            {
+                return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
+            }
+            else
+            {
+                if (MouseClickEvent != null)
+                {
+                    MouseButtons button = MouseButtons.None;
+                    int clickCount = 0;
+                    switch ((Int32)wParam)
+                    {
+                        case WM_LBUTTONDOWN:
+                            button = MouseButtons.Left;
+                            clickCount = 1;
+                            MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0));
+                            break;
+                        case WM_RBUTTONDOWN:
+                            button = MouseButtons.Right;
+                            clickCount = 1;
+                            MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0));
+                            break;
+                        case WM_MBUTTONDOWN:
+                            button = MouseButtons.Middle;
+                            clickCount = 1;
+                            MouseDownEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0));
+                            break;
+                        case WM_LBUTTONUP:
+                            button = MouseButtons.Left;
+                            clickCount = 1;
+                            MouseUpEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0));
+                            break;
+                        case WM_RBUTTONUP:
+                            button = MouseButtons.Right;
+                            clickCount = 1;
+                            MouseUpEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0));
+                            break;
+                        case WM_MBUTTONUP:
+                            button = MouseButtons.Middle;
+                            clickCount = 1;
+                            MouseUpEvent(this, new MouseEventArgs(button, clickCount, point.X, point.Y, 0));
+                            break;
+                    }
+
+                    var e = new MouseEventArgs(button, clickCount, point.X, point.Y, 0);
+                    MouseClickEvent(this, e);
+                }
+                this.Point = new Point(MyMouseHookStruct.pt.x, MyMouseHookStruct.pt.y);
+                return Win32Api.CallNextHookEx(hHook, nCode, wParam, lParam);
+            }
+        }
+
+        public delegate void MouseMoveHandler(object sender, MouseEventArgs e);
+        public event MouseMoveHandler MouseMoveEvent;
+
+        public delegate void MouseClickHandler(object sender, MouseEventArgs e);
+        public event MouseClickHandler MouseClickEvent;
+
+        public delegate void MouseDownHandler(object sender, MouseEventArgs e);
+        public event MouseDownHandler MouseDownEvent;
+
+        public delegate void MouseUpHandler(object sender, MouseEventArgs e);
+        public event MouseUpHandler MouseUpEvent;
+
+
+        public class Win32Api
+        {
+            [StructLayout(LayoutKind.Sequential)]
+            public class POINT
+            {
+                public int x;
+                public int y;
+            }
+            [StructLayout(LayoutKind.Sequential)]
+            public class MouseHookStruct
+            {
+                public POINT pt;
+                public int hwnd;
+                public int wHitTestCode;
+                public int dwExtraInfo;
+            }
+            public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
+            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
+            public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
+            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
+            public static extern bool UnhookWindowsHookEx(int idHook);
+            [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
+            public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
+        }
+
+    }
+
+
+
+}

+ 156 - 0
Util/ScreenUtil.cs

@@ -0,0 +1,156 @@
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Forms;
+
+namespace GeekDesk.Util
+{
+    public class ScreenUtil
+    {
+
+        [DllImport("user32.dll")]
+        static extern bool GetCursorPos(ref System.Drawing.Point lpPoint);
+
+        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
+        public static extern int BitBlt(IntPtr hDC, int x, int y, int nWidth, int nHeight, IntPtr hSrcDC, int xSrc, int ySrc, int dwRop);
+
+        [StructLayout(LayoutKind.Sequential)]
+        private struct RECT
+        {
+            public int left;
+            public int top;
+            public int right;
+            public int bottom;
+        }
+
+        //取得前台窗口句柄函数 
+        [DllImport("user32.dll")]
+        private static extern IntPtr GetForegroundWindow();
+        //取得桌面窗口句柄函数 
+        [DllImport("user32.dll")]
+        private static extern IntPtr GetDesktopWindow();
+        //取得Shell窗口句柄函数 
+        [DllImport("user32.dll")]
+        private static extern IntPtr GetShellWindow();
+        //取得窗口大小函数 
+        [DllImport("user32.dll", SetLastError = true)]
+        private static extern int GetWindowRect(IntPtr hwnd, out RECT rc);
+        //获取窗口标题
+        [DllImport("user32", SetLastError = true)]
+        private static extern int GetWindowText(
+            IntPtr hWnd,//窗口句柄
+            StringBuilder lpString,//标题
+            int nMaxCount //最大值
+            );
+
+        //获取类的名字
+        [DllImport("user32.dll")]
+        private static extern int GetClassName(
+            IntPtr hWnd,//句柄
+            StringBuilder lpString, //类名
+            int nMaxCount); //最大值
+
+        /// <summary>
+        /// 判断当前屏幕(鼠标最后活动屏幕)是否有全屏化应用
+        /// </summary>
+        /// <returns></returns>
+        public static bool IsPrimaryFullScreen()
+        {
+
+            //桌面窗口句柄 
+            IntPtr desktopHandle; //Window handle for the desktop  
+                                  //Shell窗口句柄 
+            IntPtr shellHandle; //Window handle for the shell  因为桌面窗口和Shell窗口也是全屏,要排除在其他全屏程序之外。               //取得桌面和Shell窗口句柄 
+            desktopHandle = GetDesktopWindow();
+            shellHandle = GetShellWindow();    //取得前台窗口句柄并判断是否全屏 
+            bool runningFullScreen = false;
+            RECT appBounds;
+            Rectangle screenBounds;
+            IntPtr hWnd;
+            //取得前台窗口 
+            hWnd = GetForegroundWindow();
+
+            StringBuilder sb = new StringBuilder(256);
+            try
+            {
+                GetClassName(hWnd, sb, sb.Capacity);
+            }
+            catch { }
+            if (sb.ToString().ToLower().Equals("workerw")) return false;
+            if (hWnd != null && !hWnd.Equals(IntPtr.Zero))
+            {
+                //判断是否桌面或shell        
+                if (!(hWnd.Equals(desktopHandle) || hWnd.Equals(shellHandle)))
+                {
+                    //取得窗口大小 
+                    GetWindowRect(hWnd, out appBounds);
+                    //判断是否全屏 
+                    screenBounds = Screen.FromHandle(hWnd).Bounds;
+                    if ((appBounds.bottom - appBounds.top) == screenBounds.Height
+                        && (appBounds.right - appBounds.left) == screenBounds.Width)
+                        runningFullScreen = true;
+                }
+            }
+            return runningFullScreen;
+        }
+
+
+        public static Color GetColorAt(System.Drawing.Point location)
+        {
+            Bitmap screenPixel = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
+
+            using (Graphics gdest = Graphics.FromImage(screenPixel))
+            {
+                using (Graphics gsrc = Graphics.FromHwnd(IntPtr.Zero))
+                {
+                    IntPtr hSrcDC = gsrc.GetHdc();
+                    IntPtr hDC = gdest.GetHdc();
+                    int retval = BitBlt(hDC, 0, 0, 1, 1, hSrcDC, location.X, location.Y, (int)CopyPixelOperation.SourceCopy);
+                    gdest.ReleaseHdc();
+                    gsrc.ReleaseHdc();
+                }
+            }
+
+            return screenPixel.GetPixel(0, 0);
+        }
+
+
+        [DllImport("gdi32")]
+        static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
+
+        public const int HORZRES = 8;
+        public const int VERTRES = 10;
+        public const int DESKTOPVERTRES = 117;
+        public const int DESKTOPHORZRES = 118;
+        /// <summary>
+        /// 获取屏幕缩放比例
+        /// </summary>
+        /// <returns></returns>
+        public static double GetScreenScalingFactor()
+        {
+            try
+            {
+                var g = Graphics.FromHwnd(IntPtr.Zero);
+                IntPtr desktop = g.GetHdc();
+                var physicalScreenHeight = GetDeviceCaps(desktop, (int)DESKTOPVERTRES);
+
+                var screenScalingFactor =
+                    (double)physicalScreenHeight / SystemParameters.PrimaryScreenHeight;
+                //SystemParameters.PrimaryScreenHeight;
+
+                return screenScalingFactor;
+            } catch (Exception e)
+            {
+                return 1;
+            }
+            
+        }
+
+    }
+}

+ 75 - 0
Util/ScrollUtil.cs

@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+
+namespace GeekDesk.Util
+{
+    public class ScrollUtil
+    {
+
+        public static bool IsBootomScrollView(ScrollViewer view)
+        {
+            try
+            {
+                bool isBottom = false;
+                double dVer = view.VerticalOffset;
+                double vViewport = view.ViewportHeight;
+                double eextent = view.ExtentHeight;
+                if (dVer + vViewport >= eextent)
+                {
+                    isBottom = true;
+                }
+                else
+                {
+                    isBottom = false;
+                }
+                return isBottom;
+            } catch (Exception e)
+            {
+                return false;
+            }
+            
+        }
+
+        public static bool IsTopScrollView(ScrollViewer view)
+        {
+            try
+            {
+                return (int)view.VerticalOffset == 0;
+            }
+            catch (Exception e)
+            {
+                return false;
+            }
+        }
+
+        public static T FindSimpleVisualChild<T>(DependencyObject element) where T : class
+        {
+            try
+            {
+                while (element != null)
+                {
+
+                    if (element is T)
+                        return element as T;
+                    if (VisualTreeHelper.GetChildrenCount(element) > 0)
+                    {
+                        element = VisualTreeHelper.GetChild(element, 0);
+                    }
+                }
+                return null;
+            }
+            catch (Exception e)
+            {
+                return null;
+            }
+
+        }
+
+    }
+}

+ 837 - 0
Util/UserActivityHook.cs

@@ -0,0 +1,837 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Reflection;
+using System.Threading;
+using System.Windows.Forms;
+using System.ComponentModel;
+
+namespace GeekDesk.Util
+{
+    /// <summary>
+    /// This class allows you to tap keyboard and mouse and / or to detect their activity even when an 
+    /// application runes in background or does not have any user interface at all. This class raises 
+    /// common .NET events with KeyEventArgs and MouseEventArgs so you can easily retrive any information you need.
+    /// </summary>
+    public class UserActivityHook
+    {
+        #region Windows structure definitions
+
+        /// <summary>
+        /// The POINT structure defines the x- and y- coordinates of a point. 
+        /// </summary>
+        /// <remarks>
+        /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/rectangl_0tiq.asp
+        /// </remarks>
+        [StructLayout(LayoutKind.Sequential)]
+        private class POINT
+        {
+            /// <summary>
+            /// Specifies the x-coordinate of the point. 
+            /// </summary>
+            public int x;
+            /// <summary>
+            /// Specifies the y-coordinate of the point. 
+            /// </summary>
+            public int y;
+        }
+
+        /// <summary>
+        /// The MOUSEHOOKSTRUCT structure contains information about a mouse event passed to a WH_MOUSE hook procedure, MouseProc. 
+        /// </summary>
+        /// <remarks>
+        /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookstructures/cwpstruct.asp
+        /// </remarks>
+        [StructLayout(LayoutKind.Sequential)]
+        private class MouseHookStruct
+        {
+            /// <summary>
+            /// Specifies a POINT structure that contains the x- and y-coordinates of the cursor, in screen coordinates. 
+            /// </summary>
+            public POINT pt;
+            /// <summary>
+            /// Handle to the window that will receive the mouse message corresponding to the mouse event. 
+            /// </summary>
+            public int hwnd;
+            /// <summary>
+            /// Specifies the hit-test value. For a list of hit-test values, see the description of the WM_NCHITTEST message. 
+            /// </summary>
+            public int wHitTestCode;
+            /// <summary>
+            /// Specifies extra information associated with the message. 
+            /// </summary>
+            public int dwExtraInfo;
+        }
+
+        /// <summary>
+        /// The MSLLHOOKSTRUCT structure contains information about a low-level keyboard input event. 
+        /// </summary>
+        [StructLayout(LayoutKind.Sequential)]
+        private class MouseLLHookStruct
+        {
+            /// <summary>
+            /// Specifies a POINT structure that contains the x- and y-coordinates of the cursor, in screen coordinates. 
+            /// </summary>
+            public POINT pt;
+            /// <summary>
+            /// If the message is WM_MOUSEWHEEL, the high-order word of this member is the wheel delta. 
+            /// The low-order word is reserved. A positive value indicates that the wheel was rotated forward, 
+            /// away from the user; a negative value indicates that the wheel was rotated backward, toward the user. 
+            /// One wheel click is defined as WHEEL_DELTA, which is 120. 
+            ///If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP,
+            /// or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released, 
+            /// and the low-order word is reserved. This value can be one or more of the following values. Otherwise, mouseData is not used. 
+            ///XBUTTON1
+            ///The first X button was pressed or released.
+            ///XBUTTON2
+            ///The second X button was pressed or released.
+            /// </summary>
+            public int mouseData;
+            /// <summary>
+            /// Specifies the event-injected flag. An application can use the following value to test the mouse flags. Value Purpose 
+            ///LLMHF_INJECTED Test the event-injected flag.  
+            ///0
+            ///Specifies whether the event was injected. The value is 1 if the event was injected; otherwise, it is 0.
+            ///1-15
+            ///Reserved.
+            /// </summary>
+            public int flags;
+            /// <summary>
+            /// Specifies the time stamp for this message.
+            /// </summary>
+            public int time;
+            /// <summary>
+            /// Specifies extra information associated with the message. 
+            /// </summary>
+            public int dwExtraInfo;
+        }
+
+
+        /// <summary>
+        /// The KBDLLHOOKSTRUCT structure contains information about a low-level keyboard input event. 
+        /// </summary>
+        /// <remarks>
+        /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookstructures/cwpstruct.asp
+        /// </remarks>
+        [StructLayout(LayoutKind.Sequential)]
+        private class KeyboardHookStruct
+        {
+            /// <summary>
+            /// Specifies a virtual-key code. The code must be a value in the range 1 to 254. 
+            /// </summary>
+            public int vkCode;
+            /// <summary>
+            /// Specifies a hardware scan code for the key. 
+            /// </summary>
+            public int scanCode;
+            /// <summary>
+            /// Specifies the extended-key flag, event-injected flag, context code, and transition-state flag.
+            /// </summary>
+            public int flags;
+            /// <summary>
+            /// Specifies the time stamp for this message.
+            /// </summary>
+            public int time;
+            /// <summary>
+            /// Specifies extra information associated with the message. 
+            /// </summary>
+            public int dwExtraInfo;
+        }
+        #endregion
+
+        #region Windows function imports
+        /// <summary>
+        /// The SetWindowsHookEx function installs an application-defined hook procedure into a hook chain. 
+        /// You would install a hook procedure to monitor the system for certain types of events. These events 
+        /// are associated either with a specific thread or with all threads in the same desktop as the calling thread. 
+        /// </summary>
+        /// <param name="idHook">
+        /// [in] Specifies the type of hook procedure to be installed. This parameter can be one of the following values.
+        /// </param>
+        /// <param name="lpfn">
+        /// [in] Pointer to the hook procedure. If the dwThreadId parameter is zero or specifies the identifier of a 
+        /// thread created by a different process, the lpfn parameter must point to a hook procedure in a dynamic-link 
+        /// library (DLL). Otherwise, lpfn can point to a hook procedure in the code associated with the current process.
+        /// </param>
+        /// <param name="hMod">
+        /// [in] Handle to the DLL containing the hook procedure pointed to by the lpfn parameter. 
+        /// The hMod parameter must be set to NULL if the dwThreadId parameter specifies a thread created by 
+        /// the current process and if the hook procedure is within the code associated with the current process. 
+        /// </param>
+        /// <param name="dwThreadId">
+        /// [in] Specifies the identifier of the thread with which the hook procedure is to be associated. 
+        /// If this parameter is zero, the hook procedure is associated with all existing threads running in the 
+        /// same desktop as the calling thread. 
+        /// </param>
+        /// <returns>
+        /// If the function succeeds, the return value is the handle to the hook procedure.
+        /// If the function fails, the return value is NULL. To get extended error information, call GetLastError.
+        /// </returns>
+        /// <remarks>
+        /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp
+        /// </remarks>
+        [DllImport("user32.dll", CharSet = CharSet.Auto,
+           CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+        private static extern int SetWindowsHookEx(
+            int idHook,
+            HookProc lpfn,
+            IntPtr hMod,
+            int dwThreadId);
+
+        /// <summary>
+        /// The UnhookWindowsHookEx function removes a hook procedure installed in a hook chain by the SetWindowsHookEx function. 
+        /// </summary>
+        /// <param name="idHook">
+        /// [in] Handle to the hook to be removed. This parameter is a hook handle obtained by a previous call to SetWindowsHookEx. 
+        /// </param>
+        /// <returns>
+        /// If the function succeeds, the return value is nonzero.
+        /// If the function fails, the return value is zero. To get extended error information, call GetLastError.
+        /// </returns>
+        /// <remarks>
+        /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp
+        /// </remarks>
+        [DllImport("user32.dll", CharSet = CharSet.Auto,
+            CallingConvention = CallingConvention.StdCall, SetLastError = true)]
+        private static extern int UnhookWindowsHookEx(int idHook);
+
+        /// <summary>
+        /// The CallNextHookEx function passes the hook information to the next hook procedure in the current hook chain. 
+        /// A hook procedure can call this function either before or after processing the hook information. 
+        /// </summary>
+        /// <param name="idHook">Ignored.</param>
+        /// <param name="nCode">
+        /// [in] Specifies the hook code passed to the current hook procedure. 
+        /// The next hook procedure uses this code to determine how to process the hook information.
+        /// </param>
+        /// <param name="wParam">
+        /// [in] Specifies the wParam value passed to the current hook procedure. 
+        /// The meaning of this parameter depends on the type of hook associated with the current hook chain. 
+        /// </param>
+        /// <param name="lParam">
+        /// [in] Specifies the lParam value passed to the current hook procedure. 
+        /// The meaning of this parameter depends on the type of hook associated with the current hook chain. 
+        /// </param>
+        /// <returns>
+        /// This value is returned by the next hook procedure in the chain. 
+        /// The current hook procedure must also return this value. The meaning of the return value depends on the hook type. 
+        /// For more information, see the descriptions of the individual hook procedures.
+        /// </returns>
+        /// <remarks>
+        /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp
+        /// </remarks>
+        [DllImport("user32.dll", CharSet = CharSet.Auto,
+             CallingConvention = CallingConvention.StdCall)]
+        private static extern int CallNextHookEx(
+            int idHook,
+            int nCode,
+            int wParam,
+            IntPtr lParam);
+
+        /// <summary>
+        /// The CallWndProc hook procedure is an application-defined or library-defined callback 
+        /// function used with the SetWindowsHookEx function. The HOOKPROC type defines a pointer 
+        /// to this callback function. CallWndProc is a placeholder for the application-defined 
+        /// or library-defined function name.
+        /// </summary>
+        /// <param name="nCode">
+        /// [in] Specifies whether the hook procedure must process the message. 
+        /// If nCode is HC_ACTION, the hook procedure must process the message. 
+        /// If nCode is less than zero, the hook procedure must pass the message to the 
+        /// CallNextHookEx function without further processing and must return the 
+        /// value returned by CallNextHookEx.
+        /// </param>
+        /// <param name="wParam">
+        /// [in] Specifies whether the message was sent by the current thread. 
+        /// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 
+        /// </param>
+        /// <param name="lParam">
+        /// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 
+        /// </param>
+        /// <returns>
+        /// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 
+        /// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 
+        /// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 
+        /// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 
+        /// procedure does not call CallNextHookEx, the return value should be zero. 
+        /// </returns>
+        /// <remarks>
+        /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/callwndproc.asp
+        /// </remarks>
+        private delegate int HookProc(int nCode, int wParam, IntPtr lParam);
+
+        /// <summary>
+        /// The ToAscii function translates the specified virtual-key code and keyboard 
+        /// state to the corresponding character or characters. The function translates the code 
+        /// using the input language and physical keyboard layout identified by the keyboard layout handle.
+        /// </summary>
+        /// <param name="uVirtKey">
+        /// [in] Specifies the virtual-key code to be translated. 
+        /// </param>
+        /// <param name="uScanCode">
+        /// [in] Specifies the hardware scan code of the key to be translated. 
+        /// The high-order bit of this value is set if the key is up (not pressed). 
+        /// </param>
+        /// <param name="lpbKeyState">
+        /// [in] Pointer to a 256-byte array that contains the current keyboard state. 
+        /// Each element (byte) in the array contains the state of one key. 
+        /// If the high-order bit of a byte is set, the key is down (pressed). 
+        /// The low bit, if set, indicates that the key is toggled on. In this function, 
+        /// only the toggle bit of the CAPS LOCK key is relevant. The toggle state 
+        /// of the NUM LOCK and SCROLL LOCK keys is ignored.
+        /// </param>
+        /// <param name="lpwTransKey">
+        /// [out] Pointer to the buffer that receives the translated character or characters. 
+        /// </param>
+        /// <param name="fuState">
+        /// [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise. 
+        /// </param>
+        /// <returns>
+        /// If the specified key is a dead key, the return value is negative. Otherwise, it is one of the following values. 
+        /// Value Meaning 
+        /// 0 The specified virtual key has no translation for the current state of the keyboard. 
+        /// 1 One character was copied to the buffer. 
+        /// 2 Two characters were copied to the buffer. This usually happens when a dead-key character 
+        /// (accent or diacritic) stored in the keyboard layout cannot be composed with the specified 
+        /// virtual key to form a single character. 
+        /// </returns>
+        /// <remarks>
+        /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/toascii.asp
+        /// </remarks>
+        [DllImport("user32")]
+        private static extern int ToAscii(
+            int uVirtKey,
+            int uScanCode,
+            byte[] lpbKeyState,
+            byte[] lpwTransKey,
+            int fuState);
+
+        /// <summary>
+        /// The GetKeyboardState function copies the status of the 256 virtual keys to the 
+        /// specified buffer. 
+        /// </summary>
+        /// <param name="pbKeyState">
+        /// [in] Pointer to a 256-byte array that contains keyboard key states. 
+        /// </param>
+        /// <returns>
+        /// If the function succeeds, the return value is nonzero.
+        /// If the function fails, the return value is zero. To get extended error information, call GetLastError. 
+        /// </returns>
+        /// <remarks>
+        /// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputfunctions/toascii.asp
+        /// </remarks>
+        [DllImport("user32")]
+        private static extern int GetKeyboardState(byte[] pbKeyState);
+
+        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
+        private static extern short GetKeyState(int vKey);
+
+        #endregion
+
+        #region Windows constants
+
+        //values from Winuser.h in Microsoft SDK.
+        /// <summary>
+        /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level mouse input events.
+        /// </summary>
+        private const int WH_MOUSE_LL       = 14;
+        /// <summary>
+        /// Windows NT/2000/XP: Installs a hook procedure that monitors low-level keyboard  input events.
+        /// </summary>
+        private const int WH_KEYBOARD_LL    = 13;
+
+        /// <summary>
+        /// Installs a hook procedure that monitors mouse messages. For more information, see the MouseProc hook procedure. 
+        /// </summary>
+        private const int WH_MOUSE          = 7;
+        /// <summary>
+        /// Installs a hook procedure that monitors keystroke messages. For more information, see the KeyboardProc hook procedure. 
+        /// </summary>
+        private const int WH_KEYBOARD       = 2;
+
+        /// <summary>
+        /// The WM_MOUSEMOVE message is posted to a window when the cursor moves. 
+        /// </summary>
+        private const int WM_MOUSEMOVE      = 0x200;
+        /// <summary>
+        /// The WM_LBUTTONDOWN message is posted when the user presses the left mouse button 
+        /// </summary>
+        private const int WM_LBUTTONDOWN    = 0x201;
+        /// <summary>
+        /// The WM_RBUTTONDOWN message is posted when the user presses the right mouse button
+        /// </summary>
+        private const int WM_RBUTTONDOWN    = 0x204;
+        /// <summary>
+        /// The WM_MBUTTONDOWN message is posted when the user presses the middle mouse button 
+        /// </summary>
+        private const int WM_MBUTTONDOWN    = 0x207;
+        /// <summary>
+        /// The WM_LBUTTONUP message is posted when the user releases the left mouse button 
+        /// </summary>
+        private const int WM_LBUTTONUP      = 0x202;
+        /// <summary>
+        /// The WM_RBUTTONUP message is posted when the user releases the right mouse button 
+        /// </summary>
+        private const int WM_RBUTTONUP      = 0x205;
+        /// <summary>
+        /// The WM_MBUTTONUP message is posted when the user releases the middle mouse button 
+        /// </summary>
+        private const int WM_MBUTTONUP      = 0x208;
+        /// <summary>
+        /// The WM_LBUTTONDBLCLK message is posted when the user double-clicks the left mouse button 
+        /// </summary>
+        private const int WM_LBUTTONDBLCLK  = 0x203;
+        /// <summary>
+        /// The WM_RBUTTONDBLCLK message is posted when the user double-clicks the right mouse button 
+        /// </summary>
+        private const int WM_RBUTTONDBLCLK  = 0x206;
+        /// <summary>
+        /// The WM_RBUTTONDOWN message is posted when the user presses the right mouse button 
+        /// </summary>
+        private const int WM_MBUTTONDBLCLK  = 0x209;
+        /// <summary>
+        /// The WM_MOUSEWHEEL message is posted when the user presses the mouse wheel. 
+        /// </summary>
+        private const int WM_MOUSEWHEEL     = 0x020A;
+
+        /// <summary>
+        /// The WM_KEYDOWN message is posted to the window with the keyboard focus when a nonsystem 
+        /// key is pressed. A nonsystem key is a key that is pressed when the ALT key is not pressed.
+        /// </summary>
+        private const int WM_KEYDOWN = 0x100;
+        /// <summary>
+        /// The WM_KEYUP message is posted to the window with the keyboard focus when a nonsystem 
+        /// key is released. A nonsystem key is a key that is pressed when the ALT key is not pressed, 
+        /// or a keyboard key that is pressed when a window has the keyboard focus.
+        /// </summary>
+        private const int WM_KEYUP = 0x101;
+        /// <summary>
+        /// The WM_SYSKEYDOWN message is posted to the window with the keyboard focus when the user 
+        /// presses the F10 key (which activates the menu bar) or holds down the ALT key and then 
+        /// presses another key. It also occurs when no window currently has the keyboard focus; 
+        /// in this case, the WM_SYSKEYDOWN message is sent to the active window. The window that 
+        /// receives the message can distinguish between these two contexts by checking the context 
+        /// code in the lParam parameter. 
+        /// </summary>
+        private const int WM_SYSKEYDOWN = 0x104;
+        /// <summary>
+        /// The WM_SYSKEYUP message is posted to the window with the keyboard focus when the user 
+        /// releases a key that was pressed while the ALT key was held down. It also occurs when no 
+        /// window currently has the keyboard focus; in this case, the WM_SYSKEYUP message is sent 
+        /// to the active window. The window that receives the message can distinguish between 
+        /// these two contexts by checking the context code in the lParam parameter. 
+        /// </summary>
+        private const int WM_SYSKEYUP = 0x105;
+
+        private const byte VK_SHIFT     = 0x10;
+        private const byte VK_CAPITAL   = 0x14;
+        private const byte VK_NUMLOCK   = 0x90;
+
+        #endregion
+
+        /// <summary>
+        /// Creates an instance of UserActivityHook object and sets mouse and keyboard hooks.
+        /// </summary>
+        /// <exception cref="Win32Exception">Any windows problem.</exception>
+        public UserActivityHook()
+        {
+            Start();
+        }
+
+        /// <summary>
+        /// Creates an instance of UserActivityHook object and installs both or one of mouse and/or keyboard hooks and starts rasing events
+        /// </summary>
+        /// <param name="InstallMouseHook"><b>true</b> if mouse events must be monitored</param>
+        /// <param name="InstallKeyboardHook"><b>true</b> if keyboard events must be monitored</param>
+        /// <exception cref="Win32Exception">Any windows problem.</exception>
+        /// <remarks>
+        /// To create an instance without installing hooks call new UserActivityHook(false, false)
+        /// </remarks>
+        public UserActivityHook(bool InstallMouseHook, bool InstallKeyboardHook)
+        {
+            Start(InstallMouseHook, InstallKeyboardHook);
+        }
+
+        /// <summary>
+        /// Destruction.
+        /// </summary>
+        ~UserActivityHook()
+        {
+            //uninstall hooks and do not throw exceptions
+            Stop(true, true, false);
+        }
+
+        /// <summary>
+        /// Occurs when the user moves the mouse, presses any mouse button or scrolls the wheel
+        /// </summary>
+        /// 
+        public bool EnableMouse = false;
+
+
+        public event MouseEventHandler OnMouseLeftDown;
+
+        public event MouseEventHandler OnMouseLeftUp;
+
+        public event MouseEventHandler OnMouseWheelDown;
+
+        public event MouseEventHandler OnMouseWheelUp;
+
+        public bool MouseLeftDownEnable()
+        {
+            return OnMouseLeftDown != null;
+        }
+        public bool MouseLeftUpEnable()
+        {
+            return OnMouseLeftUp != null;
+        }
+        public bool MouseWheelDownEnable()
+        {
+            return OnMouseWheelDown != null;
+        }
+        public bool MouseWheelUpEnable()
+        {
+            return OnMouseWheelUp != null;
+        }
+        /// <summary>
+        /// Occurs when the user presses a key
+        /// </summary>
+        public event KeyEventHandler KeyDown;
+        /// <summary>
+        /// Occurs when the user presses and releases 
+        /// </summary>
+        public event KeyPressEventHandler KeyPress;
+        /// <summary>
+        /// Occurs when the user releases a key
+        /// </summary>
+        public event KeyEventHandler KeyUp;
+
+
+        /// <summary>
+        /// Stores the handle to the mouse hook procedure.
+        /// </summary>
+        private int hMouseHook = 0;
+        /// <summary>
+        /// Stores the handle to the keyboard hook procedure.
+        /// </summary>
+        private int hKeyboardHook = 0;
+
+
+        /// <summary>
+        /// Declare MouseHookProcedure as HookProc type.
+        /// </summary>
+        private static HookProc MouseHookProcedure;
+        /// <summary>
+        /// Declare KeyboardHookProcedure as HookProc type.
+        /// </summary>
+        private static HookProc KeyboardHookProcedure;
+
+
+        /// <summary>
+        /// Installs both mouse and keyboard hooks and starts rasing events
+        /// </summary>
+        /// <exception cref="Win32Exception">Any windows problem.</exception>
+        public void Start()
+        {
+            this.Start(true, true);
+        }
+
+        /// <summary>
+        /// Installs both or one of mouse and/or keyboard hooks and starts rasing events
+        /// </summary>
+        /// <param name="InstallMouseHook"><b>true</b> if mouse events must be monitored</param>
+        /// <param name="InstallKeyboardHook"><b>true</b> if keyboard events must be monitored</param>
+        /// <exception cref="Win32Exception">Any windows problem.</exception>
+        public void Start(bool InstallMouseHook, bool InstallKeyboardHook)
+        {
+            this.EnableMouse = InstallMouseHook;
+            // install Mouse hook only if it is not installed and must be installed
+            if (hMouseHook == 0 && EnableMouse)
+            {
+                // Create an instance of HookProc.
+                MouseHookProcedure = new HookProc(MouseHookProc);
+                //install hook
+                hMouseHook = SetWindowsHookEx(
+                    WH_MOUSE_LL,
+                    MouseHookProcedure,
+                    Marshal.GetHINSTANCE(
+                        Assembly.GetExecutingAssembly().GetModules()[0]),
+                    0);
+                //If SetWindowsHookEx fails.
+                if (hMouseHook == 0)
+                {
+                    //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
+                    int errorCode = Marshal.GetLastWin32Error();
+                    //do cleanup
+                    Stop(true, false, false);
+                    //Initializes and throws a new instance of the Win32Exception class with the specified error. 
+                    throw new Win32Exception(errorCode);
+                }
+            }
+
+            // install Keyboard hook only if it is not installed and must be installed
+            if (hKeyboardHook == 0 && InstallKeyboardHook)
+            {
+                // Create an instance of HookProc.
+                KeyboardHookProcedure = new HookProc(KeyboardHookProc);
+                //install hook
+                hKeyboardHook = SetWindowsHookEx(
+                    WH_KEYBOARD_LL,
+                    KeyboardHookProcedure,
+                    Marshal.GetHINSTANCE(
+                    Assembly.GetExecutingAssembly().GetModules()[0]),
+                    0);
+                //If SetWindowsHookEx fails.
+                if (hKeyboardHook == 0)
+                {
+                    //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
+                    int errorCode = Marshal.GetLastWin32Error();
+                    //do cleanup
+                    Stop(false, true, false);
+                    //Initializes and throws a new instance of the Win32Exception class with the specified error. 
+                    throw new Win32Exception(errorCode);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Stops monitoring both mouse and keyboard events and rasing events.
+        /// </summary>
+        /// <exception cref="Win32Exception">Any windows problem.</exception>
+        public void Stop()
+        {
+            this.Stop(true, true, true);
+        }
+
+        /// <summary>
+        /// Stops monitoring both or one of mouse and/or keyboard events and rasing events.
+        /// </summary>
+        /// <param name="UninstallMouseHook"><b>true</b> if mouse hook must be uninstalled</param>
+        /// <param name="UninstallKeyboardHook"><b>true</b> if keyboard hook must be uninstalled</param>
+        /// <param name="ThrowExceptions"><b>true</b> if exceptions which occured during uninstalling must be thrown</param>
+        /// <exception cref="Win32Exception">Any windows problem.</exception>
+        public void Stop(bool UninstallMouseHook, bool UninstallKeyboardHook, bool ThrowExceptions)
+        {
+            //if mouse hook set and must be uninstalled
+            if (hMouseHook != 0 && UninstallMouseHook)
+            {
+                //uninstall hook
+                int retMouse = UnhookWindowsHookEx(hMouseHook);
+                //reset invalid handle
+                hMouseHook = 0;
+                //if failed and exception must be thrown
+                if (retMouse == 0 && ThrowExceptions)
+                {
+                    //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
+                    int errorCode = Marshal.GetLastWin32Error();
+                    //Initializes and throws a new instance of the Win32Exception class with the specified error. 
+                    throw new Win32Exception(errorCode);
+                }
+            }
+
+            //if keyboard hook set and must be uninstalled
+            if (hKeyboardHook != 0 && UninstallKeyboardHook)
+            {
+                //uninstall hook
+                int retKeyboard = UnhookWindowsHookEx(hKeyboardHook);
+                //reset invalid handle
+                hKeyboardHook = 0;
+                //if failed and exception must be thrown
+                if (retKeyboard == 0 && ThrowExceptions)
+                {
+                    //Returns the error code returned by the last unmanaged function called using platform invoke that has the DllImportAttribute.SetLastError flag set. 
+                    int errorCode = Marshal.GetLastWin32Error();
+                    //Initializes and throws a new instance of the Win32Exception class with the specified error. 
+                    throw new Win32Exception(errorCode);
+                }
+            }
+        }
+
+
+        /// <summary>
+        /// A callback function which will be called every time a mouse activity detected.
+        /// </summary>
+        /// <param name="nCode">
+        /// [in] Specifies whether the hook procedure must process the message. 
+        /// If nCode is HC_ACTION, the hook procedure must process the message. 
+        /// If nCode is less than zero, the hook procedure must pass the message to the 
+        /// CallNextHookEx function without further processing and must return the 
+        /// value returned by CallNextHookEx.
+        /// </param>
+        /// <param name="wParam">
+        /// [in] Specifies whether the message was sent by the current thread. 
+        /// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 
+        /// </param>
+        /// <param name="lParam">
+        /// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 
+        /// </param>
+        /// <returns>
+        /// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 
+        /// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 
+        /// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 
+        /// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 
+        /// procedure does not call CallNextHookEx, the return value should be zero. 
+        /// </returns>
+        private int MouseHookProc(int nCode, int wParam, IntPtr lParam)
+        {
+            // if ok and someone listens to our events
+            if ((nCode >= 0) && EnableMouse)
+            {
+                //Marshall the data from callback.
+                MouseLLHookStruct mouseHookStruct = (MouseLLHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseLLHookStruct));
+
+                //detect button clicked
+                MouseButtons button = MouseButtons.None;
+                short mouseDelta = 0;
+                switch (wParam)
+                {
+                    case WM_LBUTTONDOWN:
+                    case WM_LBUTTONUP:
+                        button = MouseButtons.Left;
+
+                        break;
+                    case WM_RBUTTONDOWN:
+                    case WM_RBUTTONUP:
+                        //case WM_RBUTTONUP: 
+                        //case WM_RBUTTONDBLCLK: 
+                        button = MouseButtons.Right;
+                        break;
+                    case WM_MOUSEWHEEL:
+                    case WM_MBUTTONDOWN:
+                    case WM_MBUTTONUP:
+                        button = MouseButtons.Middle;
+                        //If the message is WM_MOUSEWHEEL, the high-order word of mouseData member is the wheel delta. 
+                        //One wheel click is defined as WHEEL_DELTA, which is 120. 
+                        //(value >> 16) & 0xffff; retrieves the high-order word from the given 32-bit value
+                        mouseDelta = (short)((mouseHookStruct.mouseData >> 16) & 0xffff);
+                        
+                        //TODO: X BUTTONS (I havent them so was unable to test)
+                        //If the message is WM_XBUTTONDOWN, WM_XBUTTONUP, WM_XBUTTONDBLCLK, WM_NCXBUTTONDOWN, WM_NCXBUTTONUP, 
+                        //or WM_NCXBUTTONDBLCLK, the high-order word specifies which X button was pressed or released, 
+                        //and the low-order word is reserved. This value can be one or more of the following values. 
+                        //Otherwise, mouseData is not used. 
+                        break;
+                }
+
+                //double clicks
+                int clickCount = 0;
+                if (button != MouseButtons.None)
+                    if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK) clickCount = 2;
+                    else clickCount = 1;
+
+                //generate event 
+                 MouseEventArgs e = new MouseEventArgs(
+                                                    button,
+                                                    clickCount,
+                                                    mouseHookStruct.pt.x,
+                                                    mouseHookStruct.pt.y,
+                                                    mouseDelta);
+                //raise it
+                switch (wParam)
+                {
+                    case WM_LBUTTONDOWN:
+                        this.OnMouseLeftDown?.Invoke(this, e);
+                        break;
+                    case WM_LBUTTONUP:
+                        this.OnMouseLeftUp?.Invoke(this, e);
+                        break;
+                    case WM_RBUTTONDOWN:
+                        break;
+                    case WM_RBUTTONUP:
+                        break;
+                    case WM_MOUSEWHEEL:
+                        break;
+                    case WM_MBUTTONDOWN:
+                        this.OnMouseWheelDown?.Invoke(this, e);
+                        break;
+                    case WM_MBUTTONUP:
+                        this.OnMouseWheelUp?.Invoke(this, e);
+                        break;
+                }
+            }
+            //call next hook
+            return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
+        }
+
+        /// <summary>
+        /// A callback function which will be called every time a keyboard activity detected.
+        /// </summary>
+        /// <param name="nCode">
+        /// [in] Specifies whether the hook procedure must process the message. 
+        /// If nCode is HC_ACTION, the hook procedure must process the message. 
+        /// If nCode is less than zero, the hook procedure must pass the message to the 
+        /// CallNextHookEx function without further processing and must return the 
+        /// value returned by CallNextHookEx.
+        /// </param>
+        /// <param name="wParam">
+        /// [in] Specifies whether the message was sent by the current thread. 
+        /// If the message was sent by the current thread, it is nonzero; otherwise, it is zero. 
+        /// </param>
+        /// <param name="lParam">
+        /// [in] Pointer to a CWPSTRUCT structure that contains details about the message. 
+        /// </param>
+        /// <returns>
+        /// If nCode is less than zero, the hook procedure must return the value returned by CallNextHookEx. 
+        /// If nCode is greater than or equal to zero, it is highly recommended that you call CallNextHookEx 
+        /// and return the value it returns; otherwise, other applications that have installed WH_CALLWNDPROC 
+        /// hooks will not receive hook notifications and may behave incorrectly as a result. If the hook 
+        /// procedure does not call CallNextHookEx, the return value should be zero. 
+        /// </returns>
+        private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
+        {
+            //indicates if any of underlaing events set e.Handled flag
+            bool handled = false;
+            //it was ok and someone listens to events
+            if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))
+            {
+                //read structure KeyboardHookStruct at lParam
+                KeyboardHookStruct MyKeyboardHookStruct = (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct));
+                //raise KeyDown
+                if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
+                {
+                    Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
+                    KeyEventArgs e = new KeyEventArgs(keyData);
+                    KeyDown(this, e);
+                    handled = handled || e.Handled;
+                }
+
+                // raise KeyPress
+                if (KeyPress != null && wParam == WM_KEYDOWN)
+                {
+                    bool isDownShift = ((GetKeyState(VK_SHIFT) & 0x80) == 0x80 ? true : false);
+                    bool isDownCapslock = (GetKeyState(VK_CAPITAL) != 0 ? true : false);
+
+                    byte[] keyState = new byte[256];
+                    GetKeyboardState(keyState);
+                    byte[] inBuffer = new byte[2];
+                    if (ToAscii(MyKeyboardHookStruct.vkCode,
+                              MyKeyboardHookStruct.scanCode,
+                              keyState,
+                              inBuffer,
+                              MyKeyboardHookStruct.flags) == 1)
+                    {
+                        char key = (char)inBuffer[0];
+                        if ((isDownCapslock ^ isDownShift) && Char.IsLetter(key)) key = Char.ToUpper(key);
+                        KeyPressEventArgs e = new KeyPressEventArgs(key);
+                        KeyPress(this, e);
+                        handled = handled || e.Handled;
+                    }
+                }
+
+                // raise KeyUp
+                if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
+                {
+                    Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
+                    KeyEventArgs e = new KeyEventArgs(keyData);
+                    KeyUp(this, e);
+                    handled = handled || e.Handled;
+                }
+
+            }
+
+            //if event handled in application do not handoff to other listeners
+            if (handled)
+                return 1;
+            else
+                return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
+        }
+    }
+}

+ 17 - 0
ViewModel/AppConfig.cs

@@ -103,7 +103,24 @@ namespace GeekDesk.ViewModel
 
         private bool itemSpradeAnimation; //列表展开动画
 
+        private bool? secondsWindow; //秒数窗口 默认打开
+
         #region GetSet
+
+        public bool? SecondsWindow
+        {
+            get
+            {
+                if (secondsWindow == null) secondsWindow = true;
+                return secondsWindow;
+            }
+            set
+            {
+                secondsWindow = value;
+                OnPropertyChanged("SecondsWindow");
+            }
+        }
+
         public bool ItemSpradeAnimation
         {
             get

+ 79 - 0
app.manifest

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+    <security>
+      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
+        <!-- UAC 清单选项
+             如果想要更改 Windows 用户帐户控制级别,请使用
+             以下节点之一替换 requestedExecutionLevel 节点。
+
+        <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
+        <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
+        <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />
+
+            指定 requestedExecutionLevel 元素将禁用文件和注册表虚拟化。
+            如果你的应用程序需要此虚拟化来实现向后兼容性,则移除此
+            元素。
+        -->
+        <requestedExecutionLevel level="asInvoker" uiAccess="false" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- 设计此应用程序与其一起工作且已针对此应用程序进行测试的
+           Windows 版本的列表。取消评论适当的元素,
+           Windows 将自动选择最兼容的环境。 -->
+
+      <!-- Windows Vista -->
+      <!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
+
+      <!-- Windows 7 -->
+      <!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
+
+      <!-- Windows 8 -->
+      <!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
+
+      <!-- Windows 8.1 -->
+      <!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
+
+      <!-- Windows 10 -->
+      <!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
+
+    </application>
+  </compatibility>
+
+  <!-- 指示该应用程序可感知 DPI 且 Windows 在 DPI 较高时将不会对其进行
+       自动缩放。Windows Presentation Foundation (WPF)应用程序自动感知 DPI,无需
+       选择加入。选择加入此设置的 Windows 窗体应用程序(面向 .NET Framework 4.6)还应
+       在其 app.config 中将 "EnableWindowsFormsHighDpiAutoResizing" 设置设置为 "true"。
+       
+       将应用程序设为感知长路径。请参阅 https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
+  
+  <application xmlns="urn:schemas-microsoft-com:asm.v3">
+    <windowsSettings>
+      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
+      <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
+    </windowsSettings>
+  </application>
+
+
+  <!-- 启用 Windows 公共控件和对话框的主题(Windows XP 和更高版本) -->
+  <!--
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity
+          type="win32"
+          name="Microsoft.Windows.Common-Controls"
+          version="6.0.0.0"
+          processorArchitecture="*"
+          publicKeyToken="6595b64144ccf1df"
+          language="*"
+        />
+    </dependentAssembly>
+  </dependency>
+  -->
+
+</assembly>