simen-keyboard-listener 1.1.10 → 1.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -61,6 +61,7 @@ __export(index_exports, {
61
61
  getSystemContext: () => getSystemContext,
62
62
  isAppRunning: () => isAppRunning,
63
63
  isOsascriptAvailable: () => isOsascriptAvailable,
64
+ powershell: () => powershell_exports,
64
65
  readFileContent: () => readFileContent,
65
66
  readMultipleFiles: () => readMultipleFiles,
66
67
  setBlockSystemHotkeys: () => setBlockSystemHotkeys
@@ -68,7 +69,7 @@ __export(index_exports, {
68
69
  module.exports = __toCommonJS(index_exports);
69
70
  var path = __toESM(require("path"));
70
71
  var fs = __toESM(require("fs"));
71
- var import_node_child_process2 = require("child_process");
72
+ var import_node_child_process3 = require("child_process");
72
73
  var import_node_module = require("module");
73
74
  var import_url = require("url");
74
75
 
@@ -1407,10 +1408,888 @@ async function getSystemContext(options) {
1407
1408
  };
1408
1409
  }
1409
1410
 
1411
+ // src/powershell/index.ts
1412
+ var powershell_exports = {};
1413
+ __export(powershell_exports, {
1414
+ escapeForPowerShell: () => escapeForPowerShell,
1415
+ executeAndParse: () => executeAndParse2,
1416
+ executeMultilineAndParse: () => executeMultilineAndParse2,
1417
+ executePowerShell: () => executePowerShell,
1418
+ executePowerShellLines: () => executePowerShellLines,
1419
+ getAgentContext: () => getAgentContext2,
1420
+ getClipboardContent: () => getClipboardContent2,
1421
+ getClipboardText: () => getClipboardText2,
1422
+ getExplorerCurrentFolder: () => getExplorerCurrentFolder,
1423
+ getExplorerSelection: () => getExplorerSelection,
1424
+ getExplorerWindows: () => getExplorerWindows,
1425
+ getFrontmostApp: () => getFrontmostApp2,
1426
+ getSystemContext: () => getSystemContext2,
1427
+ isPowerShellAvailable: () => isPowerShellAvailable
1428
+ });
1429
+
1430
+ // src/powershell/executor.ts
1431
+ var import_node_child_process2 = require("child_process");
1432
+ var import_node_util2 = require("util");
1433
+ var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process2.execFile);
1434
+ var IS_WINDOWS = process.platform === "win32";
1435
+ var POWERSHELL_PATHS = [
1436
+ "pwsh.exe",
1437
+ // PowerShell Core (faster, recommended)
1438
+ "powershell.exe"
1439
+ // Windows PowerShell (legacy)
1440
+ ];
1441
+ var DEFAULT_TIMEOUT2 = 3e4;
1442
+ var cachedPowerShellPath = null;
1443
+ async function findPowerShell() {
1444
+ if (cachedPowerShellPath) {
1445
+ return cachedPowerShellPath;
1446
+ }
1447
+ for (const psPath of POWERSHELL_PATHS) {
1448
+ try {
1449
+ await execFileAsync2(psPath, ["-NoProfile", "-Command", "exit 0"], { timeout: 5e3 });
1450
+ cachedPowerShellPath = psPath;
1451
+ return psPath;
1452
+ } catch {
1453
+ }
1454
+ }
1455
+ return null;
1456
+ }
1457
+ function isPowerShellAvailable() {
1458
+ return IS_WINDOWS;
1459
+ }
1460
+ async function executePowerShell(script, options) {
1461
+ if (!IS_WINDOWS) {
1462
+ return {
1463
+ success: false,
1464
+ error: "PowerShell is only available on Windows"
1465
+ };
1466
+ }
1467
+ const psPath = await findPowerShell();
1468
+ if (!psPath) {
1469
+ return {
1470
+ success: false,
1471
+ error: "PowerShell not found. Please install PowerShell Core or Windows PowerShell."
1472
+ };
1473
+ }
1474
+ const timeout = options?.timeout ?? DEFAULT_TIMEOUT2;
1475
+ const startTime = Date.now();
1476
+ try {
1477
+ const { stdout, stderr } = await execFileAsync2(
1478
+ psPath,
1479
+ [
1480
+ "-NoProfile",
1481
+ // Don't load user profile (faster)
1482
+ "-NonInteractive",
1483
+ // Non-interactive mode
1484
+ "-ExecutionPolicy",
1485
+ "Bypass",
1486
+ // Bypass execution policy
1487
+ "-Command",
1488
+ script
1489
+ ],
1490
+ {
1491
+ timeout,
1492
+ // Set output encoding to UTF-8 to handle Chinese characters
1493
+ encoding: "utf8"
1494
+ }
1495
+ );
1496
+ const executionTime = Date.now() - startTime;
1497
+ if (stderr && stderr.trim() && !stdout) {
1498
+ return {
1499
+ success: false,
1500
+ error: stderr.trim(),
1501
+ executionTime
1502
+ };
1503
+ }
1504
+ return {
1505
+ success: true,
1506
+ data: stdout.trim(),
1507
+ executionTime
1508
+ };
1509
+ } catch (error) {
1510
+ const executionTime = Date.now() - startTime;
1511
+ const errorMessage = error instanceof Error ? error.message : String(error);
1512
+ return {
1513
+ success: false,
1514
+ error: errorMessage,
1515
+ executionTime
1516
+ };
1517
+ }
1518
+ }
1519
+ async function executePowerShellLines(lines, options) {
1520
+ const script = lines.join("; ");
1521
+ return executePowerShell(script, options);
1522
+ }
1523
+ async function executeAndParse2(script, parser, options) {
1524
+ const result = await executePowerShell(script, options);
1525
+ if (!result.success) {
1526
+ return {
1527
+ success: false,
1528
+ error: result.error,
1529
+ executionTime: result.executionTime
1530
+ };
1531
+ }
1532
+ try {
1533
+ const parsed = parser(result.data ?? "");
1534
+ return {
1535
+ success: true,
1536
+ data: parsed,
1537
+ executionTime: result.executionTime
1538
+ };
1539
+ } catch (parseError) {
1540
+ const errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
1541
+ return {
1542
+ success: false,
1543
+ error: `Failed to parse output: ${errorMessage}`,
1544
+ executionTime: result.executionTime
1545
+ };
1546
+ }
1547
+ }
1548
+ async function executeMultilineAndParse2(lines, parser, options) {
1549
+ const result = await executePowerShellLines(lines, options);
1550
+ if (!result.success) {
1551
+ return {
1552
+ success: false,
1553
+ error: result.error,
1554
+ executionTime: result.executionTime
1555
+ };
1556
+ }
1557
+ try {
1558
+ const parsed = parser(result.data ?? "");
1559
+ return {
1560
+ success: true,
1561
+ data: parsed,
1562
+ executionTime: result.executionTime
1563
+ };
1564
+ } catch (parseError) {
1565
+ const errorMessage = parseError instanceof Error ? parseError.message : String(parseError);
1566
+ return {
1567
+ success: false,
1568
+ error: `Failed to parse output: ${errorMessage}`,
1569
+ executionTime: result.executionTime
1570
+ };
1571
+ }
1572
+ }
1573
+ function escapeForPowerShell(str) {
1574
+ return str.replace(/`/g, "``").replace(/"/g, '`"').replace(/\$/g, "`$").replace(/\n/g, "`n").replace(/\r/g, "`r").replace(/\t/g, "`t");
1575
+ }
1576
+
1577
+ // src/powershell/scripts/batchContext.ts
1578
+ async function getAgentContext2(options) {
1579
+ const includeClipboard = options?.includeClipboard ?? true;
1580
+ const includeExplorerWindows = options?.includeExplorerWindows ?? true;
1581
+ const maxSelectedItems = options?.maxSelectedItems ?? 50;
1582
+ const script = `
1583
+ # Add required types
1584
+ try {
1585
+ Add-Type -AssemblyName System.Windows.Forms
1586
+ } catch {
1587
+ # Assembly may already be loaded, ignore error
1588
+ }
1589
+
1590
+ try {
1591
+ Add-Type @"
1592
+ using System;
1593
+ using System.Runtime.InteropServices;
1594
+ using System.Text;
1595
+
1596
+ public class Win32 {
1597
+ [DllImport("user32.dll")]
1598
+ public static extern IntPtr GetForegroundWindow();
1599
+
1600
+ [DllImport("user32.dll")]
1601
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
1602
+
1603
+ [DllImport("user32.dll")]
1604
+ public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId);
1605
+ }
1606
+ "@
1607
+ } catch {
1608
+ # Type may already be loaded, ignore error
1609
+ }
1610
+
1611
+ # Initialize result object
1612
+ $result = @{
1613
+ frontmostApp = $null
1614
+ explorerSelection = $null
1615
+ explorerCurrentFolder = $null
1616
+ explorerWindows = @()
1617
+ desktopPath = ""
1618
+ clipboard = @{
1619
+ text = $null
1620
+ hasFiles = $false
1621
+ filePaths = @()
1622
+ hasImage = $false
1623
+ }
1624
+ timestamp = (Get-Date -Format "o")
1625
+ }
1626
+
1627
+ # ============================================================================
1628
+ # 1. Get Frontmost Application
1629
+ # ============================================================================
1630
+ try {
1631
+ $hwnd = [Win32]::GetForegroundWindow()
1632
+ if ($hwnd -ne [IntPtr]::Zero) {
1633
+ $processId = 0
1634
+ [Win32]::GetWindowThreadProcessId($hwnd, [ref]$processId) | Out-Null
1635
+
1636
+ $process = Get-Process -Id $processId -ErrorAction SilentlyContinue
1637
+ if ($process) {
1638
+ $windowTitle = New-Object System.Text.StringBuilder 256
1639
+ [Win32]::GetWindowText($hwnd, $windowTitle, 256) | Out-Null
1640
+
1641
+ $processName = $process.ProcessName
1642
+ $path = ""
1643
+ try {
1644
+ $path = $process.Path
1645
+ if (-not $path) {
1646
+ $path = $process.MainModule.FileName
1647
+ }
1648
+ } catch {
1649
+ $path = ""
1650
+ }
1651
+
1652
+ $name = $process.MainWindowTitle
1653
+ if (-not $name -or $name -eq "") {
1654
+ $name = $processName
1655
+ }
1656
+
1657
+ $isExplorer = $processName -eq "explorer"
1658
+
1659
+ $result.frontmostApp = @{
1660
+ name = $name
1661
+ processName = $processName
1662
+ path = $path
1663
+ processId = $processId
1664
+ windowTitle = $windowTitle.ToString()
1665
+ isExplorer = $isExplorer
1666
+ }
1667
+ }
1668
+ }
1669
+ } catch {
1670
+ # Frontmost app detection failed
1671
+ }
1672
+
1673
+ # ============================================================================
1674
+ # 2. Get Explorer Context (if frontmost app is Explorer)
1675
+ # ============================================================================
1676
+ if ($result.frontmostApp -and $result.frontmostApp.isExplorer) {
1677
+ try {
1678
+ $shell = New-Object -ComObject Shell.Application
1679
+ $windows = $shell.Windows()
1680
+
1681
+ $activeHwnd = [Win32]::GetForegroundWindow()
1682
+ $selectedItems = @()
1683
+ $currentFolder = $null
1684
+ $explorerWindows = @()
1685
+ $foundActiveWindow = $false
1686
+
1687
+ foreach ($window in $windows) {
1688
+ if ($window.Name -eq "File Explorer" -or $window.FullName -like "*explorer.exe") {
1689
+ try {
1690
+ $path = $window.Document.Folder.Self.Path
1691
+ if ($path) {
1692
+ # Check if this is the active window
1693
+ $isActive = $false
1694
+ try {
1695
+ $hwnd = $window.HWND
1696
+ if ($hwnd -eq $activeHwnd.ToInt64()) {
1697
+ $isActive = $true
1698
+
1699
+ # Get current folder for active window
1700
+ $currentFolder = $path
1701
+
1702
+ # Get selected items for active window
1703
+ $items = $window.Document.SelectedItems()
1704
+ if ($items -and $items.Count -gt 0) {
1705
+ foreach ($item in $items) {
1706
+ if ($selectedItems.Count -ge ${maxSelectedItems}) {
1707
+ break
1708
+ }
1709
+
1710
+ $isFolder = $false
1711
+ try {
1712
+ $isFolder = $item.IsFolder
1713
+ } catch {
1714
+ try {
1715
+ if (Test-Path $item.Path -PathType Container) {
1716
+ $isFolder = $true
1717
+ }
1718
+ } catch {
1719
+ $isFolder = $false
1720
+ }
1721
+ }
1722
+
1723
+ $selectedItems += @{
1724
+ path = if ($item.Path) { $item.Path } else { "" }
1725
+ name = if ($item.Name) { $item.Name } else { "" }
1726
+ isFolder = $isFolder
1727
+ }
1728
+ }
1729
+ }
1730
+ }
1731
+ } catch {
1732
+ # HWND may not be accessible
1733
+ }
1734
+
1735
+ # Add to explorer windows list (if enabled)
1736
+ if (${includeExplorerWindows}) {
1737
+ $title = $window.LocationName
1738
+ if (-not $title) {
1739
+ $title = Split-Path $path -Leaf
1740
+ }
1741
+
1742
+ $explorerWindows += @{
1743
+ title = if ($title) { $title } else { "" }
1744
+ path = if ($path) { $path } else { "" }
1745
+ isActive = $isActive
1746
+ }
1747
+ }
1748
+ }
1749
+ } catch {
1750
+ # Window may not have a valid path
1751
+ }
1752
+ }
1753
+ }
1754
+
1755
+ # Set explorer selection
1756
+ if ($selectedItems.Count -gt 0) {
1757
+ $result.explorerSelection = @{
1758
+ items = $selectedItems
1759
+ count = $selectedItems.Count
1760
+ }
1761
+ }
1762
+
1763
+ # Set current folder
1764
+ $result.explorerCurrentFolder = $currentFolder
1765
+
1766
+ # Set explorer windows
1767
+ $result.explorerWindows = $explorerWindows
1768
+
1769
+ } catch {
1770
+ # Explorer context detection failed
1771
+ }
1772
+ }
1773
+
1774
+ # ============================================================================
1775
+ # 3. Get Desktop Path
1776
+ # ============================================================================
1777
+ try {
1778
+ $result.desktopPath = [Environment]::GetFolderPath("Desktop")
1779
+ } catch {
1780
+ $result.desktopPath = ""
1781
+ }
1782
+
1783
+ # ============================================================================
1784
+ # 4. Get Clipboard Content (if enabled)
1785
+ # ============================================================================
1786
+ if (${includeClipboard}) {
1787
+ try {
1788
+ $clipboardData = [System.Windows.Forms.Clipboard]::GetDataObject()
1789
+ if ($clipboardData) {
1790
+ # Check for text
1791
+ if ($clipboardData.GetDataPresent([System.Windows.Forms.DataFormats]::Text)) {
1792
+ $result.clipboard.text = $clipboardData.GetData([System.Windows.Forms.DataFormats]::Text)
1793
+ }
1794
+
1795
+ # Check for files
1796
+ if ($clipboardData.GetDataPresent([System.Windows.Forms.DataFormats]::FileDrop)) {
1797
+ $result.clipboard.hasFiles = $true
1798
+ $files = $clipboardData.GetData([System.Windows.Forms.DataFormats]::FileDrop)
1799
+ if ($files) {
1800
+ $result.clipboard.filePaths = @($files)
1801
+ }
1802
+ }
1803
+
1804
+ # Check for image
1805
+ if ($clipboardData.GetDataPresent([System.Windows.Forms.DataFormats]::Bitmap)) {
1806
+ $result.clipboard.hasImage = $true
1807
+ }
1808
+ }
1809
+ } catch {
1810
+ # Clipboard access failed
1811
+ }
1812
+ }
1813
+
1814
+ # ============================================================================
1815
+ # Output JSON
1816
+ # ============================================================================
1817
+ $result | ConvertTo-Json -Compress -Depth 4
1818
+ `;
1819
+ const result = await executeAndParse2(
1820
+ script,
1821
+ (output) => {
1822
+ if (!output) {
1823
+ throw new Error("No output from PowerShell script");
1824
+ }
1825
+ const parsed = JSON.parse(output);
1826
+ return {
1827
+ frontmostApp: parsed.frontmostApp || {
1828
+ name: "",
1829
+ processName: "",
1830
+ path: "",
1831
+ processId: 0,
1832
+ windowTitle: "",
1833
+ isExplorer: false
1834
+ },
1835
+ explorerSelection: parsed.explorerSelection || null,
1836
+ explorerCurrentFolder: parsed.explorerCurrentFolder || null,
1837
+ explorerWindows: parsed.explorerWindows || [],
1838
+ desktopPath: parsed.desktopPath || "",
1839
+ clipboard: {
1840
+ text: parsed.clipboard?.text || null,
1841
+ hasFiles: parsed.clipboard?.hasFiles || false,
1842
+ filePaths: parsed.clipboard?.filePaths || [],
1843
+ hasImage: parsed.clipboard?.hasImage || false
1844
+ },
1845
+ timestamp: parsed.timestamp || (/* @__PURE__ */ new Date()).toISOString()
1846
+ };
1847
+ },
1848
+ options
1849
+ );
1850
+ if (!result.success) {
1851
+ return null;
1852
+ }
1853
+ return result.data ?? null;
1854
+ }
1855
+
1856
+ // src/powershell/scripts/frontmostApp.ts
1857
+ async function getFrontmostApp2(options) {
1858
+ const script = `
1859
+ try {
1860
+ Add-Type @"
1861
+ using System;
1862
+ using System.Runtime.InteropServices;
1863
+ using System.Text;
1864
+
1865
+ public class Win32 {
1866
+ [DllImport("user32.dll")]
1867
+ public static extern IntPtr GetForegroundWindow();
1868
+
1869
+ [DllImport("user32.dll")]
1870
+ public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
1871
+
1872
+ [DllImport("user32.dll")]
1873
+ public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId);
1874
+ }
1875
+ "@
1876
+ } catch {
1877
+ # Type may already be loaded, ignore error
1878
+ }
1879
+
1880
+ $hwnd = [Win32]::GetForegroundWindow()
1881
+ if ($hwnd -eq [IntPtr]::Zero) {
1882
+ Write-Output "{}"
1883
+ exit
1884
+ }
1885
+
1886
+ $processId = 0
1887
+ [Win32]::GetWindowThreadProcessId($hwnd, [ref]$processId) | Out-Null
1888
+
1889
+ $process = Get-Process -Id $processId -ErrorAction SilentlyContinue
1890
+ if (-not $process) {
1891
+ Write-Output "{}"
1892
+ exit
1893
+ }
1894
+
1895
+ $windowTitle = New-Object System.Text.StringBuilder 256
1896
+ [Win32]::GetWindowText($hwnd, $windowTitle, 256) | Out-Null
1897
+
1898
+ $processName = $process.ProcessName
1899
+ $path = ""
1900
+ try {
1901
+ $path = $process.Path
1902
+ if (-not $path) {
1903
+ $path = $process.MainModule.FileName
1904
+ }
1905
+ } catch {
1906
+ $path = ""
1907
+ }
1908
+
1909
+ $name = $process.MainWindowTitle
1910
+ if (-not $name -or $name -eq "") {
1911
+ $name = $processName
1912
+ }
1913
+
1914
+ $isExplorer = ($processName -eq "explorer")
1915
+
1916
+ $result = @{
1917
+ name = if ($name) { $name } else { "" }
1918
+ processName = if ($processName) { $processName } else { "" }
1919
+ path = if ($path) { $path } else { "" }
1920
+ processId = $processId
1921
+ windowTitle = $windowTitle.ToString()
1922
+ isExplorer = $isExplorer
1923
+ }
1924
+
1925
+ $result | ConvertTo-Json -Compress
1926
+ `;
1927
+ const result = await executeAndParse2(
1928
+ script,
1929
+ (output) => {
1930
+ if (!output || output === "{}") {
1931
+ throw new Error("No frontmost window found");
1932
+ }
1933
+ return JSON.parse(output);
1934
+ },
1935
+ options
1936
+ );
1937
+ if (!result.success) {
1938
+ return null;
1939
+ }
1940
+ return result.data ?? null;
1941
+ }
1942
+
1943
+ // src/powershell/scripts/explorerSelection.ts
1944
+ async function getExplorerSelection(options) {
1945
+ const maxItems = 50;
1946
+ const script = `
1947
+ try {
1948
+ $shell = New-Object -ComObject Shell.Application
1949
+ $windows = $shell.Windows()
1950
+
1951
+ $selectedItems = @()
1952
+ $foundSelection = $false
1953
+
1954
+ foreach ($window in $windows) {
1955
+ if ($foundSelection) { break }
1956
+
1957
+ # Check if this is an Explorer window
1958
+ if ($window.Name -eq "File Explorer" -or $window.FullName -like "*explorer.exe") {
1959
+ try {
1960
+ $items = $window.Document.SelectedItems()
1961
+ if ($items -and $items.Count -gt 0) {
1962
+ foreach ($item in $items) {
1963
+ if ($selectedItems.Count -ge ${maxItems}) {
1964
+ break
1965
+ }
1966
+
1967
+ $isFolder = $false
1968
+ try {
1969
+ $isFolder = $item.IsFolder
1970
+ } catch {
1971
+ # If IsFolder fails, check if it's a directory
1972
+ try {
1973
+ if (Test-Path $item.Path -PathType Container) {
1974
+ $isFolder = $true
1975
+ }
1976
+ } catch {
1977
+ $isFolder = $false
1978
+ }
1979
+ }
1980
+
1981
+ $selectedItems += @{
1982
+ path = if ($item.Path) { $item.Path } else { "" }
1983
+ name = if ($item.Name) { $item.Name } else { "" }
1984
+ isFolder = $isFolder
1985
+ }
1986
+ }
1987
+ $foundSelection = $true
1988
+ }
1989
+ } catch {
1990
+ # Window may not support selection, continue to next window
1991
+ }
1992
+ }
1993
+ }
1994
+
1995
+ $result = @{
1996
+ items = $selectedItems
1997
+ count = $selectedItems.Count
1998
+ }
1999
+
2000
+ $result | ConvertTo-Json -Compress -Depth 3
2001
+ } catch {
2002
+ # COM object creation failed or other error
2003
+ Write-Output '{"items":[],"count":0}'
2004
+ }
2005
+ `;
2006
+ const result = await executeAndParse2(
2007
+ script,
2008
+ (output) => {
2009
+ if (!output) {
2010
+ return { items: [], count: 0 };
2011
+ }
2012
+ const parsed = JSON.parse(output);
2013
+ return {
2014
+ items: parsed.items || [],
2015
+ count: parsed.count || 0
2016
+ };
2017
+ },
2018
+ options
2019
+ );
2020
+ if (!result.success) {
2021
+ return null;
2022
+ }
2023
+ const data = result.data;
2024
+ if (!data || data.count === 0) {
2025
+ return null;
2026
+ }
2027
+ return data;
2028
+ }
2029
+ async function getExplorerCurrentFolder(options) {
2030
+ const script = `
2031
+ $shell = New-Object -ComObject Shell.Application
2032
+ $windows = $shell.Windows()
2033
+
2034
+ foreach ($window in $windows) {
2035
+ # Check if this is an Explorer window
2036
+ if ($window.Name -eq "File Explorer" -or $window.FullName -like "*explorer.exe") {
2037
+ try {
2038
+ $path = $window.Document.Folder.Self.Path
2039
+ if ($path) {
2040
+ Write-Output $path
2041
+ exit
2042
+ }
2043
+ } catch {
2044
+ # Window may not have a valid path
2045
+ }
2046
+ }
2047
+ }
2048
+ `;
2049
+ const result = await executeAndParse2(
2050
+ script,
2051
+ (output) => output || null,
2052
+ options
2053
+ );
2054
+ if (!result.success) {
2055
+ return null;
2056
+ }
2057
+ return result.data ?? null;
2058
+ }
2059
+
2060
+ // src/powershell/scripts/explorerWindows.ts
2061
+ async function getExplorerWindows(options) {
2062
+ const script = `
2063
+ try {
2064
+ Add-Type @"
2065
+ using System;
2066
+ using System.Runtime.InteropServices;
2067
+
2068
+ public class Win32 {
2069
+ [DllImport("user32.dll")]
2070
+ public static extern IntPtr GetForegroundWindow();
2071
+ }
2072
+ "@
2073
+ } catch {
2074
+ # Type may already be loaded, ignore error
2075
+ }
2076
+
2077
+ try {
2078
+ $shell = New-Object -ComObject Shell.Application
2079
+ $windows = $shell.Windows()
2080
+
2081
+ $activeHwnd = [Win32]::GetForegroundWindow()
2082
+
2083
+ $explorerWindows = @()
2084
+
2085
+ foreach ($window in $windows) {
2086
+ # Check if this is an Explorer window
2087
+ if ($window.Name -eq "File Explorer" -or $window.FullName -like "*explorer.exe") {
2088
+ try {
2089
+ $path = $window.Document.Folder.Self.Path
2090
+ if ($path) {
2091
+ $title = $window.LocationName
2092
+ if (-not $title) {
2093
+ $title = Split-Path $path -Leaf
2094
+ }
2095
+
2096
+ # Check if this is the active window
2097
+ $isActive = $false
2098
+ try {
2099
+ $hwnd = $window.HWND
2100
+ if ($hwnd -eq $activeHwnd.ToInt64()) {
2101
+ $isActive = $true
2102
+ }
2103
+ } catch {
2104
+ # HWND may not be accessible
2105
+ }
2106
+
2107
+ $explorerWindows += @{
2108
+ title = if ($title) { $title } else { "" }
2109
+ path = if ($path) { $path } else { "" }
2110
+ isActive = $isActive
2111
+ }
2112
+ }
2113
+ } catch {
2114
+ # Window may not have a valid path, continue to next window
2115
+ }
2116
+ }
2117
+ }
2118
+
2119
+ $result = @{
2120
+ windows = $explorerWindows
2121
+ count = $explorerWindows.Count
2122
+ }
2123
+
2124
+ $result | ConvertTo-Json -Compress -Depth 3
2125
+ } catch {
2126
+ # COM object creation failed or other error
2127
+ Write-Output '{"windows":[],"count":0}'
2128
+ }
2129
+ `;
2130
+ const result = await executeAndParse2(
2131
+ script,
2132
+ (output) => {
2133
+ if (!output) {
2134
+ return { windows: [], count: 0 };
2135
+ }
2136
+ const parsed = JSON.parse(output);
2137
+ return {
2138
+ windows: parsed.windows || [],
2139
+ count: parsed.count || 0
2140
+ };
2141
+ },
2142
+ options
2143
+ );
2144
+ if (!result.success) {
2145
+ return null;
2146
+ }
2147
+ return result.data ?? null;
2148
+ }
2149
+
2150
+ // src/powershell/scripts/clipboard.ts
2151
+ async function getClipboardText2(options) {
2152
+ const script = `
2153
+ try {
2154
+ $text = Get-Clipboard -Format Text -ErrorAction SilentlyContinue
2155
+ if ($text) {
2156
+ Write-Output $text
2157
+ }
2158
+ } catch {
2159
+ # Clipboard may be empty or contain non-text data
2160
+ }
2161
+ `;
2162
+ const result = await executeAndParse2(
2163
+ script,
2164
+ (output) => output || null,
2165
+ options
2166
+ );
2167
+ if (!result.success) {
2168
+ return null;
2169
+ }
2170
+ return result.data ?? null;
2171
+ }
2172
+ async function getClipboardContent2(options) {
2173
+ const script = `
2174
+ try {
2175
+ Add-Type -AssemblyName System.Windows.Forms
2176
+ } catch {
2177
+ # Assembly may already be loaded, ignore error
2178
+ }
2179
+
2180
+ try {
2181
+ $clipboard = [System.Windows.Forms.Clipboard]::GetDataObject()
2182
+ if (-not $clipboard) {
2183
+ Write-Output '{"text":null,"hasFiles":false,"filePaths":[],"hasImage":false}'
2184
+ exit
2185
+ }
2186
+
2187
+ $text = $null
2188
+ $hasFiles = $false
2189
+ $filePaths = @()
2190
+ $hasImage = $false
2191
+
2192
+ # Check for text
2193
+ try {
2194
+ if ($clipboard.GetDataPresent([System.Windows.Forms.DataFormats]::Text)) {
2195
+ $text = $clipboard.GetData([System.Windows.Forms.DataFormats]::Text)
2196
+ }
2197
+ } catch {
2198
+ # Text access failed, continue
2199
+ }
2200
+
2201
+ # Check for files
2202
+ try {
2203
+ if ($clipboard.GetDataPresent([System.Windows.Forms.DataFormats]::FileDrop)) {
2204
+ $hasFiles = $true
2205
+ $files = $clipboard.GetData([System.Windows.Forms.DataFormats]::FileDrop)
2206
+ if ($files) {
2207
+ $filePaths = @($files)
2208
+ }
2209
+ }
2210
+ } catch {
2211
+ # File access failed, continue
2212
+ }
2213
+
2214
+ # Check for image
2215
+ try {
2216
+ if ($clipboard.GetDataPresent([System.Windows.Forms.DataFormats]::Bitmap)) {
2217
+ $hasImage = $true
2218
+ }
2219
+ } catch {
2220
+ # Image check failed, continue
2221
+ }
2222
+
2223
+ $result = @{
2224
+ text = $text
2225
+ hasFiles = $hasFiles
2226
+ filePaths = $filePaths
2227
+ hasImage = $hasImage
2228
+ }
2229
+
2230
+ $result | ConvertTo-Json -Compress
2231
+ } catch {
2232
+ # Clipboard access completely failed
2233
+ Write-Output '{"text":null,"hasFiles":false,"filePaths":[],"hasImage":false}'
2234
+ }
2235
+ `;
2236
+ const result = await executeAndParse2(
2237
+ script,
2238
+ (output) => {
2239
+ if (!output || output === "{}") {
2240
+ return {
2241
+ text: null,
2242
+ hasFiles: false,
2243
+ filePaths: [],
2244
+ hasImage: false
2245
+ };
2246
+ }
2247
+ const parsed = JSON.parse(output);
2248
+ return {
2249
+ text: parsed.text || null,
2250
+ hasFiles: parsed.hasFiles || false,
2251
+ filePaths: parsed.filePaths || [],
2252
+ hasImage: parsed.hasImage || false
2253
+ };
2254
+ },
2255
+ options
2256
+ );
2257
+ if (!result.success) {
2258
+ return null;
2259
+ }
2260
+ return result.data ?? null;
2261
+ }
2262
+
2263
+ // src/powershell/index.ts
2264
+ async function getSystemContext2(options) {
2265
+ if (!isPowerShellAvailable()) {
2266
+ return null;
2267
+ }
2268
+ const frontmostApp = await getFrontmostApp2(options);
2269
+ if (!frontmostApp) {
2270
+ return null;
2271
+ }
2272
+ let explorerSelection = null;
2273
+ let explorerCurrentFolder = null;
2274
+ if (frontmostApp.isExplorer) {
2275
+ [explorerSelection, explorerCurrentFolder] = await Promise.all([
2276
+ getExplorerSelection(options),
2277
+ getExplorerCurrentFolder(options)
2278
+ ]);
2279
+ }
2280
+ const clipboard = await getClipboardContent2(options);
2281
+ return {
2282
+ frontmostApp,
2283
+ explorerSelection,
2284
+ explorerCurrentFolder,
2285
+ clipboard: clipboard ?? { text: null, hasFiles: false, filePaths: [], hasImage: false }
2286
+ };
2287
+ }
2288
+
1410
2289
  // src/index.ts
1411
2290
  var import_meta = {};
1412
2291
  var IS_MACOS2 = process.platform === "darwin";
1413
- var IS_WINDOWS = process.platform === "win32";
2292
+ var IS_WINDOWS2 = process.platform === "win32";
1414
2293
  var PLATFORM_PACKAGES = {
1415
2294
  "darwin-arm64": "@simen-keyboard-listener/darwin-arm64",
1416
2295
  "win32-x64": "@simen-keyboard-listener/win32-x64"
@@ -1563,7 +2442,7 @@ var NativeKeyboardListener = class _NativeKeyboardListener {
1563
2442
  }
1564
2443
  };
1565
2444
  function getGlobalKeyboardListener() {
1566
- if (!IS_MACOS2 && !IS_WINDOWS) {
2445
+ if (!IS_MACOS2 && !IS_WINDOWS2) {
1567
2446
  throw new Error(`Unsupported platform for global keyboard listener: ${process.platform}`);
1568
2447
  }
1569
2448
  return NativeKeyboardListener.getInstance();
@@ -1572,7 +2451,7 @@ function createGlobalKeyboardListener() {
1572
2451
  return getGlobalKeyboardListener();
1573
2452
  }
1574
2453
  function checkKeyboardPermission() {
1575
- if (!IS_MACOS2 && !IS_WINDOWS) {
2454
+ if (!IS_MACOS2 && !IS_WINDOWS2) {
1576
2455
  return false;
1577
2456
  }
1578
2457
  try {
@@ -1593,7 +2472,7 @@ function openMacAccessibilitySettings() {
1593
2472
  }
1594
2473
  lastMacAccessibilitySettingsOpenTs = now;
1595
2474
  try {
1596
- (0, import_node_child_process2.execFileSync)("open", ["x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"], {
2475
+ (0, import_node_child_process3.execFileSync)("open", ["x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"], {
1597
2476
  stdio: "ignore"
1598
2477
  });
1599
2478
  } catch {
@@ -1658,7 +2537,7 @@ function getSelectedTextSmart() {
1658
2537
  }
1659
2538
  }
1660
2539
  function setBlockSystemHotkeys(block) {
1661
- if (!IS_WINDOWS) {
2540
+ if (!IS_WINDOWS2) {
1662
2541
  return;
1663
2542
  }
1664
2543
  try {
@@ -1700,6 +2579,7 @@ function setBlockSystemHotkeys(block) {
1700
2579
  getSystemContext,
1701
2580
  isAppRunning,
1702
2581
  isOsascriptAvailable,
2582
+ powershell,
1703
2583
  readFileContent,
1704
2584
  readMultipleFiles,
1705
2585
  setBlockSystemHotkeys