Added: automatic detection of Throttle plug in / out
Added: actual SimConnect connection and auto-reconnect
This commit is contained in:
parent
f1b9a63fda
commit
4d0e2a5af6
@ -101,7 +101,6 @@ object ButtonFunctionForm: TButtonFunctionForm
|
|||||||
OnFocusChanged = vstFunctionsFocusChanged
|
OnFocusChanged = vstFunctionsFocusChanged
|
||||||
OnGetText = vstFunctionsGetText
|
OnGetText = vstFunctionsGetText
|
||||||
OnPaintText = vstFunctionsPaintText
|
OnPaintText = vstFunctionsPaintText
|
||||||
ExplicitHeight = 383
|
|
||||||
Columns = <
|
Columns = <
|
||||||
item
|
item
|
||||||
Position = 0
|
Position = 0
|
||||||
@ -122,7 +121,6 @@ object ButtonFunctionForm: TButtonFunctionForm
|
|||||||
Align = alClient
|
Align = alClient
|
||||||
BevelOuter = bvNone
|
BevelOuter = bvNone
|
||||||
TabOrder = 1
|
TabOrder = 1
|
||||||
ExplicitHeight = 383
|
|
||||||
object pnlName: TPanel
|
object pnlName: TPanel
|
||||||
Left = 0
|
Left = 0
|
||||||
Top = 0
|
Top = 0
|
||||||
@ -194,7 +192,6 @@ object ButtonFunctionForm: TButtonFunctionForm
|
|||||||
Align = alClient
|
Align = alClient
|
||||||
BorderStyle = bsNone
|
BorderStyle = bsNone
|
||||||
TabOrder = 1
|
TabOrder = 1
|
||||||
ExplicitHeight = 286
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
object pnlHeader: TPanel
|
object pnlHeader: TPanel
|
||||||
|
@ -469,7 +469,7 @@ begin
|
|||||||
FreeAndNil(FComboBox);
|
FreeAndNil(FComboBox);
|
||||||
FreeAndNil(FStateLabel);
|
FreeAndNil(FStateLabel);
|
||||||
|
|
||||||
inherited;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@ -356,6 +356,10 @@ object MainForm: TMainForm
|
|||||||
object tsAbout: TTabSheet
|
object tsAbout: TTabSheet
|
||||||
Caption = 'About'
|
Caption = 'About'
|
||||||
ImageIndex = 1
|
ImageIndex = 1
|
||||||
|
ExplicitLeft = 0
|
||||||
|
ExplicitTop = 0
|
||||||
|
ExplicitWidth = 0
|
||||||
|
ExplicitHeight = 0
|
||||||
object lblVersionCaption: TLabel
|
object lblVersionCaption: TLabel
|
||||||
Left = 16
|
Left = 16
|
||||||
Top = 67
|
Top = 67
|
||||||
@ -842,16 +846,5 @@ object MainForm: TMainForm
|
|||||||
ParentFont = False
|
ParentFont = False
|
||||||
ExplicitWidth = 401
|
ExplicitWidth = 401
|
||||||
end
|
end
|
||||||
object btnRetry: TButton
|
|
||||||
Left = 374
|
|
||||||
Top = 20
|
|
||||||
Width = 75
|
|
||||||
Height = 25
|
|
||||||
Anchors = [akTop, akRight]
|
|
||||||
Caption = '&Retry'
|
|
||||||
TabOrder = 0
|
|
||||||
Visible = False
|
|
||||||
OnClick = btnRetryClick
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,15 +2,15 @@ unit MainFrm;
|
|||||||
|
|
||||||
interface
|
interface
|
||||||
uses
|
uses
|
||||||
Classes,
|
System.Classes,
|
||||||
Contnrs,
|
System.Contnrs,
|
||||||
Controls,
|
Vcl.ComCtrls,
|
||||||
ComCtrls,
|
Vcl.Controls,
|
||||||
ExtCtrls,
|
Vcl.ExtCtrls,
|
||||||
Forms,
|
Vcl.Forms,
|
||||||
Messages,
|
Vcl.StdCtrls,
|
||||||
StdCtrls,
|
Winapi.Messages,
|
||||||
Windows,
|
Winapi.Windows,
|
||||||
|
|
||||||
OtlComm,
|
OtlComm,
|
||||||
OtlEventMonitor,
|
OtlEventMonitor,
|
||||||
@ -20,7 +20,7 @@ uses
|
|||||||
X2UtPersistIntf,
|
X2UtPersistIntf,
|
||||||
|
|
||||||
LEDStateConsumer,
|
LEDStateConsumer,
|
||||||
Profile;
|
Profile, Vcl.AppEvnts;
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
@ -31,6 +31,12 @@ const
|
|||||||
|
|
||||||
LED_COUNT = 8;
|
LED_COUNT = 8;
|
||||||
|
|
||||||
|
DBT_DEVICEARRIVAL = $8000;
|
||||||
|
DBT_DEVICEREMOVECOMPLETE = $8004;
|
||||||
|
DBT_DEVTYP_DEVICEINTERFACE = $0005;
|
||||||
|
DEVICE_NOTIFY_ALL_INTERFACE_CLASSES = $0004;
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TLEDControls = record
|
TLEDControls = record
|
||||||
ConfigureButton: TButton;
|
ConfigureButton: TButton;
|
||||||
@ -44,7 +50,6 @@ type
|
|||||||
lblG940Throttle: TLabel;
|
lblG940Throttle: TLabel;
|
||||||
imgStateFound: TImage;
|
imgStateFound: TImage;
|
||||||
lblG940ThrottleState: TLabel;
|
lblG940ThrottleState: TLabel;
|
||||||
btnRetry: TButton;
|
|
||||||
PageControl: TPageControl;
|
PageControl: TPageControl;
|
||||||
pnlG940: TPanel;
|
pnlG940: TPanel;
|
||||||
tsAbout: TTabSheet;
|
tsAbout: TTabSheet;
|
||||||
@ -91,7 +96,6 @@ type
|
|||||||
bvlProfiles: TBevel;
|
bvlProfiles: TBevel;
|
||||||
|
|
||||||
procedure FormCreate(Sender: TObject);
|
procedure FormCreate(Sender: TObject);
|
||||||
procedure btnRetryClick(Sender: TObject);
|
|
||||||
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
|
||||||
procedure lblLinkLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType);
|
procedure lblLinkLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType);
|
||||||
procedure btnCheckUpdatesClick(Sender: TObject);
|
procedure btnCheckUpdatesClick(Sender: TObject);
|
||||||
@ -107,6 +111,14 @@ type
|
|||||||
FActiveProfile: TProfile;
|
FActiveProfile: TProfile;
|
||||||
FLoadingProfiles: Boolean;
|
FLoadingProfiles: Boolean;
|
||||||
FStateConsumerTask: IOmniTaskControl;
|
FStateConsumerTask: IOmniTaskControl;
|
||||||
|
|
||||||
|
FDeviceNotification: Pointer;
|
||||||
|
FG940Found: Boolean;
|
||||||
|
protected
|
||||||
|
procedure RegisterDeviceArrival;
|
||||||
|
procedure UnregisterDeviceArrival;
|
||||||
|
|
||||||
|
procedure WMDeviceChange(var Msg: TMessage); message WM_DEVICECHANGE;
|
||||||
protected
|
protected
|
||||||
procedure FindLEDControls;
|
procedure FindLEDControls;
|
||||||
procedure LoadProfiles;
|
procedure LoadProfiles;
|
||||||
@ -126,9 +138,6 @@ type
|
|||||||
procedure EventMonitorTerminated(const task: IOmniTaskControl);
|
procedure EventMonitorTerminated(const task: IOmniTaskControl);
|
||||||
|
|
||||||
procedure HandleDeviceStateMessage(ATask: IOmniTaskControl; AMessage: TOmniMessage);
|
procedure HandleDeviceStateMessage(ATask: IOmniTaskControl; AMessage: TOmniMessage);
|
||||||
procedure HandleRunInMainThreadMessage(ATask: IOmniTaskControl; AMessage: TOmniMessage);
|
|
||||||
procedure HandleProviderKilled(ATask: IOmniTaskControl; AMessage: TOmniMessage);
|
|
||||||
procedure HandleProviderKilledFSX(ATask: IOmniTaskControl; AMessage: TOmniMessage);
|
|
||||||
|
|
||||||
procedure CMAskAutoUpdate(var Msg: TMessage); message CM_ASKAUTOUPDATE;
|
procedure CMAskAutoUpdate(var Msg: TMessage); message CM_ASKAUTOUPDATE;
|
||||||
|
|
||||||
@ -204,9 +213,10 @@ begin
|
|||||||
FProfiles := TProfileList.Create(True);
|
FProfiles := TProfileList.Create(True);
|
||||||
LoadProfiles;
|
LoadProfiles;
|
||||||
|
|
||||||
|
// TODO implement profile changing properly
|
||||||
FStateConsumerTask.Comm.Send(TM_LOADPROFILE, ActiveProfile);
|
FStateConsumerTask.Comm.Send(TM_LOADPROFILE, ActiveProfile);
|
||||||
// LoadFunctions(TFSXLEDStateProvider, FFSXComboBoxes);
|
|
||||||
// LoadDefaultProfile;
|
RegisterDeviceArrival;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -225,10 +235,63 @@ end;
|
|||||||
|
|
||||||
procedure TMainForm.FormDestroy(Sender: TObject);
|
procedure TMainForm.FormDestroy(Sender: TObject);
|
||||||
begin
|
begin
|
||||||
|
UnregisterDeviceArrival;
|
||||||
|
|
||||||
FreeAndNil(FProfiles);
|
FreeAndNil(FProfiles);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMainForm.RegisterDeviceArrival;
|
||||||
|
type
|
||||||
|
TDevBroadcastDeviceInterface = packed record
|
||||||
|
dbcc_size: DWORD;
|
||||||
|
dbcc_devicetype: DWORD;
|
||||||
|
dbcc_reserved: DWORD;
|
||||||
|
dbcc_classguid: TGUID;
|
||||||
|
dbcc_name: PChar;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
request: TDevBroadcastDeviceInterface;
|
||||||
|
|
||||||
|
begin
|
||||||
|
ZeroMemory(@request, SizeOf(request));
|
||||||
|
request.dbcc_size := SizeOf(request);
|
||||||
|
request.dbcc_devicetype := DBT_DEVTYP_DEVICEINTERFACE;
|
||||||
|
|
||||||
|
FDeviceNotification := RegisterDeviceNotification(Self.Handle, @request,
|
||||||
|
DEVICE_NOTIFY_WINDOW_HANDLE or
|
||||||
|
DEVICE_NOTIFY_ALL_INTERFACE_CLASSES);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMainForm.UnregisterDeviceArrival;
|
||||||
|
begin
|
||||||
|
if Assigned(FDeviceNotification) then
|
||||||
|
begin
|
||||||
|
UnregisterDeviceNotification(FDeviceNotification);
|
||||||
|
FDeviceNotification := nil;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMainForm.WMDeviceChange(var Msg: TMessage);
|
||||||
|
begin
|
||||||
|
if not Assigned(StateConsumerTask) then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
case Msg.WParam of
|
||||||
|
DBT_DEVICEARRIVAL:
|
||||||
|
if (not FG940Found) then
|
||||||
|
StateConsumerTask.Comm.Send(TM_FINDTHROTTLEDEVICE);
|
||||||
|
|
||||||
|
DBT_DEVICEREMOVECOMPLETE:
|
||||||
|
if FG940Found then
|
||||||
|
StateConsumerTask.Comm.Send(TM_TESTTHROTTLEDEVICE);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.FindLEDControls;
|
procedure TMainForm.FindLEDControls;
|
||||||
|
|
||||||
function ComponentByName(const AName: string; ATag: NativeInt): TComponent;
|
function ComponentByName(const AName: string; ATag: NativeInt): TComponent;
|
||||||
@ -417,36 +480,11 @@ begin
|
|||||||
|
|
||||||
imgStateFound.Visible := AFound;
|
imgStateFound.Visible := AFound;
|
||||||
imgStateNotFound.Visible := not AFound;
|
imgStateNotFound.Visible := not AFound;
|
||||||
|
|
||||||
|
FG940Found := AFound;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
//procedure TMainForm.ReadFunctions(AReader: IX2PersistReader; AComboBoxes: TComboBoxArray);
|
|
||||||
//var
|
|
||||||
// comboBox: TComboBoxEx;
|
|
||||||
// value: Integer;
|
|
||||||
// itemIndex: Integer;
|
|
||||||
//
|
|
||||||
//begin
|
|
||||||
// if AReader.BeginSection(SECTION_FSX) then
|
|
||||||
// try
|
|
||||||
// for comboBox in AComboBoxes do
|
|
||||||
// begin
|
|
||||||
// if AReader.ReadInteger('Function' + IntToStr(comboBox.Tag), value) then
|
|
||||||
// begin
|
|
||||||
// for itemIndex := 0 to Pred(comboBox.ItemsEx.Count) do
|
|
||||||
// if Integer(comboBox.ItemsEx[itemIndex].Data) = value then
|
|
||||||
// begin
|
|
||||||
// comboBox.ItemIndex := itemIndex;
|
|
||||||
// break;
|
|
||||||
// end;
|
|
||||||
// end;
|
|
||||||
// end;
|
|
||||||
// finally
|
|
||||||
// AReader.EndSection;
|
|
||||||
// end;
|
|
||||||
//end;
|
|
||||||
|
|
||||||
|
|
||||||
//procedure TMainForm.ReadAutoUpdate(AReader: IX2PersistReader);
|
//procedure TMainForm.ReadAutoUpdate(AReader: IX2PersistReader);
|
||||||
//var
|
//var
|
||||||
// checkUpdates: Boolean;
|
// checkUpdates: Boolean;
|
||||||
@ -484,29 +522,6 @@ end;
|
|||||||
//end;
|
//end;
|
||||||
|
|
||||||
|
|
||||||
//procedure TMainForm.InitializeStateProvider(AProviderClass: TLEDStateProviderClass);
|
|
||||||
//begin
|
|
||||||
// UpdateMapping;
|
|
||||||
// LEDStateConsumer.InitializeStateProvider(StateConsumerTask, AProviderClass);
|
|
||||||
//end;
|
|
||||||
//
|
|
||||||
//
|
|
||||||
//procedure TMainForm.FinalizeStateProvider;
|
|
||||||
//begin
|
|
||||||
// LEDStateConsumer.FinalizeStateProvider(StateConsumerTask);
|
|
||||||
//end;
|
|
||||||
|
|
||||||
|
|
||||||
//procedure TMainForm.UpdateMapping;
|
|
||||||
//begin
|
|
||||||
// if not Assigned(StateConsumerTask) then
|
|
||||||
// Exit;
|
|
||||||
//
|
|
||||||
// LEDStateConsumer.ClearFunctions(StateConsumerTask);
|
|
||||||
// SetFunctions(FFSXComboBoxes);
|
|
||||||
//end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.LEDButtonClick(Sender: TObject);
|
procedure TMainForm.LEDButtonClick(Sender: TObject);
|
||||||
var
|
var
|
||||||
buttonIndex: NativeInt;
|
buttonIndex: NativeInt;
|
||||||
@ -628,32 +643,31 @@ end;
|
|||||||
procedure TMainForm.EventMonitorMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
|
procedure TMainForm.EventMonitorMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
|
||||||
begin
|
begin
|
||||||
case msg.MsgID of
|
case msg.MsgID of
|
||||||
TM_NOTIFY_DEVICESTATE: HandleDeviceStateMessage(task, msg);
|
TM_NOTIFY_DEVICESTATE:
|
||||||
// MSG_RUN_IN_MAINTHREAD: HandleRunInMainThreadMessage(task, msg);
|
HandleDeviceStateMessage(task, msg);
|
||||||
// MSG_PROVIDER_KILLED: HandleProviderKilled(task, msg);
|
|
||||||
|
|
||||||
MSG_UPDATE:
|
MSG_UPDATE:
|
||||||
if MessageBox(Self.Handle, 'An update is available on the G940 LED Control website.'#13#10'Do you want to go there now?',
|
if MessageBox(Self.Handle, 'An update is available on the G940 LED Control website.'#13#10'Do you want to go there now?',
|
||||||
'Update available', MB_YESNO or MB_ICONINFORMATION) = ID_YES then
|
'Update available', MB_YESNO or MB_ICONINFORMATION) = ID_YES then
|
||||||
ShellExecute(Self.Handle, 'open', PChar('http://g940.x2software.net/#download'), nil, nil, SW_SHOWNORMAL);
|
ShellExecute(Self.Handle, 'open', PChar('http://g940.x2software.net/#download'), nil, nil, SW_SHOWNORMAL);
|
||||||
|
|
||||||
// MSG_NOUPDATE:
|
MSG_NOUPDATE:
|
||||||
// if msg.MsgData.AsBoolean then
|
if msg.MsgData.AsBoolean then
|
||||||
// MessageBox(Self.Handle, 'You are using the latest version.', 'No update available', MB_OK or MB_ICONINFORMATION)
|
MessageBox(Self.Handle, 'You are using the latest version.', 'No update available', MB_OK or MB_ICONINFORMATION)
|
||||||
// else
|
else
|
||||||
// MessageBox(Self.Handle, 'Failed to check for updates. Maybe try again later?', 'Uh-oh', MB_OK or MB_ICONWARNING);
|
MessageBox(Self.Handle, 'Failed to check for updates. Maybe try again later?', 'Uh-oh', MB_OK or MB_ICONWARNING);
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.EventMonitorTerminated(const task: IOmniTaskControl);
|
procedure TMainForm.EventMonitorTerminated(const task: IOmniTaskControl);
|
||||||
begin
|
begin
|
||||||
// if task = StateConsumerTask then
|
if task = StateConsumerTask then
|
||||||
// begin
|
begin
|
||||||
// FStateConsumerTask := nil;
|
FStateConsumerTask := nil;
|
||||||
// Close;
|
Close;
|
||||||
// end else if task.Name = 'CheckForUpdatesThread' then
|
end else if task.Name = 'CheckForUpdatesThread' then
|
||||||
// btnCheckUpdates.Enabled := True;
|
btnCheckUpdates.Enabled := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -667,42 +681,8 @@ begin
|
|||||||
SetDeviceState(TEXT_STATE_FOUND, True);
|
SetDeviceState(TEXT_STATE_FOUND, True);
|
||||||
|
|
||||||
DEVICESTATE_NOTFOUND:
|
DEVICESTATE_NOTFOUND:
|
||||||
begin
|
|
||||||
SetDeviceState(TEXT_STATE_NOTFOUND, False);
|
SetDeviceState(TEXT_STATE_NOTFOUND, False);
|
||||||
btnRetry.Visible := True;
|
|
||||||
end;
|
end;
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.HandleRunInMainThreadMessage(ATask: IOmniTaskControl; AMessage: TOmniMessage);
|
|
||||||
var
|
|
||||||
executor: IRunInMainThread;
|
|
||||||
|
|
||||||
begin
|
|
||||||
executor := (AMessage.MsgData.AsInterface as IRunInMainThread);
|
|
||||||
executor.Execute;
|
|
||||||
executor.Signal;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.HandleProviderKilled(ATask: IOmniTaskControl; AMessage: TOmniMessage);
|
|
||||||
begin
|
|
||||||
HandleProviderKilledFSX(ATask, AMessage);
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.HandleProviderKilledFSX(ATask: IOmniTaskControl; AMessage: TOmniMessage);
|
|
||||||
var
|
|
||||||
msg: string;
|
|
||||||
|
|
||||||
begin
|
|
||||||
// btnFSXDisconnect.Enabled := False;
|
|
||||||
// btnFSXConnect.Enabled := True;
|
|
||||||
|
|
||||||
msg := AMessage.MsgData;
|
|
||||||
if Length(msg) > 0 then
|
|
||||||
ShowMessage(msg);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -712,13 +692,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.btnRetryClick(Sender: TObject);
|
|
||||||
begin
|
|
||||||
btnRetry.Visible := False;
|
|
||||||
// StateConsumerTask.Comm.Send(MSG_FINDTHROTTLEDEVICE);
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure TMainForm.lblLinkLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType);
|
procedure TMainForm.lblLinkLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType);
|
||||||
begin
|
begin
|
||||||
ShellExecute(Self.Handle, 'open', PChar(Link), nil, nil, SW_SHOWNORMAL);
|
ShellExecute(Self.Handle, 'open', PChar(Link), nil, nil, SW_SHOWNORMAL);
|
||||||
|
@ -98,7 +98,6 @@
|
|||||||
<DCC_UNIT_PLATFORM>False</DCC_UNIT_PLATFORM>
|
<DCC_UNIT_PLATFORM>False</DCC_UNIT_PLATFORM>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
|
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
|
||||||
<DCC_DebugDCUs>true</DCC_DebugDCUs>
|
|
||||||
<VerInfo_IncludeVerInfo>false</VerInfo_IncludeVerInfo>
|
<VerInfo_IncludeVerInfo>false</VerInfo_IncludeVerInfo>
|
||||||
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=0.2.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=0.2;Comments=</VerInfo_Keys>
|
<VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=0.2.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=0.2;Comments=</VerInfo_Keys>
|
||||||
<Manifest_File>F:\Components\X2Utils\Resources\VistaManAsInvoker.manifest</Manifest_File>
|
<Manifest_File>F:\Components\X2Utils\Resources\VistaManAsInvoker.manifest</Manifest_File>
|
||||||
|
@ -92,13 +92,13 @@ type
|
|||||||
{ Worker implementations }
|
{ Worker implementations }
|
||||||
TFSXEngineFunctionWorker = class(TCustomFSXFunctionWorker)
|
TFSXEngineFunctionWorker = class(TCustomFSXFunctionWorker)
|
||||||
protected
|
protected
|
||||||
procedure RegisterVariables; override;
|
procedure RegisterVariables(ADefinition: IFSXSimConnectDefinition); override;
|
||||||
procedure HandleData(AData: Pointer); override;
|
procedure HandleData(AData: Pointer); override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TFSXGearFunctionWorker = class(TCustomFSXFunctionWorker)
|
TFSXGearFunctionWorker = class(TCustomFSXFunctionWorker)
|
||||||
protected
|
protected
|
||||||
procedure RegisterVariables; override;
|
procedure RegisterVariables(ADefinition: IFSXSimConnectDefinition); override;
|
||||||
procedure HandleData(AData: Pointer); override;
|
procedure HandleData(AData: Pointer); override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ type
|
|||||||
private
|
private
|
||||||
FStateMask: Integer;
|
FStateMask: Integer;
|
||||||
protected
|
protected
|
||||||
procedure RegisterVariables; override;
|
procedure RegisterVariables(ADefinition: IFSXSimConnectDefinition); override;
|
||||||
procedure HandleData(AData: Pointer); override;
|
procedure HandleData(AData: Pointer); override;
|
||||||
public
|
public
|
||||||
property StateMask: Integer read FStateMask write FStateMask;
|
property StateMask: Integer read FStateMask write FStateMask;
|
||||||
@ -140,21 +140,21 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
{ TFSXEngineFunctionWorker }
|
{ TFSXEngineFunctionWorker }
|
||||||
procedure TFSXEngineFunctionWorker.RegisterVariables;
|
procedure TFSXEngineFunctionWorker.RegisterVariables(ADefinition: IFSXSimConnectDefinition);
|
||||||
var
|
var
|
||||||
engineIndex: Integer;
|
engineIndex: Integer;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Definition.AddVariable('NUMBER OF ENGINES', FSX_UNIT_NUMBER, SIMCONNECT_DATAType_INT32);
|
ADefinition.AddVariable('NUMBER OF ENGINES', FSX_UNIT_NUMBER, SIMCONNECT_DATAType_INT32);
|
||||||
|
|
||||||
for engineIndex := 1 to FSX_MAX_ENGINES do
|
for engineIndex := 1 to FSX_MAX_ENGINES do
|
||||||
Definition.AddVariable(Format('GENERAL ENG COMBUSTION:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
ADefinition.AddVariable(Format('GENERAL ENG COMBUSTION:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
||||||
|
|
||||||
for engineIndex := 1 to FSX_MAX_ENGINES do
|
for engineIndex := 1 to FSX_MAX_ENGINES do
|
||||||
Definition.AddVariable(Format('ENG FAILED:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
ADefinition.AddVariable(Format('ENG FAILED:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
||||||
|
|
||||||
for engineIndex := 1 to FSX_MAX_ENGINES do
|
for engineIndex := 1 to FSX_MAX_ENGINES do
|
||||||
Definition.AddVariable(Format('ENG ON FIRE:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
ADefinition.AddVariable(Format('ENG ON FIRE:%d', [engineIndex]), FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -236,12 +236,12 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
{ TFSXGearFunctionWorker }
|
{ TFSXGearFunctionWorker }
|
||||||
procedure TFSXGearFunctionWorker.RegisterVariables;
|
procedure TFSXGearFunctionWorker.RegisterVariables(ADefinition: IFSXSimConnectDefinition);
|
||||||
begin
|
begin
|
||||||
Definition.AddVariable('IS GEAR RETRACTABLE', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
ADefinition.AddVariable('IS GEAR RETRACTABLE', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
||||||
Definition.AddVariable('GEAR TOTAL PCT EXTENDED', FSX_UNIT_PERCENT, SIMCONNECT_DATAType_FLOAT64);
|
ADefinition.AddVariable('GEAR TOTAL PCT EXTENDED', FSX_UNIT_PERCENT, SIMCONNECT_DATAType_FLOAT64);
|
||||||
Definition.AddVariable('GEAR DAMAGE BY SPEED', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
ADefinition.AddVariable('GEAR DAMAGE BY SPEED', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
||||||
Definition.AddVariable('GEAR SPEED EXCEEDED', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
ADefinition.AddVariable('GEAR SPEED EXCEEDED', FSX_UNIT_BOOL, SIMCONNECT_DATAType_INT32);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -349,9 +349,9 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
{ TFSXLightStatesFunctionWorker }
|
{ TFSXLightStatesFunctionWorker }
|
||||||
procedure TFSXLightStatesFunctionWorker.RegisterVariables;
|
procedure TFSXLightStatesFunctionWorker.RegisterVariables(ADefinition: IFSXSimConnectDefinition);
|
||||||
begin
|
begin
|
||||||
Definition.AddVariable('LIGHT ON STATES', FSX_UNIT_MASK, SIMCONNECT_DATATYPE_INT32);
|
ADefinition.AddVariable('LIGHT ON STATES', FSX_UNIT_MASK, SIMCONNECT_DATATYPE_INT32);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ type
|
|||||||
|
|
||||||
TFSXLEDFunctionProvider = class(TCustomLEDFunctionProvider, IFSXSimConnectObserver)
|
TFSXLEDFunctionProvider = class(TCustomLEDFunctionProvider, IFSXSimConnectObserver)
|
||||||
private
|
private
|
||||||
FSimConnect: IFSXSimConnect;
|
FSimConnect: TInterfacedObject;
|
||||||
FSimConnectLock: TCriticalSection;
|
FSimConnectLock: TCriticalSection;
|
||||||
protected
|
protected
|
||||||
procedure RegisterFunctions; override;
|
procedure RegisterFunctions; override;
|
||||||
@ -41,6 +41,8 @@ type
|
|||||||
FDisplayName: string;
|
FDisplayName: string;
|
||||||
FUID: string;
|
FUID: string;
|
||||||
protected
|
protected
|
||||||
|
function DoCreateWorker(ASettings: ILEDFunctionWorkerSettings): TCustomLEDFunctionWorker; override;
|
||||||
|
|
||||||
property Provider: TFSXLEDFunctionProvider read FProvider;
|
property Provider: TFSXLEDFunctionProvider read FProvider;
|
||||||
protected
|
protected
|
||||||
function GetCategoryName: string; override;
|
function GetCategoryName: string; override;
|
||||||
@ -54,26 +56,30 @@ type
|
|||||||
TCustomFSXFunctionClass = class of TCustomFSXFunction;
|
TCustomFSXFunctionClass = class of TCustomFSXFunction;
|
||||||
|
|
||||||
|
|
||||||
TCustomFSXFunctionWorker = class(TCustomLEDFunctionWorker, IFSXSimConnectDataHandler)
|
TCustomFSXFunctionWorker = class(TCustomLEDFunctionWorker)
|
||||||
private
|
private
|
||||||
|
FDataHandler: IFSXSimConnectDataHandler;
|
||||||
|
FDefinitionID: Cardinal;
|
||||||
FSimConnect: IFSXSimConnect;
|
FSimConnect: IFSXSimConnect;
|
||||||
FDefinition: IFSXSimConnectDefinition;
|
|
||||||
FCurrentStateLock: TCriticalSection;
|
FCurrentStateLock: TCriticalSection;
|
||||||
FCurrentState: ILEDStateWorker;
|
FCurrentState: ILEDStateWorker;
|
||||||
protected
|
protected
|
||||||
procedure RegisterVariables; virtual; abstract;
|
procedure RegisterStates(AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings); override;
|
||||||
|
procedure RegisterVariables(ADefinition: IFSXSimConnectDefinition); virtual; abstract;
|
||||||
|
|
||||||
procedure SetCurrentState(const AUID: string);
|
procedure SetCurrentState(const AUID: string; ANotifyObservers: Boolean = True); overload; virtual;
|
||||||
|
procedure SetCurrentState(AState: ILEDStateWorker; ANotifyObservers: Boolean = True); overload; virtual;
|
||||||
|
procedure SetSimConnect(const Value: IFSXSimConnect); virtual;
|
||||||
|
|
||||||
property Definition: IFSXSimConnectDefinition read FDefinition;
|
property DataHandler: IFSXSimConnectDataHandler read FDataHandler;
|
||||||
property SimConnect: IFSXSimConnect read FSimConnect;
|
property DefinitionID: Cardinal read FDefinitionID;
|
||||||
|
property SimConnect: IFSXSimConnect read FSimConnect write SetSimConnect;
|
||||||
protected
|
protected
|
||||||
function GetCurrentState: ILEDStateWorker; override;
|
function GetCurrentState: ILEDStateWorker; override;
|
||||||
|
|
||||||
{ IFSXSimConnectDataHandler }
|
|
||||||
procedure HandleData(AData: Pointer); virtual; abstract;
|
procedure HandleData(AData: Pointer); virtual; abstract;
|
||||||
public
|
public
|
||||||
constructor Create(AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings; ASimConnect: IFSXSimConnect);
|
constructor Create(AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings); override;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -89,6 +95,20 @@ uses
|
|||||||
SimConnect;
|
SimConnect;
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
TCustomFSXFunctionWorkerDataHandler = class(TInterfacedObject, IFSXSimConnectDataHandler)
|
||||||
|
private
|
||||||
|
FWorker: TCustomFSXFunctionWorker;
|
||||||
|
protected
|
||||||
|
{ IFSXSimConnectDataHandler }
|
||||||
|
procedure HandleData(AData: Pointer);
|
||||||
|
|
||||||
|
property Worker: TCustomFSXFunctionWorker read FWorker;
|
||||||
|
public
|
||||||
|
constructor Create(AWorker: TCustomFSXFunctionWorker);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ TFSXLEDFunctionProvider }
|
{ TFSXLEDFunctionProvider }
|
||||||
constructor TFSXLEDFunctionProvider.Create;
|
constructor TFSXLEDFunctionProvider.Create;
|
||||||
@ -167,11 +187,13 @@ begin
|
|||||||
try
|
try
|
||||||
if not Assigned(FSimConnect) then
|
if not Assigned(FSimConnect) then
|
||||||
begin
|
begin
|
||||||
|
{ Keep an object reference so we don't increment the reference count.
|
||||||
|
We'll know when it's gone through the ObserveDestroy. }
|
||||||
FSimConnect := TFSXSimConnectInterface.Create;
|
FSimConnect := TFSXSimConnectInterface.Create;
|
||||||
FSimConnect.Attach(Self);
|
(FSimConnect as IFSXSimConnect).Attach(Self);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
Result := FSimConnect;
|
Result := (FSimConnect as IFSXSimConnect);
|
||||||
finally
|
finally
|
||||||
FSimConnectLock.Release;
|
FSimConnectLock.Release;
|
||||||
end;
|
end;
|
||||||
@ -189,6 +211,14 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TCustomFSXFunction.DoCreateWorker(ASettings: ILEDFunctionWorkerSettings): TCustomLEDFunctionWorker;
|
||||||
|
begin
|
||||||
|
Result := inherited DoCreateWorker(ASettings);
|
||||||
|
|
||||||
|
(Result as TCustomFSXFunctionWorker).SimConnect := Provider.GetSimConnect;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
function TCustomFSXFunction.GetCategoryName: string;
|
function TCustomFSXFunction.GetCategoryName: string;
|
||||||
begin
|
begin
|
||||||
Result := FSXCategory;
|
Result := FSXCategory;
|
||||||
@ -208,18 +238,16 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
{ TCustomFSXFunctionWorker }
|
{ TCustomFSXFunctionWorker }
|
||||||
constructor TCustomFSXFunctionWorker.Create(AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings; ASimConnect: IFSXSimConnect);
|
constructor TCustomFSXFunctionWorker.Create(AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings);
|
||||||
begin
|
begin
|
||||||
inherited Create(AStates, ASettings);
|
|
||||||
|
|
||||||
FCurrentStateLock := TCriticalSection.Create;
|
FCurrentStateLock := TCriticalSection.Create;
|
||||||
FSimConnect := ASimConnect;
|
|
||||||
|
|
||||||
FDefinition := ASimConnect.CreateDefinition;
|
{ We can't pass ourselves as the Data Handler, as it would keep a reference to
|
||||||
RegisterVariables;
|
this worker from the SimConnect interface. That'd mean the worker never
|
||||||
|
gets destroyed, and SimConnect never shuts down. Hence this proxy class. }
|
||||||
|
FDataHandler := TCustomFSXFunctionWorkerDataHandler.Create(Self);
|
||||||
|
|
||||||
// TODO pass self as callback for this definition
|
inherited Create(AStates, ASettings);
|
||||||
ASimConnect.AddDefinition(FDefinition, Self);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -227,7 +255,20 @@ destructor TCustomFSXFunctionWorker.Destroy;
|
|||||||
begin
|
begin
|
||||||
FreeAndNil(FCurrentStateLock);
|
FreeAndNil(FCurrentStateLock);
|
||||||
|
|
||||||
inherited;
|
if DefinitionID <> 0 then
|
||||||
|
SimConnect.RemoveDefinition(DefinitionID, DataHandler);
|
||||||
|
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TCustomFSXFunctionWorker.RegisterStates(AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings);
|
||||||
|
begin
|
||||||
|
inherited RegisterStates(AStates, ASettings);
|
||||||
|
|
||||||
|
{ Make sure we have a default state }
|
||||||
|
if States.Count > 0 then
|
||||||
|
SetCurrentState((States[0] as ILEDStateWorker), False);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -242,17 +283,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TCustomFSXFunctionWorker.SetCurrentState(const AUID: string);
|
procedure TCustomFSXFunctionWorker.SetCurrentState(const AUID: string; ANotifyObservers: Boolean);
|
||||||
var
|
begin
|
||||||
newState: ILEDStateWorker;
|
SetCurrentState(FindState(AUID), ANotifyObservers);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TCustomFSXFunctionWorker.SetCurrentState(AState: ILEDStateWorker; ANotifyObservers: Boolean);
|
||||||
begin
|
begin
|
||||||
FCurrentStateLock.Acquire;
|
FCurrentStateLock.Acquire;
|
||||||
try
|
try
|
||||||
newState := FindState(AUID);
|
if AState <> FCurrentState then
|
||||||
if newState <> FCurrentState then
|
|
||||||
begin
|
begin
|
||||||
FCurrentState := newState;
|
FCurrentState := AState;
|
||||||
|
|
||||||
|
if ANotifyObservers then
|
||||||
NotifyObservers;
|
NotifyObservers;
|
||||||
end;
|
end;
|
||||||
finally
|
finally
|
||||||
@ -261,6 +306,38 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TCustomFSXFunctionWorker.SetSimConnect(const Value: IFSXSimConnect);
|
||||||
|
var
|
||||||
|
definition: IFSXSimConnectDefinition;
|
||||||
|
|
||||||
|
begin
|
||||||
|
FSimConnect := Value;
|
||||||
|
|
||||||
|
if Assigned(SimConnect) then
|
||||||
|
begin
|
||||||
|
definition := SimConnect.CreateDefinition;
|
||||||
|
RegisterVariables(definition);
|
||||||
|
|
||||||
|
FDefinitionID := SimConnect.AddDefinition(definition, DataHandler);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TCustomFSXFunctionWorkerDataHandler }
|
||||||
|
constructor TCustomFSXFunctionWorkerDataHandler.Create(AWorker: TCustomFSXFunctionWorker);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
|
||||||
|
FWorker := AWorker;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TCustomFSXFunctionWorkerDataHandler.HandleData(AData: Pointer);
|
||||||
|
begin
|
||||||
|
Worker.HandleData(AData);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
TLEDFunctionRegistry.Register(TFSXLEDFunctionProvider.Create);
|
TLEDFunctionRegistry.Register(TFSXLEDFunctionProvider.Create);
|
||||||
|
|
||||||
|
@ -2,6 +2,8 @@ unit FSXResources;
|
|||||||
|
|
||||||
interface
|
interface
|
||||||
const
|
const
|
||||||
|
FSXSimConnectAppName = 'G940 LED Control';
|
||||||
|
|
||||||
FSXProviderUID = 'fsx';
|
FSXProviderUID = 'fsx';
|
||||||
FSXCategory = 'Flight Simulator X';
|
FSXCategory = 'Flight Simulator X';
|
||||||
FSXCategoryLights = FSXCategory + ' - Lights';
|
FSXCategoryLights = FSXCategory + ' - Lights';
|
||||||
|
@ -23,8 +23,8 @@ type
|
|||||||
procedure Detach(AObserver: IFSXSimConnectObserver);
|
procedure Detach(AObserver: IFSXSimConnectObserver);
|
||||||
|
|
||||||
function CreateDefinition: IFSXSimConnectDefinition;
|
function CreateDefinition: IFSXSimConnectDefinition;
|
||||||
procedure AddDefinition(ADefinition: IFSXSimConnectDefinition; ADataHandler: IFSXSimConnectDataHandler);
|
function AddDefinition(ADefinition: IFSXSimConnectDefinition; ADataHandler: IFSXSimConnectDataHandler): Integer;
|
||||||
procedure RemoveDefinition(ADataHandler: IFSXSimConnectDataHandler);
|
procedure RemoveDefinition(ADefinitionID: Cardinal; ADataHandler: IFSXSimConnectDataHandler);
|
||||||
public
|
public
|
||||||
constructor Create;
|
constructor Create;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
@ -33,36 +33,149 @@ type
|
|||||||
|
|
||||||
implementation
|
implementation
|
||||||
uses
|
uses
|
||||||
|
Generics.Collections,
|
||||||
|
System.Math,
|
||||||
|
System.SyncObjs,
|
||||||
System.SysUtils,
|
System.SysUtils,
|
||||||
|
Winapi.Windows,
|
||||||
|
|
||||||
SimConnect;
|
OtlComm,
|
||||||
|
OtlCommon,
|
||||||
|
SimConnect,
|
||||||
|
|
||||||
|
FSXResources;
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
TM_ADDDEFINITION = 3001;
|
TM_ADDDEFINITION = 3001;
|
||||||
TM_REMOVEDEFINITION = 3002;
|
TM_REMOVEDEFINITION = 3002;
|
||||||
|
TM_TRYSIMCONNECT = 3003;
|
||||||
|
|
||||||
|
TIMER_TRYSIMCONNECT = 201;
|
||||||
|
|
||||||
|
INTERVAL_TRYSIMCONNECT = 5000;
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
TFSXSimConnectClient = class(TOmniWorker)
|
TFSXSimConnectDefinitionRef = class(TObject)
|
||||||
|
private
|
||||||
|
FDefinition: IFSXSimConnectDefinitionAccess;
|
||||||
|
FDataHandlers: TInterfaceList;
|
||||||
|
protected
|
||||||
|
property DataHandlers: TInterfaceList read FDataHandlers;
|
||||||
|
public
|
||||||
|
constructor Create(ADefinition: IFSXSimConnectDefinitionAccess);
|
||||||
|
destructor Destroy; override;
|
||||||
|
|
||||||
|
procedure Attach(ADataHandler: IFSXSimConnectDataHandler);
|
||||||
|
procedure Detach(ADataHandler: IFSXSimConnectDataHandler);
|
||||||
|
|
||||||
|
procedure HandleData(AData: Pointer);
|
||||||
|
|
||||||
|
property Definition: IFSXSimConnectDefinitionAccess read FDefinition;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
TFSXSimConnectDefinition = class(TInterfacedObject, IFSXSimConnectDefinition)
|
TFSXSimConnectDefinitionMap = TDictionary<Cardinal, TFSXSimConnectDefinitionRef>;
|
||||||
|
|
||||||
|
TFSXSimConnectClient = class(TOmniWorker)
|
||||||
|
private
|
||||||
|
FDefinitions: TFSXSimConnectDefinitionMap;
|
||||||
|
FLastDefinitionID: Cardinal;
|
||||||
|
FSimConnectHandle: THandle;
|
||||||
|
FSimConnectDataEvent: TEvent;
|
||||||
|
protected
|
||||||
|
procedure TMAddDefinition(var Msg: TOmniMessage); message TM_ADDDEFINITION;
|
||||||
|
procedure TMRemoveDefinition(var Msg: TOmniMessage); message TM_REMOVEDEFINITION;
|
||||||
|
procedure TMTrySimConnect(var Msg: TOmniMessage); message TM_TRYSIMCONNECT;
|
||||||
|
|
||||||
|
procedure HandleSimConnectDataEvent;
|
||||||
|
protected
|
||||||
|
function Initialize: Boolean; override;
|
||||||
|
procedure Cleanup; override;
|
||||||
|
|
||||||
|
procedure TrySimConnect;
|
||||||
|
|
||||||
|
procedure RegisterDefinitions;
|
||||||
|
procedure RegisterDefinition(ADefinitionID: Cardinal; ADefinition: IFSXSimConnectDefinitionAccess);
|
||||||
|
|
||||||
|
function SameDefinition(ADefinition1, ADefinition2: IFSXSimConnectDefinitionAccess): Boolean;
|
||||||
|
|
||||||
|
property Definitions: TFSXSimConnectDefinitionMap read FDefinitions;
|
||||||
|
property LastDefinitionID: Cardinal read FLastDefinitionID;
|
||||||
|
property SimConnectHandle: THandle read FSimConnectHandle;
|
||||||
|
property SimConnectDataEvent: TEvent read FSimConnectDataEvent;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
TFSXSimConnectVariable = class(TInterfacedPersistent, IFSXSimConnectVariable)
|
||||||
|
private
|
||||||
|
FVariableName: string;
|
||||||
|
FUnitsName: string;
|
||||||
|
FDataType: SIMCONNECT_DATAType;
|
||||||
|
FEpsilon: Single;
|
||||||
|
protected
|
||||||
|
{ IFSXSimConnectVariable }
|
||||||
|
function GetVariableName: string;
|
||||||
|
function GetUnitsName: string;
|
||||||
|
function GetDataType: SIMCONNECT_DATAType;
|
||||||
|
function GetEpsilon: Single;
|
||||||
|
public
|
||||||
|
constructor Create(AVariableName, AUnitsName: string; ADataType: SIMCONNECT_DATAType; AEpsilon: Single);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
TFSXSimConnectVariableList = TObjectList<TFSXSimConnectVariable>;
|
||||||
|
|
||||||
|
TFSXSimConnectDefinition = class(TInterfacedObject, IFSXSimConnectDefinition, IFSXSimConnectDefinitionAccess)
|
||||||
private
|
private
|
||||||
FSimConnect: IFSXSimConnect;
|
FSimConnect: IFSXSimConnect;
|
||||||
|
FVariables: TFSXSimConnectVariableList;
|
||||||
protected
|
protected
|
||||||
property SimConnect: IFSXSimConnect read FSimConnect;
|
property SimConnect: IFSXSimConnect read FSimConnect;
|
||||||
|
property Variables: TFSXSimConnectVariableList read FVariables;
|
||||||
protected
|
protected
|
||||||
{ IFSXSimConnectDefinition }
|
{ IFSXSimConnectDefinition }
|
||||||
procedure AddVariable(AVariableName, AUnitsName: string; ADatumType: SIMCONNECT_DATAType; AEpsilon: Single = 0);
|
procedure AddVariable(AVariableName, AUnitsName: string; ADataType: SIMCONNECT_DATAType; AEpsilon: Single = 0);
|
||||||
procedure Apply(ASimConnectHandle: THandle; ADefinitionID: Integer);
|
|
||||||
|
{ IFSXSimConnectDefinitionAccess }
|
||||||
|
function GetVariableCount: Integer;
|
||||||
|
function GetVariable(AIndex: Integer): IFSXSimConnectVariable;
|
||||||
public
|
public
|
||||||
constructor Create(ASimConnect: IFSXSimConnect);
|
constructor Create;
|
||||||
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TAddDefinitionValue = class(TOmniWaitableValue)
|
||||||
|
private
|
||||||
|
FDataHandler: IFSXSimConnectDataHandler;
|
||||||
|
FDefinition: IFSXSimConnectDefinition;
|
||||||
|
FDefinitionID: Cardinal;
|
||||||
|
|
||||||
|
procedure SetDefinitionID(const Value: Cardinal);
|
||||||
|
public
|
||||||
|
constructor Create(ADefinition: IFSXSimConnectDefinition; ADataHandler: IFSXSimConnectDataHandler);
|
||||||
|
|
||||||
|
property DataHandler: IFSXSimConnectDataHandler read FDataHandler;
|
||||||
|
property Definition: IFSXSimConnectDefinition read FDefinition;
|
||||||
|
|
||||||
|
property DefinitionID: Cardinal read FDefinitionID write SetDefinitionID;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
TRemoveDefinitionValue = class(TOmniWaitableValue)
|
||||||
|
private
|
||||||
|
FDataHandler: IFSXSimConnectDataHandler;
|
||||||
|
FDefinitionID: Cardinal;
|
||||||
|
public
|
||||||
|
constructor Create(ADefinitionID: Cardinal; ADataHandler: IFSXSimConnectDataHandler);
|
||||||
|
|
||||||
|
property DataHandler: IFSXSimConnectDataHandler read FDataHandler;
|
||||||
|
property DefinitionID: Cardinal read FDefinitionID;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TFSXSimConnectInterface }
|
{ TFSXSimConnectInterface }
|
||||||
constructor TFSXSimConnectInterface.Create;
|
constructor TFSXSimConnectInterface.Create;
|
||||||
@ -70,21 +183,30 @@ var
|
|||||||
worker: IOmniWorker;
|
worker: IOmniWorker;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
worker := TFSXSimConnectClient.Create;
|
inherited Create;
|
||||||
FClient := CreateTask(worker);
|
|
||||||
|
|
||||||
FObservers := TInterfaceList.Create;
|
FObservers := TInterfaceList.Create;
|
||||||
|
|
||||||
|
worker := TFSXSimConnectClient.Create;
|
||||||
|
FClient := CreateTask(worker).Run;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
destructor TFSXSimConnectInterface.Destroy;
|
destructor TFSXSimConnectInterface.Destroy;
|
||||||
|
var
|
||||||
|
observer: IInterface;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
for observer in Observers do
|
||||||
|
(observer as IFSXSimConnectObserver).ObserveDestroy(Self);
|
||||||
|
|
||||||
FreeAndNil(FObservers);
|
FreeAndNil(FObservers);
|
||||||
|
|
||||||
|
// TODO this doesn't get triggered yet. The connection is killed fine, but not because of us. Needs work.
|
||||||
FClient.Terminate;
|
FClient.Terminate;
|
||||||
FClient := nil;
|
FClient := nil;
|
||||||
|
|
||||||
inherited;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -102,41 +224,386 @@ end;
|
|||||||
|
|
||||||
function TFSXSimConnectInterface.CreateDefinition: IFSXSimConnectDefinition;
|
function TFSXSimConnectInterface.CreateDefinition: IFSXSimConnectDefinition;
|
||||||
begin
|
begin
|
||||||
Result := TFSXSimConnectDefinition.Create(Self);
|
Result := TFSXSimConnectDefinition.Create;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TFSXSimConnectInterface.AddDefinition(ADefinition: IFSXSimConnectDefinition; ADataHandler: IFSXSimConnectDataHandler);
|
function TFSXSimConnectInterface.AddDefinition(ADefinition: IFSXSimConnectDefinition; ADataHandler: IFSXSimConnectDataHandler): Integer;
|
||||||
|
var
|
||||||
|
addDefinition: TAddDefinitionValue;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Client.Comm.Send(TM_ADDDEFINITION, [ADefinition, ADataHandler]);
|
addDefinition := TAddDefinitionValue.Create(ADefinition, ADataHandler);
|
||||||
// TODO pass to thread; if definition already exists (same variables), link to existing definition to avoid too many SimConnect definition
|
Client.Comm.Send(TM_ADDDEFINITION, addDefinition);
|
||||||
|
|
||||||
|
addDefinition.WaitFor(INFINITE);
|
||||||
|
Result := addDefinition.DefinitionID;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TFSXSimConnectInterface.RemoveDefinition(ADataHandler: IFSXSimConnectDataHandler);
|
procedure TFSXSimConnectInterface.RemoveDefinition(ADefinitionID: Cardinal; ADataHandler: IFSXSimConnectDataHandler);
|
||||||
|
var
|
||||||
|
removeDefinition: TRemoveDefinitionValue;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
Client.Comm.Send(TM_REMOVEDEFINITION, ADataHandler);
|
removeDefinition := TRemoveDefinitionValue.Create(ADefinitionID, ADataHandler);
|
||||||
|
Client.Comm.Send(TM_REMOVEDEFINITION, removeDefinition);
|
||||||
|
|
||||||
|
removeDefinition.WaitFor(INFINITE);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{ TFSXSimConnectDefinition }
|
{ TFSXSimConnectDefinition }
|
||||||
constructor TFSXSimConnectDefinition.Create(ASimConnect: IFSXSimConnect);
|
constructor TFSXSimConnectDefinition.Create;
|
||||||
begin
|
begin
|
||||||
|
inherited Create;
|
||||||
|
|
||||||
|
FVariables := TFSXSimConnectVariableList.Create(True);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TFSXSimConnectDefinition.AddVariable(AVariableName, AUnitsName: string; ADatumType: SIMCONNECT_DATAType; AEpsilon: Single);
|
destructor TFSXSimConnectDefinition.Destroy;
|
||||||
begin
|
begin
|
||||||
|
FreeAndNil(FVariables);
|
||||||
|
|
||||||
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TFSXSimConnectDefinition.Apply(ASimConnectHandle: THandle; ADefinitionID: Integer);
|
procedure TFSXSimConnectDefinition.AddVariable(AVariableName, AUnitsName: string; ADataType: SIMCONNECT_DATAType; AEpsilon: Single);
|
||||||
begin
|
begin
|
||||||
// SimConnect_AddToDataDefinition(ASimConnectHandle, ADefinitionID,
|
Variables.Add(TFSXSimConnectVariable.Create(AVariableName, AUnitsName, ADataType, AEpsilon));
|
||||||
// AnsiString(AVariableName), AnsiString(AUnitsName), ADatumType, AEpsilon, 0);
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFSXSimConnectDefinition.GetVariable(AIndex: Integer): IFSXSimConnectVariable;
|
||||||
|
begin
|
||||||
|
Result := Variables[AIndex];
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFSXSimConnectDefinition.GetVariableCount: Integer;
|
||||||
|
begin
|
||||||
|
Result := Variables.Count;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TFSXSimConnectClient }
|
||||||
|
function TFSXSimConnectClient.Initialize: Boolean;
|
||||||
|
begin
|
||||||
|
Result := inherited Initialize;
|
||||||
|
if not Result then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
FDefinitions := TFSXSimConnectDefinitionMap.Create;
|
||||||
|
FSimConnectDataEvent := TEvent.Create(nil, False, False, '');
|
||||||
|
|
||||||
|
Task.RegisterWaitObject(SimConnectDataEvent.Handle, HandleSimConnectDataEvent);
|
||||||
|
|
||||||
|
TrySimConnect;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectClient.Cleanup;
|
||||||
|
begin
|
||||||
|
// TODO unregister definitions ?
|
||||||
|
if SimConnectHandle <> 0 then
|
||||||
|
SimConnect_Close(SimConnectHandle);
|
||||||
|
|
||||||
|
FreeAndNil(FSimConnectDataEvent);
|
||||||
|
FreeAndNil(FDefinitions);
|
||||||
|
|
||||||
|
inherited Cleanup;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectClient.TrySimConnect;
|
||||||
|
begin
|
||||||
|
if SimConnectHandle <> 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
if InitSimConnect then
|
||||||
|
begin
|
||||||
|
if SimConnect_Open(FSimConnectHandle, FSXSimConnectAppName, 0, 0, SimConnectDataEvent.Handle, 0) = S_OK then
|
||||||
|
begin
|
||||||
|
Task.ClearTimer(TIMER_TRYSIMCONNECT);
|
||||||
|
RegisterDefinitions;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if SimConnectHandle = 0 then
|
||||||
|
Task.SetTimer(TIMER_TRYSIMCONNECT, INTERVAL_TRYSIMCONNECT, TM_TRYSIMCONNECT);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectClient.HandleSimConnectDataEvent;
|
||||||
|
var
|
||||||
|
data: PSimConnectRecv;
|
||||||
|
dataSize: Cardinal;
|
||||||
|
simObjectData: PSimConnectRecvSimObjectData;
|
||||||
|
definitionRef: TFSXSimConnectDefinitionRef;
|
||||||
|
|
||||||
|
begin
|
||||||
|
while (SimConnectHandle <> 0) and
|
||||||
|
(SimConnect_GetNextDispatch(SimConnectHandle, data, dataSize) = S_OK) do
|
||||||
|
begin
|
||||||
|
case SIMCONNECT_RECV_ID(data^.dwID) of
|
||||||
|
SIMCONNECT_RECV_ID_SIMOBJECT_DATA:
|
||||||
|
begin
|
||||||
|
simObjectData := PSimConnectRecvSimObjectData(data);
|
||||||
|
|
||||||
|
if Definitions.ContainsKey(simObjectData^.dwDefineID) then
|
||||||
|
begin
|
||||||
|
definitionRef := Definitions[simObjectData^.dwDefineID];
|
||||||
|
definitionRef.HandleData(@simObjectData^.dwData);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
SIMCONNECT_RECV_ID_QUIT:
|
||||||
|
begin
|
||||||
|
FSimConnectHandle := 0;
|
||||||
|
Task.SetTimer(TIMER_TRYSIMCONNECT, INTERVAL_TRYSIMCONNECT, TM_TRYSIMCONNECT);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectClient.RegisterDefinitions;
|
||||||
|
var
|
||||||
|
definitionID: Cardinal;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if SimConnectHandle = 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
for definitionID in Definitions.Keys do
|
||||||
|
RegisterDefinition(definitionID, Definitions[definitionID].Definition);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectClient.RegisterDefinition(ADefinitionID: Cardinal; ADefinition: IFSXSimConnectDefinitionAccess);
|
||||||
|
var
|
||||||
|
variableIndex: Integer;
|
||||||
|
variable: IFSXSimConnectVariable;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if SimConnectHandle = 0 then
|
||||||
|
exit;
|
||||||
|
|
||||||
|
for variableIndex := 0 to Pred(ADefinition.GetVariableCount) do
|
||||||
|
begin
|
||||||
|
variable := ADefinition.GetVariable(variableIndex);
|
||||||
|
SimConnect_AddToDataDefinition(SimConnectHandle, ADefinitionID,
|
||||||
|
AnsiString(variable.GetVariableName),
|
||||||
|
AnsiString(variable.GetUnitsName),
|
||||||
|
variable.GetDataType,
|
||||||
|
variable.GetEpsilon);
|
||||||
|
end;
|
||||||
|
|
||||||
|
SimConnect_RequestDataOnSimObject(SimConnectHandle, ADefinitionID, ADefinitionID,
|
||||||
|
SIMCONNECT_OBJECT_ID_USER,
|
||||||
|
SIMCONNECT_PERIOD_SIM_FRAME,
|
||||||
|
SIMCONNECT_DATA_REQUEST_FLAG_CHANGED);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFSXSimConnectClient.SameDefinition(ADefinition1, ADefinition2: IFSXSimConnectDefinitionAccess): Boolean;
|
||||||
|
var
|
||||||
|
variableIndex: Integer;
|
||||||
|
variable1: IFSXSimConnectVariable;
|
||||||
|
variable2: IFSXSimConnectVariable;
|
||||||
|
|
||||||
|
begin
|
||||||
|
if ADefinition1.GetVariableCount = ADefinition2.GetVariableCount then
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
|
||||||
|
{ Order is very important in the definitions, as the Data Handler depends
|
||||||
|
on it to interpret the data. }
|
||||||
|
for variableIndex := 0 to Pred(ADefinition1.GetVariableCount) do
|
||||||
|
begin
|
||||||
|
variable1 := ADefinition1.GetVariable(variableIndex);
|
||||||
|
variable2 := ADefinition2.GetVariable(variableIndex);
|
||||||
|
|
||||||
|
if (variable1.GetVariableName <> variable2.GetVariableName) or
|
||||||
|
(variable1.GetUnitsName <> variable2.GetUnitsName) or
|
||||||
|
(variable1.GetDataType <> variable2.GetDataType) or
|
||||||
|
(not SameValue(variable1.GetEpsilon, variable2.GetEpsilon, 0.00001)) then
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end else
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectClient.TMAddDefinition(var Msg: TOmniMessage);
|
||||||
|
var
|
||||||
|
addDefinition: TAddDefinitionValue;
|
||||||
|
definitionID: Cardinal;
|
||||||
|
definitionRef: TFSXSimConnectDefinitionRef;
|
||||||
|
definitionAccess: IFSXSimConnectDefinitionAccess;
|
||||||
|
hasDefinition: Boolean;
|
||||||
|
|
||||||
|
begin
|
||||||
|
addDefinition := Msg.MsgData;
|
||||||
|
definitionAccess := (addDefinition.Definition as IFSXSimConnectDefinitionAccess);
|
||||||
|
hasDefinition := False;
|
||||||
|
|
||||||
|
{ Attempt to re-use existing definition to save on SimConnect traffic }
|
||||||
|
for definitionID in Definitions.Keys do
|
||||||
|
begin
|
||||||
|
definitionRef := Definitions[definitionID];
|
||||||
|
|
||||||
|
if SameDefinition(definitionRef.Definition, definitionAccess) then
|
||||||
|
begin
|
||||||
|
definitionRef.Attach(addDefinition.DataHandler);
|
||||||
|
addDefinition.DefinitionID := definitionID;
|
||||||
|
hasDefinition := True;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not hasDefinition then
|
||||||
|
begin
|
||||||
|
{ Add as new definition }
|
||||||
|
Inc(FLastDefinitionID);
|
||||||
|
|
||||||
|
definitionRef := TFSXSimConnectDefinitionRef.Create(definitionAccess);
|
||||||
|
definitionRef.Attach(addDefinition.DataHandler);
|
||||||
|
|
||||||
|
Definitions.Add(LastDefinitionID, definitionRef);
|
||||||
|
addDefinition.DefinitionID := LastDefinitionID;
|
||||||
|
|
||||||
|
{ Register with SimConnect }
|
||||||
|
RegisterDefinition(LastDefinitionID, definitionAccess);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectClient.TMRemoveDefinition(var Msg: TOmniMessage);
|
||||||
|
var
|
||||||
|
removeDefinition: TRemoveDefinitionValue;
|
||||||
|
|
||||||
|
begin
|
||||||
|
removeDefinition := Msg.MsgData;
|
||||||
|
|
||||||
|
// TODO actually remove the definition
|
||||||
|
|
||||||
|
removeDefinition.Signal;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectClient.TMTrySimConnect(var Msg: TOmniMessage);
|
||||||
|
begin
|
||||||
|
TrySimConnect;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TFSXSimConnectDefinitionRef }
|
||||||
|
constructor TFSXSimConnectDefinitionRef.Create(ADefinition: IFSXSimConnectDefinitionAccess);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
|
||||||
|
FDataHandlers := TInterfaceList.Create;
|
||||||
|
FDefinition := ADefinition;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
destructor TFSXSimConnectDefinitionRef.Destroy;
|
||||||
|
begin
|
||||||
|
FreeAndNil(FDataHandlers);
|
||||||
|
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectDefinitionRef.HandleData(AData: Pointer);
|
||||||
|
var
|
||||||
|
dataHandler: IInterface;
|
||||||
|
|
||||||
|
begin
|
||||||
|
for dataHandler in DataHandlers do
|
||||||
|
(dataHandler as IFSXSimConnectDataHandler).HandleData(AData);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectDefinitionRef.Attach(ADataHandler: IFSXSimConnectDataHandler);
|
||||||
|
begin
|
||||||
|
DataHandlers.Add(ADataHandler as IFSXSimConnectDataHandler);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TFSXSimConnectDefinitionRef.Detach(ADataHandler: IFSXSimConnectDataHandler);
|
||||||
|
begin
|
||||||
|
DataHandlers.Remove(ADataHandler as IFSXSimConnectDataHandler);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TFSXSimConnectVariable }
|
||||||
|
constructor TFSXSimConnectVariable.Create(AVariableName, AUnitsName: string; ADataType: SIMCONNECT_DATAType; AEpsilon: Single);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
|
||||||
|
FVariableName := AVariableName;
|
||||||
|
FUnitsName := AUnitsName;
|
||||||
|
FDataType := ADataType;
|
||||||
|
FEpsilon := AEpsilon;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFSXSimConnectVariable.GetVariableName: string;
|
||||||
|
begin
|
||||||
|
Result := FVariableName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFSXSimConnectVariable.GetUnitsName: string;
|
||||||
|
begin
|
||||||
|
Result := FUnitsName;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFSXSimConnectVariable.GetDataType: SIMCONNECT_DATAType;
|
||||||
|
begin
|
||||||
|
Result := FDataType;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TFSXSimConnectVariable.GetEpsilon: Single;
|
||||||
|
begin
|
||||||
|
Result := FEpsilon;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TAddDefinitionValue }
|
||||||
|
constructor TAddDefinitionValue.Create(ADefinition: IFSXSimConnectDefinition; ADataHandler: IFSXSimConnectDataHandler);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
|
||||||
|
FDefinition := ADefinition;
|
||||||
|
FDataHandler := ADataHandler;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TAddDefinitionValue.SetDefinitionID(const Value: Cardinal);
|
||||||
|
begin
|
||||||
|
FDefinitionID := Value;
|
||||||
|
Signal;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TRemoveDefinitionValue }
|
||||||
|
constructor TRemoveDefinitionValue.Create(ADefinitionID: Cardinal; ADataHandler: IFSXSimConnectDataHandler);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
|
||||||
|
FDefinitionID := ADefinitionID;
|
||||||
|
FDataHandler := ADataHandler;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@ -28,18 +28,32 @@ type
|
|||||||
procedure Detach(AObserver: IFSXSimConnectObserver);
|
procedure Detach(AObserver: IFSXSimConnectObserver);
|
||||||
|
|
||||||
function CreateDefinition: IFSXSimConnectDefinition;
|
function CreateDefinition: IFSXSimConnectDefinition;
|
||||||
procedure AddDefinition(ADefinition: IFSXSimConnectDefinition; ADataHandler: IFSXSimConnectDataHandler);
|
function AddDefinition(ADefinition: IFSXSimConnectDefinition; ADataHandler: IFSXSimConnectDataHandler): Integer;
|
||||||
procedure RemoveDefinition(ADataHandler: IFSXSimConnectDataHandler);
|
procedure RemoveDefinition(ADefinitionID: Cardinal; ADataHandler: IFSXSimConnectDataHandler);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
IFSXSimConnectDefinition = interface
|
IFSXSimConnectDefinition = interface
|
||||||
['{F1EAB3B1-0A3D-4B06-A75F-823E15C313B8}']
|
['{F1EAB3B1-0A3D-4B06-A75F-823E15C313B8}']
|
||||||
procedure AddVariable(AVariableName, AUnitsName: string; ADatumType: SIMCONNECT_DATAType; AEpsilon: Single = 0);
|
procedure AddVariable(AVariableName, AUnitsName: string; ADataType: SIMCONNECT_DATAType; AEpsilon: Single = 0);
|
||||||
procedure Apply(ASimConnectHandle: THandle; ADefinitionID: Integer);
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
IFSXSimConnectVariable = interface
|
||||||
|
['{A41AD003-77C0-4E34-91E3-B0BAADD08FCE}']
|
||||||
|
function GetVariableName: string;
|
||||||
|
function GetUnitsName: string;
|
||||||
|
function GetDataType: SIMCONNECT_DATAType;
|
||||||
|
function GetEpsilon: Single;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
IFSXSimConnectDefinitionAccess = interface
|
||||||
|
['{2592534C-0344-4442-8A5F-1AB34B96E1B5}']
|
||||||
|
function GetVariableCount: Integer;
|
||||||
|
function GetVariable(AIndex: Integer): IFSXSimConnectVariable;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
const
|
const
|
||||||
FSX_UNIT_PERCENT = 'percent';
|
FSX_UNIT_PERCENT = 'percent';
|
||||||
|
@ -13,7 +13,9 @@ uses
|
|||||||
|
|
||||||
const
|
const
|
||||||
TM_FINDTHROTTLEDEVICE = 2001;
|
TM_FINDTHROTTLEDEVICE = 2001;
|
||||||
TM_NOTIFY_DEVICESTATE = 2002;
|
TM_TESTTHROTTLEDEVICE = 2002;
|
||||||
|
|
||||||
|
TM_NOTIFY_DEVICESTATE = 2003;
|
||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
@ -21,10 +23,13 @@ type
|
|||||||
private
|
private
|
||||||
FDirectInput: IDirectInput8;
|
FDirectInput: IDirectInput8;
|
||||||
FThrottleDevice: IDirectInputDevice8;
|
FThrottleDevice: IDirectInputDevice8;
|
||||||
|
FTHrottleDeviceGUID: TGUID;
|
||||||
protected
|
protected
|
||||||
procedure MsgFindThrottleDevice(var msg: TOmniMessage); message TM_FINDTHROTTLEDEVICE;
|
procedure TMFindThrottleDevice(var Msg: TOmniMessage); message TM_FINDTHROTTLEDEVICE;
|
||||||
|
procedure TMTestThrottleDevice(var Msg: TOmniMessage); message TM_TESTTHROTTLEDEVICE;
|
||||||
protected
|
protected
|
||||||
function Initialize: Boolean; override;
|
function Initialize: Boolean; override;
|
||||||
|
procedure Cleanup; override;
|
||||||
|
|
||||||
procedure FindThrottleDevice;
|
procedure FindThrottleDevice;
|
||||||
procedure FoundThrottleDevice(ADeviceGUID: TGUID);
|
procedure FoundThrottleDevice(ADeviceGUID: TGUID);
|
||||||
@ -35,6 +40,7 @@ type
|
|||||||
|
|
||||||
property DirectInput: IDirectInput8 read FDirectInput;
|
property DirectInput: IDirectInput8 read FDirectInput;
|
||||||
property ThrottleDevice: IDirectInputDevice8 read FThrottleDevice;
|
property ThrottleDevice: IDirectInputDevice8 read FThrottleDevice;
|
||||||
|
property ThrottleDeviceGUID: TGUID read FTHrottleDeviceGUID;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -63,23 +69,6 @@ const
|
|||||||
G940_BUTTONCOUNT = 8;
|
G940_BUTTONCOUNT = 8;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(*
|
|
||||||
type
|
|
||||||
TRunInMainThreadSetLEDs = class(TOmniWaitableValue, IRunInMainThread)
|
|
||||||
private
|
|
||||||
FDevice: IDirectInputDevice8;
|
|
||||||
FRed: Byte;
|
|
||||||
FGreen: Byte;
|
|
||||||
protected
|
|
||||||
{ IRunInMainThread }
|
|
||||||
procedure Execute;
|
|
||||||
public
|
|
||||||
constructor Create(ADevice: IDirectInputDevice8; ARed, AGreen: Byte);
|
|
||||||
end;
|
|
||||||
*)
|
|
||||||
|
|
||||||
|
|
||||||
function EnumDevicesProc(var lpddi: TDIDeviceInstanceW; pvRef: Pointer): BOOL; stdcall;
|
function EnumDevicesProc(var lpddi: TDIDeviceInstanceW; pvRef: Pointer): BOOL; stdcall;
|
||||||
var
|
var
|
||||||
vendorID: Word;
|
vendorID: Word;
|
||||||
@ -127,81 +116,13 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{
|
procedure TG940LEDStateConsumer.Cleanup;
|
||||||
procedure TG940LEDStateConsumer.ResetLEDState;
|
|
||||||
begin
|
begin
|
||||||
FRed := 0;
|
inherited Cleanup;
|
||||||
FGreen := $FF;
|
|
||||||
|
|
||||||
inherited;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
procedure TG940LEDStateConsumer.LEDStateChanged(ALEDIndex: Integer; AState: TLEDState);
|
|
||||||
|
|
||||||
procedure SetBit(var AMask: Byte; ABit: Integer; ASet: Boolean); inline;
|
|
||||||
begin
|
|
||||||
if ASet then
|
|
||||||
AMask := AMask or (1 shl ABit)
|
|
||||||
else
|
|
||||||
AMask := AMask and not (1 shl ABit);
|
|
||||||
end;
|
|
||||||
|
|
||||||
var
|
|
||||||
red: Boolean;
|
|
||||||
green: Boolean;
|
|
||||||
|
|
||||||
begin
|
|
||||||
red := False;
|
|
||||||
green := False;
|
|
||||||
|
|
||||||
case AState of
|
|
||||||
lsGreen:
|
|
||||||
green := True;
|
|
||||||
|
|
||||||
lsAmber:
|
|
||||||
begin
|
|
||||||
red := True;
|
|
||||||
green := True;
|
|
||||||
end;
|
|
||||||
|
|
||||||
lsRed:
|
|
||||||
red := True;
|
|
||||||
|
|
||||||
lsWarning:
|
|
||||||
begin
|
|
||||||
red := True;
|
|
||||||
green := True;
|
|
||||||
|
|
||||||
StartBlinkTimer;
|
|
||||||
end;
|
|
||||||
|
|
||||||
lsError:
|
|
||||||
begin
|
|
||||||
red := True;
|
|
||||||
|
|
||||||
StartBlinkTimer;
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
SetBit(FRed, ALEDIndex, red);
|
|
||||||
SetBit(FGreen, ALEDIndex, green);
|
|
||||||
|
|
||||||
inherited;
|
|
||||||
end;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
procedure TG940LEDStateConsumer.Changed;
|
|
||||||
begin
|
|
||||||
inherited;
|
|
||||||
|
|
||||||
if Assigned(ThrottleDevice) then
|
if Assigned(ThrottleDevice) then
|
||||||
{ Logitech SDK will not change the color outside of the main thread
|
SetLEDs(ThrottleDevice, 0, $FF);
|
||||||
RunInMainThread(TRunInMainThreadSetLEDs.Create(ThrottleDevice, FRed, FGreen), Destroying);
|
|
||||||
end;
|
end;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
procedure TG940LEDStateConsumer.FindThrottleDevice;
|
procedure TG940LEDStateConsumer.FindThrottleDevice;
|
||||||
@ -222,7 +143,10 @@ end;
|
|||||||
procedure TG940LEDStateConsumer.FoundThrottleDevice(ADeviceGUID: TGUID);
|
procedure TG940LEDStateConsumer.FoundThrottleDevice(ADeviceGUID: TGUID);
|
||||||
begin
|
begin
|
||||||
if DirectInput.CreateDevice(ADeviceGUID, FThrottleDevice, nil) = S_OK then
|
if DirectInput.CreateDevice(ADeviceGUID, FThrottleDevice, nil) = S_OK then
|
||||||
|
begin
|
||||||
|
FTHrottleDeviceGUID := ADeviceGUID;
|
||||||
SetDeviceState(DEVICESTATE_FOUND);
|
SetDeviceState(DEVICESTATE_FOUND);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -279,28 +203,22 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TG940LEDStateConsumer.MsgFindThrottleDevice(var msg: TOmniMessage);
|
procedure TG940LEDStateConsumer.TMFindThrottleDevice(var Msg: TOmniMessage);
|
||||||
begin
|
begin
|
||||||
FindThrottleDevice;
|
FindThrottleDevice;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{ TRunInMainThreadSetLEDs }
|
procedure TG940LEDStateConsumer.TMTestThrottleDevice(var Msg: TOmniMessage);
|
||||||
(*
|
|
||||||
constructor TRunInMainThreadSetLEDs.Create(ADevice: IDirectInputDevice8; ARed, AGreen: Byte);
|
|
||||||
begin
|
begin
|
||||||
inherited Create;
|
if Assigned(ThrottleDevice) then
|
||||||
|
begin
|
||||||
FDevice := ADevice;
|
if DirectInput.GetDeviceStatus(ThrottleDeviceGUID) = DI_NOTATTACHED then
|
||||||
FRed := ARed;
|
begin
|
||||||
FGreen := AGreen;
|
FThrottleDevice := nil;
|
||||||
|
SetDeviceState(DEVICESTATE_NOTFOUND);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TRunInMainThreadSetLEDs.Execute;
|
|
||||||
begin
|
|
||||||
SetLEDs(FDevice, FRed, FGreen);
|
|
||||||
end;
|
|
||||||
*)
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@ -81,8 +81,8 @@ type
|
|||||||
|
|
||||||
function GetCurrentState: ILEDStateWorker; virtual; abstract;
|
function GetCurrentState: ILEDStateWorker; virtual; abstract;
|
||||||
public
|
public
|
||||||
constructor Create; overload;
|
constructor Create; overload; virtual;
|
||||||
constructor Create(AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings); overload;
|
constructor Create(AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings); overload; virtual;
|
||||||
|
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
end;
|
end;
|
||||||
@ -138,7 +138,7 @@ destructor TCustomMultiStateLEDFunction.Destroy;
|
|||||||
begin
|
begin
|
||||||
FreeAndNil(FStates);
|
FreeAndNil(FStates);
|
||||||
|
|
||||||
inherited;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -229,6 +229,8 @@ var
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
Result := nil;
|
Result := nil;
|
||||||
|
if not Assigned(States) then
|
||||||
|
exit;
|
||||||
|
|
||||||
for state in States do
|
for state in States do
|
||||||
if (state as ICustomLEDState).GetUID = AUID then
|
if (state as ICustomLEDState).GetUID = AUID then
|
||||||
@ -263,7 +265,7 @@ destructor TCustomLEDFunctionProvider.Destroy;
|
|||||||
begin
|
begin
|
||||||
FreeAndNil(FFunctions);
|
FreeAndNil(FFunctions);
|
||||||
|
|
||||||
inherited;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ destructor TLEDFunctionRegistry.Destroy;
|
|||||||
begin
|
begin
|
||||||
FreeAndNil(FProviders);
|
FreeAndNil(FProviders);
|
||||||
|
|
||||||
inherited;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -155,7 +155,7 @@ destructor TLEDFunctionProviderList.Destroy;
|
|||||||
begin
|
begin
|
||||||
FreeAndNil(FList);
|
FreeAndNil(FList);
|
||||||
|
|
||||||
inherited;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -21,13 +21,7 @@ const
|
|||||||
|
|
||||||
|
|
||||||
type
|
type
|
||||||
IRunInMainThread = interface(IOmniWaitableValue)
|
TLEDStateConsumer = class(TOmniWorker, ILEDFunctionObserver)
|
||||||
['{68B8F2F7-ED40-4078-9D99-503D7AFA068B}']
|
|
||||||
procedure Execute;
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
TLEDStateConsumer = class(TOmniWorker)
|
|
||||||
private
|
private
|
||||||
FButtonWorkers: TInterfaceList;
|
FButtonWorkers: TInterfaceList;
|
||||||
FButtonColors: TInterfaceList;
|
FButtonColors: TInterfaceList;
|
||||||
@ -42,6 +36,9 @@ type
|
|||||||
property ButtonColors: TInterfaceList read FButtonColors;
|
property ButtonColors: TInterfaceList read FButtonColors;
|
||||||
property HasTickTimer: Boolean read FHasTickTimer;
|
property HasTickTimer: Boolean read FHasTickTimer;
|
||||||
protected
|
protected
|
||||||
|
{ ILEDFunctionObserver }
|
||||||
|
procedure ObserveUpdate(Sender: ILEDFunctionWorker);
|
||||||
|
|
||||||
procedure Changed; virtual;
|
procedure Changed; virtual;
|
||||||
procedure Update; virtual; abstract;
|
procedure Update; virtual; abstract;
|
||||||
protected
|
protected
|
||||||
@ -171,22 +168,50 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TLEDStateConsumer.ObserveUpdate(Sender: ILEDFunctionWorker);
|
||||||
|
begin
|
||||||
|
Changed;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
procedure TLEDStateConsumer.TMLoadProfile(var Msg: TOmniMessage);
|
procedure TLEDStateConsumer.TMLoadProfile(var Msg: TOmniMessage);
|
||||||
var
|
var
|
||||||
|
oldWorkers: TInterfaceList;
|
||||||
|
oldWorker: IInterface;
|
||||||
profile: TProfile;
|
profile: TProfile;
|
||||||
buttonIndex: Integer;
|
buttonIndex: Integer;
|
||||||
|
worker: ILEDFunctionWorker;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
profile := Msg.MsgData;
|
profile := Msg.MsgData;
|
||||||
|
|
||||||
|
{ Keep a copy of the old workers until all the new ones are initialized,
|
||||||
|
so we don't get unneccessary SimConnect reconnects. }
|
||||||
|
oldWorkers := TInterfaceList.Create;
|
||||||
|
try
|
||||||
|
for oldWorker in ButtonWorkers do
|
||||||
|
begin
|
||||||
|
if Assigned(oldWorker) then
|
||||||
|
oldWorkers.Add(oldWorker);
|
||||||
|
end;
|
||||||
|
|
||||||
ButtonWorkers.Clear;
|
ButtonWorkers.Clear;
|
||||||
|
|
||||||
for buttonIndex := 0 to Pred(profile.ButtonCount) do
|
for buttonIndex := 0 to Pred(profile.ButtonCount) do
|
||||||
begin
|
begin
|
||||||
if profile.HasButton(buttonIndex) then
|
if profile.HasButton(buttonIndex) then
|
||||||
ButtonWorkers.Add(CreateWorker(profile.Buttons[buttonIndex]) as ILEDFunctionWorker)
|
begin
|
||||||
else
|
worker := CreateWorker(profile.Buttons[buttonIndex]) as ILEDFunctionWorker;
|
||||||
|
ButtonWorkers.Add(worker);
|
||||||
|
|
||||||
|
if Assigned(worker) then
|
||||||
|
worker.Attach(Self);
|
||||||
|
end else
|
||||||
ButtonWorkers.Add(nil);
|
ButtonWorkers.Add(nil);
|
||||||
end;
|
end;
|
||||||
|
finally
|
||||||
|
FreeAndNil(oldWorkers);
|
||||||
|
end;
|
||||||
|
|
||||||
Changed;
|
Changed;
|
||||||
end;
|
end;
|
||||||
|
@ -188,7 +188,7 @@ destructor TProfile.Destroy;
|
|||||||
begin
|
begin
|
||||||
FreeAndNil(FButtons);
|
FreeAndNil(FButtons);
|
||||||
|
|
||||||
inherited;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user