Вся история началась с покупки тюнера AverTV Hybrid+FM PCI. Стандартная софтина завелась с полоборота (Aver Media Center) и было счастье до тех пор, пока не захотелось лени ради использовать пульт от тюнера для управления тем же VLC и Winamp.
Перебрал кучу утилит, типа Girder, но так ни одна из них не поняла что от нее требуется. Пришлось искать свой вариант решения проблемы. На этом же форуме нашел похожую статейку, только там обсуждался тюнер типа AverTV 305. К сожалению, в моем случае архитектура оказалась другой и пришлось искать другие способы выхода из сложившийся ситуации.
Небольшой поиск импортируемых функций из комплекта установки стандартного ПО подсказал, что ответ надо искать в службе AverTV Remote Service. Хостовый файл у меня на машине находиться здесь:
C:\Program Files\Common Files\AVerMedia\Service\AVerRemote.exe
Дальше дело пошло быстрее. В среде Delphi создаем новый проект и делаем
Project->Import Type Library->RemoteService 1.0 Type Library->OK
В ответ система должна сгенерировать либу REMOTESERVICELib_TLB. Нас здесь, в первую очередь, интересуют интефейсы
...............
_IRemoteEvents = dispinterface
['{6EC509E3-78E2-4FCB-93A4-035A1DA24AC9}']
procedure OnRemoteData(nKeyFun: SYSUINT; nKey: SYSUINT; dwKeyCode: LongWord); dispid 1;
..............
IRemoteCtrl = interface(IDispatch)
['{CF52E9A5-F2E0-4AB9-AF6D-52AF7AAE1AE4}']
procedure GetDeviceNum(out nDeviceNum: SYSUINT); safecall;
procedure EnumDeviceInfo(nIndex: SYSUINT; out hwInfo: tagHWINFO); safecall;
procedure DetectHW; safecall;
procedure Initialize; safecall;
...................
class function CoRemote.Create: IRemoteCtrl;
begin
Result := CreateComObject(CLASS_Remote) as IRemoteCtrl;
end;
....................._IRemoteEvents - это именно то, что нужно. Интерфейс предопределяет нужный нам эвент для обработки нажатия кнопки пульта : OnRemoteData
Теперь надо придумать как "привязать" его к нашему проекту. Здесь мне существенно помог юнит EvSink соотечественника Алекса Дерискибы. Он находится по адресу :
Ну и, собственно, вот что приблизительно должно получится :
.........
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, REMOTESERVICELib_TLB, StdCtrls, ComObj, ActiveX, EvSink;
..............
TfmIREventHandler = class(TForm)
.................
procedure OnRemoteData(nKeyFun: SYSUINT; nKey: SYSUINT; dwKeyCode: LongWord);
//обработчик обязательно должен находится в секции published описания формы
.........
private
DevNum : Cardinal;
RemoteCtrl : Remote;
EventSink: IEventSink;
............
end;
var
fmIREventHandler: TfmIREventHandler;
implementation
..............
procedure TfmIREventHandler.FormCreate(Sender: TObject);
begin
............
RemoteCtrl := CoRemote.Create;
//создаем COM Automation-объект
end;
............
procedure TfmIREventHandler.FormShow(Sender: TObject);
var hwInfo: tagHWINFO;
i : integer;
begin
//без этих двух строчек эвент работать не будет
RemoteCtrl.Initialize;
RemoteCtrl.DetectHW;
//получаем к-во пультов
RemoteCtrl.GetDeviceNum(DevNum);
for I := 0 to DevNum - 1 do
begin
//получаем информацию по каждому пульту
RemoteCtrl.EnumDeviceInfo(I, hwInfo);
with hwInfo do
begin
ShowMessage(
Format( 'Device name : %s' + #13#10 +
'Device PnPID : %s' + #13#10 +
'EnumRemoteID : %d' + #13#10 +
'EnumMCERemoteID : %d' + #13#10 +
'CurRemoteID : %d' + #13#10 +
'SelectedAP : %d' + #13#10 +
'IsRemoteSupport : %d' + #13#10 +
'IsEnable : %d' + #13#10 +
'IRemoteControlEnumEx : %d' + #13#10 +
'HWRemoteNotify : %d' + #13#10 +
'IRemoteControlEnum : %d',
[szDeviceName, szDevicePNPID, lEnumRemoteID,
lEnumMCERemoteID, lCurRemoteID, lSelectedAP,
wIsRemoteSupport, bIsEnable, bIRemoteControlEnumEx,
bHWRemoteNotify, bIRemoteControlEnum] )
);
end;
end;
// Создаем обработчик (event sink) и говорим ему, что он должен обрабатывать интерфейс DIID__IRemoteEvents
EventSink := TEventSink.Create(DIID__IRemoteEvents);
// теперь связываем sink с обработчиком формы OnRemoteData
// 1 это DispID метода OnRemoteData в интерфейсе _IRemoteEvents
EventSink.AddEventHandler(1, fmIREventHandler, 'OnRemoteData');
// Привязываем эвент к COM-источнику
EventSink.Connect(RemoteCtrl);
end;
procedure TfmIREventHandler.OnRemoteData(nKeyFun, nKey: SYSUINT; dwKeyCode: LongWord);
begin
ShowMessage(IntToStr(nKeyFun));
//Здесь делаем то, что нам нужно. nKeyFun - код нажатой клавиши (1-54)
end;Всё - скелет готов. Моя программа загружает клавишные профили для разных приложений и, в зависимости от выбранного профиля, активизирует приложение и эмулирует отсылку ему заданной в конфигурации комбинации клавиш (реализовано на основе стандартного модуля sndkey32). При активизации стандартного приложения (AverTV Media Center) можно дизейблить прогу, чтобы избежать конфликтов. Для этого у меня висит поток, который периодически проверяет наличие главного окна с классом AverTV_Control.
Есть и небольшие баги - иногда, когда программа активна, AverTV Media Center перестает реагировать на сигналы от пульта. Почему - еще не разобрался.
Все собиралось в среде Delphi 7, но и в 2009 пойдет (лень было крутить старый sndkey32








