📄 ioirmain.pas
字号:
unit IOIRMain;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms, Dialogs, Buttons, StdCtrls, ComCtrls,
JvHidControllerClass;
const
cCodeMercenariesVID = $07C0;
cIOWarrior24PID = $1501;
cIRCommand = $0C;
cIRReportID = $0C;
cIROff = $00;
cIROn = $01;
// translation of RC5-Address to device names
AddressNames: array [0..31] of PChar =
(
'TV1',
'TV2',
'Teletext',
'Video',
'LV1',
'VCR1',
'VCR2',
'Experimental',
'Sat1',
'Camera',
'Sat2',
'11',
'CDV',
'Camcorder',
'14',
'15',
'Pre-amp1',
'Tuner',
'Recorder1',
'Pre-amp2',
'CD Player',
'Phono',
'SatA',
'Recorder2',
'24',
'25',
'CDR',
'27',
'28',
'Lighting1',
'Lighting2',
'Phone'
);
type
// data structure received from IO-Warrior 24
PIOWarriorIRInputReport = ^TIOWarriorIRInputReport;
TIOWarriorIRInputReport = packed record
Command: Byte; // data part 0..63 of IR RC5 code
Address: Byte; // device ID part 0..31 of IR RC5 code
Empty: array [1..5] of Byte; // 5 bytes containing 0
end;
// data structure to send to IO-Warrior 24
PIOWarriorIROutputReport = ^TIOWarriorIROutputReport;
TIOWarriorIROutputReport = packed record
ReportID: Byte; // needed for output
IOData: array [0..6] of Byte; // 7 Bytes for IO-Warrior
end;
// RC5 data and assigned key combination
PKeyData = ^TKeyData;
TKeyData = record
Command: Byte; // decoded RC5-Command
Address: Byte; // decoded RC5-Address
Toggle: Boolean; // toggles with each RC5 keypress
Key: Word; // assigned key
Shift: TShiftState; // assigned modifier keys
ExtendedKey: Boolean; // numpad key or not
end;
TMainForm = class(TForm)
HidCtl: TJvHidDeviceController;
IOWarriorDetected: TLabel;
CodeList: TListView;
Description: TLabel;
Clear: TButton;
procedure HidCtlDeviceChange(Sender: TObject);
procedure HidCtlDeviceData(HidDev: TJvHidDevice;
ReportID: Byte; const Data: Pointer; Size: Word);
procedure CodeListDblClick(Sender: TObject);
procedure ClearClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
public
IOWarrior: TJvHidDevice;
procedure UpdateControls;
end;
var
MainForm: TMainForm;
implementation
uses
KeyEdit;
{$R *.dfm}
// untangle the RC5 data
procedure DecodeRC5Data(const Report: TIOWarriorIRInputReport;
var KeyData: TKeyData);
begin
// only 6 bits meaningful
KeyData.Command := Report.Command and $3F;
// move the inverted /C6 bit from Address to Command
KeyData.Command := KeyData.Command or
((not Report.Address) and $40);
// only 5 bits are address
KeyData.Address := Report.Address and $1F;
KeyData.Toggle := (Report.Address and $20) <> 0;
end;
// send the assigned key combination as if
// coming from keyboard
procedure SendKeycodes(KeyData: PKeyData);
var
ExtKey: DWORD;
begin
if KeyData.Key = 0 then
Exit;
// the modifier keys go down
if ssShift in KeyData^.Shift then
keybd_event(VK_SHIFT, 0, 0, 0);
if ssCtrl in KeyData^.Shift then
keybd_event(VK_CONTROL, 0, 0, 0);
if ssAlt in KeyData^.Shift then
keybd_event(VK_MENU, 0, 0, 0);
// add the extended bit as flag
if KeyData^.ExtendedKey then
ExtKey := KEYEVENTF_EXTENDEDKEY
else
ExtKey := 0;
// the key goes down and up
keybd_event(KeyData^.Key, 0, ExtKey, 0);
keybd_event(KeyData^.Key, 0, ExtKey or KEYEVENTF_KEYUP, 0);
// the modifier keys go up (reverse order)
if ssAlt in KeyData^.Shift then
keybd_event(VK_MENU, 0, KEYEVENTF_KEYUP, 0);
if ssCtrl in KeyData^.Shift then
keybd_event(VK_CONTROL, 0, KEYEVENTF_KEYUP, 0);
if ssShift in KeyData^.Shift then
keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
end;
procedure TMainForm.UpdateControls;
const
cIOWMessage = 'IO-Warrior with IR is plugged in';
begin
Description.Enabled := Assigned(IOWarrior);
if Assigned(IOWarrior) then
IOWarriorDetected.Caption := cIOWMessage
else
IOWarriorDetected.Caption := 'No ' + cIOWMessage;
end;
// callback function to search for the IO-Warrior
function FindIOWarrior(HidDev: TJvHidDevice): Boolean; stdcall;
begin
// the IO-Warrior shows up as two devices
// we want access to the IO-Warrior device for the IR command
// the other one with a InputReportByteLength of 3 is for
// access to the IO pins
Result :=
(HidDev.Attributes.VendorID = cCodeMercenariesVID) and
(HidDev.Attributes.ProductID = cIOWarrior24PID) and
(HidDev.Caps.InputReportByteLength = 8);
end;
// check if the IO-Warrior was plugged or unplugged
procedure TMainForm.HidCtlDeviceChange(Sender: TObject);
var
BytesWritten: Cardinal;
IOWarriorOutputReport: TIOWarriorIROutputReport;
begin
// Free the device object if it has been unplugged
if Assigned(IOWarrior) and not IOWarrior.IsPluggedIn then
FreeAndNil(IOWarrior);
// if no IO-Warrior in use yet then search for one
if not Assigned(IOWarrior) then
if HidCtl.CheckOutByCallback(IOWarrior, FindIOWarrior) then
begin
// enable IR mode
FillChar(IOWarriorOutputReport,
SizeOf(IOWarriorOutputReport), #0);
IOWarriorOutputReport.ReportID := cIRCommand;
IOWarriorOutputReport.IOData[0] := cIROn;
IOWarrior.WriteFile(IOWarriorOutputReport,
SizeOf(IOWarriorOutputReport), BytesWritten);
end;
UpdateControls;
end;
// IR data arrived from the device
procedure TMainForm.HidCtlDeviceData(HidDev: TJvHidDevice;
ReportID: Byte; const Data: Pointer; Size: Word);
var
I: Integer;
KeyData: TKeyData;
PData: PKeyData;
FoundAt: Integer;
Item: TListItem;
IOWarriorInputReport: TIOWarriorIRInputReport;
begin
IOWarriorInputReport := PIOWarriorIRInputReport(Data)^;
if ReportID = cIRReportID then
begin
// extract data payload from report
FillChar(KeyData, SizeOf(KeyData), #0);
DecodeRC5Data(IOWarriorInputReport, KeyData);
// search if RC5 data is already in list
FoundAt := -1;
for I := 0 to CodeList.Items.Count-1 do
begin
PData := PKeyData(CodeList.Items[I].Data);
if (KeyData.Command = PData^.Command) and
(KeyData.Address = PData^.Address) then
begin
FoundAt := I;
Break;
end;
end;
if FoundAt = -1 then
begin
// RC5 data not found so add it to list
Item := CodeList.Items.Add;
Item.Caption := AddressNames[KeyData.Address];
Item.SubItems.Add(Format('%d', [KeyData.Command]));
Item.SubItems.Add('--'); // no name yet
Item.SubItems.Add(''); // no key assigned yet
// store KeyData in Data of Item
GetMem(PData, SizeOf(TKeyData));
PData^ := KeyData;
Item.Data := PData;
end
else
begin
// code found so send the assigned key combination
Item := CodeList.Items[FoundAt];
CodeList.ItemIndex := FoundAt;
SendKeycodes(Item.Data);
end;
end;
end;
// edit an entry of the CodeList
procedure TMainForm.CodeListDblClick(Sender: TObject);
var
Item: TListItem;
PData: PKeyData;
begin
// see if an item is selected
Item := nil;
if CodeList.ItemIndex >= 0 then
Item := CodeList.Items[CodeList.ItemIndex];
if Assigned(Item) then
// create edit form
with TKeyEditForm.Create(Self) do
begin
// initialize controls
PData := Item.Data;
KeyData := PData^;
Address.Caption := Item.Caption;
Value.Caption := Item.SubItems[0];
Name.Text := Item.SubItems[1];
Keys.Text := Item.SubItems[2];
ExtKey.Checked := KeyData.ExtendedKey;
if ShowModal = mrOk then
begin
// get back edited values
Item.SubItems[1] := Name.Text;
Item.SubItems[2] := Keys.Text;
PData^ := KeyData;
end;
Free;
end;
end;
// clear all assignments
procedure TMainForm.ClearClick(Sender: TObject);
var
I: Integer;
begin
CodeList.Items.BeginUpdate;
for I := CodeList.Items.Count-1 downto 0 do
begin
FreeMem(CodeList.Items[I].Data);
CodeList.Items.Delete(I);
end;
CodeList.Items.EndUpdate;
end;
// always clean up properly
procedure TMainForm.FormDestroy(Sender: TObject);
begin
ClearClick(Self);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -