- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有一个没有音乐键的键盘,用于调高和调低我 PC 中音乐的音量、播放、停止等。不懂就this是我的键盘和this不是。
我想在 Windows 和 Delphi 或 C# 中实现键盘 Hook 以在我的键盘中创建音量功能,但我不知道如何通过代码调高和调低音量。我正在尝试 this和 this示例,但没有用(顺便说一句,全部在 Delphi 中)。
你知道怎么用代码调高音量和调低音量吗?
最佳答案
Delphi 代码如下。
我的 keyhook 向我的主窗体发送一条消息,其中包含 LParam 中的 key VK 代码,
procedure TmainFrm.keyHook(var msg: TMessage);
begin
case msg.LParam of
VK_VOLUME_UP : g_mixer.volume := g_mixer.volume + 2048;
VK_VOLUME_DOWN: g_mixer.volume := g_mixer.volume - 2048;
VK_VOLUME_MUTE: g_mixer.muted := not g_mixer.muted;
end;
end;
音量范围是0 .. 65535;带外值会被静默更正。
-
unit Mixer;
interface
type
Tmixer = class
protected
function getMute: boolean; virtual; abstract;
function getVolume: integer; virtual; abstract;
procedure setVolume(Value: integer); virtual; abstract;
procedure setMute(Value: boolean); virtual; abstract;
public
property volume: integer read getVolume write setVolume;
property muted: boolean read getMute write setMute;
end;
function g_mixer: Tmixer;
implementation
uses
Windows, MMSystem, MMDevApi_tlb, ComObj, ActiveX, SysUtils;
// ---------------------------------------------------------------------------
type
TxpMixer = class(Tmixer)
private
Fmxct: integer;
Fmixer: HMIXER;
procedure chk(r: MMRESULT);
protected
function getMute: boolean; override;
function getVolume: integer; override;
procedure setVolume(Value: integer); override;
procedure setMute(Value: boolean); override;
public
constructor Create;
destructor Destroy; override;
end;
TvistaMixer = class(Tmixer)
private
FmmDev: IMMDevice;
FmmDevEnum: IMMDeviceEnumerator;
FmmEndpoint: IMMAudioEndpointVolume;
protected
function getMute: boolean; override;
function getVolume: integer; override;
procedure setVolume(Value: integer); override;
procedure setMute(Value: boolean); override;
public
constructor Create;
end;
// ---------------------------------------------------------------------------
var
_g_mixer: Tmixer;
function g_mixer: Tmixer;
var
VerInfo: TOSVersioninfo;
begin
if (_g_mixer = nil) then
begin
VerInfo.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
GetVersionEx(VerInfo);
if (VerInfo.dwMajorVersion >= 6) then
_g_mixer := TvistaMixer.Create
else
_g_mixer := TxpMixer.Create;
end;
result := _g_mixer;
end;
// ---------------------------------------------------------------------------
{ TxpMixer }
procedure TxpMixer.chk(r: MMRESULT);
var
s: string;
begin
if (r = MMSYSERR_NOERROR) then
exit;
setLength(s, MMSystem.MAXERRORLENGTH + 1);
waveOutGetErrorText(r, @s[1], MMSystem.MAXERRORLENGTH);
raise Exception.Create(StrPas(pChar(s)));
end;
// ---------------------------------------------------------------------------
constructor TxpMixer.Create;
begin
Fmxct := MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
chk(mixerOpen(@Fmixer, 0, 0, 0, 0));
end;
// ---------------------------------------------------------------------------
destructor TxpMixer.Destroy;
begin
if (Fmixer <> 0) then
mixerClose(Fmixer);
inherited;
end;
// ---------------------------------------------------------------------------
function TxpMixer.getMute: boolean;
var
MasterMute: TMixerControl;
Details: TMixerControlDetails;
BoolDetails: TMixerControlDetailsBoolean;
Line: TMixerLine;
Controls: TMixerLineControls;
begin
ZeroMemory(@Line, SizeOf(Line));
Line.cbStruct := SizeOf(Line);
Line.dwComponentType := Fmxct;
chk(mixerGetLineInfo(0, @Line, MIXER_GETLINEINFOF_COMPONENTTYPE));
ZeroMemory(@Controls, SizeOf(Controls));
Controls.cbStruct := SizeOf(Controls);
Controls.dwLineID := Line.dwLineID;
Controls.cControls := 1;
Controls.dwControlType := MIXERCONTROL_CONTROLTYPE_MUTE;
Controls.cbmxctrl := SizeOf(MasterMute);
Controls.pamxctrl := @MasterMute;
chk(mixerGetLineControls(0, @Controls, MIXER_GETLINECONTROLSF_ONEBYTYPE));
Details.cbStruct := SizeOf(Details);
Details.dwControlID := MasterMute.dwControlID;
Details.cChannels := 1;
Details.cMultipleItems := 0;
Details.cbDetails := SizeOf(BoolDetails);
Details.paDetails := @BoolDetails;
chk(mixerGetControlDetails(0, @Details, MIXER_GETCONTROLDETAILSF_VALUE));
result := BoolDetails.fValue <> 0;
end;
// ---------------------------------------------------------------------------
function TxpMixer.getVolume: integer;
var
Line: TMixerLine;
Controls: TMixerLineControls;
MasterVolume: TMixerControl;
Details: TMixerControlDetails;
UnsignedDetails: TMixerControlDetailsUnsigned;
begin
ZeroMemory(@Line, SizeOf(Line));
Line.cbStruct := SizeOf(Line);
Line.dwComponentType := Fmxct;
chk(mixerGetLineInfo(Fmixer, @Line, MIXER_GETLINEINFOF_COMPONENTTYPE));
ZeroMemory(@Controls, SizeOf(Controls));
Controls.cbStruct := SizeOf(Controls);
Controls.dwLineID := Line.dwLineID;
Controls.cControls := 1;
Controls.dwControlType := MIXERCONTROL_CONTROLTYPE_VOLUME;
Controls.cbmxctrl := SizeOf(MasterVolume);
Controls.pamxctrl := @MasterVolume;
chk(mixerGetLineControls(Fmixer, @Controls, MIXER_GETLINECONTROLSF_ONEBYTYPE));
details.cbStruct := SizeOf(Details);
details.dwControlID := MasterVolume.dwControlID;
details.cChannels := 1;
details.cMultipleItems := 0;
details.cbDetails := SizeOf(UnsignedDetails);
details.paDetails := @UnsignedDetails;
chk(mixerGetControlDetails(Fmixer, @Details, MIXER_GETCONTROLDETAILSF_VALUE));
result := UnsignedDetails.dwValue;
end;
// ---------------------------------------------------------------------------
procedure TxpMixer.setMute(Value: boolean);
var
Line: TMixerLine;
Controls: TMixerLineControls;
MasterMute: TMixerControl;
Details: TMixerControlDetails;
BoolDetails: TMixerControlDetailsBoolean;
begin
ZeroMemory(@Line, SizeOf(Line));
Line.cbStruct := SizeOf(Line);
Line.dwComponentType := Fmxct;
chk(mixerGetLineInfo(Fmixer, @Line, MIXER_GETLINEINFOF_COMPONENTTYPE));
ZeroMemory(@Controls, SizeOf(Controls));
Controls.cbStruct := SizeOf(Controls);
Controls.dwLineID := Line.dwLineID;
Controls.cControls := 1;
Controls.dwControlType := MIXERCONTROL_CONTROLTYPE_MUTE;
Controls.cbmxctrl := SizeOf(masterMute);
Controls.pamxctrl := @masterMute;
chk(mixerGetLineControls(Fmixer, @Controls, MIXER_GETLINECONTROLSF_ONEBYTYPE));
details.cbStruct := SizeOf(Details);
details.dwControlID := MasterMute.dwControlID;
details.cChannels := 1;
details.cMultipleItems := 0;
details.cbDetails := SizeOf(BoolDetails);
details.paDetails := @BoolDetails;
mixerGetControlDetails(0, @Details, MIXER_GETCONTROLDETAILSF_VALUE);
if (Value) then
BoolDetails.fValue := 1
else
BoolDetails.fValue := 0;
chk(mixerSetControlDetails(0, @Details, MIXER_SETCONTROLDETAILSF_VALUE));
end;
// ---------------------------------------------------------------------------
procedure TxpMixer.setVolume(Value: integer);
var
Line: TMixerLine;
Controls: TMixerLineControls;
MasterVolume: TMixerControl;
Details: TMixerControlDetails;
UnsignedDetails: TMixerControlDetailsUnsigned;
begin
if (value < 0) then
value := 0;
if (value > 65535) then
value := 65535;
ZeroMemory(@Line, SizeOf(Line));
Line.cbStruct := SizeOf(Line);
Line.dwComponentType := Fmxct;
chk(mixerGetLineInfo(Fmixer, @Line, MIXER_GETLINEINFOF_COMPONENTTYPE));
ZeroMemory(@Controls, SizeOf(Controls));
Controls.cbStruct := SizeOf(Controls);
Controls.dwLineID := Line.dwLineID;
Controls.cControls := 1;
Controls.dwControlType := MIXERCONTROL_CONTROLTYPE_VOLUME;
Controls.cbmxctrl := SizeOf(MasterVolume);
Controls.pamxctrl := @MasterVolume;
chk(mixerGetLineControls(Fmixer, @Controls, MIXER_GETLINECONTROLSF_ONEBYTYPE));
details.cbStruct := SizeOf(Details);
details.dwControlID := MasterVolume.dwControlID;
details.cChannels := 1;
details.cMultipleItems := 0;
details.cbDetails := SizeOf(UnsignedDetails);
details.paDetails := @UnsignedDetails;
UnsignedDetails.dwValue := Value;
chk(mixerSetControlDetails(Fmixer, @Details, MIXER_SETCONTROLDETAILSF_VALUE));
end;
// ---------------------------------------------------------------------------
{ TvistaMixer }
constructor TvistaMixer.Create;
begin
CoCreateInstance(CLSID_MMDeviceEnumerator, nil, CLSCTX_ALL, IID_IMMDeviceEnumerator, FmmDevEnum);
FmmDevEnum.GetDefaultAudioEndpoint(eRender, eMultimedia, FmmDev);
FmmDev.Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, nil, FmmEndpoint);
end;
// ---------------------------------------------------------------------------
function TvistaMixer.getMute: boolean;
begin
FmmEndpoint.GetMute(Result);
end;
// ---------------------------------------------------------------------------
function TvistaMixer.getVolume: integer;
var
VolLevel: Single;
begin
FmmEndpoint.GetMasterVolumeLevelScalar(VolLevel);
result := Round(VolLevel * 65535);
end;
// ---------------------------------------------------------------------------
procedure TvistaMixer.setMute(Value: boolean);
begin
FmmEndpoint.SetMute(Value, nil);
end;
// ---------------------------------------------------------------------------
procedure TvistaMixer.setVolume(Value: integer);
var
fValue: Single;
begin
if (value < 0) then
value := 0;
if (value > 65535) then
value := 65535;
fValue := Value / 65535;
FmmEndpoint.SetMasterVolumeLevelScalar(fValue, nil);
end;
// ---------------------------------------------------------------------------
end.
-
unit MMDevApi_tlb;
interface
uses Windows, ActiveX, Classes, Graphics, OleServer, OleCtrls, StdVCL,ComObj;
const
// TypeLibrary Major and minor versions
CLSID_MMDeviceEnumerator: TGUID = '{BCDE0395-E52F-467C-8E3D-C4579291692E}';
IID_IMMDeviceEnumerator: TGUID = '{A95664D2-9614-4F35-A746-DE8DB63617E6}';
IID_IMMDevice: TGUID = '{D666063F-1587-4E43-81F1-B948E807363F}';
IID_IMMDeviceCollection: TGUID = '{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}';
IID_IAudioEndpointVolume: TGUID = '{5CDF2C82-841E-4546-9722-0CF74078229A}';
IID_IAudioMeterInformation : TGUID = '{C02216F6-8C67-4B5B-9D00-D008E73E0064}';
IID_IAudioEndpointVolumeCallback: TGUID = '{657804FA-D6AD-4496-8A60-352752AF4F89}';
GUID_NULL: TGUID = '{00000000-0000-0000-0000-000000000000}';
DEVICE_STATE_ACTIVE = $00000001;
DEVICE_STATE_UNPLUGGED = $00000002;
DEVICE_STATE_NOTPRESENT = $00000004;
DEVICE_STATEMASK_ALL = $00000007;
type
EDataFlow = TOleEnum;
const
eRender = $00000000;
eCapture = $00000001;
eAll = $00000002;
EDataFlow_enum_count = $00000003;
type
ERole = TOleEnum;
const
eConsole = $00000000;
eMultimedia = $00000001;
eCommunications = $00000002;
ERole_enum_count = $00000003;
type
IAudioEndpointVolumeCallback = interface(IUnknown)
['{657804FA-D6AD-4496-8A60-352752AF4F89}']
end;
IMMAudioEndpointVolume = interface(IUnknown)
['{5CDF2C82-841E-4546-9722-0CF74078229A}']
Function RegisterControlChangeNotify( AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
Function UnregisterControlChangeNotify( AudioEndPtVol: IAudioEndpointVolumeCallback): Integer; stdcall;
Function GetChannelCount(out PInteger): Integer; stdcall;
Function SetMasterVolumeLevel(fLevelDB: single; pguidEventContext: PGUID):Integer; stdcall;
Function SetMasterVolumeLevelScalar(fLevelDB: single; pguidEventContext: PGUID):Integer; stdcall;
Function GetMasterVolumeLevel(out fLevelDB: single):Integer; stdcall;
Function GetMasterVolumeLevelScalar(out fLevel: single):Integer; stdcall;
Function SetChannelVolumeLevel(nChannel: Integer; fLevelDB: double; pguidEventContext: TGUID):Integer; stdcall;
Function SetChannelVolumeLevelScalar(nChannel: Integer; fLevelDB: single; pguidEventContext: TGUID):Integer; stdcall;
Function GetChannelVolumeLevel(nChannel: Integer; out fLevelDB: double) : Integer; stdcall;
Function GetChannelVolumeLevelScalar(nChannel: Integer; out fLevel: double) : Integer; stdcall;
Function SetMute(bMute: Boolean ; pguidEventContext: PGUID) :Integer; stdcall;
Function GetMute(out bMute: Boolean ) :Integer; stdcall;
Function GetVolumeStepInfo( pnStep: Integer; out pnStepCount: Integer):Integer; stdcall;
Function VolumeStepUp(pguidEventContext: TGUID) :Integer; stdcall;
Function VolumeStepDown(pguidEventContext: TGUID) :Integer; stdcall;
Function QueryHardwareSupport(out pdwHardwareSupportMask): Integer; stdcall;
Function GetVolumeRange(out pflVolumeMindB: double; out pflVolumeMaxdB: double; out pflVolumeIncrementdB: double): Integer; stdcall;
end;
IPropertyStore = interface(IUnknown)
end;
type
IMMDevice = interface(IUnknown)
['{D666063F-1587-4E43-81F1-B948E807363F}']
Function Activate( const refId :TGUID;
dwClsCtx: DWORD;
pActivationParams: PInteger ;
out pEndpointVolume: IMMAudioEndpointVolume): Hresult; stdCall;
Function OpenPropertyStore(stgmAccess: DWORD; out ppProperties :IPropertyStore): Hresult; stdcall;
Function GetId(out ppstrId: PLPWSTR ): Hresult; stdcall;
Function GetState(out State :Integer): Hresult; stdcall;
end;
IMMDeviceCollection = interface(IUnknown)
['{0BD7A1BE-7A1A-44DB-8397-CC5392387B5E}']
end;
IMMNotificationClient = interface (IUnknown)
['{7991EEC9-7E89-4D85-8390-6C703CEC60C0}']
end;
IMMDeviceEnumerator = interface(IUnknown)
['{A95664D2-9614-4F35-A746-DE8DB63617E6}']
Function EnumAudioEndpoints( dataFlow: EDataFlow; deviceState: SYSUINT; DevCollection:IMMDeviceCollection ): Hresult ; stdcall;
Function GetDefaultAudioEndpoint(EDF: SYSUINT; ER: SYSUINT; out Dev :IMMDevice ): Hresult ; stdcall;
Function GetDevice( pwstrId: pointer ; out Dev :IMMDevice) : HResult; stdcall;
Function RegisterEndpointNotificationCallback(pClient :IMMNotificationClient) :Hresult; stdcall;
end;
implementation
end.
关于c# - 如何以编程方式控制我的电脑的音量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2376279/
我一直在阅读有关汇编函数的内容,但对于是使用进入和退出还是仅使用调用/返回指令来快速执行,我感到很困惑。一种方式快而另一种方式更小吗?例如,在不内联函数的情况下,在汇编中执行此操作的最快(stdcal
我正在处理一个元组列表,如下所示: res = [('stori', 'JJ'), ('man', 'NN'), ('unnatur', 'JJ'), ('feel', 'NN'), ('pig',
最近我一直在做很多网络或 IO 绑定(bind)操作,使用线程有助于加快代码速度。我注意到我一直在一遍又一遍地编写这样的代码: threads = [] for machine, user, data
假设我有一个名为 user_stats 的资源,其中包含用户拥有的帖子、评论、喜欢和关注者的数量。是否有一种 RESTful 方式只询问该统计数据的一部分(即,对于 user_stats/3,请告诉我
我有一个简单的 api,它的工作原理是这样的: 用户创建一个请求 ( POST /requests ) 另一个用户检索所有请求 ( GET /requests ) 然后向请求添加报价 ( POST /
考虑以下 CDK Python 中的示例(对于这个问题,不需要 AWS 知识,这应该对基本上任何构建器模式都有效,我只是在这个示例中使用 CDK,因为我使用这个库遇到了这个问题。): from aws
Scala 中管理对象池的首选方法是什么? 我需要单线程创建和删除大规模对象(不需要同步)。在 C++ 中,我使用了静态对象数组。 在 Scala 中处理它的惯用和有效方法是什么? 最佳答案 我会把它
我有一个带有一些内置方法的类。这是该类的抽象示例: class Foo: def __init__(self): self.a = 0 self.b = 0
返回和检查方法执行的 Pythonic 方式 我目前在 python 代码中使用 golang 编码风格,决定移动 pythonic 方式 例子: import sys from typing imp
我正在开发一个 RESTful API。其中一个 URL 允许调用者通过 id 请求特定人员的记录。 返回该 id 不存在的记录的常规值是什么?服务器是否应该发回一个空对象或者一个 404,或者其他什
我正在使用 pathlib.Path() 检查文件是否存在,并使用 rasterio 将其作为图像打开. filename = pathlib.Path("./my_file-name.tif") 但
我正在寻找一种 Pythonic 方式来从列表和字典创建嵌套字典。以下两个语句产生相同的结果: a = [3, 4] b = {'a': 1, 'b': 2} c = dict(zip(b, a))
我有一个正在操裁剪理设备的脚本。设备有时会发生物理故障,当它发生时,我想重置设备并继续执行脚本。我有这个: while True: do_device_control() device
做组合别名的最pythonic和正确的方法是什么? 这是一个假设的场景: class House: def cleanup(self, arg1, arg2, kwarg1=False):
我正在开发一个小型客户端服务器程序来收集订单。我想以“REST(ful)方式”来做到这一点。 我想做的是: 收集所有订单行(产品和数量)并将完整订单发送到服务器 目前我看到有两种选择: 将每个订单行发
我知道在 Groovy 中您可以使用字符串调用类/对象上的方法。例如: Foo."get"(1) /* or */ String meth = "get" Foo."$meth"(1) 有没有办法
在 ECMAScript6 中,您可以使用扩展运算符来解构这样的对象 const {a, ...rest} = obj; 它将 obj 浅拷贝到 rest,不带属性 a。 有没有一种干净的方法可以在
我有几个函数返回数字或None。我希望我的包装函数返回第一个不是 None 的结果。除了下面的方法之外,还有其他方法吗? def func1(): return None def func2(
假设我想设计一个 REST api 来讨论歌曲、专辑和艺术家(实际上我就是这样做的,就像我之前的 1312414 个人一样)。 歌曲资源始终与其所属专辑相关联。相反,专辑资源与其包含的所有歌曲相关联。
这是我认为必须经常出现的问题,但我一直无法找到一个好的解决方案。假设我有一个函数,它可以作为参数传递一个开放资源(如文件或数据库连接对象),或者需要自己创建一个。如果函数需要自己打开文件,最佳实践通常
我是一名优秀的程序员,十分优秀!