261 lines
9.0 KiB
ObjectPascal
261 lines
9.0 KiB
ObjectPascal
|
|
{******************************************************************
|
||
|
|
|
||
|
|
JEDI-VCL Demo
|
||
|
|
|
||
|
|
Copyright (C) 2002 Project JEDI
|
||
|
|
|
||
|
|
Original author:
|
||
|
|
|
||
|
|
Contributor(s):
|
||
|
|
|
||
|
|
You may retrieve the latest version of this file at the JEDI-JVCL
|
||
|
|
home page, located at http://jvcl.sourceforge.net
|
||
|
|
|
||
|
|
The contents of this file are used with permission, subject to
|
||
|
|
the Mozilla Public License Version 1.1 (the "License"); you may
|
||
|
|
not use this file except in compliance with the License. You may
|
||
|
|
obtain a copy of the License at
|
||
|
|
http://www.mozilla.org/MPL/MPL-1_1Final.html
|
||
|
|
|
||
|
|
Software distributed under the License is distributed on an
|
||
|
|
"AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
||
|
|
implied. See the License for the specific language governing
|
||
|
|
rights and limitations under the License.
|
||
|
|
|
||
|
|
******************************************************************}
|
||
|
|
|
||
|
|
unit CollectionMain;
|
||
|
|
|
||
|
|
interface
|
||
|
|
|
||
|
|
uses
|
||
|
|
Windows, SysUtils, Classes, Controls, Forms, ComCtrls,
|
||
|
|
JvHidControllerClass, Dialogs, StdCtrls;
|
||
|
|
|
||
|
|
type
|
||
|
|
TCollectionDemoForm = class(TForm)
|
||
|
|
HidCtl: TJvHidDeviceController;
|
||
|
|
DeviceTree: TTreeView;
|
||
|
|
Save: TButton;
|
||
|
|
SaveDialog: TSaveDialog;
|
||
|
|
Description: TLabel;
|
||
|
|
procedure FormShow(Sender: TObject);
|
||
|
|
procedure HidCtlDeviceChange(Sender: TObject);
|
||
|
|
function HidCtlEnumerate(HidDev: TJvHidDevice;
|
||
|
|
Index: Integer): Boolean;
|
||
|
|
procedure SaveClick(Sender: TObject);
|
||
|
|
public
|
||
|
|
Root: TTreeNode;
|
||
|
|
procedure EnumerateCaps(HidDev: TJvHidDevice;
|
||
|
|
Parent: TTreeNode; Idx: Word);
|
||
|
|
procedure EnumerateNodes(HidDev: TJvHidDevice;
|
||
|
|
Parent: TTreeNode; Idx: Word; NumSiblings: Word);
|
||
|
|
end;
|
||
|
|
|
||
|
|
var
|
||
|
|
CollectionDemoForm: TCollectionDemoForm;
|
||
|
|
|
||
|
|
implementation
|
||
|
|
|
||
|
|
uses
|
||
|
|
UsagesInfo, Hid;
|
||
|
|
|
||
|
|
{$R *.DFM}
|
||
|
|
|
||
|
|
procedure TCollectionDemoForm.FormShow(Sender: TObject);
|
||
|
|
begin
|
||
|
|
// this compensates the possibility that HidCtlDeviceChange
|
||
|
|
// may not be able to fill the treeview the first time
|
||
|
|
HidCtlDeviceChange(Self);
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TCollectionDemoForm.HidCtlDeviceChange(Sender: TObject);
|
||
|
|
begin
|
||
|
|
// HidCtlDeviceChange happens before TCollectionDemoForm.Create completed
|
||
|
|
// DeviceTree may have not been created yet
|
||
|
|
if Assigned(DeviceTree) then
|
||
|
|
begin
|
||
|
|
// each time something happens to the HID devices the treeview is filled
|
||
|
|
DeviceTree.Items.Clear;
|
||
|
|
Root := DeviceTree.Items.Add(nil, 'HID-Devices');
|
||
|
|
HidCtl.Enumerate;
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TCollectionDemoForm.EnumerateCaps(HidDev: TJvHidDevice; Parent: TTreeNode; Idx: Word);
|
||
|
|
|
||
|
|
procedure EnumerateButtonCaps(HidDev: TJvHidDevice; Parent: TTreeNode;
|
||
|
|
ReportType: THIDPReportType; ReportText: string);
|
||
|
|
var
|
||
|
|
I: Integer;
|
||
|
|
Ret: Integer;
|
||
|
|
N: WORD;
|
||
|
|
UsagePageText: string;
|
||
|
|
UsageText: string;
|
||
|
|
// 256 Caps entries should be always sufficient
|
||
|
|
BtnCaps: array [0..255] of THIDPButtonCaps;
|
||
|
|
begin
|
||
|
|
N := 255;
|
||
|
|
// get ALL ButtonCaps of the specified ReportType
|
||
|
|
HidDev.ReportTypeParam := ReportType;
|
||
|
|
Ret := HidDev.GetSpecificButtonCaps(@BtnCaps[0], N);
|
||
|
|
if Ret = HIDP_STATUS_SUCCESS then
|
||
|
|
for I := 0 to N-1 do
|
||
|
|
if BtnCaps[I].LinkCollection = Idx then
|
||
|
|
begin
|
||
|
|
UsageAndUsagePageText(BtnCaps[I].UsagePage, BtnCaps[I].Usage, UsagePageText, UsageText);
|
||
|
|
if BtnCaps[I].IsRange then
|
||
|
|
DeviceTree.Items.AddChild(Parent,
|
||
|
|
Format('Button %s Range: UsagePage=%s ($%.4x) %d..%d',
|
||
|
|
[ReportText, UsagePageText, BtnCaps[I].UsagePage, BtnCaps[I].UsageMin, BtnCaps[I].UsageMax]))
|
||
|
|
else
|
||
|
|
DeviceTree.Items.AddChild(Parent,
|
||
|
|
Format('Button %s: UsagePage=%s ($%.4x) Usage=%s ($%.4x)',
|
||
|
|
[ReportText, UsagePageText, BtnCaps[I].UsagePage, UsageText, BtnCaps[I].Usage]));
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure EnumerateValueCaps(HidDev: TJvHidDevice; Parent: TTreeNode;
|
||
|
|
ReportType: THIDPReportType; ReportText: string);
|
||
|
|
var
|
||
|
|
I: Integer;
|
||
|
|
Ret: Integer;
|
||
|
|
N: WORD;
|
||
|
|
UsagePageText: string;
|
||
|
|
UsageText: string;
|
||
|
|
// 256 Caps entries should be always sufficient
|
||
|
|
ValCaps: array [0..255] of THIDPValueCaps;
|
||
|
|
begin
|
||
|
|
N := 255;
|
||
|
|
// get ALL ValueCaps of the specified ReportType
|
||
|
|
HidDev.ReportTypeParam := ReportType;
|
||
|
|
Ret := HidDev.GetSpecificValueCaps(@ValCaps[0], N);
|
||
|
|
if Ret = HIDP_STATUS_SUCCESS then
|
||
|
|
for I := 0 to N-1 do
|
||
|
|
if ValCaps[I].LinkCollection = Idx then
|
||
|
|
begin
|
||
|
|
UsageAndUsagePageText(ValCaps[I].UsagePage, ValCaps[I].Usage, UsagePageText, UsageText);
|
||
|
|
if ValCaps[I].IsRange then
|
||
|
|
DeviceTree.Items.AddChild(Parent,
|
||
|
|
Format('Value %s Range: UsagePage=%s ($%.4x) %d..%d',
|
||
|
|
[ReportText, UsagePageText, ValCaps[I].UsagePage, ValCaps[I].UsageMin, ValCaps[I].UsageMax]))
|
||
|
|
else
|
||
|
|
DeviceTree.Items.AddChild(Parent,
|
||
|
|
Format('Value %s: UsagePage=%s ($%.4x) Usage=%s ($%.4x)',
|
||
|
|
[ReportText, UsagePageText, ValCaps[I].UsagePage, UsageText, ValCaps[I].Usage]));
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
|
||
|
|
begin
|
||
|
|
// set the params to get ALL Caps
|
||
|
|
HidDev.UsagePageParam := 0;
|
||
|
|
HidDev.UsageParam := 0;
|
||
|
|
HidDev.LinkCollectionParam := HIDP_LINK_COLLECTION_UNSPECIFIED;
|
||
|
|
EnumerateButtonCaps(HidDev, Parent, HidP_Input, 'Input');
|
||
|
|
EnumerateButtonCaps(HidDev, Parent, HidP_Output, 'Output');
|
||
|
|
EnumerateButtonCaps(HidDev, Parent, HidP_Feature, 'Feature');
|
||
|
|
EnumerateValueCaps (HidDev, Parent, HidP_Input, 'Input');
|
||
|
|
EnumerateValueCaps (HidDev, Parent, HidP_Output, 'Output');
|
||
|
|
EnumerateValueCaps (HidDev, Parent, HidP_Feature, 'Feature');
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TCollectionDemoForm.EnumerateNodes(HidDev: TJvHidDevice;
|
||
|
|
Parent: TTreeNode; Idx: Word; NumSiblings: Word);
|
||
|
|
var
|
||
|
|
I: Word;
|
||
|
|
Node: TTreeNode;
|
||
|
|
UsagePageText: string;
|
||
|
|
UsageText: string;
|
||
|
|
CollectionTypeText: string;
|
||
|
|
NodeText: string;
|
||
|
|
begin
|
||
|
|
// add a list of sibling nodes to the device tree node Parent
|
||
|
|
for I := 1 to NumSiblings do
|
||
|
|
begin
|
||
|
|
UsageAndUsagePageText(HidDev.LinkCollectionNodes[Idx].LinkUsagePage,
|
||
|
|
HidDev.LinkCollectionNodes[Idx].LinkUsage, UsagePageText, UsageText);
|
||
|
|
case HidDev.LinkCollectionNodes[Idx].CollectionType of
|
||
|
|
$00:
|
||
|
|
CollectionTypeText := 'Physical';
|
||
|
|
$01:
|
||
|
|
CollectionTypeText := 'Application';
|
||
|
|
$02:
|
||
|
|
CollectionTypeText := 'Logical';
|
||
|
|
$03:
|
||
|
|
CollectionTypeText := 'Report';
|
||
|
|
$04:
|
||
|
|
CollectionTypeText := 'Named Array';
|
||
|
|
$05:
|
||
|
|
CollectionTypeText := 'Usage Switch';
|
||
|
|
$06:
|
||
|
|
CollectionTypeText := 'Usage Modifier';
|
||
|
|
$07..$7F:
|
||
|
|
CollectionTypeText := Format('Reserved $%.2x',
|
||
|
|
[Cardinal(HidDev.LinkCollectionNodes[Idx].CollectionType)]);
|
||
|
|
$80..$FF:
|
||
|
|
CollectionTypeText := Format('Vendor-defined $%.2x',
|
||
|
|
[Cardinal(HidDev.LinkCollectionNodes[Idx].CollectionType)]);
|
||
|
|
end;
|
||
|
|
|
||
|
|
NodeText :=
|
||
|
|
'UsagePage=' + UsagePageText + Format(' ($%.4x) ', [HidDev.LinkCollectionNodes[Idx].LinkUsagePage]) +
|
||
|
|
'Usage=' + UsageText + Format(' ($%.4x) ', [HidDev.LinkCollectionNodes[Idx].LinkUsage]) +
|
||
|
|
'CollectionType=' + CollectionTypeText + Format(' ($%.2x)', [HidDev.LinkCollectionNodes[Idx].CollectionType]);
|
||
|
|
if HidDev.LinkCollectionNodes[Idx].IsAlias <> 0 then
|
||
|
|
NodeText := NodeText + ' IsAlias';
|
||
|
|
Node := DeviceTree.Items.AddChild(Parent, NodeText);
|
||
|
|
|
||
|
|
EnumerateCaps(HidDev, Node, Idx);
|
||
|
|
|
||
|
|
// recurse to the children nodes
|
||
|
|
if HidDev.LinkCollectionNodes[Idx].FirstChild <> 0 then
|
||
|
|
EnumerateNodes(HidDev, Node,
|
||
|
|
HidDev.LinkCollectionNodes[Idx].FirstChild,
|
||
|
|
HidDev.LinkCollectionNodes[Idx].NumberOfChildren);
|
||
|
|
// secure against buggy descriptors
|
||
|
|
if HidDev.LinkCollectionNodes[Idx].NextSibling <> 0 then
|
||
|
|
// follow the link to the next sibling
|
||
|
|
Idx := HidDev.LinkCollectionNodes[Idx].NextSibling
|
||
|
|
else
|
||
|
|
Break;
|
||
|
|
end;
|
||
|
|
end;
|
||
|
|
|
||
|
|
function TCollectionDemoForm.HidCtlEnumerate(HidDev: TJvHidDevice;
|
||
|
|
Index: Integer): Boolean;
|
||
|
|
var
|
||
|
|
Idx: Word;
|
||
|
|
Node: TTreeNode;
|
||
|
|
Name: string;
|
||
|
|
begin
|
||
|
|
// give the treeview node for the device a descriptive name
|
||
|
|
if HidDev.ProductName <> '' then
|
||
|
|
Name := Format('"%s" VID=$%.4x PID=$%.4x',
|
||
|
|
[HidDev.ProductName, HidDev.Attributes.VendorID, HidDev.Attributes.ProductID])
|
||
|
|
else
|
||
|
|
Name := Format('VID=$%.4x PID=$%.4x',
|
||
|
|
[HidDev.Attributes.VendorID, HidDev.Attributes.ProductID]);
|
||
|
|
Node := DeviceTree.Items.AddChild(Root, Name);
|
||
|
|
|
||
|
|
// there is only one root node, but we try to enumerate siblings anyway
|
||
|
|
// in case there is a bad descriptor
|
||
|
|
Idx := 0;
|
||
|
|
repeat
|
||
|
|
EnumerateNodes(HidDev, Node, Idx, 1);
|
||
|
|
Idx := HidDev.LinkCollectionNodes[Idx].NextSibling;
|
||
|
|
until Idx = 0;
|
||
|
|
|
||
|
|
DeviceTree.FullExpand;
|
||
|
|
Result := True;
|
||
|
|
end;
|
||
|
|
|
||
|
|
procedure TCollectionDemoForm.SaveClick(Sender: TObject);
|
||
|
|
begin
|
||
|
|
// write the treeview content to a file to avoid the need
|
||
|
|
// to send screenshots
|
||
|
|
if SaveDialog.Execute then
|
||
|
|
DeviceTree.SaveToFile(SaveDialog.FileName);
|
||
|
|
end;
|
||
|
|
|
||
|
|
end.
|