Я разрабатываю приложение, которое работает в фоновом режиме, и когда происходит конкретное событие, музыка, которую играют медиаплееры, должна быть остановлена.Как остановить музыку в системе? (VK_MEDIA_STOP не работает повсюду)
основных музыкальных плееров, таких как Spotify и поддержка Windows Media Player управляется с помощью специальных клавиш клавиатуры «Стоп», «Пуск», «Следующий трек» и т.д.
Так что я хотел бы использовать эту функцию, чтобы контролировать все запускать медиаплееров и говорить им прекратить играть.
Медиаплееры, не реализующие эти ключи, не будут нацелены на мое приложение; они будут несовместимы.
В настоящее время, я следующая функция, которая работает до сих пор:
procedure StopMusic;
const
KEYEVENTF_KEYDOWN = 0;
KEYEVENTF_KEYUP = 2;
begin
keybd_event(VK_MEDIA_STOP, 0, KEYEVENTF_KEYDOWN, 0);
keybd_event(VK_MEDIA_STOP, 0, KEYEVENTF_KEYUP, 0);
end;
Я не знаю точно, как работает этот механизм. Операционная система отправляет сообщения всем приложениям, независимо от того, в каком приложении я сейчас работаю, но только при вызове keybd_event. (SendMessage WM_KEYDOWN не будет работать)
Проблема, с которой я сталкиваюсь, заключается в том, что некоторые приложения, такие как OwnCloud, проглатывают эти клавиши, если их окно сфокусировано (также при нажатии на реальной клавиатуре). Я свяжусь с ними, чтобы сообщить об этой ошибке. Но в то же время я хочу попытаться сделать обходной путь для этого.
Моя идея для решения проблемы, чтобы быстро переключить фокус в другое окно, а затем выполнить виртуальную клавишу нажмите, а затем переключиться обратно в окно, которое было активным:
procedure StopMusic;
const
KEYEVENTF_KEYDOWN = 0;
KEYEVENTF_KEYUP = 2;
var
hBak: HWND;
begin
hBak := GetForegroundWindow();
try
SetForegroundWindow(GetDesktopWindow());
keybd_event(VK_MEDIA_STOP, 0, KEYEVENTF_KEYDOWN, 0);
keybd_event(VK_MEDIA_STOP, 0, KEYEVENTF_KEYUP, 0);
finally
SetForegroundWindow(hBak);
end;
end;
Но эта функция не работает вообще. Он не имеет никакого эффекта, независимо от того, какое Окно в настоящее время сосредоточено. Я думаю, это потому, что Desktop не может получить фокус.
Поэтому мой вопрос:
- Какой обходной путь я могу сделать? (Помимо запроса OwnCloud исправить эту ошибку)
- Или существует ли совершенно другая стратегия/API, позволяющая медиаплеерам перестать играть?
UPDATE: Решение 1 (Dirty)
Первый обходной путь, чтобы переключить фокус на панель задач. Но, очевидно, это грязное решение, поскольку это деталь реализации Windows.
procedure StopMusic;
const
KEYEVENTF_KEYDOWN = 0;
KEYEVENTF_KEYUP = 2;
var
hBak: HWND;
begin
hBak := GetForegroundWindow();
try
SetForegroundWindow(FindWindow('Shell_TrayWnd', nil));
keybd_event(VK_MEDIA_STOP, 0, KEYEVENTF_KEYDOWN, 0);
keybd_event(VK_MEDIA_STOP, 0, KEYEVENTF_KEYUP, 0);
finally
SetForegroundWindow(hBak);
end;
end;
UPDATE: Решение 2 (Dirty)
Это решение также работает. Это не жесткая цепочка, такая как Shell_TrayWnd, но все еще используется вызов недокументированного API.
function TaskmanWindow: HWND;
type
TGetTaskmanWindow = function(): HWND; stdcall;
var
hUser32: THandle;
GetTaskmanWindow: TGetTaskmanWindow;
begin
Result := 0;
hUser32 := GetModuleHandle('user32.dll');
if (hUser32 > 0) then
begin
@GetTaskmanWindow := GetProcAddress(hUser32, 'GetTaskmanWindow'); // Undocumented
if Assigned(GetTaskmanWindow) then
begin
Result := GetTaskmanWindow;
end;
end;
end;
procedure StopMusic;
const
KEYEVENTF_KEYDOWN = 0;
KEYEVENTF_KEYUP = 2;
var
hBak: HWND;
begin
hBak := GetForegroundWindow();
try
SetForegroundWindow(TaskmanWindow);
keybd_event(VK_MEDIA_STOP, 0, KEYEVENTF_KEYDOWN, 0);
keybd_event(VK_MEDIA_STOP, 0, KEYEVENTF_KEYUP, 0);
finally
SetForegroundWindow(hBak);
end;
end;
UPDATE: Решение 3 (Хорошо)
Чистое решение проблемы заключается в том, чтобы отправить AppCommand ко всем приложениям
procedure StopMusic;
begin
SendMessage(HWND_BROADCAST, WM_APPCOMMAND, 0, MAKELONG(0, APPCOMMAND_MEDIA_STOP));
end;
UPDATE: отчет об ошибке
Друг с учетной записью github отправил the bugreport для меня.
AutoHotKey выполнит это. Однако никогда не используйте keybd_event. Прочтите его документацию, чтобы узнать, почему нет. –
Это по усмотрению приложения, следует ли соблюдать ключи или нет. Если он не отвечает на настоящую клавиатуру, когда она находится на переднем плане, это не приведет к ее созданию. –
@SertacAkyuz Да; поэтому я хотел переключиться на окно, где я знаю, что он принимает ключи. –