commit e08f1a596d09207d5bb7adbb3cfd3632ce08b9a1 Author: kjqwer <2990346238@qq.com> Date: Tue Jul 1 20:36:16 2025 +0800 初始化 diff --git a/MediaControl.exe b/MediaControl.exe new file mode 100644 index 0000000..d2d5c7f Binary files /dev/null and b/MediaControl.exe differ diff --git a/MediaControl.ps1 b/MediaControl.ps1 new file mode 100644 index 0000000..9c85e48 --- /dev/null +++ b/MediaControl.ps1 @@ -0,0 +1,351 @@ +# 全局媒体控制脚本 - 播放/暂停 +# 使用Windows API发送系统级媒体控制命令 + +Add-Type -TypeDefinition @" +using System; +using System.Runtime.InteropServices; + +public class MediaControl { + [DllImport("user32.dll")] + public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); + + [DllImport("user32.dll")] + public static extern IntPtr FindWindow(string lpClassName, string lpWindowName); + + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32.dll")] + public static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); + + [DllImport("user32.dll")] + public static extern IntPtr GetDesktopWindow(); + + [DllImport("user32.dll")] + public static extern IntPtr GetShellWindow(); + + public const uint WM_APPCOMMAND = 0x0319; + public const uint APPCOMMAND_MEDIA_PLAY_PAUSE = 14; + public const uint APPCOMMAND_MEDIA_NEXTTRACK = 11; + public const uint APPCOMMAND_MEDIA_PREVIOUSTRACK = 12; + public const uint APPCOMMAND_MEDIA_STOP = 13; + + public static void SendMediaCommand(uint command) { + // 发送到桌面窗口,系统会自动路由到当前活跃的媒体播放器 + IntPtr desktopWindow = GetDesktopWindow(); + IntPtr shellWindow = GetShellWindow(); + + // 尝试多个目标窗口以确保命令被接收 + PostMessage(desktopWindow, WM_APPCOMMAND, IntPtr.Zero, (IntPtr)(command << 16)); + PostMessage(shellWindow, WM_APPCOMMAND, IntPtr.Zero, (IntPtr)(command << 16)); + + // 也尝试发送到当前前台窗口 + IntPtr foregroundWindow = GetForegroundWindow(); + if (foregroundWindow != IntPtr.Zero) { + PostMessage(foregroundWindow, WM_APPCOMMAND, IntPtr.Zero, (IntPtr)(command << 16)); + } + } +} +"@ + +function Test-MediaPlayerRunning { + <# + .SYNOPSIS + 检测媒体播放器是否正在运行 + + .DESCRIPTION + 检查常见的媒体播放器进程是否在运行 + + .PARAMETER Silent + 静默模式,不输出信息 + + .RETURNS + bool - 如果媒体播放器正在运行返回true,否则返回false + #> + param([bool]$Silent = $false) + + # 检查常见的媒体播放器进程 + $mediaPlayers = @( + "Music.UI", + "ZuneMusic", + "GrooveMusic", + "WindowsMediaPlayer", + "spotify", + "chrome", + "msedge", + "firefox", + "QQMusic", + "Microsoft.Media.Player" + ) + + foreach ($player in $mediaPlayers) { + $process = Get-Process -Name $player -ErrorAction SilentlyContinue + if ($process) { + if (-not $Silent) { + Write-Host "检测到媒体播放器进程: $player" -ForegroundColor Yellow + } + return $true + } + } + + # 辅助:检测窗口标题 + $found = Get-Process | Where-Object { $_.MainWindowTitle -eq "媒体播放器" } + if ($found) { + if (-not $Silent) { + Write-Host "检测到媒体播放器窗口" -ForegroundColor Yellow + } + return $true + } + + return $false +} + +function Start-MediaPlayer { + <# + .SYNOPSIS + 启动媒体播放器 + + .DESCRIPTION + 通过快捷方式启动Windows 11媒体播放器 + + .PARAMETER Silent + 静默模式,不输出信息 + #> + param([bool]$Silent = $false) + + $shortcutPath = "D:\1awd\快速使用\应用\mus.lnk" + + if (Test-Path $shortcutPath) { + try { + if (-not $Silent) { + Write-Host "正在启动媒体播放器..." -ForegroundColor Yellow + } + Start-Process $shortcutPath + if (-not $Silent) { + Write-Host "媒体播放器已启动" -ForegroundColor Green + } + + # 等待一下让播放器完全启动 + Start-Sleep -Seconds 2 + return $true + } + catch { + Write-Error "启动媒体播放器失败: $($_.Exception.Message)" + return $false + } + } + else { + Write-Error "找不到媒体播放器快捷方式: $shortcutPath" + return $false + } +} + +function Initialize-MediaPlayer { + <# + .SYNOPSIS + 确保媒体播放器正在运行 + + .DESCRIPTION + 检查媒体播放器是否运行,如果没有运行则启动它 + + .PARAMETER Silent + 静默模式,不输出信息 + #> + param([bool]$Silent = $false) + + if (-not (Test-MediaPlayerRunning -Silent $Silent)) { + if (-not $Silent) { + Write-Host "未检测到媒体播放器运行,正在启动..." -ForegroundColor Yellow + } + if (-not (Start-MediaPlayer -Silent $Silent)) { + if (-not $Silent) { + Write-Warning "无法启动媒体播放器,但将继续尝试发送媒体控制命令" + } + } + } +} + +function Send-PlayPause { + <# + .SYNOPSIS + 发送播放/暂停命令到当前活跃的媒体播放器 + + .DESCRIPTION + 使用Windows API发送系统级播放/暂停命令,适用于所有支持Windows Media Session的播放器 + + .PARAMETER Silent + 静默模式,不输出信息 + + .EXAMPLE + Send-PlayPause + #> + param([bool]$Silent = $false) + + try { + # 确保媒体播放器正在运行 + Initialize-MediaPlayer -Silent $Silent + + if (-not $Silent) { + Write-Host "发送播放/暂停命令..." -ForegroundColor Green + } + [MediaControl]::SendMediaCommand([MediaControl]::APPCOMMAND_MEDIA_PLAY_PAUSE) + if (-not $Silent) { + Write-Host "命令已发送!" -ForegroundColor Green + } + } + catch { + Write-Error "发送命令时出错: $($_.Exception.Message)" + } +} + +function Send-NextTrack { + <# + .SYNOPSIS + 发送下一首命令 + + .PARAMETER Silent + 静默模式,不输出信息 + + .EXAMPLE + Send-NextTrack + #> + param([bool]$Silent = $false) + + try { + # 确保媒体播放器正在运行 + Initialize-MediaPlayer -Silent $Silent + + if (-not $Silent) { + Write-Host "发送下一首命令..." -ForegroundColor Green + } + [MediaControl]::SendMediaCommand([MediaControl]::APPCOMMAND_MEDIA_NEXTTRACK) + if (-not $Silent) { + Write-Host "命令已发送!" -ForegroundColor Green + } + } + catch { + Write-Error "发送命令时出错: $($_.Exception.Message)" + } +} + +function Send-PreviousTrack { + <# + .SYNOPSIS + 发送上一首命令 + + .PARAMETER Silent + 静默模式,不输出信息 + + .EXAMPLE + Send-PreviousTrack + #> + param([bool]$Silent = $false) + + try { + # 确保媒体播放器正在运行 + Initialize-MediaPlayer -Silent $Silent + + if (-not $Silent) { + Write-Host "发送上一首命令..." -ForegroundColor Green + } + [MediaControl]::SendMediaCommand([MediaControl]::APPCOMMAND_MEDIA_PREVIOUSTRACK) + if (-not $Silent) { + Write-Host "命令已发送!" -ForegroundColor Green + } + } + catch { + Write-Error "发送命令时出错: $($_.Exception.Message)" + } +} + +function Send-Stop { + <# + .SYNOPSIS + 发送停止命令 + + .PARAMETER Silent + 静默模式,不输出信息 + + .EXAMPLE + Send-Stop + #> + param([bool]$Silent = $false) + + try { + # 确保媒体播放器正在运行 + Initialize-MediaPlayer -Silent $Silent + + if (-not $Silent) { + Write-Host "发送停止命令..." -ForegroundColor Green + } + [MediaControl]::SendMediaCommand([MediaControl]::APPCOMMAND_MEDIA_STOP) + if (-not $Silent) { + Write-Host "命令已发送!" -ForegroundColor Green + } + } + catch { + Write-Error "发送命令时出错: $($_.Exception.Message)" + } +} + +# 主程序逻辑 +function Main { + param( + [Parameter(Position=0)] + [ValidateSet("play", "pause", "playpause", "next", "prev", "stop", "help")] + [string]$Action = "playpause", + + [Parameter()] + [switch]$Silent + ) + + switch ($Action.ToLower()) { + "play" { Send-PlayPause -Silent $Silent } + "pause" { Send-PlayPause -Silent $Silent } + "playpause" { Send-PlayPause -Silent $Silent } + "next" { Send-NextTrack -Silent $Silent } + "prev" { Send-PreviousTrack -Silent $Silent } + "stop" { Send-Stop -Silent $Silent } + "help" { + Write-Host @" +全局媒体控制脚本 + +用法: + .\MediaControl.ps1 [命令] [-Silent] + +可用命令: + playpause - 播放/暂停 (默认) + play - 播放/暂停 + pause - 播放/暂停 + next - 下一首 + prev - 上一首 + stop - 停止 + help - 显示此帮助 + +参数: + -Silent - 静默模式,不显示输出信息 + +示例: + .\MediaControl.ps1 # 播放/暂停 + .\MediaControl.ps1 next # 下一首 + .\MediaControl.ps1 prev # 上一首 + .\MediaControl.ps1 stop # 停止 + .\MediaControl.ps1 -Silent # 静默播放/暂停 + +功能特性: + - 自动检测媒体播放器是否运行 + - 如果播放器未运行,自动启动Windows 11媒体播放器 + - 适用于所有支持Windows Media Session的播放器 + - 支持静默模式运行 + +注意: 此脚本适用于所有支持Windows Media Session的播放器 +"@ -ForegroundColor Cyan + } + } +} + +# 如果脚本被直接运行(不是被导入),则执行主程序 +if ($MyInvocation.InvocationName -ne '.') { + # 默认使用静默模式 + Main @args -Silent +} \ No newline at end of file diff --git a/OpenProcessDirectory.exe b/OpenProcessDirectory.exe new file mode 100644 index 0000000..a5ad8ea Binary files /dev/null and b/OpenProcessDirectory.exe differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..acb7a2e --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +# 工具集 + +简单的个人脚本集合,以后脚本都存入此处。 + +## 脚本说明 + +### MediaControl.ps1 +全局媒体控制脚本,可以控制任何支持 Windows Media Session 的播放器。 + +**功能:** +- 播放/暂停 +- 上一首/下一首 +- 停止播放 +- 自动启动媒体播放器 + +**用法:** +```powershell +.\MediaControl.ps1 # 播放/暂停 +.\MediaControl.ps1 next # 下一首 +.\MediaControl.ps1 prev # 上一首 +.\MediaControl.ps1 stop # 停止 +``` + +### open_process_directory.ps1 +快速打开当前活动窗口进程的工作目录(主要通过exe快捷键映射后使用)。 + +**功能:** +- 自动获取当前活动窗口的进程 +- 打开该进程的可执行文件所在目录 +- 智能跳过控制台/终端窗口 + +**用法:** +```powershell +.\open_process_directory.ps1 +``` + +## 编译版本 + +项目包含 PowerShell 脚本的编译版本(.exe),可以直接双击运行,但主要是通过快捷键映射之后使用。 + +## 编译工具 + +### 安装 ps2exe +```powershell +Install-Module -Name ps2exe -Force +``` + +### 编译脚本 +```powershell +# 编译 open_process_directory.ps1 +Invoke-ps2exe -InputFile "open_process_directory.ps1" -OutputFile "OpenProcessDirectory.exe" -RequireAdmin + +# 编译 MediaControl.ps1 +Invoke-ps2exe -InputFile "MediaControl.ps1" -OutputFile "MediaControl.exe" -RequireAdmin +``` + +编译后的 .exe 文件可以直接运行,无需 PowerShell 环境。 \ No newline at end of file diff --git a/open_process_directory.ps1 b/open_process_directory.ps1 new file mode 100644 index 0000000..756b5ab --- /dev/null +++ b/open_process_directory.ps1 @@ -0,0 +1,165 @@ +# 获取当前活动窗口的程序目录并在文件资源管理器中打开 +# 需要管理员权限才能获取某些系统进程的路径 + +Add-Type -TypeDefinition @" +using System; +using System.Runtime.InteropServices; +using System.Collections.Generic; + +public class Win32 { + [DllImport("user32.dll")] + public static extern IntPtr GetForegroundWindow(); + + [DllImport("user32.dll")] + public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); + + [DllImport("user32.dll")] + public static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd); + + [DllImport("user32.dll")] + public static extern bool IsWindow(IntPtr hWnd); + + [DllImport("user32.dll")] + public static extern bool IsWindowVisible(IntPtr hWnd); + + [DllImport("user32.dll")] + public static extern bool EnumWindows(EnumWindowsProc lpEnumFunc, IntPtr lParam); + + [DllImport("user32.dll")] + public static extern bool GetWindowText(IntPtr hWnd, System.Text.StringBuilder lpString, int nMaxCount); + + [DllImport("user32.dll")] + public static extern bool IsIconic(IntPtr hWnd); + + [DllImport("user32.dll")] + public static extern IntPtr GetShellWindow(); + + public delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam); + + public const uint GW_HWNDPREV = 3; + public const uint GW_HWNDNEXT = 2; +} +"@ + +# 全局变量存储窗口列表 +$script:windowList = @() + +# 枚举窗口的回调函数 +$enumWindowsCallback = { + param([IntPtr]$hWnd, [IntPtr]$lParam) + + if ([Win32]::IsWindow($hWnd) -and [Win32]::IsWindowVisible($hWnd) -and -not [Win32]::IsIconic($hWnd)) { + $title = New-Object System.Text.StringBuilder 256 + [Win32]::GetWindowText($hWnd, $title, 256) + + if ($title.ToString().Length -gt 0) { + $processId = 0 + [Win32]::GetWindowThreadProcessId($hWnd, [ref]$processId) + + if ($processId -gt 0) { + $windowInfo = @{ + Handle = $hWnd + ProcessId = $processId + Title = $title.ToString() + } + $script:windowList += $windowInfo + } + } + } + return $true +} + +try { + # 短暂延迟,确保获取到快捷键触发前的窗口 + Start-Sleep -Milliseconds 200 + + # 枚举所有可见窗口 + [Win32]::EnumWindows($enumWindowsCallback, [IntPtr]::Zero) + + # 获取当前活动窗口 + $foregroundWindow = [Win32]::GetForegroundWindow() + $foregroundProcessId = 0 + [Win32]::GetWindowThreadProcessId($foregroundWindow, [ref]$foregroundProcessId) + + # 找到合适的窗口 + $targetWindow = $null + $targetProcessId = 0 + + # 首先尝试找到非控制台/终端的前一个窗口 + foreach ($window in $script:windowList) { + if ($window.ProcessId -eq $foregroundProcessId) { + continue # 跳过当前活动窗口 + } + + try { + $process = Get-Process -Id $window.ProcessId -ErrorAction SilentlyContinue + if ($process) { + # 跳过控制台、终端、脚本相关进程 + if ($process.ProcessName -notin @("powershell", "cmd", "conhost", "WindowsTerminal", "wt") -and + $process.ProcessName -notlike "*OpenProcessDirectory*" -and + $process.ProcessName -notlike "*ps2exe*") { + + $targetWindow = $window.Handle + $targetProcessId = $window.ProcessId + break + } + } + } catch { + continue + } + } + + # 如果没找到合适的窗口,使用当前活动窗口 + if (-not $targetWindow) { + $targetWindow = $foregroundWindow + $targetProcessId = $foregroundProcessId + } + + if ($targetProcessId -eq 0) { + Write-Host "无法获取当前窗口的进程ID" -ForegroundColor Red + exit 1 + } + + # 获取进程信息 + $process = Get-Process -Id $targetProcessId -ErrorAction SilentlyContinue + + if (-not $process) { + Write-Host "无法获取进程信息 (PID: $targetProcessId)" -ForegroundColor Red + exit 1 + } + + # 获取进程的可执行文件路径 + $processPath = $process.MainModule.FileName + + if (-not $processPath) { + Write-Host "无法获取进程路径 (进程: $($process.ProcessName))" -ForegroundColor Red + exit 1 + } + + # 获取文件所在目录 + $directory = Split-Path -Parent $processPath + + Write-Host "当前活动窗口进程: $($process.ProcessName)" -ForegroundColor Green + Write-Host "进程路径: $processPath" -ForegroundColor Green + Write-Host "程序目录: $directory" -ForegroundColor Green + + # 检查目录是否存在 + if (Test-Path $directory) { + Write-Host "正在打开目录..." -ForegroundColor Yellow + # 在文件资源管理器中打开目录 + Start-Process "explorer.exe" -ArgumentList $directory + Write-Host "目录已打开!" -ForegroundColor Green + } else { + Write-Host "目录不存在: $directory" -ForegroundColor Red + exit 1 + } + +} catch { + Write-Host "发生错误: $($_.Exception.Message)" -ForegroundColor Red + Write-Host "可能需要管理员权限来获取某些系统进程的路径" -ForegroundColor Yellow + exit 1 +} + +# 等待用户按键后退出 +# Write-Host "`n按任意键退出..." -ForegroundColor Cyan +# $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") \ No newline at end of file