|
3 | 3 | using System.Diagnostics; |
4 | 4 | using System.Globalization; |
5 | 5 | using System.Runtime.InteropServices; |
| 6 | +using System.Threading; |
6 | 7 | using System.Windows; |
7 | 8 | using System.Windows.Interop; |
8 | 9 | using System.Windows.Media; |
|
13 | 14 | using Windows.Win32.Graphics.Dwm; |
14 | 15 | using Windows.Win32.UI.Input.KeyboardAndMouse; |
15 | 16 | using Windows.Win32.UI.WindowsAndMessaging; |
| 17 | +using WindowsInput; |
| 18 | +using WindowsInput.Native; |
16 | 19 | using Point = System.Windows.Point; |
17 | 20 |
|
18 | 21 | namespace Flow.Launcher.Infrastructure |
@@ -605,5 +608,86 @@ public static void OpenImeSettings() |
605 | 608 | } |
606 | 609 |
|
607 | 610 | #endregion |
| 611 | + |
| 612 | + #region Quick Switch |
| 613 | + |
| 614 | + // Edited from: https://github.com/idkidknow/Flow.Launcher.Plugin.DirQuickJump |
| 615 | + |
| 616 | + internal static bool DirJump(InputSimulator inputSimulator, string path, HWND dialogHandle, bool altD = true) |
| 617 | + { |
| 618 | + // Alt-D or Ctrl-L to focus on the path input box |
| 619 | + if (altD) |
| 620 | + { |
| 621 | + inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LMENU, VirtualKeyCode.VK_D); |
| 622 | + } |
| 623 | + else |
| 624 | + { |
| 625 | + inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LCONTROL, VirtualKeyCode.VK_L); |
| 626 | + } |
| 627 | + |
| 628 | + // Get the handle of the path input box and then set the text. |
| 629 | + // The window with class name "ComboBoxEx32" is not visible when the path input box is not with the keyboard focus. |
| 630 | + var controlHandle = PInvoke.FindWindowEx(dialogHandle, HWND.Null, "WorkerW", null); |
| 631 | + controlHandle = PInvoke.FindWindowEx(controlHandle, HWND.Null, "ReBarWindow32", null); |
| 632 | + controlHandle = PInvoke.FindWindowEx(controlHandle, HWND.Null, "Address Band Root", null); |
| 633 | + controlHandle = PInvoke.FindWindowEx(controlHandle, HWND.Null, "msctls_progress32", null); |
| 634 | + controlHandle = PInvoke.FindWindowEx(controlHandle, HWND.Null, "ComboBoxEx32", null); |
| 635 | + if (controlHandle == HWND.Null) |
| 636 | + { |
| 637 | + return DirJumpOnLegacyDialog(inputSimulator, path, dialogHandle); |
| 638 | + } |
| 639 | + |
| 640 | + var timeOut = !SpinWait.SpinUntil(() => |
| 641 | + { |
| 642 | + int style = PInvoke.GetWindowLong(controlHandle, WINDOW_LONG_PTR_INDEX.GWL_STYLE); |
| 643 | + return (style & (int)WINDOW_STYLE.WS_VISIBLE) != 0; |
| 644 | + }, 1000); |
| 645 | + if (timeOut) |
| 646 | + { |
| 647 | + return false; |
| 648 | + } |
| 649 | + |
| 650 | + var editHandle = PInvoke.FindWindowEx(controlHandle, HWND.Null, "ComboBox", null); |
| 651 | + editHandle = PInvoke.FindWindowEx(editHandle, HWND.Null, "Edit", null); |
| 652 | + if (editHandle == HWND.Null) |
| 653 | + { |
| 654 | + return false; |
| 655 | + } |
| 656 | + |
| 657 | + SetWindowText(editHandle, path); |
| 658 | + inputSimulator.Keyboard.KeyPress(VirtualKeyCode.RETURN); |
| 659 | + |
| 660 | + return true; |
| 661 | + } |
| 662 | + |
| 663 | + internal static bool DirJumpOnLegacyDialog(InputSimulator inputSimulator, string path, HWND dialogHandle) |
| 664 | + { |
| 665 | + // https://github.com/idkidknow/Flow.Launcher.Plugin.DirQuickJump/issues/1 |
| 666 | + var controlHandle = PInvoke.FindWindowEx(dialogHandle, HWND.Null, "ComboBoxEx32", null); |
| 667 | + controlHandle = PInvoke.FindWindowEx(controlHandle, HWND.Null, "ComboBox", null); |
| 668 | + controlHandle = PInvoke.FindWindowEx(controlHandle, HWND.Null, "Edit", null); |
| 669 | + if (controlHandle == HWND.Null) |
| 670 | + { |
| 671 | + return false; |
| 672 | + } |
| 673 | + |
| 674 | + SetWindowText(controlHandle, path); |
| 675 | + // Alt-O (equivalent to press the Open button) twice. In normal cases it suffices to press once, |
| 676 | + // but when the focus is on an irrelevant folder, that press once will just open the irrelevant one. |
| 677 | + inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LMENU, VirtualKeyCode.VK_O); |
| 678 | + inputSimulator.Keyboard.ModifiedKeyStroke(VirtualKeyCode.LMENU, VirtualKeyCode.VK_O); |
| 679 | + |
| 680 | + return true; |
| 681 | + } |
| 682 | + |
| 683 | + private static unsafe nint SetWindowText(HWND handle, string text) |
| 684 | + { |
| 685 | + fixed (char* textPtr = text + '\0') |
| 686 | + { |
| 687 | + return PInvoke.SendMessage(handle, PInvoke.WM_SETTEXT, 0, (nint)textPtr).Value; |
| 688 | + } |
| 689 | + } |
| 690 | + |
| 691 | + #endregion |
608 | 692 | } |
609 | 693 | } |
0 commit comments