ScreenshotWindow.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Runtime.InteropServices;
  5. using System.Windows;
  6. using System.Windows.Controls;
  7. using System.Windows.Input;
  8. using System.Windows.Media;
  9. using System.Windows.Media.Imaging;
  10. using HandyControl.Data;
  11. using HandyControl.Tools;
  12. using HandyControl.Tools.Extension;
  13. using HandyControl.Tools.Interop;
  14. namespace HandyControl.Controls;
  15. [TemplatePart(Name = ElementCanvas, Type = typeof(InkCanvas))]
  16. [TemplatePart(Name = ElementMaskAreaLeft, Type = typeof(FrameworkElement))]
  17. [TemplatePart(Name = ElementMaskAreaTop, Type = typeof(FrameworkElement))]
  18. [TemplatePart(Name = ElementMaskAreaRight, Type = typeof(FrameworkElement))]
  19. [TemplatePart(Name = ElementMaskAreaBottom, Type = typeof(FrameworkElement))]
  20. [TemplatePart(Name = ElementTargetArea, Type = typeof(InkCanvas))]
  21. [TemplatePart(Name = ElementMagnifier, Type = typeof(FrameworkElement))]
  22. public class ScreenshotWindow : System.Windows.Window
  23. {
  24. #region fields
  25. private readonly Screenshot _screenshot;
  26. private VisualBrush _visualPreview;
  27. private Size _viewboxSize;
  28. private BitmapSource _imageSource;
  29. private static readonly Guid BmpGuid = new("{b96b3cab-0728-11d3-9d7b-0000f81ef32e}");
  30. #region const
  31. private const int IntervalLength = 1;
  32. private const int IntervalBigLength = 10;
  33. private const int SnapLength = 4;
  34. #endregion
  35. #region IntPtr
  36. private IntPtr _desktopWindowHandle;
  37. private IntPtr _mouseOverWindowHandle;
  38. private readonly IntPtr _screenshotWindowHandle;
  39. #endregion
  40. #region status
  41. private InteropValues.RECT _desktopWindowRect;
  42. private InteropValues.RECT _targetWindowRect;
  43. private readonly int[] _flagArr = new int[4];
  44. private bool _isOut;
  45. private bool _canDrag;
  46. private bool _receiveMoveMsg = true;
  47. private Point _mousePointOld;
  48. private Point _pointFixed;
  49. private InteropValues.POINT _pointFloating;
  50. private bool _saveScreenshot;
  51. #endregion
  52. #endregion
  53. #region Elements
  54. internal InkCanvas Canvas { get; set; }
  55. internal FrameworkElement MaskAreaLeft { get; set; }
  56. internal FrameworkElement MaskAreaTop { get; set; }
  57. internal FrameworkElement MaskAreaRight { get; set; }
  58. internal FrameworkElement MaskAreaBottom { get; set; }
  59. internal FrameworkElement TargetArea { get; set; }
  60. private FrameworkElement _magnifier;
  61. #endregion
  62. #region const
  63. private const string ElementCanvas = "PART_Canvas";
  64. private const string ElementMaskAreaLeft = "PART_MaskAreaLeft";
  65. private const string ElementMaskAreaTop = "PART_MaskAreaTop";
  66. private const string ElementMaskAreaRight = "PART_MaskAreaRight";
  67. private const string ElementMaskAreaBottom = "PART_MaskAreaBottom";
  68. private const string ElementTargetArea = "PART_TargetArea";
  69. private const string ElementMagnifier = "PART_Magnifier";
  70. #endregion
  71. #region prop
  72. public static readonly DependencyProperty IsDrawingProperty = DependencyProperty.Register(
  73. nameof(IsDrawing), typeof(bool), typeof(ScreenshotWindow), new PropertyMetadata(ValueBoxes.FalseBox));
  74. public bool IsDrawing
  75. {
  76. get => (bool) GetValue(IsDrawingProperty);
  77. internal set => SetValue(IsDrawingProperty, ValueBoxes.BooleanBox(value));
  78. }
  79. public static readonly DependencyProperty IsSelectingProperty = DependencyProperty.Register(
  80. nameof(IsSelecting), typeof(bool), typeof(ScreenshotWindow), new PropertyMetadata(ValueBoxes.FalseBox));
  81. public bool IsSelecting
  82. {
  83. get => (bool) GetValue(IsSelectingProperty);
  84. internal set => SetValue(IsSelectingProperty, ValueBoxes.BooleanBox(value));
  85. }
  86. public static readonly DependencyProperty SizeProperty = DependencyProperty.Register(
  87. nameof(Size), typeof(Size), typeof(ScreenshotWindow), new PropertyMetadata(default(Size)));
  88. public Size Size
  89. {
  90. get => (Size) GetValue(SizeProperty);
  91. internal set => SetValue(SizeProperty, value);
  92. }
  93. public static readonly DependencyProperty SizeStrProperty = DependencyProperty.Register(
  94. nameof(SizeStr), typeof(string), typeof(ScreenshotWindow), new PropertyMetadata(default(string)));
  95. public string SizeStr
  96. {
  97. get => (string) GetValue(SizeStrProperty);
  98. internal set => SetValue(SizeStrProperty, value);
  99. }
  100. public static readonly DependencyProperty PixelColorProperty = DependencyProperty.Register(
  101. nameof(PixelColor), typeof(Color), typeof(ScreenshotWindow), new PropertyMetadata(default(Color)));
  102. public Color PixelColor
  103. {
  104. get => (Color) GetValue(PixelColorProperty);
  105. internal set => SetValue(PixelColorProperty, value);
  106. }
  107. public static readonly DependencyProperty PixelColorStrProperty = DependencyProperty.Register(
  108. nameof(PixelColorStr), typeof(string), typeof(ScreenshotWindow), new PropertyMetadata(default(string)));
  109. public string PixelColorStr
  110. {
  111. get => (string) GetValue(PixelColorStrProperty);
  112. internal set => SetValue(PixelColorStrProperty, value);
  113. }
  114. public static readonly DependencyPropertyKey PreviewBrushPropertyKey = DependencyProperty.RegisterReadOnly(
  115. "PreviewBrush", typeof(Brush), typeof(ScreenshotWindow), new PropertyMetadata(default(Brush)));
  116. public static readonly DependencyProperty PreviewBrushProperty = PreviewBrushPropertyKey.DependencyProperty;
  117. public Brush PreviewBrush
  118. {
  119. get => (Brush) GetValue(PreviewBrushProperty);
  120. set => SetValue(PreviewBrushProperty, value);
  121. }
  122. #endregion
  123. public ScreenshotWindow(Screenshot screenshot)
  124. {
  125. Style = ResourceHelper.GetResourceInternal<Style>(ResourceToken.Window4ScreenshotStyle);
  126. _screenshot = screenshot;
  127. DataContext = this;
  128. _screenshotWindowHandle = this.GetHandle();
  129. InteropMethods.EnableWindow(_screenshotWindowHandle, false);
  130. Loaded += ScreenshotWindow_Loaded;
  131. Closed += ScreenshotWindow_Closed;
  132. }
  133. public override void OnApplyTemplate()
  134. {
  135. base.OnApplyTemplate();
  136. Canvas = GetTemplateChild(ElementCanvas) as InkCanvas;
  137. MaskAreaLeft = GetTemplateChild(ElementMaskAreaLeft) as FrameworkElement;
  138. MaskAreaTop = GetTemplateChild(ElementMaskAreaTop) as FrameworkElement;
  139. MaskAreaRight = GetTemplateChild(ElementMaskAreaRight) as FrameworkElement;
  140. MaskAreaBottom = GetTemplateChild(ElementMaskAreaBottom) as FrameworkElement;
  141. TargetArea = GetTemplateChild(ElementTargetArea) as FrameworkElement;
  142. _magnifier = GetTemplateChild(ElementMagnifier) as FrameworkElement;
  143. if (_magnifier != null)
  144. {
  145. _viewboxSize = new Size(29, 21);
  146. }
  147. _visualPreview = new VisualBrush(Canvas)
  148. {
  149. ViewboxUnits = BrushMappingMode.Absolute
  150. };
  151. SetValue(PreviewBrushPropertyKey, _visualPreview);
  152. _magnifier.Show();
  153. }
  154. protected override void OnPreviewKeyDown(KeyEventArgs e)
  155. {
  156. if (e.Key == Key.Escape) Close();
  157. if (IsDrawing)
  158. {
  159. switch (e.Key)
  160. {
  161. case Key.Left:
  162. {
  163. MoveTargetArea(MoveRect(_targetWindowRect, -1, rightFlag: -1));
  164. }
  165. break;
  166. case Key.Up:
  167. {
  168. MoveTargetArea(MoveRect(_targetWindowRect, bottomFlag: -1, topFlag: -1));
  169. }
  170. break;
  171. case Key.Right:
  172. {
  173. MoveTargetArea(MoveRect(_targetWindowRect, 1, rightFlag: 1));
  174. }
  175. break;
  176. case Key.Down:
  177. {
  178. MoveTargetArea(MoveRect(_targetWindowRect, bottomFlag: 1, topFlag: 1));
  179. }
  180. break;
  181. case Key.Enter:
  182. _saveScreenshot = true;
  183. Close();
  184. break;
  185. }
  186. }
  187. }
  188. protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) => _mousePointOld = e.GetPosition(this);
  189. protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e) => _magnifier.Collapse();
  190. protected override void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
  191. {
  192. _saveScreenshot = true;
  193. Close();
  194. }
  195. protected override void OnPreviewMouseMove(MouseEventArgs e)
  196. {
  197. if (e.LeftButton != MouseButtonState.Pressed)
  198. {
  199. UpdateStatus(e.GetPosition(TargetArea));
  200. return;
  201. }
  202. var newPoint = Mouse.GetPosition(this);
  203. var offsetX = (int) (newPoint.X - _mousePointOld.X);
  204. var offsetY = (int) (newPoint.Y - _mousePointOld.Y);
  205. if (IsDrawing)
  206. {
  207. if (_isOut) return;
  208. var rect = _targetWindowRect;
  209. if (_canDrag)
  210. {
  211. rect.Left += offsetX;
  212. rect.Top += offsetY;
  213. rect.Right += offsetX;
  214. rect.Bottom += offsetY;
  215. }
  216. else
  217. {
  218. var magnifierPos = new InteropValues.POINT((int) newPoint.X, (int) newPoint.Y);
  219. if (_flagArr[0] > 0)
  220. {
  221. _pointFloating.X += offsetX * _flagArr[0];
  222. magnifierPos.X = _pointFloating.X;
  223. }
  224. else if (_flagArr[2] > 0)
  225. {
  226. _pointFloating.X += offsetX * _flagArr[2];
  227. magnifierPos.X = _pointFloating.X - 1;
  228. }
  229. if (_flagArr[1] > 0)
  230. {
  231. _pointFloating.Y += offsetY * _flagArr[1];
  232. magnifierPos.Y = _pointFloating.Y;
  233. }
  234. else if (_flagArr[3] > 0)
  235. {
  236. _pointFloating.Y += offsetY * _flagArr[3];
  237. magnifierPos.Y = _pointFloating.Y - 1;
  238. }
  239. rect.Left = (int) Math.Min(_pointFixed.X, _pointFloating.X);
  240. rect.Top = (int) Math.Min(_pointFixed.Y, _pointFloating.Y);
  241. rect.Right = (int) Math.Max(_pointFixed.X, _pointFloating.X);
  242. rect.Bottom = (int) Math.Max(_pointFixed.Y, _pointFloating.Y);
  243. _magnifier.Show();
  244. MoveMagnifier(magnifierPos);
  245. }
  246. MoveTargetArea(rect);
  247. _mousePointOld = newPoint;
  248. }
  249. else if (IsSelecting)
  250. {
  251. var minX = (int) Math.Min(_mousePointOld.X, newPoint.X);
  252. var maxX = (int) Math.Max(_mousePointOld.X, newPoint.X);
  253. var minY = (int) Math.Min(_mousePointOld.Y, newPoint.Y);
  254. var maxY = (int) Math.Max(_mousePointOld.Y, newPoint.Y);
  255. MoveTargetArea(new InteropValues.RECT(minX, minY, maxX, maxY));
  256. }
  257. else if (!IsSelecting && offsetX > 0 && offsetY > 0)
  258. {
  259. IsSelecting = true;
  260. }
  261. }
  262. private void ScreenshotWindow_Closed(object sender, EventArgs e)
  263. {
  264. if (_saveScreenshot)
  265. {
  266. SaveScreenshot();
  267. }
  268. StopHooks();
  269. IsDrawing = false;
  270. Loaded -= ScreenshotWindow_Loaded;
  271. Closed -= ScreenshotWindow_Closed;
  272. }
  273. private void ScreenshotWindow_Loaded(object sender, RoutedEventArgs e)
  274. {
  275. _imageSource = GetDesktopSnapshot();
  276. var image = new Image
  277. {
  278. Source = _imageSource
  279. };
  280. RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.NearestNeighbor);
  281. Canvas.Children.Add(image);
  282. StartHooks();
  283. InteropMethods.GetCursorPos(out var point);
  284. MoveElement(point);
  285. MoveMagnifier(point);
  286. }
  287. private void UpdateStatus(Point point)
  288. {
  289. Cursor cursor;
  290. var leftAbs = Math.Abs(point.X);
  291. var topAbs = Math.Abs(point.Y);
  292. var rightAbs = Math.Abs(point.X - _targetWindowRect.Width);
  293. var downAbs = Math.Abs(point.Y - _targetWindowRect.Height);
  294. _canDrag = false;
  295. _isOut = false;
  296. _flagArr[0] = 0;
  297. _flagArr[1] = 0;
  298. _flagArr[2] = 0;
  299. _flagArr[3] = 0;
  300. if (leftAbs <= SnapLength)
  301. {
  302. if (topAbs > SnapLength)
  303. {
  304. if (downAbs > SnapLength)
  305. {
  306. // left
  307. cursor = Cursors.SizeWE;
  308. _pointFixed = new Point(_targetWindowRect.Right, _targetWindowRect.Top);
  309. _pointFloating = new InteropValues.POINT(_targetWindowRect.Left, _targetWindowRect.Bottom);
  310. _flagArr[0] = 1;
  311. }
  312. else
  313. {
  314. //left bottom
  315. cursor = Cursors.SizeNESW;
  316. _pointFixed = new Point(_targetWindowRect.Right, _targetWindowRect.Top);
  317. _pointFloating = new InteropValues.POINT(_targetWindowRect.Left, _targetWindowRect.Bottom);
  318. _flagArr[0] = 1;
  319. _flagArr[3] = 1;
  320. }
  321. }
  322. else
  323. {
  324. // left top
  325. cursor = Cursors.SizeNWSE;
  326. _pointFixed = new Point(_targetWindowRect.Right, _targetWindowRect.Bottom);
  327. _pointFloating = new InteropValues.POINT(_targetWindowRect.Left, _targetWindowRect.Top);
  328. _flagArr[0] = 1;
  329. _flagArr[1] = 1;
  330. }
  331. }
  332. else if (rightAbs > SnapLength)
  333. {
  334. if (topAbs > SnapLength)
  335. {
  336. if (downAbs > SnapLength)
  337. {
  338. if (TargetArea.IsMouseOver)
  339. {
  340. //drag
  341. cursor = Cursors.SizeAll;
  342. _canDrag = true;
  343. }
  344. else
  345. {
  346. //out
  347. cursor = Cursors.Arrow;
  348. _isOut = true;
  349. }
  350. }
  351. else
  352. {
  353. //bottom
  354. cursor = Cursors.SizeNS;
  355. _pointFixed = new Point(_targetWindowRect.Left, _targetWindowRect.Top);
  356. _pointFloating = new InteropValues.POINT(_targetWindowRect.Right, _targetWindowRect.Bottom);
  357. _flagArr[3] = 1;
  358. }
  359. }
  360. else
  361. {
  362. //top
  363. cursor = Cursors.SizeNS;
  364. _pointFixed = new Point(_targetWindowRect.Right, _targetWindowRect.Bottom);
  365. _pointFloating = new InteropValues.POINT(_targetWindowRect.Left, _targetWindowRect.Top);
  366. _flagArr[1] = 1;
  367. }
  368. }
  369. else if (rightAbs <= SnapLength)
  370. {
  371. if (topAbs > SnapLength)
  372. {
  373. if (downAbs > SnapLength)
  374. {
  375. //right
  376. cursor = Cursors.SizeWE;
  377. _pointFixed = new Point(_targetWindowRect.Left, _targetWindowRect.Bottom);
  378. _pointFloating = new InteropValues.POINT(_targetWindowRect.Right, _targetWindowRect.Top);
  379. _flagArr[2] = 1;
  380. }
  381. else
  382. {
  383. //right bottom
  384. cursor = Cursors.SizeNWSE;
  385. _pointFixed = new Point(_targetWindowRect.Left, _targetWindowRect.Top);
  386. _pointFloating = new InteropValues.POINT(_targetWindowRect.Right, _targetWindowRect.Bottom);
  387. _flagArr[2] = 1;
  388. _flagArr[3] = 1;
  389. }
  390. }
  391. else
  392. {
  393. // right top
  394. cursor = Cursors.SizeNESW;
  395. _pointFixed = new Point(_targetWindowRect.Left, _targetWindowRect.Bottom);
  396. _pointFloating = new InteropValues.POINT(_targetWindowRect.Right, _targetWindowRect.Top);
  397. _flagArr[1] = 1;
  398. _flagArr[2] = 1;
  399. }
  400. }
  401. else
  402. {
  403. //out
  404. cursor = Cursors.Arrow;
  405. _isOut = true;
  406. }
  407. TargetArea.Cursor = cursor;
  408. }
  409. private void StopHooks()
  410. {
  411. MouseHook.Stop();
  412. MouseHook.StatusChanged -= MouseHook_StatusChanged;
  413. }
  414. private void StartHooks()
  415. {
  416. MouseHook.Start();
  417. MouseHook.StatusChanged += MouseHook_StatusChanged;
  418. }
  419. private void MouseHook_StatusChanged(object sender, MouseHookEventArgs e)
  420. {
  421. switch (e.MessageType)
  422. {
  423. case MouseHookMessageType.MouseMove:
  424. MoveElement(e.Point);
  425. MoveMagnifier(e.Point);
  426. break;
  427. case MouseHookMessageType.LeftButtonDown:
  428. _receiveMoveMsg = false;
  429. _mousePointOld = new Point(e.Point.X, e.Point.Y);
  430. InteropMethods.EnableWindow(_screenshotWindowHandle, true);
  431. break;
  432. case MouseHookMessageType.RightButtonDown:
  433. if (!IsDrawing) Close();
  434. break;
  435. case MouseHookMessageType.LeftButtonUp:
  436. StopHooks();
  437. IsSelecting = false;
  438. IsDrawing = true;
  439. _magnifier.Collapse();
  440. break;
  441. }
  442. }
  443. private void SaveScreenshot()
  444. {
  445. var cb = new CroppedBitmap(_imageSource, new Int32Rect(_targetWindowRect.Left, _targetWindowRect.Top, _targetWindowRect.Width, _targetWindowRect.Height));
  446. _screenshot.OnSnapped(cb);
  447. Close();
  448. }
  449. private BitmapSource GetDesktopSnapshot()
  450. {
  451. _desktopWindowHandle = InteropMethods.GetDesktopWindow();
  452. var hdcSrc = InteropMethods.GetWindowDC(_desktopWindowHandle);
  453. var hdcDest = InteropMethods.CreateCompatibleDC(hdcSrc);
  454. InteropMethods.GetWindowRect(_desktopWindowHandle, out _desktopWindowRect);
  455. var desktopWindowWidth = _desktopWindowRect.Right - _desktopWindowRect.Left;
  456. var desktopWindowHeight = _desktopWindowRect.Bottom - _desktopWindowRect.Top;
  457. var hbitmap = InteropMethods.CreateCompatibleBitmap(hdcSrc, desktopWindowWidth, desktopWindowHeight);
  458. var hOld = InteropMethods.SelectObject(hdcDest, hbitmap);
  459. InteropMethods.BitBlt(hdcDest, 0, 0, desktopWindowWidth, desktopWindowHeight, hdcSrc, 0, 0, InteropValues.SRCCOPY);
  460. InteropMethods.SelectObject(hdcDest, hOld);
  461. InteropMethods.DeleteDC(hdcDest);
  462. InteropMethods.ReleaseDC(_desktopWindowHandle, hdcSrc);
  463. var status = InteropMethods.Gdip.GdipCreateBitmapFromHBITMAP(new HandleRef(null, hbitmap), new HandleRef(null, IntPtr.Zero), out var bitmap);
  464. if (status != InteropMethods.Gdip.Ok) throw InteropMethods.Gdip.StatusException(status);
  465. using var ms = new MemoryStream();
  466. status = InteropMethods.Gdip.GdipGetImageEncodersSize(out var numEncoders, out var size);
  467. if (status != InteropMethods.Gdip.Ok) throw InteropMethods.Gdip.StatusException(status);
  468. var memory = Marshal.AllocHGlobal(size);
  469. try
  470. {
  471. status = InteropMethods.Gdip.GdipGetImageEncoders(numEncoders, size, memory);
  472. if (status != InteropMethods.Gdip.Ok) throw InteropMethods.Gdip.StatusException(status);
  473. var codecInfo = ImageCodecInfo.ConvertFromMemory(memory, numEncoders).FirstOrDefault(item => item.FormatID.Equals(BmpGuid));
  474. if (codecInfo == null) throw new Exception("ImageCodecInfo is null");
  475. var encoderParamsMemory = IntPtr.Zero;
  476. try
  477. {
  478. var g = codecInfo.Clsid;
  479. status = InteropMethods.Gdip.GdipSaveImageToStream(new HandleRef(this, bitmap),
  480. new InteropValues.ComStreamFromDataStream(ms), ref g,
  481. new HandleRef(null, encoderParamsMemory));
  482. }
  483. finally
  484. {
  485. if (encoderParamsMemory != IntPtr.Zero)
  486. {
  487. Marshal.FreeHGlobal(encoderParamsMemory);
  488. }
  489. }
  490. if (status != InteropMethods.Gdip.Ok)
  491. {
  492. throw InteropMethods.Gdip.StatusException(status);
  493. }
  494. }
  495. finally
  496. {
  497. Marshal.FreeHGlobal(memory);
  498. }
  499. var bitmapImage = new BitmapImage();
  500. bitmapImage.BeginInit();
  501. bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
  502. bitmapImage.StreamSource = ms;
  503. bitmapImage.EndInit();
  504. bitmapImage.Freeze();
  505. return bitmapImage;
  506. }
  507. private void MoveElement(InteropValues.POINT point)
  508. {
  509. if (!_receiveMoveMsg) return;
  510. var mouseOverWindowHandle = InteropMethods.ChildWindowFromPointEx(_desktopWindowHandle,
  511. new InteropValues.POINT
  512. {
  513. X = point.X,
  514. Y = point.Y
  515. }, 1 | 2);
  516. if (mouseOverWindowHandle != _mouseOverWindowHandle && mouseOverWindowHandle != IntPtr.Zero)
  517. {
  518. _mouseOverWindowHandle = mouseOverWindowHandle;
  519. InteropMethods.GetWindowRect(_mouseOverWindowHandle, out var windowRect);
  520. MoveTargetArea(windowRect);
  521. }
  522. }
  523. private static InteropValues.RECT MoveRect(InteropValues.RECT rect, int leftFlag = 0, int topFlag = 0, int rightFlag = 0, int bottomFlag = 0)
  524. {
  525. var moveLength = Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)
  526. ? IntervalBigLength
  527. : IntervalLength;
  528. rect.Left += leftFlag * moveLength;
  529. rect.Top += topFlag * moveLength;
  530. rect.Right += rightFlag * moveLength;
  531. rect.Bottom += bottomFlag * moveLength;
  532. return rect;
  533. }
  534. private void MoveTargetArea(InteropValues.RECT rect)
  535. {
  536. if (rect.Left < 0)
  537. {
  538. rect.Right -= rect.Left;
  539. rect.Left = 0;
  540. }
  541. if (rect.Top < 0)
  542. {
  543. rect.Bottom -= rect.Top;
  544. rect.Top = 0;
  545. }
  546. if (rect.Right > _desktopWindowRect.Width)
  547. {
  548. rect.Left -= rect.Right - _desktopWindowRect.Width;
  549. rect.Right = _desktopWindowRect.Width;
  550. }
  551. if (rect.Bottom > _desktopWindowRect.Height)
  552. {
  553. rect.Top -= rect.Bottom - _desktopWindowRect.Height;
  554. rect.Bottom = _desktopWindowRect.Height;
  555. }
  556. rect.Left = Math.Max(0, rect.Left);
  557. rect.Top = Math.Max(0, rect.Top);
  558. var width = rect.Width;
  559. var height = rect.Height;
  560. var left = rect.Left;
  561. var top = rect.Top;
  562. TargetArea.Width = width;
  563. TargetArea.Height = height;
  564. TargetArea.Margin = new Thickness(left, top, 0, 0);
  565. _targetWindowRect = new InteropValues.RECT(left, top, left + width, top + height);
  566. Size = _targetWindowRect.Size;
  567. SizeStr = $"{_targetWindowRect.Width} x {_targetWindowRect.Height}";
  568. MoveMaskArea();
  569. }
  570. private void MoveMaskArea()
  571. {
  572. MaskAreaLeft.Width = TargetArea.Margin.Left;
  573. MaskAreaLeft.Height = _desktopWindowRect.Height;
  574. MaskAreaTop.Margin = new Thickness(TargetArea.Margin.Left, 0, 0, 0);
  575. MaskAreaTop.Width = TargetArea.Width;
  576. MaskAreaTop.Height = TargetArea.Margin.Top;
  577. MaskAreaRight.Margin = new Thickness(TargetArea.Width + TargetArea.Margin.Left, 0, 0, 0);
  578. MaskAreaRight.Width = _desktopWindowRect.Width - TargetArea.Margin.Left - TargetArea.Width;
  579. MaskAreaRight.Height = _desktopWindowRect.Height;
  580. MaskAreaBottom.Margin = new Thickness(TargetArea.Margin.Left, TargetArea.Height + TargetArea.Margin.Top, 0, 0);
  581. MaskAreaBottom.Width = TargetArea.Width;
  582. MaskAreaBottom.Height = _desktopWindowRect.Height - TargetArea.Height - TargetArea.Margin.Top;
  583. }
  584. private void MoveMagnifier(InteropValues.POINT point)
  585. {
  586. _magnifier.Margin = new Thickness(point.X + 4, point.Y + 26, 0, 0);
  587. _visualPreview.Viewbox = new Rect(new Point(point.X - _viewboxSize.Width / 2 + 0.5, point.Y - _viewboxSize.Height / 2 + 0.5), _viewboxSize);
  588. }
  589. }