GoodGuyOnWeb
Member
How to detect laptop (Windows/Mac OS) lid close event in b4j ? I want to run a b4j app on lid close instead of the default 'sleep'/shutdown options shown in laptop's power setting.
wevtutil qe System /c:10 /rd:true /f:text
'NOTES:
'in Tools set system->power & sleep->additional power settings->choose what to do when lid closes->Nothing
Sub Class_Globals
Private Root As B4XView
Private xui As XUI
Private LLL As LaptopLidLogger
End Sub
Public Sub Initialize
' B4XPages.GetManager.LogEvents = True
End Sub
Private Sub B4XPage_Created (Root1 As B4XView)
Root = Root1
Root.LoadLayout("MainPage")
LLL.Initialize(Me)
End Sub
Private Sub Button1_Click
LLL.StartLogging
Sleep(5000)
Log("Last change: " & LLL.LastChange)
Sleep(5000)
LLL.StopLogging
End Sub
'NOTE: the LaptopLidlogger polls the status once per second (LLL.PollTimer(1000))
Public Sub Lid_Change(status As String)
Log(status)
End Sub
//Modified C# Code From https://stackoverflow.com/questions/3355606/detect-laptop-lid-closure-and-opening
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.IO;
namespace WpfApplication1
{
public partial class MainWindow : Window
{
[DllImport(@"User32", SetLastError = true, EntryPoint = "RegisterPowerSettingNotification", CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid, Int32 Flags);
private System.Windows.Threading.DispatcherTimer dispatcherTimer;
internal struct POWERBROADCAST_SETTING
{
public Guid PowerSetting;
public uint DataLength;
public byte Data;
}
Guid GUID_LIDSWITCH_STATE_CHANGE = new Guid(0xBA3E0F4D, 0xB817, 0x4094, 0xA2, 0xD1, 0xD5, 0x63, 0x79, 0xE6, 0xA0, 0xF3);
const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000;
const int WM_POWERBROADCAST = 0x0218;
const int PBT_POWERSETTINGCHANGE = 0x8013;
private bool? _previousLidState = null;
public MainWindow()
{
if (!File.Exists("LidLogger.txt"))
{
Debug.WriteLine("{0}: File does not exist 1!", DateTime.Now);
this.Close();
}
InitializeComponent();
this.SourceInitialized += MainWindow_SourceInitialized;
dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 2);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
if (!File.Exists("LidLogger.txt"))
{
dispatcherTimer.Stop();
Debug.WriteLine("{0}: File does not exist 3!", DateTime.Now);
this.Close();
}
}
void MainWindow_SourceInitialized(object sender, EventArgs e)
{
RegisterForPowerNotifications();
IntPtr hwnd = new WindowInteropHelper(this).Handle;
HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc));
}
private void RegisterForPowerNotifications()
{
IntPtr handle = new WindowInteropHelper(this).Handle;
IntPtr hLIDSWITCHSTATECHANGE = RegisterPowerSettingNotification(handle, ref GUID_LIDSWITCH_STATE_CHANGE, DEVICE_NOTIFY_WINDOW_HANDLE);
}
IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
switch (msg)
{
case WM_POWERBROADCAST:
OnPowerBroadcast(wParam, lParam);
break;
default:
break;
}
return IntPtr.Zero;
}
private void OnPowerBroadcast(IntPtr wParam, IntPtr lParam)
{
if (!File.Exists("LidLogger.txt"))
{
Debug.WriteLine("{0}: File does not exist 2", DateTime.Now);
this.Close();
}
if ((int)wParam == PBT_POWERSETTINGCHANGE)
{
POWERBROADCAST_SETTING ps = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(lParam, typeof(POWERBROADCAST_SETTING));
IntPtr pData = (IntPtr)((long)lParam + Marshal.SizeOf(ps));
Int32 iData = (Int32)Marshal.PtrToStructure(pData, typeof(Int32));
if (ps.PowerSetting == GUID_LIDSWITCH_STATE_CHANGE)
{
bool isLidOpen = ps.Data != 0;
if (!isLidOpen == _previousLidState)
{
LidStatusChanged(isLidOpen);
}
_previousLidState = isLidOpen;
}
}
}
private void LidStatusChanged(bool isLidOpen)
{
if (isLidOpen)
{
File.AppendAllText("LidLogger.txt", $"{DateTime.Now}: OPEN\n");
}
else
{
File.AppendAllText("LidLogger.txt", $"{DateTime.Now}: CLOSED\n");
}
}
}
}
Brilliant ... I didn't see you found a solution...My response to this thread is a little late, but it took some time to figure this out.
I needed this same function for my laptop app.
I use my laptop as a console for my music collection app as well as other more complex tasks.
I like my lid closed for music, but the when I open it I would like the music to fade and my other work to show on the screen.
I found C# .Net code to do this and it worked, but to integrate it into B4J was a little more complicated.
https://stackoverflow.com/questions/3355606/detect-laptop-lid-closure-and-opening
The attached is how I did it. It won't work on MacOS of course.
The Log output of the attached example:
→Logging Started
→2022-05-27 11:22:20 AM: OPEN
→Last change: 2022-05-27 11:22:20 AM: OPEN
→2022-05-27 11:22:25 AM: CLOSED
→Logging Stopped
The LaptopLidLogger Class (in attached example) takes care of the precise sequence needed for this to work.
B4X:'NOTES: 'in Tools set system->power & sleep->additional power settings->choose what to do when lid closes->Nothing Sub Class_Globals Private Root As B4XView Private xui As XUI Private LLL As LaptopLidLogger End Sub Public Sub Initialize ' B4XPages.GetManager.LogEvents = True End Sub Private Sub B4XPage_Created (Root1 As B4XView) Root = Root1 Root.LoadLayout("MainPage") LLL.Initialize(Me) End Sub Private Sub Button1_Click LLL.StartLogging Sleep(5000) Log("Last change: " & LLL.LastChange) Sleep(5000) LLL.StopLogging End Sub 'NOTE: the LaptopLidlogger polls the status once per second (LLL.PollTimer(1000)) Public Sub Lid_Change(status As String) Log(status) End Sub
You need Visual Studio set for WpfApplication and C# to modify the code below.
B4X://Modified C# Code From https://stackoverflow.com/questions/3355606/detect-laptop-lid-closure-and-opening using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Interop; using System.IO; namespace WpfApplication1 { public partial class MainWindow : Window { [DllImport(@"User32", SetLastError = true, EntryPoint = "RegisterPowerSettingNotification", CallingConvention = CallingConvention.StdCall)] private static extern IntPtr RegisterPowerSettingNotification(IntPtr hRecipient, ref Guid PowerSettingGuid, Int32 Flags); private System.Windows.Threading.DispatcherTimer dispatcherTimer; internal struct POWERBROADCAST_SETTING { public Guid PowerSetting; public uint DataLength; public byte Data; } Guid GUID_LIDSWITCH_STATE_CHANGE = new Guid(0xBA3E0F4D, 0xB817, 0x4094, 0xA2, 0xD1, 0xD5, 0x63, 0x79, 0xE6, 0xA0, 0xF3); const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000; const int WM_POWERBROADCAST = 0x0218; const int PBT_POWERSETTINGCHANGE = 0x8013; private bool? _previousLidState = null; public MainWindow() { if (!File.Exists("LidLogger.txt")) { Debug.WriteLine("{0}: File does not exist 1!", DateTime.Now); this.Close(); } InitializeComponent(); this.SourceInitialized += MainWindow_SourceInitialized; dispatcherTimer = new System.Windows.Threading.DispatcherTimer(); dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick); dispatcherTimer.Interval = new TimeSpan(0, 0, 2); dispatcherTimer.Start(); } private void dispatcherTimer_Tick(object sender, EventArgs e) { if (!File.Exists("LidLogger.txt")) { dispatcherTimer.Stop(); Debug.WriteLine("{0}: File does not exist 3!", DateTime.Now); this.Close(); } } void MainWindow_SourceInitialized(object sender, EventArgs e) { RegisterForPowerNotifications(); IntPtr hwnd = new WindowInteropHelper(this).Handle; HwndSource.FromHwnd(hwnd).AddHook(new HwndSourceHook(WndProc)); } private void RegisterForPowerNotifications() { IntPtr handle = new WindowInteropHelper(this).Handle; IntPtr hLIDSWITCHSTATECHANGE = RegisterPowerSettingNotification(handle, ref GUID_LIDSWITCH_STATE_CHANGE, DEVICE_NOTIFY_WINDOW_HANDLE); } IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) { switch (msg) { case WM_POWERBROADCAST: OnPowerBroadcast(wParam, lParam); break; default: break; } return IntPtr.Zero; } private void OnPowerBroadcast(IntPtr wParam, IntPtr lParam) { if (!File.Exists("LidLogger.txt")) { Debug.WriteLine("{0}: File does not exist 2", DateTime.Now); this.Close(); } if ((int)wParam == PBT_POWERSETTINGCHANGE) { POWERBROADCAST_SETTING ps = (POWERBROADCAST_SETTING)Marshal.PtrToStructure(lParam, typeof(POWERBROADCAST_SETTING)); IntPtr pData = (IntPtr)((long)lParam + Marshal.SizeOf(ps)); Int32 iData = (Int32)Marshal.PtrToStructure(pData, typeof(Int32)); if (ps.PowerSetting == GUID_LIDSWITCH_STATE_CHANGE) { bool isLidOpen = ps.Data != 0; if (!isLidOpen == _previousLidState) { LidStatusChanged(isLidOpen); } _previousLidState = isLidOpen; } } } private void LidStatusChanged(bool isLidOpen) { if (isLidOpen) { File.AppendAllText("LidLogger.txt", $"{DateTime.Now}: OPEN\n"); } else { File.AppendAllText("LidLogger.txt", $"{DateTime.Now}: CLOSED\n"); } } } }