2010-03-04 131 views
5

我有一个键盘没有音乐键,用于在我的电脑中上下音乐,播放,停止等音乐。如果你不明白,this是我的键盘,this不是。如何以编程方式控制我的电脑的音量?

我想在Windows和Delphi或C#中实现一个键盘钩子来在我的键盘上创建音量功能,但是我不知道如何通过代码来调高音量。我试图thisthis的例子,但没有工作(顺便提一句,所有在德尔福)。

你知道如何通过代码调高音量吗?

+0

你可能想读一些文章:http://www.codeguru.com/csharp/csharp/cs_graphics/sound/article.php/c10931 http://www.dreamincode.net/forums/的index.php?showtopic = 45693 – 2010-03-04 01:27:26

回答

6

Autohotkey会做的伎俩。它有一个“SoundSet”命令,可以调整所有音频设备的音量/静音电平。

+0

它仍然需要一些脚本 - 如果你四处游荡,有人可能已经创建了autohotkey脚本。 – 2010-03-04 01:32:58

+1

不错! '^!NumpadSub :: Send {Volume_Up 10}' '^!NumpadAdd :: Send {Volume_Down 10}' '^!NumpadEnter :: Send {Volume_Mute}' – Joe 2012-10-09 00:26:07

8

Delphi代码如下。

我keyhook将消息发送到我的与密钥的VK代码Lparam型主要形式,

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. 
0

这是一个除了水珠的出色答卷。 SetMute/GetMute函数的声明必须使用32位整数值

unit MMDevApi_tlb; 
const 
    DEVICE_STATE_ACTIVE  = $00000001; 
    DEVICE_STATE_UNPLUGGED = $00000002; 
    DEVICE_STATE_NOTPRESENT = $00000004; 
    DEVICE_STATEMASK_ALL  = $00000007; 

    IMMAudioEndpointVolume = interface(IUnknown) 
    ['{5CDF2C82-841E-4546-9722-0CF74078229A}'] 
    Function SetMute(iMute: Integer; pguidEventContext: PGUID) :Integer; stdcall; 
    Function GetMute(out iMute: Integer) :Integer; stdcall; 

变化SetMute和GetMute声明整数变量和投德尔福布尔整数。

方法调用然后 VAR iMute:整数 AudioEndVol.SetMute(整数(CheckBox1.Checked),@GUID_NULL); AudioEndVol.GetMute(iMute);

使用bool不会使托盘图标正确识别静音状态,并且取消静音完全不起作用。 getmute一样,它必须使用32位整数输出参数或内存对齐被随机破坏。我不明白如此搜索的推理,并找到了一篇极好的JEDI文章。

一些win32调用对于按位值非常非常挑剔,Delphi Bool/Boolean并不总是适合C对应。使用32位整数来表示C布尔变量以具有精确的按位匹配。大多数win32 C方法都不是那么严格,并且可以在bool/boolean下正常工作。这个特定的MMDeviceAPI.SetMute函数是一个罕见的案例,Delphi程序员受到重创。 http://blog.delphi-jedi.net/2008/09/25/bool-boolean-and-integer/