Merge pull request #817 from IceStormNG/clamshell-detection

Automatic Clamshell Mode Toggle
This commit is contained in:
Serge
2023-07-19 12:22:22 +02:00
committed by GitHub
7 changed files with 158 additions and 0 deletions

17
app/Extra.Designer.cs generated
View File

@@ -101,6 +101,7 @@ namespace GHelper
pictureSettings = new PictureBox();
labelSettings = new Label();
panelSettings = new Panel();
checkAutoToggleClamshellMode = new CheckBox();
checkAutoApplyWindowsPowerMode = new CheckBox();
checkTopmost = new CheckBox();
checkNoOverdrive = new CheckBox();
@@ -1003,6 +1004,7 @@ namespace GHelper
//
panelSettings.AutoSize = true;
panelSettings.AutoSizeMode = AutoSizeMode.GrowAndShrink;
panelSettings.Controls.Add(checkAutoToggleClamshellMode);
panelSettings.Controls.Add(checkAutoApplyWindowsPowerMode);
panelSettings.Controls.Add(checkTopmost);
panelSettings.Controls.Add(checkNoOverdrive);
@@ -1017,6 +1019,20 @@ namespace GHelper
panelSettings.Size = new Size(983, 304);
panelSettings.TabIndex = 46;
//
// checkAutoToggleClamshellMode
//
checkAutoToggleClamshellMode.AutoSize = true;
checkAutoToggleClamshellMode.Dock = DockStyle.Top;
checkAutoToggleClamshellMode.Location = new Point(10, 163);
checkAutoToggleClamshellMode.Margin = new Padding(2);
checkAutoToggleClamshellMode.Name = "checkAutoToggleClamshellMode";
checkAutoToggleClamshellMode.Padding = new Padding(2);
checkAutoToggleClamshellMode.Size = new Size(481, 23);
checkAutoToggleClamshellMode.TabIndex = 58;
checkAutoToggleClamshellMode.Text = "Auto Toggle Clamshell Mode";
checkAutoToggleClamshellMode.UseVisualStyleBackColor = true;
checkAutoToggleClamshellMode.CheckedChanged += checkAutoToggleClamshellMode_CheckedChanged;
//
// checkAutoApplyWindowsPowerMode
//
checkAutoApplyWindowsPowerMode.AutoSize = true;
@@ -1246,5 +1262,6 @@ namespace GHelper
private PictureBox pictureService;
private Slider sliderBrightness;
private PictureBox pictureLog;
private CheckBox checkAutoToggleClamshellMode;
}
}

View File

@@ -106,6 +106,7 @@ namespace GHelper
checkUSBC.Text = Properties.Strings.OptimizedUSBC;
checkAutoApplyWindowsPowerMode.Text = Properties.Strings.ApplyWindowsPowerPlan;
checkFnLock.Text = Properties.Strings.FnLock;
checkAutoToggleClamshellMode.Text = Properties.Strings.ToggleClamshellMode;
labelBacklightKeyboard.Text = Properties.Strings.Keyboard;
labelBacklightBar.Text = Properties.Strings.Lightbar;
@@ -210,6 +211,9 @@ namespace GHelper
}
}
checkAutoToggleClamshellMode.Checked = AppConfig.Is("toggle_clamshell_mode");
checkTopmost.Checked = AppConfig.Is("topmost");
checkTopmost.CheckedChanged += CheckTopmost_CheckedChanged; ;
@@ -466,5 +470,12 @@ namespace GHelper
{
AppConfig.Set("auto_apply_power_plan", checkAutoApplyWindowsPowerMode.Checked ? 1 : 0);
}
private void checkAutoToggleClamshellMode_CheckedChanged(object sender, EventArgs e)
{
AppConfig.Set("toggle_clamshell_mode", checkAutoToggleClamshellMode.Checked ? 1 : 0);
ClamshellModeControl ctrl = new ClamshellModeControl();
ctrl.ToggleLidAction();
}
}
}

View File

@@ -0,0 +1,76 @@
using GHelper.Display;
using GHelper.Mode;
using Microsoft.Win32;
namespace GHelper.Helpers
{
internal class ClamshellModeControl
{
public bool IsExternalDisplayConnected()
{
var devices = ScreenInterrogatory.GetAllDevices().ToArray();
foreach (var device in devices)
{
if (device.outputTechnology != ScreenInterrogatory.DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY.DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL &&
device.outputTechnology != ScreenInterrogatory.DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY.DISPLAYCONFIG_OUTPUT_TECHNOLOGY_DISPLAYPORT_EMBEDDED)
{
Logger.WriteLine("Found external screen: " + device.monitorFriendlyDeviceName + ":" + device.outputTechnology.ToString());
//Already found one, we do not have to check whether there are more
return true;
}
}
return false;
}
public bool IsClamshellEnabled()
{
return AppConfig.Get("toggle_clamshell_mode") != 0;
}
public bool IsChargerConnected()
{
return SystemInformation.PowerStatus.PowerLineStatus == PowerLineStatus.Online;
}
public bool IsInClamshellMode()
{
return IsExternalDisplayConnected() && IsChargerConnected();
}
public void ToggleLidAction()
{
if (IsInClamshellMode() && IsClamshellEnabled())
{
PowerNative.SetLidAction(0, true);
Logger.WriteLine("Engaging Clamshell Mode");
}
else
{
PowerNative.SetLidAction(1, true);
Logger.WriteLine("Disengaging Clamshell Mode");
}
}
public void UnregisterDisplayEvents()
{
SystemEvents.DisplaySettingsChanged -= SystemEvents_DisplaySettingsChanged;
}
public void RegisterDisplayEvents()
{
SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
}
private void SystemEvents_DisplaySettingsChanged(object? sender, EventArgs e)
{
Logger.WriteLine("Display configuration changed.");
if (IsClamshellEnabled())
ToggleLidAction();
}
}
}

View File

@@ -60,6 +60,9 @@ namespace GHelper.Mode
private static Guid GUID_SLEEP_SUBGROUP = new Guid("238c9fa8-0aad-41ed-83f4-97be242c8f20");
private static Guid GUID_HIBERNATEIDLE = new Guid("9d7815a6-7ee4-497e-8888-515a05f02364");
private static Guid GUID_SYSTEM_BUTTON_SUBGROUP = new Guid("4f971e89-eebd-4455-a8de-9e59040e7347");
private static Guid GUID_LIDACTION = new Guid("5CA83367-6E45-459F-A27B-476B1D01C936");
[DllImportAttribute("powrprof.dll", EntryPoint = "PowerGetActualOverlayScheme")]
public static extern uint PowerGetActualOverlayScheme(out Guid ActualOverlayGuid);
@@ -163,5 +166,40 @@ namespace GHelper.Mode
break;
}
}
public static void SetLidAction(int action, bool acOnly = false)
{
/**
* 1: Do nothing
* 2: Seelp
* 3: Hibernate
* 4: Shutdown
*/
Guid activeSchemeGuid = GetActiveScheme();
var hrAC = PowerWriteACValueIndex(
IntPtr.Zero,
activeSchemeGuid,
GUID_SYSTEM_BUTTON_SUBGROUP,
GUID_LIDACTION,
action);
PowerSetActiveScheme(IntPtr.Zero, activeSchemeGuid);
if (!acOnly)
{
var hrDC = PowerWriteDCValueIndex(
IntPtr.Zero,
activeSchemeGuid,
GUID_SYSTEM_BUTTON_SUBGROUP,
GUID_LIDACTION,
action);
PowerSetActiveScheme(IntPtr.Zero, activeSchemeGuid);
}
Logger.WriteLine("Changed Lid Action to " + action);
}
}
}

View File

@@ -30,6 +30,7 @@ namespace GHelper
public static ModeControl modeControl = new ModeControl();
static GPUModeControl gpuControl = new GPUModeControl(settingsForm);
static ScreenControl screenControl = new ScreenControl();
static ClamshellModeControl clamshellControl = new ClamshellModeControl();
public static ToastForm toast = new ToastForm();
@@ -99,6 +100,8 @@ namespace GHelper
// Subscribing for system power change events
SystemEvents.PowerModeChanged += SystemEvents_PowerModeChanged;
SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
clamshellControl.RegisterDisplayEvents();
clamshellControl.ToggleLidAction();
// Subscribing for monitor power on events
PowerSettingGuid settingGuid = new NativeMethods.PowerSettingGuid();
@@ -238,6 +241,7 @@ namespace GHelper
static void OnExit(object sender, EventArgs e)
{
trayIcon.Visible = false;
clamshellControl.UnregisterDisplayEvents();
NativeMethods.UnregisterPowerSettingNotification(unRegPowerNotify);
Application.Exit();
}

View File

@@ -1177,6 +1177,15 @@ namespace GHelper.Properties {
return ResourceManager.GetString("ToggleAura", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Auto Toggle Clamshell Mode.
/// </summary>
internal static string ToggleClamshellMode {
get {
return ResourceManager.GetString("ToggleClamshellMode", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Toggle Fn-Lock.

View File

@@ -491,6 +491,9 @@ Do you still want to continue?</value>
<data name="ToggleAura" xml:space="preserve">
<value>Toggle Aura</value>
</data>
<data name="ToggleClamshellMode" xml:space="preserve">
<value>Auto Toggle Clamshell Mode</value>
</data>
<data name="ToggleFnLock" xml:space="preserve">
<value>Toggle Fn-Lock</value>
</data>