1
0
Fork 0
mirror of https://github.com/hawkeye-stan/msfs-popout-panel-manager.git synced 2024-10-16 06:00:45 +00:00

Version v3.4.1 Release

This commit is contained in:
Stanley 2022-07-29 22:29:20 -04:00
parent f9ebd4bf3f
commit a4151b9c05
26 changed files with 197 additions and 221 deletions

View file

@ -10,9 +10,9 @@
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<RootNamespace>MSFSPopoutPanelManager.ArduinoAgent</RootNamespace>
<Platforms>x64</Platforms>
<Version>3.4.0.0</Version>
<AssemblyVersion>3.4.0.0</AssemblyVersion>
<FileVersion>3.4.0.0</FileVersion>
<Version>3.4.1.0</Version>
<AssemblyVersion>3.4.1.0</AssemblyVersion>
<FileVersion>3.4.1.0</FileVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<DebugType>Embedded</DebugType>
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>

View file

@ -10,9 +10,9 @@
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<RootNamespace>MSFSPopoutPanelManager.Orchestration</RootNamespace>
<Platforms>x64</Platforms>
<Version>3.4.0.0</Version>
<AssemblyVersion>3.4.0.0</AssemblyVersion>
<FileVersion>3.4.0.0</FileVersion>
<Version>3.4.1.0</Version>
<AssemblyVersion>3.4.1.0</AssemblyVersion>
<FileVersion>3.4.1.0</FileVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<DebugType>Embedded</DebugType>
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>

View file

@ -107,6 +107,9 @@ namespace MSFSPopoutPanelManager.Orchestration
TouchEventManager.Hook();
else if (ActiveProfile.PanelConfigs.All(p => !p.TouchEnabled) && TouchEventManager.IsHooked)
TouchEventManager.UnHook();
if (!panelConfig.TouchEnabled)
panelConfig.DisableGameRefocus = false;
break;
}
}

View file

@ -239,6 +239,10 @@ namespace MSFSPopoutPanelManager.Orchestration
if (handle != IntPtr.Zero)
WindowActionManager.MoveWindow(handle, PanelType.CustomPopout, 0, 0, 800, 600);
// Make window always on top to make sure it is clickable and not obstruct by other user windows
//WindowActionManager.ApplyAlwaysOnTop(handle, PanelType.WPFWindow, true);
//Thread.Sleep(500);
if (i > 1)
SeparatePanel(panels[0].PanelHandle); // The joined panel is always the first panel that got popped out
@ -269,6 +273,10 @@ namespace MSFSPopoutPanelManager.Orchestration
PInvoke.SetWindowText(panel.PanelHandle, panel.PanelName + " (Custom)");
}
// Remove window always on top setting
//WindowActionManager.ApplyAlwaysOnTop(panels[0].PanelHandle, PanelType.WPFWindow, false);
//Thread.Sleep(500);
//Performance validation, make sure the number of pop out panels is equal to the number of selected panel
if (WindowActionManager.GetWindowsCountByPanelType(new List<PanelType>() { PanelType.CustomPopout }) != ActiveProfile.PanelSourceCoordinates.Count)
{

View file

@ -132,7 +132,7 @@ namespace MSFSPopoutPanelManager.Orchestration
// Turn off TrackIR if TrackIR is started
FlightSimOrchestrator.TurnOffTrackIR();
if (AppSetting.UseAutoPanning && FlightSimData.IsEnteredFlight)
if (AppSetting.UseAutoPanning)
InputEmulationManager.LoadCustomView(AppSetting.AutoPanningKeyBinding);
}

View file

@ -14,31 +14,19 @@ Please follow [FlightSimulator.com](https://forums.flightsimulator.com/t/msfs-po
<hr>
## ** Updated Touch Panel Feature **
## ** Updated Touch Panel Feature (July 30th, 2022) **
With SU10 Beta v1.27.11, Asobo seems to have fix a major [bug](#touch-enable-pop-out-feature) (in SU9 and before) that stops Pop Out Manager's touch panel feature from working reliably. I'm happy to announce touch enabled feature works pretty well out of the box on either direct connected touch monitor or on pop out window that is displayed on tablet using software tool such as SpaceDesk. Until Asobo actually allow touch passthrough for panels, this tool can serve as a stopgap solution.
I've tested touch operation on GTN750, KingAir PFD/MFD, TMB 930 FMS and they are operational with couple of caveats listed below. Please report any issues that you encounter when using touch enable feature. There is still lots of room for improvement and I'll continue my effort to make touch work better and better.
I've tested touch operation on GTN750, GTN530, KingAir PFD/MFD, TMB 930 FMS, Flybywire A32NX EFB and they are operational. Please report any issues that you encounter when using touch enable feature. There is still lots of room for improvement and I'll continue my effort to make touch work better and better.
Things that work:
Things that work out of the box:
* General button click
* General button click using touch
* Touch and drag such as when panning maps or using scrollbars
* Works on touch monitor or tablet with SpaceDesk
* Flight control will be regained after 0.5 second (adjustable) of touch inactivity on a panel. This will minimize the lost of flight control when when operating touch panel.
Know issues and workarounds:
* (Reported July 24th) - When trying to click and drag a map on touch enabled panel on tablet using SpaceDesk or Duet, touch is not responsive. I'm active working on a fix or implement a better solution for touch and drag.
* When setting a panel to be touch enabled, please refrain form using a mouse to operate the panel since it is going to drive you insane. In the application, when no touch (click) action occurs within 1 second after the last touch action, the mouse cursor is going to jump back into the game window in order to give flight control back to the user. If you're using a mouse to interact with a panel that is designated as touch enabled, your mouse cursor is going to jump around. You can turn off game refocus setting but then you'll lose control of the plane as soon as you interact with a pop out panel. I believe the lost of flight control is on Asobo bug list waiting to be fixed.
* Panels are designed in the game for mouse interaction which means it has a built-in assumption for slow-er mouse click response. But using finger to touch is definitely much faster than using a mouse and some panel UI will not be able to keep up with the speed of touch entry if you send touch input too fast. When you encounter UI lag in response or button click not responding to your touch input, please slow down your touch input speed a bit and let the panel catch up. (On my to-do list for improvement.)
* With the point above and because panels are coded by different developers, they will have vary software performance when using them. Touch event may register consistently for one panel and not another. There is a new touch setting in preferences menu to adjust the time delay to allow a panel to register a touch (mouse down then up). If your panel has trouble receiving your touch input, increase this value one step at a time to compensate for the delay.
* Unlike using a mouse, to pan a map, you've to touch the map first to set the map in focus before touching and dragging to pan the map. This is a limitation of touch vs direct mouse click when using drag action in pop out panel. (On my to-do list for improvement.)
* Touch dragging a scrollbar. Since the current scrollbar implementation in MSFS has a very small target zone when using a finger compares to using a mouse, you may have to try couple times to hit the required scrollbar area to scroll. A easier approach to activate the scrollbar is by touching the scrollbar with your finger, hold for about 1 second, then move your finger to scroll. This gives time for MSFS side to register the start scroll event.
* In SU 10 beta (1.27.11.0) or before, when using Touch Enabled and Full Screen Mode simultaneously for a panel, touch event will not register since Full Screen mode does not get treated as a pop out window by Asobo. Please run the panel in regular pop out window and use "Hide toolbar" option instead of full screen mode to simulator full screen. (On my to-do list for improvement.)
If using SpaceDesk to host pop out panel display, since there is a latency for touch response in wireless display, your touch may not register consistently. Please go to Preferences => Touch Settings => Touch Down Touch Up Delay, and increase the value to 25ms or higher to increase touch sensitivity.
## Application Features
* Display resolution independent. Supports 1080p/1440p/4k display and ultrawide displays.
@ -242,6 +230,8 @@ You can backup this folder and restore this folder if you want to uninstall and
## Common Problem Resolution
* If Pop Out Panel Manager is not running correctly such as panels fail to pop out even all keyboard control bindings are set correctly, please try running the application as administrator and it may resolve the issue..
* Unable to pop out panels when creating a profile for the first time with error such as "Unable to pop out panel #X". If the panel is not being obstructed by another window, by changing the sequence of the pop out when defining the profile may help solve the issue. Currently there are some panels in certain plane configuration that does not follow predefined MSFS pop out rule.
* Unable to pop out panels on subsequent flight. Please follow status message instruction. Also, if using auto-panning, Ctrl-Alt-0 may not have been saved correctly during profile creation. You can trigger a force camera angle save by clicking the "Save Auto Panning Camera" button for the profile.

View file

@ -18,6 +18,7 @@
HideTitlebar,
FullScreen,
TouchEnabled,
DisableGameRefocus,
Invalid
}
}

View file

@ -11,9 +11,9 @@
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<RootNamespace>MSFSPopoutPanelManager.Shared</RootNamespace>
<Platforms>x64</Platforms>
<Version>3.4.0.0</Version>
<AssemblyVersion>3.4.0.0</AssemblyVersion>
<FileVersion>3.4.0.0</FileVersion>
<Version>3.4.1.0</Version>
<AssemblyVersion>3.4.1.0</AssemblyVersion>
<FileVersion>3.4.1.0</FileVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<DebugType>Embedded</DebugType>
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>

View file

@ -11,9 +11,9 @@
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<RootNamespace>MSFSPopoutPanelManager.SimConnectAgent</RootNamespace>
<Platforms>x64</Platforms>
<Version>3.4.0.0</Version>
<AssemblyVersion>3.4.0.0</AssemblyVersion>
<FileVersion>3.4.0.0</FileVersion>
<Version>3.4.1.0</Version>
<AssemblyVersion>3.4.1.0</AssemblyVersion>
<FileVersion>3.4.1.0</FileVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<DebugType>Embedded</DebugType>
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>

View file

@ -11,9 +11,9 @@
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<RootNamespace>MSFSPopoutPanelManager.TouchPanelAgent</RootNamespace>
<Platforms>x64</Platforms>
<Version>3.4.0.0</Version>
<AssemblyVersion>3.4.0.0</AssemblyVersion>
<FileVersion>3.4.0.0</FileVersion>
<Version>3.4.1.0</Version>
<AssemblyVersion>3.4.1.0</AssemblyVersion>
<FileVersion>3.4.1.0</FileVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<DebugType>Embedded</DebugType>
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>

View file

@ -129,13 +129,16 @@ namespace MSFSPopoutPanelManager.UserDataAgent
{
public TouchScreenSettings()
{
MouseUpDownDelay = 25;
TouchDownUpDelay = 0;
RefocusGameWindow = true;
RefocusGameWindowDelay = 500;
}
public int MouseUpDownDelay { get; set; }
public int TouchDownUpDelay { get; set; }
public bool RefocusGameWindow { get; set; }
public int RefocusGameWindowDelay { get; set; }
}
public class TouchPanelSettings : ObservableObject

View file

@ -92,6 +92,8 @@ namespace MSFSPopoutPanelManager.UserDataAgent
public bool TouchEnabled { get; set; }
public bool DisableGameRefocus { get; set; }
[JsonIgnore]
public bool IsCustomPopOut { get { return PanelType == PanelType.CustomPopout; } }

View file

@ -10,9 +10,9 @@
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<RootNamespace>MSFSPopoutPanelManager.UserDataAgent</RootNamespace>
<Platforms>x64</Platforms>
<Version>3.4.0.0</Version>
<AssemblyVersion>3.4.0.0</AssemblyVersion>
<FileVersion>3.4.0.0</FileVersion>
<Version>3.4.1.0</Version>
<AssemblyVersion>3.4.1.0</AssemblyVersion>
<FileVersion>3.4.1.0</FileVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<DebugType>Embedded</DebugType>
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>

View file

@ -2,13 +2,25 @@
<hr/>
## Version 3.4.1
* Button responsiveness
* Full screen mode works now
* Panning works naturally
* Adjustable getting flight control back almost instantaneous (0.5sec)
* Fixed scroll bar issue. Just scroll like you normally would
Known issue:
* After map scrolling is completed, when try to touch the map again to retarget the crosshair (in GTN 750) or just focus on a point in the map (Other touch panel), the target point may jump off screen. Right now, I'm unable to resolve this since MSFS code keeps track of internal coordinates and I'm unable to override it. Need more investigation to work around this issue. In the mean time, just touch the map again to recenter the crosshair.
This release is solely focus on addressing issues regarding touch panel capabilities as well as making improvements to touch feature. Panels I used for testing are
PMT GTN750, WT G3X mod, PMS GTN530, FBW A32NX EFB, King Air 350 PFD/MFD touch screen.
When using SpaceDesk, please increase touch down touch up delay to 25ms in preference touch settings to improve sensitivity in registering touch input.
* Implemented new algorithm to improve general performance for touch panel.
* Button touches are now more responsive. On touch monitor, lag after touch had been minimized and is now performing much closer to a mouse click. On SpaceDesk, the lag is more in line with latency of remote display technology. When using SpaceDesk, you can increase touch delay to 25ms in preference settings to account for the latency if your touch is not register consistently.
* You can now slide your finger to pan the map in panel. There is still a slight delay but touch response is much improved.
* Full screen mode for touch panel can now be turned on.
* Improved scroll bars touch response. They can be dragged and moved much more easily.
* Added adjustable flight control refocus (0.5 sec to 2 sec). The lowest setting makes flight control input refocus seems instantaneous after touch inactivity.
* Added ability to disable flight control refocus for a panel. Set panel to "Disable Game Refocus" will be useful in panel such as Flybywire A32NX EFB since textbox entries in this panel will lose focus if mouse cursor moves away from EFB.
## Version 3.4

View file

@ -11,9 +11,9 @@
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<RootNamespace>MSFSPopoutPanelManager.WebServer</RootNamespace>
<Platforms>x64</Platforms>
<Version>3.4.0.0</Version>
<AssemblyVersion>3.4.0.0</AssemblyVersion>
<FileVersion>3.4.0.0</FileVersion>
<Version>3.4.1.0</Version>
<AssemblyVersion>3.4.1.0</AssemblyVersion>
<FileVersion>3.4.1.0</FileVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<DebugType>Embedded</DebugType>
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>

View file

@ -113,6 +113,7 @@ namespace MSFSPopoutPanelManager.WindowsAgent
PInvoke.SetForegroundWindow(simualatorProcess.Handle);
LeftClick(x, y);
Thread.Sleep(200);
// First center view using Ctrl-Space
PInvoke.keybd_event(Convert.ToByte(VK_LCONTROL), 0, KEYEVENTF_KEYDOWN, 0);
@ -157,6 +158,7 @@ namespace MSFSPopoutPanelManager.WindowsAgent
// First center view to make sure recalling custom camera works on the first press
InputEmulationManager.CenterView();
Thread.Sleep(500);
uint customViewKey = (uint)(Convert.ToInt32(keybinding) + KEY_0);

View file

@ -1,7 +1,6 @@
using MSFSPopoutPanelManager.UserDataAgent;
using System;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
@ -15,12 +14,10 @@ namespace MSFSPopoutPanelManager.WindowsAgent
private static IntPtr _hHook = IntPtr.Zero;
private static PInvoke.WindowsHookExProc callbackDelegate = HookCallBack;
private static bool _isTouchDown;
private static int _mouseMoveCount;
private static bool _isMouseMoveBlock = false;
private static object _mouseTouchLock = new object();
private static int _mouseMoveUnblockCount = 0;
private static int _mouseMoveCount = 0;
private static bool _touchUsePreClick = false;
private static Point _blockPoint;
private static bool _isDragged = false;
private const int PANEL_MENUBAR_HEIGHT = 31;
private const uint TOUCH_FLAG = 0xFF515700;
@ -31,8 +28,7 @@ namespace MSFSPopoutPanelManager.WindowsAgent
private const uint WM_RBUTTONUP = 0x0205;
private const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
private const uint MOUSEEVENTF_LEFTUP = 0x0004;
private const uint MOUSEEVENTF_RIGHTDOWN = 0x0008;
private const uint MOUSEEVENTF_RIGHTUP = 0x0010;
private const uint MOUSEEVENTF_MOVE = 0x0001;
public static Profile ActiveProfile { private get; set; }
@ -83,11 +79,13 @@ namespace MSFSPopoutPanelManager.WindowsAgent
// Touch
// If touch point is within pop out panel boundaries and have touch enabled
if (!ActiveProfile.PanelConfigs.Any(p => p.TouchEnabled
var panelConfig = ActiveProfile.PanelConfigs.FirstOrDefault(p => p.TouchEnabled
&& info.pt.X > p.Left
&& info.pt.X < p.Left + p.Width
&& info.pt.Y > p.Top + (p.HideTitlebar || p.FullScreen ? 5 : PANEL_MENUBAR_HEIGHT)
&& info.pt.Y < p.Top + p.Height))
&& info.pt.Y < p.Top + p.Height);
if (panelConfig == null)
return PInvoke.CallNextHookEx(_hHook, code, wParam, lParam);
switch ((uint)wParam)
@ -100,55 +98,48 @@ namespace MSFSPopoutPanelManager.WindowsAgent
if (!_isTouchDown)
{
_isTouchDown = true;
_isMouseMoveBlock = true;
lock (_mouseTouchLock)
{
Task.Run(() =>
{
_isMouseMoveBlock = true;
Thread.Sleep(25);
if (_mouseMoveCount > 1 || _mouseMoveCount > 1)
if (_mouseMoveCount > 1)
{
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, _blockPoint.X, _blockPoint.Y, 0, 0);
Thread.Sleep(25);
_touchUsePreClick = true;
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, info.pt.X, info.pt.Y, 0, 0);
_isDragged = true;
}
PInvoke.mouse_event(MOUSEEVENTF_LEFTDOWN, _blockPoint.X, _blockPoint.Y, 0, 0);
Thread.Sleep(AppSetting.TouchScreenSettings.TouchDownUpDelay + 25);
PInvoke.mouse_event(MOUSEEVENTF_LEFTDOWN, info.pt.X, info.pt.Y, 0, 0);
Thread.Sleep(AppSetting.TouchScreenSettings.TouchDownUpDelay + 50);
_isMouseMoveBlock = false;
_mouseMoveUnblockCount = 0;
_mouseMoveCount = 0;
});
}
}
break;
case WM_LBUTTONUP:
if (_isTouchDown)
{
lock (_mouseTouchLock)
{
Task.Run(() =>
{
Thread.Sleep(AppSetting.TouchScreenSettings.MouseUpDownDelay + (_touchUsePreClick ? 175 : 125));
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, info.pt.X, info.pt.Y, 0, 0);
_isTouchDown = false;
_touchUsePreClick = false;
RefocusMsfsGameWindow();
});
}
return 1;
}
return 1;
case WM_LBUTTONUP:
Task.Run(() =>
{
while (_isTouchDown) { }
PInvoke.mouse_event(MOUSEEVENTF_LEFTUP, info.pt.X, info.pt.Y, 0, 0);
if (_isDragged)
{
// Override GTN750 bug - must execute this to fix GTN750 cursor moving offscreen issue when doing touch and drag
Thread.Sleep(AppSetting.TouchScreenSettings.TouchDownUpDelay + 50);
PInvoke.SetCursorPos(info.pt.X, info.pt.Y);
Thread.Sleep(100);
InputEmulationManager.LeftClickFast(info.pt.X, info.pt.Y);
_isDragged = false;
}
_mouseMoveCount = 0;
RefocusMsfsGameWindow(panelConfig);
});
return 1;
case WM_MOUSEMOVE:
if (_isMouseMoveBlock)
{
_mouseMoveUnblockCount++;
_blockPoint = new Point(info.pt.X, info.pt.Y);
break;
}
return 1;
_mouseMoveCount++;
break;
@ -158,12 +149,11 @@ namespace MSFSPopoutPanelManager.WindowsAgent
}
private static void RefocusMsfsGameWindow()
private static void RefocusMsfsGameWindow(PanelConfig panelConfig)
{
// ToDo: Adjustable refocus MSFS game, min 500 milliseconds
Thread.Sleep(1000);
Thread.Sleep(AppSetting.TouchScreenSettings.RefocusGameWindowDelay);
if (!_isTouchDown && AppSetting.TouchScreenSettings.RefocusGameWindow)
if (!_isTouchDown && AppSetting.TouchScreenSettings.RefocusGameWindow && !panelConfig.DisableGameRefocus)
{
var rectangle = WindowActionManager.GetWindowRect(_simulatorProcess.Handle);
var clientRectangle = WindowActionManager.GetClientRect(_simulatorProcess.Handle);

View file

@ -10,7 +10,7 @@ namespace MSFSPopoutPanelManager.WindowsAgent
var systemAssemblyVersion = System.Reflection.Assembly.GetEntryAssembly().GetName().Version;
var appVersion = $"{systemAssemblyVersion.Major}.{systemAssemblyVersion.Minor}.{systemAssemblyVersion.Build}";
if (systemAssemblyVersion.Revision > 0)
appVersion += "." + systemAssemblyVersion.Revision;
appVersion += "." + systemAssemblyVersion.Revision.ToString("D4"); ;
return appVersion;
}

View file

@ -11,9 +11,9 @@
<PackageProjectUrl>https://github.com/hawkeye-stan/msfs-popout-panel-manager</PackageProjectUrl>
<RootNamespace>MSFSPopoutPanelManager.WindowsAgent</RootNamespace>
<Platforms>x64</Platforms>
<Version>3.4.0.0</Version>
<AssemblyVersion>3.4.0.0</AssemblyVersion>
<FileVersion>3.4.0.0</FileVersion>
<Version>3.4.1.0</Version>
<AssemblyVersion>3.4.1.0</AssemblyVersion>
<FileVersion>3.4.1.0</FileVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<DebugType>Embedded</DebugType>
<Configurations>Debug;Release;DebugTouchPanel;ReleaseTouchPanel</Configurations>

View file

@ -42,7 +42,7 @@ namespace MSFSPopoutPanelManager.WpfApp
private void HandleTaskSchedulerUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
FileLogger.WriteException(e.Exception.Message, e.Exception);
ShowExceptionDialog();
//ShowExceptionDialog();
}
private void HandleDispatcherException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
@ -51,7 +51,7 @@ namespace MSFSPopoutPanelManager.WpfApp
if (e.Exception.Message != "E_INVALIDARG") // Ignore this error
{
FileLogger.WriteException(e.Exception.Message, e.Exception);
ShowExceptionDialog();
//ShowExceptionDialog();
}
}
@ -59,7 +59,7 @@ namespace MSFSPopoutPanelManager.WpfApp
{
var exception = (Exception)e.ExceptionObject;
FileLogger.WriteException(exception.Message, exception);
ShowExceptionDialog();
//ShowExceptionDialog();
}
private void ShowExceptionDialog()

View file

@ -233,18 +233,24 @@
<TextBlock Style="{StaticResource TextBlockHeading}">Refocus Game Window</TextBlock>
<Line Stretch="Fill" Stroke="Gray" X2="1"/>
<CheckBox IsChecked="{Binding AppSettingData.AppSetting.TouchScreenSettings.RefocusGameWindow, Mode=TwoWay}" >
<AccessText TextWrapping="Wrap">Automactically set focus back to game window after 1 second if inactivity on touch enabled panel. This will give your flight control back when using pop out panel. </AccessText>
<AccessText TextWrapping="Wrap">Automactically set focus back to game window after a period of inactivity on touch enabled panel. This will give your flight control back when using pop out panel.</AccessText>
</CheckBox>
<WrapPanel Margin="0,10,0,0">
<mah:NumericUpDown Width="100" Minimum="500" Maximum="2000" Interval="500" FontSize="16" Height="32" Value="{Binding AppSettingData.AppSetting.TouchScreenSettings.RefocusGameWindowDelay, Mode=TwoWay}"></mah:NumericUpDown>
<AccessText Margin="10,0,0,0" Width="490">Amount of time in milliseconds to wait for touch inactivity before input focus goes back to game window.</AccessText>
</WrapPanel>
</WrapPanel>
<WrapPanel Orientation="Vertical" Margin="0,0,0,20">
<TextBlock Style="{StaticResource TextBlockHeading}">Touch Down Touch Up Delay</TextBlock>
<Line Stretch="Fill" Stroke="Gray" X2="1"/>
<WrapPanel>
<mah:NumericUpDown Width="100" Minimum="0" Maximum="200" Interval="25" FontSize="16" Height="32" Value="{Binding AppSettingData.AppSetting.TouchScreenSettings.MouseUpDownDelay, Mode=TwoWay}"></mah:NumericUpDown>
<AccessText Margin="10,0,0,0" Width="490">Amount of time to delay the touch down and then touch up event when operating touch enabled panel. If your touch is not registering consistently, increasing this value will help.
For example on a direct connected touch monitor, 25 milliseconds work really well. But when operating a panel on a tablet using software such as Spacedesk, since there is delay for touch signal sending back to Windows OS
by the software, increasing this value to 50 or higher may compensate for the delay. The speed of your PC or the type of panel on each plane could also be a factor for touch consistency.
You can experiment by increasing or decreasing this value one step at time until you get a consistent touch response. (Default: 25 milliseconds)</AccessText>
<mah:NumericUpDown Width="100" Minimum="0" Maximum="50" Interval="25" FontSize="16" Height="32" Value="{Binding AppSettingData.AppSetting.TouchScreenSettings.TouchDownUpDelay, Mode=TwoWay}"></mah:NumericUpDown>
<AccessText Margin="10,0,0,0" Width="490">Amount of time to delay touch down and then touch up event when operating touch enabled panel. If your touch is not registering consistently, increasing this value will help.</AccessText>
<TextBlock FontSize="14" TextWrapping="Wrap" Margin="0,10,0,0">
For panel display on direct connected touch monitor, 0 milliseconds work really well.<LineBreak/><LineBreak/>
For panel display on a tablet using software such as Spacedesk, since there is higher latency for touch signal increasing this value to 25 or higher may compensate for this latency.
</TextBlock>
</WrapPanel>
</WrapPanel>
</WrapPanel>

View file

@ -39,10 +39,10 @@
</UserControl.InputBindings>
<Grid>
<DockPanel>
<WrapPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="20,10,0,0" HorizontalAlignment="Left">
<WrapPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="19,10,0,0" HorizontalAlignment="Left">
<Label Content="Panel Locations and Settings -" Margin="0,0,0,0" HorizontalAlignment="Left"/>
<Label Content="{Binding ProfileData.ActiveProfile.ProfileName}" Margin="0,0,0,0" HorizontalAlignment="Left"/>
<DataGrid Name="PanelConfigGrid" HorizontalAlignment="Center" Width="880" Height="430" Margin="0 10 0 0" AutoGenerateColumns="False" CanUserResizeColumns="False" HorizontalScrollBarVisibility="Disabled"
<DataGrid Name="PanelConfigGrid" HorizontalAlignment="Center" Width="882" Height="430" Margin="0 10 0 0" AutoGenerateColumns="False" CanUserResizeColumns="False" HorizontalScrollBarVisibility="Disabled"
CanUserReorderColumns="False" CanUserResizeRows="False" HorizontalGridLinesBrush="#B9B9B9" VerticalGridLinesBrush="#B9B9B9" GridLinesVisibility="Horizontal" SelectionUnit="Cell"
BorderThickness="1" CanUserAddRows="False" CanUserSortColumns="False" KeyboardNavigation.TabNavigation="None" KeyboardNavigation.IsTabStop="False"
ItemsSource="{Binding ProfileData.ActiveProfile.PanelConfigs}">
@ -63,14 +63,13 @@
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock TextWrapping="Wrap" TextAlignment="Center" Text="{Binding}"></TextBlock>
<TextBlock TextWrapping="Wrap" TextAlignment="Center" Text="{Binding}" FontSize="14"></TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="controls:ControlsHelper.ContentCharacterCasing" Value="Normal"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Height" Value="50"/>
<Setter Property="Height" Value="70"/>
<Setter Property="Background" Value="#FF576573"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="#FFB9B9B9"/>
@ -90,15 +89,15 @@
</Style>
</DataGrid.CellStyle>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Panel Name" Width="230" >
<DataGridTemplateColumn Header="Panel Name" Width="220" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Name="PanelName" Width="230" BorderThickness="0" TextAlignment="Left" Text="{Binding PanelName, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=LostFocus}"
<TextBox Name="PanelName" Width="220" BorderThickness="0" TextAlignment="Left" Text="{Binding PanelName, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=LostFocus}"
SourceUpdated="GridData_SourceUpdated" IsReadOnly="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path=DataContext.ProfileData.ActiveProfile.IsLocked}" IsEnabled="{Binding IsCustomPopOut}">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Focusable" Value="True"/>
<Setter Property="FontSize" Value="16" />
<Setter Property="FontSize" Value="14" />
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Margin" Value="5, 5, 5, 5"/>
@ -108,66 +107,70 @@
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="X-Pos" Width="80">
<DataGridTemplateColumn Header="X-Pos" Width="70">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Name="Left" Width="80" BorderThickness="0"
<TextBox Name="Left" Width="70" BorderThickness="0"
Text="{Binding Left, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=LostFocus}"
SourceUpdated="GridData_SourceUpdated"
Style="{StaticResource TextBoxColumnFocus}"
IsReadOnly="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path=DataContext.ProfileData.ActiveProfile.IsLocked}"
IsHitTestVisible="{c:Binding Path='!FullScreen'}"
GotFocus="NumericDataPoint_GotFocus"
LostFocus="NumericDataPoint_LostFocus"/>
LostFocus="NumericDataPoint_LostFocus"
FontSize="14"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Y-Pos" Width="80">
<DataGridTemplateColumn Header="Y-Pos" Width="70">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Name="Top" Width="80" BorderThickness="0"
<TextBox Name="Top" Width="70" BorderThickness="0"
Text="{Binding Top, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=LostFocus}"
SourceUpdated="GridData_SourceUpdated"
Style="{StaticResource TextBoxColumnFocus}"
IsReadOnly="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path=DataContext.ProfileData.ActiveProfile.IsLocked}"
IsHitTestVisible="{c:Binding Path='!FullScreen'}"
GotFocus="NumericDataPoint_GotFocus"
LostFocus="NumericDataPoint_LostFocus"/>
LostFocus="NumericDataPoint_LostFocus"
FontSize="14"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Width" Width="80">
<DataGridTemplateColumn Header="Width" Width="70">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Name="Width" Width="80" BorderThickness="0"
<TextBox Name="Width" Width="70" BorderThickness="0"
Text="{Binding Width, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=LostFocus}"
SourceUpdated="GridData_SourceUpdated"
Style="{StaticResource TextBoxColumnFocus}"
IsReadOnly="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path=DataContext.ProfileData.ActiveProfile.IsLocked}"
IsHitTestVisible="{c:Binding Path='!FullScreen'}"
GotFocus="NumericDataPoint_GotFocus"
LostFocus="NumericDataPoint_LostFocus"/>
LostFocus="NumericDataPoint_LostFocus"
FontSize="14"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Height" Width="80">
<DataGridTemplateColumn Header="Height" Width="70">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Name="Height" Width="80" BorderThickness="0"
<TextBox Name="Height" Width="70" BorderThickness="0"
Text="{Binding Height, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=LostFocus}"
SourceUpdated="GridData_SourceUpdated"
Style="{StaticResource TextBoxColumnFocus}"
IsReadOnly="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='DataContext.ProfileData.ActiveProfile.IsLocked'}"
IsHitTestVisible="{c:Binding Path='!FullScreen'}"
GotFocus="NumericDataPoint_GotFocus"
LostFocus="NumericDataPoint_LostFocus"/>
LostFocus="NumericDataPoint_LostFocus"
FontSize="14"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Always on Top" Width="80">
<DataGridTemplateColumn Header="Always on Top" Width="75">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="AlwaysOnTop" Width="80" Margin="30 0 0 0"
<CheckBox Name="AlwaysOnTop" Width="75" Margin="30 0 0 0"
SourceUpdated="GridData_SourceUpdated"
IsChecked="{Binding AlwaysOnTop, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='!DataContext.ProfileData.ActiveProfile.IsLocked'}"
@ -175,10 +178,10 @@
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Hide Title Bar" Width="80">
<DataGridTemplateColumn Header="Hide Title Bar" Width="75">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="HideTitlebar" Width="80" Margin="30 0 0 0"
<CheckBox Name="HideTitlebar" Width="75" Margin="30 0 0 0"
SourceUpdated="GridData_SourceUpdated"
IsChecked="{Binding HideTitlebar, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='!DataContext.ProfileData.ActiveProfile.IsLocked '}"
@ -186,10 +189,10 @@
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Full Screen Mode" Width="90">
<DataGridTemplateColumn Header="Full Screen Mode" Width="80">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="FullScreen" Width="90" Margin="35 0 0 0"
<CheckBox Name="FullScreen" Width="80" Margin="32 0 0 0"
SourceUpdated="GridData_SourceUpdated"
IsChecked="{Binding FullScreen, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='!DataContext.ProfileData.ActiveProfile.IsLocked'}"
@ -197,10 +200,10 @@
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Touch Enabled" Width="80">
<DataGridTemplateColumn Header="Touch Enabled" Width="75">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="TouchEnabled" Width="80" Margin="30 0 0 0"
<CheckBox Name="TouchEnabled" Width="75" Margin="30 0 0 0"
SourceUpdated="GridData_SourceUpdated"
IsChecked="{Binding TouchEnabled, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='!DataContext.ProfileData.ActiveProfile.IsLocked'}"
@ -208,6 +211,17 @@
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Disable Game Refocus" Width="75">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="DisableGameRefocus" Width="75" Margin="30 0 0 0"
SourceUpdated="GridData_SourceUpdated"
IsChecked="{Binding DisableGameRefocus, Mode=TwoWay, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{c:Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid, AncestorLevel=1}, Path='!DataContext.ProfileData.ActiveProfile.IsLocked'}"
IsHitTestVisible="{c:Binding Path='!FullScreen and IsCustomPopOut and TouchEnabled'}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</WrapPanel>

View file

@ -70,6 +70,9 @@ namespace MSFSPopoutPanelManager.WpfApp
case "Touch Enabled":
selectedProperty = PanelConfigPropertyName.TouchEnabled;
break;
case "Disable Game Refocus":
selectedProperty = PanelConfigPropertyName.DisableGameRefocus;
break;
}
_panelConfigurationViewModel.SelectedPanelConfigItem = new PanelConfigItem() { PanelIndex = panelConfig.PanelIndex, PanelConfigProperty = selectedProperty };

View file

@ -22,6 +22,7 @@ namespace MSFSPopoutPanelManager.WpfApp.ViewModel
ChangeProfileCommand = new DelegateCommand<object>(OnChangeProfile);
AddProfileBindingCommand = new DelegateCommand(OnAddProfileBinding, () => ProfileData.HasActiveProfile && FlightSimData.HasCurrentMsfsPlaneTitle && ProfileData.IsAllowedAddAircraftBinding && FlightSimData.IsSimulatorStarted)
.ObservesProperty(() => ProfileData.ActiveProfile)
.ObservesProperty(() => FlightSimData.HasCurrentMsfsPlaneTitle)
.ObservesProperty(() => ProfileData.HasActiveProfile)
.ObservesProperty(() => ProfileData.IsAllowedAddAircraftBinding)

View file

@ -14,9 +14,9 @@
<RootNamespace>MSFSPopoutPanelManager.WpfApp</RootNamespace>
<ApplicationIcon>logo.ico</ApplicationIcon>
<Platforms>x64</Platforms>
<Version>3.4.0.0</Version>
<AssemblyVersion>3.4.0.0</AssemblyVersion>
<FileVersion>3.4.0.0</FileVersion>
<Version>3.4.1.0</Version>
<AssemblyVersion>3.4.1.0</AssemblyVersion>
<FileVersion>3.4.1.0</FileVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<DebugType>embedded</DebugType>
<SatelliteResourceLanguages>en</SatelliteResourceLanguages>

View file

@ -1,93 +1,34 @@
Version 3.4.0.0
Version 3.4.1.0
This release is optional. It added major new features and made performance improvements to the
core of the application. I encouraged you to update to this latest version. You're still welcome
to skip this update and continue to use older version of the applicaiton but they will no longer
be supported going forward.
This release is optional and changes in this release is solely focus on addressing issues
regarding touch panel capabilities as well as making improvements to touch feature. Panels
I used for testing are PMT GTN750, WT G3X mod, PMS GTN530, FBW A32NX EFB, King Air 350
PFD/MFD touch screen.
************************************************************************************************
IMPORTANT
1. In this update, your user data files including your application settings and profiles will
be upgraded and moved to new a folder location in user "Documents" foder. You can backup all
files within subfolder "userdata" (appsettingdata.json, userprofiledata.json) before this
update occurs. To do so, plese close this update dialog using the X button in the upper
right corner (do not click update button) and exit the application. Then backup the folder
and relaunch the application. This update dialog will reappear and you can perform the update
at that time. After the data migration, all orphan files in the installation folder will be
deleted.
2. A major change to application architecture resulted in an update download size of 60MB. The
update now includes .NET framework 6.0 as part of the package and you will no longer need
to install .NET framework with a separate download.
3. New additional community plugin installation is required to use Auto Pop Out Panel feature.
Please see information below regarding Auto Pop Out Panel improvement for installation
instruciton.
************************************************************************************************
When using SpaceDesk, if touch is not registering consistently, please increase touch down
touch up delay to 25ms or higher in preferences touch settings to improve sensitivity in
registering touch input.
Change Log:
* Changed where user data files are stored. Previously, the files are saved in subfolder
"userdata" in your installation folder. Now they're moved to your Windows "Documents"
folder under "MSFS Pop Out Panel Manager" for easy access. When you first start the
application, a data migration step will occur and your user data files will be upgraded and
moved to this new folder location. This change will allow you to install Pop Out Manager to
folder of your choice on your machine since the application no longer requires write access
to your installation folder.
* Implemented new algorithm to improve general performance for touch panel.
* Upgraded the application to use latest .NET 6.0 framework. You'll notice after user data
migration, your installation folder will have only one executable file left. Please don't
be alarmed when this file is 60MB since all .NET dependencies and application files
are now packaged into a single file. You no longer need to manually install .NET framework
to run this application.
* Button touches are now more responsive. On touch monitor, lag after touch had been
minimized and is now performing much closer to a mouse click. On SpaceDesk, the lag is more
in line with latency of remote display technology. When using SpaceDesk, you can increase
touch delay to 25ms in preference settings to account for the latency if your touch is not
register consistently.
* Major improvement in how Auto Pop Out Panel works. The application no longer tries to hunt
and click "Ready to Fly" button to continue pop out process by using "Ready to Fly Button
Skipper" plugin I created. This plugin is included in the installation folder and is
required for Auto Pop Out Panel to work. Please copy the folder
"zzz-ready-to-fly-button-skipper" into your MSFS community folder.
* You can now slide your finger to pan the map in panel. There is still a slight delay but
touch response is much improved.
* Major improvement in support for touch enabled panel. Using SU10 Beta v1.27.11, touch panel
capabilities has greatly improved including new support for touch down and touch up events.
This update enables smooth touch operations (click and drag) for panel running on connected
touch monitor or on tablet using software tool such as SpaceDesk. There is a new preference
settings section for touch operation adjustments. Please see README.md for current known
issue and workaround for touch operations.
* Full screen mode for touch panel can now be turned on.
* Updated how the application detects Sim Start and Sim Stop to perform Auto Pop Out. It now
uses the much more reliable camera state SimConnect variable for detection.
* Improved scroll bars touch response. They can be dragged and moved much more easily.
* Fixed an issue where full screen mode panel does not expand the panel to fill the entire
monitor. To use full screen mode correctly, once panel is popped out, move panel to desire
monitor and adjust panel window to remove all top/bottom/left/right black bar. Then click
on full screen mode checkbox for the panel. Next time when pop out is executed, panel will
be moved to correct monitor and it will expand to fill the entire screen. [(Issue #27)]
https://github.com/hawkeye-stan/msfs-popout-panel-manager/issues/27
* Added adjustable flight control refocus (0.5 sec to 2 sec). The lowest setting makes flight
control input refocus seems instantaneous after touch inactivity.
* Added a new feature to enable or disable fall back camera once pop out is completed. You can
also define a custom camera view to load if centering cockpit view does not work for you.
(Issue #28) https://github.com/hawkeye-stan/msfs-popout-panel-manager/issues/28
* Added feature to change message dialog on screen duration. You can disable on screen message
by setting the duration value to zero.
* (New for SU10) Added additional keystroke option to pop out panel Ctrl + Right Ctrl + Left
click instead of just Right-Alt + Left click. This is designed for users that have a keyboard
without the Right-Alt key. To use this feature, please map (CTRL + RIGHT CTRL) in
Control Options => Miscellaneous => New UI Window Mode in the game.
* Cleaned up UI and improved UI guidance for user by enabling/disabling buttons and actions
throughout the pop out process.
* Lots of the code is rewritten from the ground up for better performance and stability. It
also prepares the code architecture for v4.0 new features. Please be patient as I continue
to implement v4.0. As always, please report issue and comment and I welcome all feedbacks
and will do my best to fix or implement requested features.
Known Issues:
* In SU 10 beta (1.27.11.0), when using Touch Enabled and Full Screen Mode simultaneously for
a panel, touch event may not register correctly. Please run the panel in regular pop out
window with "Hide toolbar" option instead of full screen mode.
* Added ability to disable flight control refocus for a panel. Set panel to "Disable Game
Refocus" will be useful in panel such as Flybywire A32NX EFB since textbox entries in this
panel will lose focus if mouse cursor moves away from EFB.