diff --git a/G940LEDControl/Forms/MainFrm.dfm b/G940LEDControl/Forms/MainFrm.dfm
index 6eb6928..ea9ac7a 100644
--- a/G940LEDControl/Forms/MainFrm.dfm
+++ b/G940LEDControl/Forms/MainFrm.dfm
@@ -28,7 +28,7 @@ object MainForm: TMainForm
Margins.Top = 8
Margins.Right = 8
Margins.Bottom = 8
- ActivePage = tsFSX
+ ActivePage = tsAbout
Align = alClient
TabOrder = 1
object tsFSX: TTabSheet
@@ -438,6 +438,7 @@ object MainForm: TMainForm
object tsAbout: TTabSheet
Caption = 'About'
ImageIndex = 1
+ ExplicitLeft = 12
object lblVersionCaption: TLabel
Left = 16
Top = 67
@@ -486,6 +487,19 @@ object MainForm: TMainForm
Height = 13
Caption = 'E-mail:'
end
+ object lblProxy: TLabel
+ Left = 36
+ Top = 368
+ Width = 246
+ Height = 13
+ Caption = 'This might not work if you'#39're behind a proxy, sorry!'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clGrayText
+ Font.Height = -11
+ Font.Name = 'Tahoma'
+ Font.Style = []
+ ParentFont = False
+ end
object lblWebsiteLink: TLinkLabel
Left = 75
Top = 111
@@ -508,6 +522,23 @@ object MainForm: TMainForm
TabOrder = 1
OnLinkClick = lblLinkLinkClick
end
+ object cbCheckUpdates: TCheckBox
+ Left = 16
+ Top = 344
+ Width = 305
+ Height = 17
+ Caption = ' Automatically check for &updates'
+ TabOrder = 2
+ end
+ object btnCheckUpdates: TButton
+ Left = 344
+ Top = 340
+ Width = 83
+ Height = 25
+ Caption = '&Check now'
+ TabOrder = 3
+ OnClick = btnCheckUpdatesClick
+ end
end
end
object pnlG940: TPanel
@@ -900,7 +931,7 @@ object MainForm: TMainForm
Width = 75
Height = 25
Anchors = [akTop, akRight]
- Caption = 'Retry'
+ Caption = '&Retry'
TabOrder = 0
Visible = False
OnClick = btnRetryClick
diff --git a/G940LEDControl/Forms/MainFrm.pas b/G940LEDControl/Forms/MainFrm.pas
index 2e29851..e07ffc1 100644
--- a/G940LEDControl/Forms/MainFrm.pas
+++ b/G940LEDControl/Forms/MainFrm.pas
@@ -15,6 +15,7 @@ uses
OtlComm,
OtlEventMonitor,
OtlTaskControl,
+ OtlTask,
pngimage,
X2UtPersistIntf,
@@ -23,10 +24,15 @@ uses
LEDStateProvider;
+const
+ CM_ASKAUTOUPDATE = WM_APP + 1;
+
+ MSG_UPDATE = 1;
+ MSG_NOUPDATE = 2;
+
type
TComboBoxArray = array[0..7] of TComboBoxEx;
-
TMainForm = class(TForm)
imgStateNotFound: TImage;
lblG940Throttle: TLabel;
@@ -79,6 +85,9 @@ type
lblEmailLink: TLinkLabel;
lblWebsite: TLabel;
lblEmail: TLabel;
+ cbCheckUpdates: TCheckBox;
+ btnCheckUpdates: TButton;
+ lblProxy: TLabel;
procedure FormCreate(Sender: TObject);
procedure btnRetryClick(Sender: TObject);
@@ -88,6 +97,7 @@ type
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FunctionComboBoxChange(Sender: TObject);
procedure lblLinkLinkClick(Sender: TObject; const Link: string; LinkType: TSysLinkType);
+ procedure btnCheckUpdatesClick(Sender: TObject);
private
FEventMonitor: TOmniEventMonitor;
FStateConsumerTask: IOmniTaskControl;
@@ -100,8 +110,10 @@ type
procedure ReadFunctions(AReader: IX2PersistReader; AComboBoxes: TComboBoxArray);
procedure ReadFSXExtra(AReader: IX2PersistReader);
+ procedure ReadAutoUpdate(AReader: IX2PersistReader);
procedure WriteFunctions(AWriter: IX2PersistWriter; AComboBoxes: TComboBoxArray);
procedure WriteFSXExtra(AWriter: IX2PersistWriter);
+ procedure WriteAutoUpdate(AWriter: IX2PersistWriter);
procedure LoadDefaultProfile;
procedure SaveDefaultProfile;
@@ -114,6 +126,9 @@ type
procedure UpdateMapping;
+ procedure CheckForUpdatesThread(const ATask: IOmniTask);
+ procedure CheckForUpdates(AReportNoUpdates: Boolean);
+
procedure EventMonitorMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
procedure EventMonitorTerminated(const task: IOmniTaskControl);
@@ -122,6 +137,8 @@ type
procedure HandleProviderKilled(ATask: IOmniTaskControl; AMessage: TOmniMessage);
procedure HandleProviderKilledFSX(ATask: IOmniTaskControl; AMessage: TOmniMessage);
+ procedure CMAskAutoUpdate(var Msg: TMessage); message CM_ASKAUTOUPDATE;
+
property EventMonitor: TOmniEventMonitor read FEventMonitor;
property StateConsumerTask: IOmniTaskControl read FStateConsumerTask;
end;
@@ -134,8 +151,9 @@ uses
ShellAPI,
SysUtils,
+ IdException,
+ IdHTTP,
OtlCommon,
- OtlTask,
X2UtApp,
X2UtPersistRegistry,
@@ -154,8 +172,10 @@ const
TEXT_STATE_NOTFOUND = 'Not found';
TEXT_STATE_FOUND = 'Connected';
- KEY_DEFAULTPROFILE = '\Software\X2Software\G940LEDControl\DefaultProfile\';
+ KEY_SETTINGS = '\Software\X2Software\G940LEDControl\';
+ SECTION_DEFAULTPROFILE = 'DefaultProfile';
SECTION_FSX = 'FSX';
+ SECTION_SETTINGS = 'Settings';
type
@@ -221,6 +241,17 @@ begin
end;
+procedure TMainForm.CMAskAutoUpdate(var Msg: TMessage);
+begin
+ if MessageBox(Self.Handle, 'I''m sorry to delay your flight, but I will only ask this once.'#13#10 +
+ 'Do you want to automatically check for updates?', 'Check for updates', MB_YESNO or MB_ICONQUESTION) = ID_YES then
+ begin
+ cbCheckUpdates.Checked := True;
+ CheckForUpdates(False);
+ end;
+end;
+
+
procedure TMainForm.SetDeviceState(const AMessage: string; AFound: Boolean);
begin
lblG940ThrottleState.Caption := AMessage;
@@ -326,6 +357,32 @@ begin
end;
+procedure TMainForm.ReadAutoUpdate(AReader: IX2PersistReader);
+var
+ checkUpdates: Boolean;
+ askAutoUpdate: Boolean;
+
+begin
+ askAutoUpdate := True;
+
+ if AReader.BeginSection(SECTION_SETTINGS) then
+ try
+ if AReader.ReadBoolean('CheckUpdates', checkUpdates) then
+ begin
+ cbCheckUpdates.Checked := checkUpdates;
+ askAutoUpdate := False;
+ end;
+ finally
+ AReader.EndSection;
+ end;
+
+ if askAutoUpdate then
+ PostMessage(Self.Handle, CM_ASKAUTOUPDATE, 0, 0)
+ else if cbCheckUpdates.Checked then
+ CheckForUpdates(False);
+end;
+
+
procedure TMainForm.WriteFunctions(AWriter: IX2PersistWriter; AComboBoxes: TComboBoxArray);
var
comboBox: TComboBoxEx;
@@ -362,6 +419,17 @@ begin
end;
+procedure TMainForm.WriteAutoUpdate(AWriter: IX2PersistWriter);
+begin
+ if AWriter.BeginSection(SECTION_SETTINGS) then
+ try
+ AWriter.WriteBoolean('CheckUpdates', cbCheckUpdates.Checked);
+ finally
+ AWriter.EndSection;
+ end;
+end;
+
+
procedure TMainForm.LoadDefaultProfile;
var
registryReader: TX2UtPersistRegistry;
@@ -371,12 +439,19 @@ begin
registryReader := TX2UtPersistRegistry.Create;
try
registryReader.RootKey := HKEY_CURRENT_USER;
- registryReader.Key := KEY_DEFAULTPROFILE;
+ registryReader.Key := KEY_SETTINGS;
reader := registryReader.CreateReader;
- ReadFunctions(reader, FFSXComboBoxes);
- ReadFSXExtra(reader);
+ if reader.BeginSection(SECTION_DEFAULTPROFILE) then
+ try
+ ReadFunctions(reader, FFSXComboBoxes);
+ ReadFSXExtra(reader);
+ finally
+ reader.EndSection;
+ end;
+
+ ReadAutoUpdate(reader);
finally
FreeAndNil(registryReader);
end;
@@ -392,11 +467,18 @@ begin
registryWriter := TX2UtPersistRegistry.Create;
try
registryWriter.RootKey := HKEY_CURRENT_USER;
- registryWriter.Key := KEY_DEFAULTPROFILE;
+ registryWriter.Key := KEY_SETTINGS;
writer := registryWriter.CreateWriter;
- WriteFunctions(writer, FFSXComboBoxes);
- WriteFSXExtra(writer);
+ if writer.BeginSection(SECTION_DEFAULTPROFILE) then
+ try
+ WriteFunctions(writer, FFSXComboBoxes);
+ WriteFSXExtra(writer);
+ finally
+ writer.EndSection;
+ end;
+
+ WriteAutoUpdate(writer);
finally
FreeAndNil(registryWriter);
end;
@@ -426,12 +508,123 @@ begin
end;
+function FetchNextNumber(var AValue: string; out ANumber: Integer): Boolean;
+var
+ dotPos: Integer;
+ number: string;
+
+begin
+ ANumber := 0;
+
+ dotPos := AnsiPos('.', AValue);
+ if dotPos > 0 then
+ begin
+ number := Copy(AValue, 1, Pred(dotPos));
+ Delete(AValue, 1, dotPos);
+ end
+ else
+ begin
+ number := AValue;
+ AValue := '';
+ end;
+
+ Result := TryStrToInt(number, ANumber);
+end;
+
+
+function VersionIsNewer(const AVersion1, AVersion2: string): Boolean;
+var
+ version1: string;
+ version2: string;
+ number1: Integer;
+ number2: Integer;
+
+begin
+ if Length(AVersion1) = 0 then
+ begin
+ Result := True;
+ Exit;
+ end;
+
+ Result := False;
+ version1 := AVersion1;
+ version2 := AVersion2;
+
+ while (not Result) and
+ FetchNextNumber(version1, number1) and
+ FetchNextNumber(version2, number2) do
+ begin
+ if number2 > number1 then
+ Result := True
+ else if number2 < number1 then
+ Break;
+ end;
+end;
+
+
+procedure TMainForm.CheckForUpdatesThread(const ATask: IOmniTask);
+var
+ httpClient: TIdHTTP;
+ msgSent: Boolean;
+ latestVersion: string;
+
+begin
+ msgSent := False;
+ try
+ httpClient := TIdHTTP.Create(nil);
+ try
+ latestVersion := httpClient.Get('http://g940.x2software.net/version');
+ if VersionIsNewer(Format('%d.%d.%d', [App.Version.Major, App.Version.Minor, App.Version.Release]), latestVersion) then
+ ATask.Comm.Send(MSG_UPDATE)
+ else
+ begin
+ if ATask.Param.ByName('ReportNoUpdates').AsBoolean then
+ ATask.Comm.Send(MSG_NOUPDATE, True);
+ end;
+
+ msgSent := True;
+ finally
+ FreeAndNil(httpClient);
+ end;
+ except
+ on E:EIdSilentException do;
+ on E:Exception do
+ begin
+ if not msgSent then
+ ATask.Comm.Send(MSG_NOUPDATE, False);
+ end;
+ end;
+end;
+
+
+procedure TMainForm.CheckForUpdates(AReportNoUpdates: Boolean);
+begin
+ btnCheckUpdates.Enabled := False;
+
+ CreateTask(CheckForUpdatesThread, 'CheckForUpdatesThread')
+ .MonitorWith(EventMonitor)
+ .SetParameter('ReportNoUpdates', AReportNoUpdates)
+ .Run;
+end;
+
+
procedure TMainForm.EventMonitorMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
begin
case msg.MsgID of
MSG_NOTIFY_DEVICESTATE: HandleDeviceStateMessage(task, msg);
MSG_RUN_IN_MAINTHREAD: HandleRunInMainThreadMessage(task, msg);
MSG_PROVIDER_KILLED: HandleProviderKilled(task, msg);
+
+ 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?',
+ 'Update available', MB_YESNO or MB_ICONINFORMATION) = ID_YES then
+ ShellExecute(Self.Handle, 'open', PChar('http://g940.x2software.net/#download'), nil, nil, SW_SHOWNORMAL);
+
+ MSG_NOUPDATE:
+ if msg.MsgData.AsBoolean then
+ MessageBox(Self.Handle, 'You are using the latest version.', 'No update available', MB_OK or MB_ICONINFORMATION)
+ else
+ MessageBox(Self.Handle, 'Failed to check for updates. Maybe try again later?', 'Uh-oh', MB_OK or MB_ICONWARNING);
end;
end;
@@ -442,7 +635,8 @@ begin
begin
FStateConsumerTask := nil;
Close;
- end;
+ end else if task.Name = 'CheckForUpdatesThread' then
+ btnCheckUpdates.Enabled := True;
end;
@@ -495,6 +689,11 @@ begin
end;
+procedure TMainForm.btnCheckUpdatesClick(Sender: TObject);
+begin
+ CheckForUpdates(True);
+end;
+
procedure TMainForm.btnFSXConnectClick(Sender: TObject);
begin
SaveDefaultProfile;
diff --git a/G940LEDControl/G940LEDControl.dpr b/G940LEDControl/G940LEDControl.dpr
index 2e0394d..0510214 100644
--- a/G940LEDControl/G940LEDControl.dpr
+++ b/G940LEDControl/G940LEDControl.dpr
@@ -3,14 +3,14 @@ program G940LEDControl;
uses
Forms,
MainFrm in 'Forms\MainFrm.pas' {MainForm},
- FSXLEDStateProvider in 'Units\FSXLEDStateProvider.pas',
- LEDStateConsumer in 'Units\LEDStateConsumer.pas',
- LEDStateProvider in 'Units\LEDStateProvider.pas',
- LEDFunctionMap in 'Units\LEDFunctionMap.pas',
- G940LEDStateConsumer in 'Units\G940LEDStateConsumer.pas',
LogiJoystickDLL in '..\Shared\LogiJoystickDLL.pas',
SimConnect in '..\Shared\SimConnect.pas',
- ButtonSelectFrm in 'Forms\ButtonSelectFrm.pas' {ButtonSelectForm};
+ ButtonSelectFrm in 'Forms\ButtonSelectFrm.pas' {ButtonSelectForm},
+ FSXLEDStateProvider in 'Units\FSXLEDStateProvider.pas',
+ G940LEDStateConsumer in 'Units\G940LEDStateConsumer.pas',
+ LEDFunctionMap in 'Units\LEDFunctionMap.pas',
+ LEDStateConsumer in 'Units\LEDStateConsumer.pas',
+ LEDStateProvider in 'Units\LEDStateProvider.pas';
{$R *.res}
diff --git a/G940LEDControl/G940LEDControl.dproj b/G940LEDControl/G940LEDControl.dproj
index 8b9dff9..4edf5e7 100644
--- a/G940LEDControl/G940LEDControl.dproj
+++ b/G940LEDControl/G940LEDControl.dproj
@@ -163,17 +163,17 @@
-
-
-
-
-
dfm
+
+
+
+
+
Cfg_2
Base
diff --git a/G940LEDControl/Units/LEDStateConsumer.pas b/G940LEDControl/Units/LEDStateConsumer.pas
index 44d5d9b..e0aac12 100644
--- a/G940LEDControl/Units/LEDStateConsumer.pas
+++ b/G940LEDControl/Units/LEDStateConsumer.pas
@@ -11,19 +11,19 @@ uses
const
- MSG_CLEAR_FUNCTIONS = 1;
- MSG_SET_FUNCTION = 2;
- MSG_INITIALIZE_PROVIDER = 3;
- MSG_FINALIZE_PROVIDER = 4;
- MSG_PROCESS_MESSAGES = 5;
- MSG_FINALIZE = 6;
+ MSG_CLEAR_FUNCTIONS = 1001;
+ MSG_SET_FUNCTION = 1002;
+ MSG_INITIALIZE_PROVIDER = 1003;
+ MSG_FINALIZE_PROVIDER = 1004;
+ MSG_PROCESS_MESSAGES = 1005;
+ MSG_FINALIZE = 1006;
- MSG_PROVIDER_KILLED = 7;
- MSG_RUN_IN_MAINTHREAD = 8;
+ MSG_PROVIDER_KILLED = 1007;
+ MSG_RUN_IN_MAINTHREAD = 1008;
MSG_CONSUMER_OFFSET = MSG_RUN_IN_MAINTHREAD;
- TIMER_PROCESSMESSAGES = 1;
+ TIMER_PROCESSMESSAGES = 1001;
TIMER_CONSUMER_OFFSET = TIMER_PROCESSMESSAGES;