Skip to content

Commit e2ca5aa

Browse files
committed
First working version (Beta 1)
Demostrates basic functions. Can be easilly extended to support VHF2 too. No tests yet.
1 parent 966cf52 commit e2ca5aa

8 files changed

Lines changed: 822 additions & 7 deletions

File tree

JeehellRMP/App.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8" ?>
22
<configuration>
3-
<startup>
3+
<startup useLegacyV2RuntimeActivationPolicy="true">
44
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
55
</startup>
66
</configuration>

JeehellRMP/App.xaml

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,55 @@
44
xmlns:local="clr-namespace:JeehellRMP"
55
StartupUri="MainWindow.xaml">
66
<Application.Resources>
7-
7+
<Style TargetType="{x:Type TextBlock}">
8+
<Setter Property="Foreground" Value="White" />
9+
<Setter Property="TextAlignment" Value="Center"/>
10+
</Style>
11+
<Style BasedOn="{StaticResource {x:Type TextBlock}}" TargetType="{x:Type TextBlock}" x:Key="RmpButtonText">
12+
<Setter Property="Canvas.Top" Value="5.5"/>
13+
<Setter Property="Width" Value="13.5"/>
14+
<Setter Property="FontSize" Value="4"/>
15+
<Setter Property="Cursor" Value="Hand"/>
16+
</Style>
17+
<Style TargetType="{x:Type Rectangle}" x:Key="RmpButton">
18+
<Setter Property="Canvas.Top" Value="4"/>
19+
<Setter Property="Width" Value="13.5"/>
20+
<Setter Property="Height" Value="9"/>
21+
<Setter Property="Fill" Value="Black"/>
22+
<Setter Property="RadiusX" Value="1"/>
23+
<Setter Property="RadiusY" Value="1"/>
24+
<Setter Property="Cursor" Value="Hand"/>
25+
</Style>
26+
<Style TargetType="{x:Type Path}" x:Key="RmpButtonIndicator">
27+
<Setter Property="Fill" Value="Black"/>
28+
<Setter Property="Canvas.Left" Value="4.25"/>
29+
<Setter Property="Data" Value="M0,0 L5,0 L2.5,2.5 Z"/>
30+
<Style.Triggers>
31+
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=DataContext}" Value="True">
32+
<Setter Property="Fill" Value="GreenYellow" />
33+
</DataTrigger>
34+
</Style.Triggers>
35+
</Style>
36+
<Style BasedOn="{StaticResource {x:Type TextBlock}}" TargetType="{x:Type TextBlock}" x:Key="SelIndicator">
37+
<Setter Property="Canvas.Top" Value="5.5"/>
38+
<Setter Property="Width" Value="13.5"/>
39+
<Setter Property="FontSize" Value="4"/>
40+
<Setter Property="Foreground" Value="Gray"/>
41+
<Style.Triggers>
42+
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=DataContext}" Value="True">
43+
<Setter Property="Foreground" Value="Orange" />
44+
</DataTrigger>
45+
</Style.Triggers>
46+
</Style>
47+
<Style BasedOn="{StaticResource {x:Type TextBlock}}" TargetType="{x:Type TextBlock}" x:Key="FreqWindowText">
48+
<Setter Property="Canvas.Top" Value="10"/>
49+
<Setter Property="Width" Value="50"/>
50+
<Setter Property="Height" Value="14"/>
51+
<Setter Property="Background" Value="Black"/>
52+
<Setter Property="Foreground" Value="Yellow"/>
53+
<Setter Property="FontFamily" Value="Courier New"/>
54+
<Setter Property="FontSize" Value="10"/>
55+
<Setter Property="Padding" Value="0,2,0,0"/>
56+
</Style>
857
</Application.Resources>
958
</Application>

JeehellRMP/JeehellRMP.csproj

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@
1414
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
1515
<WarningLevel>4</WarningLevel>
1616
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
17+
<PublishUrl>publish\</PublishUrl>
18+
<Install>true</Install>
19+
<InstallFrom>Disk</InstallFrom>
20+
<UpdateEnabled>false</UpdateEnabled>
21+
<UpdateMode>Foreground</UpdateMode>
22+
<UpdateInterval>7</UpdateInterval>
23+
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
24+
<UpdatePeriodically>false</UpdatePeriodically>
25+
<UpdateRequired>false</UpdateRequired>
26+
<MapFileExtensions>true</MapFileExtensions>
27+
<ApplicationRevision>0</ApplicationRevision>
28+
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
29+
<IsWebBootstrapper>false</IsWebBootstrapper>
30+
<UseApplicationTrust>false</UseApplicationTrust>
31+
<BootstrapperEnabled>true</BootstrapperEnabled>
1732
</PropertyGroup>
1833
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
1934
<PlatformTarget>AnyCPU</PlatformTarget>
@@ -35,6 +50,11 @@
3550
<WarningLevel>4</WarningLevel>
3651
</PropertyGroup>
3752
<ItemGroup>
53+
<Reference Include="Microsoft.FlightSimulator.SimConnect, Version=10.0.61259.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=x86">
54+
<SpecificVersion>False</SpecificVersion>
55+
<HintPath>C:\Prepar3Dv3\redist\Interface\FSX-SP2-XPACK\retail\lib\managed\Microsoft.FlightSimulator.SimConnect.dll</HintPath>
56+
<Private>True</Private>
57+
</Reference>
3858
<Reference Include="System" />
3959
<Reference Include="System.Data" />
4060
<Reference Include="System.Xml" />
@@ -55,6 +75,8 @@
5575
<Generator>MSBuild:Compile</Generator>
5676
<SubType>Designer</SubType>
5777
</ApplicationDefinition>
78+
<Compile Include="RmpData.cs" />
79+
<Compile Include="SimData.cs" />
5880
<Page Include="MainWindow.xaml">
5981
<Generator>MSBuild:Compile</Generator>
6082
<SubType>Designer</SubType>
@@ -91,10 +113,23 @@
91113
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
92114
</None>
93115
<AppDesigner Include="Properties\" />
116+
<None Include="Readme.md" />
94117
</ItemGroup>
95118
<ItemGroup>
96119
<None Include="App.config" />
97120
</ItemGroup>
121+
<ItemGroup>
122+
<BootstrapperPackage Include=".NETFramework,Version=v4.5.2">
123+
<Visible>False</Visible>
124+
<ProductName>Microsoft .NET Framework 4.5.2 %28x86 and x64%29</ProductName>
125+
<Install>true</Install>
126+
</BootstrapperPackage>
127+
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
128+
<Visible>False</Visible>
129+
<ProductName>.NET Framework 3.5 SP1</ProductName>
130+
<Install>false</Install>
131+
</BootstrapperPackage>
132+
</ItemGroup>
98133
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
99134
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
100135
Other similar extension points exist, see Microsoft.Common.targets.

JeehellRMP/MainWindow.xaml

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,114 @@
55
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
66
xmlns:local="clr-namespace:JeehellRMP"
77
mc:Ignorable="d"
8-
Title="MainWindow" Height="350" Width="525">
9-
<Grid>
10-
11-
</Grid>
8+
Title="Jeehell RMP" Height="330" Width="518" Background="#FF576975">
9+
<Window.Resources>
10+
<local:RmpData x:Key="RmpSimData"/>
11+
</Window.Resources>
12+
<Viewbox>
13+
<Canvas Height="87" Width="150" Background="#FF576975" DataContext="{Binding Source={StaticResource RmpSimData}}">
14+
<!--Frequency window markings-->
15+
<TextBlock Canvas.Left="15" Canvas.Top="1" Width="50" FontSize="5">ACTIVE</TextBlock>
16+
<TextBlock Canvas.Left="85" Canvas.Top="1" Width="50" FontSize="5">STBY/CRS</TextBlock>
17+
<!--STBY NAV markings-->
18+
<Path Data="M15,66.5 L55,66.5" Stroke="White" StrokeEndLineCap="Round" StrokeStartLineCap="Round"/>
19+
<Path Data="M85,66.5 L118,66.5 L118,70" Stroke="White" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeLineJoin="Round"/>
20+
<TextBlock Canvas.Left="59" Canvas.Top="63" FontSize="5">STBY NAV</TextBlock>
21+
<!--On/OFF switch markings-->
22+
<TextBlock Canvas.Left="127" Canvas.Top="63" Width="10" FontSize="5" Cursor="Hand">ON</TextBlock>
23+
<TextBlock Canvas.Left="127" Canvas.Top="78" Width="10" FontSize="5" Cursor="Hand">OFF</TextBlock>
24+
<Ellipse Width="8" Height="8" Canvas.Left="128" Canvas.Top="70" Stroke="White"/>
25+
<Ellipse Width="6" Height="6" Canvas.Left="129" Canvas.Top="71" Fill="Black"/>
26+
27+
<!--Active UI elements-->
28+
<TextBlock Canvas.Left="15" Style="{DynamicResource FreqWindowText}" Text="{Binding Path=ActiveFreq}" />
29+
<TextBlock Canvas.Left="85" Style="{DynamicResource FreqWindowText}" Text="{Binding Path=StandbyFreq}"/>
30+
31+
<Canvas Name="buttonTransfer" Canvas.Top="13" Canvas.Left="68" Cursor="Hand" MouseLeftButtonDown="buttonTransfer_MouseLeftButtonDown">
32+
<Rectangle Width="13.5" Height="9" Fill="Black" RadiusX="1" RadiusY="1"/>
33+
<Path Canvas.Top="2.5" Canvas.Left="1.75" Data="M0,2 L3,0 L3,4 L0,2 L10,2 L7,0 L7,4 L10,2" Fill="GreenYellow" StrokeLineJoin="Round" StrokeMiterLimit="2" StrokeStartLineCap="Round" StrokeEndLineCap="Round" Stroke="GreenYellow"/>
34+
<Path Canvas.Top="2.5" Canvas.Left="1.75" Data="M3,2 L7,2" Stroke="GreenYellow" StrokeThickness="2"/>
35+
</Canvas>
36+
37+
<Canvas Name="buttonVHF1" Canvas.Top="31" Canvas.Left="16">
38+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedVhf1Set}"/>
39+
<Rectangle Style="{DynamicResource RmpButton}"/>
40+
<TextBlock Style="{DynamicResource RmpButtonText}">VHF1</TextBlock>
41+
</Canvas>
42+
43+
<Canvas Name="buttonVHF2" Canvas.Top="31" Canvas.Left="33">
44+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedVhf2Set}"/>
45+
<Rectangle Style="{DynamicResource RmpButton}"/>
46+
<TextBlock Style="{DynamicResource RmpButtonText}">VHF2</TextBlock>
47+
</Canvas>
48+
49+
<Canvas Name="buttonVHF3" Canvas.Top="31" Canvas.Left="50.5">
50+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedVhf3Set}"/>
51+
<Rectangle Style="{DynamicResource RmpButton}"/>
52+
<TextBlock Style="{DynamicResource RmpButtonText}">VHF3</TextBlock>
53+
</Canvas>
54+
55+
<Canvas Name="buttonHF1" Canvas.Top="46" Canvas.Left="16">
56+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedHf1Set}"/>
57+
<Rectangle Style="{DynamicResource RmpButton}"/>
58+
<TextBlock Style="{DynamicResource RmpButtonText}">HF1</TextBlock>
59+
</Canvas>
60+
61+
<Canvas Name="indicatorSEL" Canvas.Top="46" Canvas.Left="33">
62+
<Ellipse Canvas.Top="4" Canvas.Left="2" Width="9" Height="9" Fill="Black"/>
63+
<TextBlock Style="{DynamicResource SelIndicator}" DataContext="{Binding Path=LedSelSet}">SEL</TextBlock>
64+
</Canvas>
65+
66+
<Canvas Name="buttonHF2" Canvas.Top="46" Canvas.Left="50.5">
67+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedHf2Set}"/>
68+
<Rectangle Style="{DynamicResource RmpButton}"/>
69+
<TextBlock Style="{DynamicResource RmpButtonText}">HF2</TextBlock>
70+
</Canvas>
71+
72+
<Canvas Name="buttonAM" Canvas.Top="46" Canvas.Left="68">
73+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedAmSet}"/>
74+
<Rectangle Style="{DynamicResource RmpButton}"/>
75+
<TextBlock Style="{DynamicResource RmpButtonText}">AM</TextBlock>
76+
</Canvas>
77+
78+
<Canvas Name="buttonNAV" Canvas.Top="70" Canvas.Left="16">
79+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedNavSet}"/>
80+
<Rectangle Style="{DynamicResource RmpButton}"/>
81+
<TextBlock Style="{DynamicResource RmpButtonText}">NAV</TextBlock>
82+
</Canvas>
83+
84+
<Canvas Name="buttonVOR" Canvas.Top="70" Canvas.Left="33">
85+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedVorSet}"/>
86+
<Rectangle Style="{DynamicResource RmpButton}"/>
87+
<TextBlock Style="{DynamicResource RmpButtonText}">VOR</TextBlock>
88+
</Canvas>
89+
90+
<Canvas Name="buttonILS" Canvas.Top="70" Canvas.Left="50.5">
91+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedIlsSet}"/>
92+
<Rectangle Style="{DynamicResource RmpButton}"/>
93+
<TextBlock Style="{DynamicResource RmpButtonText}">ILS</TextBlock>
94+
</Canvas>
95+
96+
<Canvas Name="buttonMLS" Canvas.Top="70" Canvas.Left="68">
97+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedMlsSet}"/>
98+
<Rectangle Style="{DynamicResource RmpButton}"/>
99+
<TextBlock Style="{DynamicResource RmpButtonText}">MLS</TextBlock>
100+
</Canvas>
101+
102+
<Canvas Name="buttonBFO" Canvas.Top="70" Canvas.Left="85.5">
103+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedBfoSet}"/>
104+
<Rectangle Style="{DynamicResource RmpButton}"/>
105+
<TextBlock Style="{DynamicResource RmpButtonText}">BFO</TextBlock>
106+
</Canvas>
107+
108+
<Canvas Name="buttonADF" Canvas.Top="70" Canvas.Left="103">
109+
<Path Style="{DynamicResource RmpButtonIndicator}" DataContext="{Binding Path=LedAdfSet}"/>
110+
<Rectangle Style="{DynamicResource RmpButton}"/>
111+
<TextBlock Style="{DynamicResource RmpButtonText}">ADF</TextBlock>
112+
</Canvas>
113+
114+
<Ellipse Name="OuterKnob" Width="25" Height="25" Canvas.Left="92" Canvas.Top="34" StrokeThickness="0" Fill="WhiteSmoke" Cursor="Hand" MouseDown="Knob_MouseDown"/>
115+
<Ellipse Name="InnerKnob" Width="17" Height="17" Canvas.Left="96" Canvas.Top="38" Stroke="Gray" Fill="White" Cursor="Hand" MouseDown="Knob_MouseDown"/>
116+
</Canvas>
117+
</Viewbox>
12118
</Window>

JeehellRMP/MainWindow.xaml.cs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Diagnostics;
34
using System.Linq;
5+
using System.Runtime.InteropServices;
46
using System.Text;
57
using System.Threading.Tasks;
68
using System.Windows;
79
using System.Windows.Controls;
810
using System.Windows.Data;
911
using System.Windows.Documents;
1012
using System.Windows.Input;
13+
using System.Windows.Interop;
1114
using System.Windows.Media;
1215
using System.Windows.Media.Imaging;
1316
using System.Windows.Navigation;
@@ -20,9 +23,68 @@ namespace JeehellRMP
2023
/// </summary>
2124
public partial class MainWindow : Window
2225
{
26+
internal static WindowInteropHelper Window;
27+
2328
public MainWindow()
2429
{
2530
InitializeComponent();
31+
32+
/* To get data from SimConnect you either poll at fixed intervals (bad) or you use the "old" windows
33+
* messaging to let SimConnect signal you when it has something to say. To do this you need to pass the handle
34+
* of the window that will receive the messages and handle that reception (traditionally by overriding DefWndProc).
35+
*
36+
* WPF doesn't want anything to do with the Win32 past so all window messaging is gone. Fortunately
37+
* class System.Windows.Interop is there to bring back these features.
38+
*
39+
* TODO: Investigate if it is possible to create a (hidden) traditional W32 window inside SimData class and have that receive
40+
* messages or alternatively move all Interop code in SimData. MainWindow shouldn't really know anything about SimData. The
41+
* static Window variable is particularly ugly and SimData should probably be able to use reflection on the Application to
42+
* figure it out.
43+
*/
44+
this.Loaded += MainWindow_Loaded;
45+
}
46+
47+
void MainWindow_Loaded(object sender, RoutedEventArgs e)
48+
{
49+
Window = new WindowInteropHelper(this);
50+
HwndSource source = HwndSource.FromHwnd(Window.Handle);
51+
source.AddHook(new HwndSourceHook(WndProc));
52+
}
53+
54+
public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
55+
{
56+
if (msg == SimData.WM_USER_SIMCONNECT)
57+
{
58+
try
59+
{
60+
SimData.ReceiveMessage();
61+
}
62+
catch (COMException ex)
63+
{
64+
//TODO: An exception is firing almost every time FS is closed. My guess is that a message is sent when simconnect discovers
65+
//it is going away but by the we process it, it is already gone, causing a method call on a non existent object.
66+
//TODO: The exception handler can probably be moved into the SimData class
67+
Debug.WriteLine("MainWindow:COMException {0}:{1}", ex.ErrorCode, ex.Message);
68+
69+
//TODO: Remove messagebox after proper logging is available. Left it here to nag me into fixing this.
70+
MessageBox.Show("MainWindow:COMException" + ex.ErrorCode + ":" + ex.Message);
71+
}
72+
}
73+
return IntPtr.Zero;
74+
}
75+
76+
private void buttonTransfer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
77+
{
78+
SimData.TransferKeyPressed();
79+
}
80+
81+
private void Knob_MouseDown(object sender, MouseButtonEventArgs e)
82+
{
83+
var knob = sender as Ellipse;
84+
SimData.Knob knobTurned = (knob.Name == "OuterKnob") ? SimData.Knob.OuterKnob : SimData.Knob.InnerKnob;
85+
SimData.KnobDirection knobTurnDirection = e.LeftButton.HasFlag(MouseButtonState.Pressed) ? SimData.KnobDirection.CounterClockWise : SimData.KnobDirection.Clockwise;
86+
87+
SimData.KnobTurned(knobTurned, knobTurnDirection);
2688
}
2789
}
28-
}
90+
}

0 commit comments

Comments
 (0)