Skip to content

Commit

Permalink
Allow the screen to switch off when the user session is locked.
Browse files Browse the repository at this point in the history
  • Loading branch information
PolarGoose committed Sep 29, 2023
1 parent dad4bcf commit d27c392
Show file tree
Hide file tree
Showing 20 changed files with 282 additions and 313 deletions.
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ charset = utf-8
indent_style = space
indent_size = 4

[*.{xml,wxs,csproj,yaml,props,wixproj}]
[*.{xml,wxs, csproj, wixproj, config, sln, svg, manifest, json}]
indent_size = 2
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ on: push

jobs:
build:
runs-on: windows-2022
runs-on: windows-latest
steps:
- uses: actions/checkout@v2
- run: .github/workflows/build.ps1
- uses: actions/upload-artifact@v2
- uses: actions/checkout@v3
- run: .\build.ps1
- uses: actions/upload-artifact@v3
with:
name: Build artifacts
path: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/build/
.vs/
.idea/
*.csproj.user
launchSettings.json
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
# CoffeeBean
![Screenshot](doc/Screenshot.png)<br>
An utility to prevent a policy-enforced screen lock in Windows.<br>
Sometimes Windows is configured to lock the screen after some time of inactivity.<br>
In case this option is enforced by corporate IT policies, it impossible to disable it via Windows settings.<br>
This utility was created as a convenient and reliable way to solve this problem.
A utility to prevent a policy-enforced screen lock in Windows.<br>
Windows can be configured to lock the screen after some time of inactivity.<br>
In case corporate IT policies enforce this option, it is impossible to disable it via Windows settings.<br>
This utility is a convenient and reliable way to solve this problem.

# System requirements
The application uses `.Net Framework 4.6.1` which is already present on any version of `Windows 10` and `Windows 11`.
* Windows 7 x32/x64 or higher (you might need to install [.Net Framework 4.6.2](https://dotnet.microsoft.com/en-us/download/dotnet-framework/thank-you/net462-web-installer))

# How to install
* Download `CoffeeBean.exe.zip` (portable executable) or `CoffeeBean.msi` from the latest [release](https://github.com/PolarGoose/CoffeeBean/releases)
* Run the installer if you want to install the application. The installer will install into a `%AppData%\CoffeeBean` folder and create a desktop icon.

# How to use
* Start the application and you will get an icon in the system tray
* As you keep this tool running it prevents the screen from auto locking
* You can still lock the screen manually, if you want, by using Windows default methods/shortcuts (for example by pressing `Win+L`)
* To close the utility, click `Close` in the tray icon context menu. After utility is closed, screen locking behavior returns to what it was before you started the utility
* Use `Launch at startup` context menu item if you want the application to run automatically when Windows starts.
* Use `Enable` context menu item to enable or disable screen lock prevention functionality.
* Start the application, and you will get an icon in the system tray
* As you keep this tool running, it prevents the screen from auto-locking
* You can still lock the screen manually, if you want, by using Windows default methods/shortcuts (for example, by pressing `Win+L`)
* To close the utility, click `Close` in the tray icon context menu. After the utility is closed, the locking behavior returns to what it was before you started the utility
* Use the `Launch at startup` context menu item if you want the application to run at Windows startup.
* Use the `Enable` context menu item to turn the screen lock prevention functionality on or off.

## Running the application from console
There are command line arguments to control screen lock functionality. You can use them in the following way:
* Launch the application with screen lock prevention functionality enabled or enable screen lock prevention functionality of already running instance of the application:
* Launch the application with screen lock prevention functionality enabled or enable the screen lock prevention functionality of an already running instance of the application:
```
CoffeeBean.exe enable
```
* Launch the application with screen lock prevention functionality disabled or disable screen lock functionality of already running instance of the application:
* Launch the application with screen lock prevention functionality disabled or turn off screen lock functionality of an already running instance of the application:
```
CoffeeBean.exe disable
```

# How it works
The application uses [SetThreadExecutionState](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setthreadexecutionstate) WinAPI method which allows an application to keep system "in use" even if there is no user activity. It is better than simulating key presses or mouse movements. For instance, it is the function which is used by video players to keep the screen on while playing a video.
The application uses [SetThreadExecutionState](https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setthreadexecutionstate) WinAPI method, which allows an application to keep the system "in use" even if there is no user activity. It is better than simulating key presses or mouse movements. For instance, it is the function that video players use to keep the screen on while playing a video.

# How to build
* Use `Visual Studio 2022` with [Wix Toolset Visual Studio 2022 Extension](https://marketplace.visualstudio.com/items?itemName=WixToolset.WixToolsetVisualStudio2022Extension) and [Wix Toolset](https://wixtoolset.org/releases/)
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/build.ps1 → build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"

$root = Resolve-Path "$PSScriptRoot/../.."
$root = Resolve-Path $PSScriptRoot
$publishDir = "$root/build/Release"
$projectName = "CoffeeBean"
$version = GetVersion
Expand All @@ -88,4 +88,4 @@ Info "Build project"
$root/$projectName.sln
CheckReturnCodeOfPreviousCommand "build failed"

CreateZipArchive "$publishDir/net461/${projectName}.exe" "$publishDir/${projectName}.exe.zip"
CreateZipArchive "$publishDir/net462/${projectName}.exe" "$publishDir/${projectName}.exe.zip"
9 changes: 8 additions & 1 deletion src/App/CoffeeBean.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,21 @@

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net461</TargetFramework>
<TargetFramework>net462</TargetFramework>
<UseWPF>true</UseWPF>
<UseWindowsForms>true</UseWindowsForms>
<Platforms>x86</Platforms>
<ApplicationIcon>Icon\icon.ico</ApplicationIcon>
<StartupObject>CoffeeBean.EntryPoint</StartupObject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="PolySharp" Version="1.13.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualBasic" />
Expand Down
2 changes: 1 addition & 1 deletion src/App/ContextMenu.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</forms:ToolStripMenuItem>
<forms:ToolStripSeparator/>
<forms:ToolStripMenuItem Text="Enabled" CheckOnClick="true" CheckedChanged="EnabledMenuItem_CheckedChanged" x:Name="EnabledMenuItem" ToolTipText="Shows if screen lock prevention is enabled or not"/>
<forms:ToolStripMenuItem Text="Launch at startup" CheckOnClick="true" CheckedChanged="LaunchAtStatrupMenuItem_CheckedChanged" x:Name="LaunchAtStartupMenuItem"/>
<forms:ToolStripMenuItem Text="Launch at startup" CheckOnClick="true" CheckedChanged="LaunchAtStartupMenuItem_CheckedChanged" x:Name="LaunchAtStartupMenuItem"/>
<forms:ToolStripSeparator/>
<forms:ToolStripMenuItem Text="Close" Click="Close_OnClick"/>
</forms:ContextMenuStrip.Items>
Expand Down
70 changes: 31 additions & 39 deletions src/App/ContextMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,49 @@
using System.Diagnostics;
using System.Windows;

namespace CoffeeBean
namespace CoffeeBean;

public partial class ContextMenu
{
public partial class ContextMenu
private readonly string githubUrl = "https://github.com/PolarGoose/CoffeeBean";
private readonly ScreenLockController screenLockController;

public ContextMenu(ScreenLockController screenLockController)
{
private readonly string githubUrl = "https://github.com/PolarGoose/CoffeeBean";
private readonly ScreenLockPreventer screenLockPreventer;
InitializeComponent();

public ContextMenu(ScreenLockPreventer screenLockPreventer)
{
InitializeComponent();
VersionMenuItem.Text = $"Version: {AssemblyInfoRetriever.InformationalVersion}\n{githubUrl}";

VersionMenuItem.Text = $"Version: {AssemblyInfoRetriever.InformationalVersion}\n{githubUrl}";
LaunchAtStartupMenuItem.Checked = AutoStartup.IsEnabled;

LaunchAtStartupMenuItem.Checked = AutoStartup.IsEnabled;
this.screenLockController = screenLockController;
this.screenLockController.EnabledChanged += () => EnabledMenuItem.Checked = this.screenLockController.Enabled;
}

this.screenLockPreventer = screenLockPreventer;
this.screenLockPreventer.EnabledChanged += () => EnabledMenuItem.Checked = this.screenLockPreventer.Enabled;
}
private void About_OnClick(object sender, EventArgs e)
{
_ = Process.Start("explorer", githubUrl);
}

private void About_OnClick(object sender, EventArgs e)
{
_ = Process.Start("explorer", githubUrl);
}
private void Close_OnClick(object sender, EventArgs e)
{
Application.Current.Shutdown();
}

private void Close_OnClick(object sender, EventArgs e)
private void LaunchAtStartupMenuItem_CheckedChanged(object sender, EventArgs e)
{
if (LaunchAtStartupMenuItem.Checked)
{
Application.Current.Shutdown();
AutoStartup.Enable();
}

private void LaunchAtStatrupMenuItem_CheckedChanged(object sender, EventArgs e)
else
{
if (LaunchAtStartupMenuItem.Checked)
{
AutoStartup.Enable();
}
else
{
AutoStartup.Disable();
}
AutoStartup.Disable();
}
}

private void EnabledMenuItem_CheckedChanged(object sender, EventArgs e)
{
if (EnabledMenuItem.Checked)
{
screenLockPreventer.Enabled = true;
}
else
{
screenLockPreventer.Enabled = false;
}
}
private void EnabledMenuItem_CheckedChanged(object sender, EventArgs e)
{
screenLockController.Enabled = EnabledMenuItem.Checked;
}
}
115 changes: 58 additions & 57 deletions src/App/EntryPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,81 +4,82 @@
using System.Collections.Generic;
using System.Windows.Forms;

namespace CoffeeBean
namespace CoffeeBean;

// https://stackoverflow.com/a/19326/7585517
// https://github.com/microsoft/WPF-Samples/tree/master/Application%20Management/SingleInstanceDetection
internal sealed class SingleInstanceManager : WindowsFormsApplicationBase
{
// https://stackoverflow.com/a/19326/7585517
// https://github.com/microsoft/WPF-Samples/tree/master/Application%20Management/SingleInstanceDetection
internal sealed class SingleInstanceManager : WindowsFormsApplicationBase
{
private ScreenLockPreventer screenLockPreventer;
private NotifyIcon trayIcon;
private ScreenLockController _screenLockController;
private NotifyIcon trayIcon;
private UserSessionStatusMonitor userSessionStatusMonitor;

public SingleInstanceManager()
{
IsSingleInstance = true;
}
public SingleInstanceManager()
{
IsSingleInstance = true;
}

protected override bool OnStartup(StartupEventArgs e)
protected override bool OnStartup(StartupEventArgs e)
{
_screenLockController = new ScreenLockController();
userSessionStatusMonitor = new UserSessionStatusMonitor(_screenLockController);
trayIcon = new NotifyIcon
{
screenLockPreventer = new ScreenLockPreventer();
trayIcon = new NotifyIcon
{
Icon = new System.Drawing.Icon(System.Windows.Application.GetResourceStream(new Uri("/Icon/icon.ico", UriKind.Relative)).Stream),
Visible = true,
Text = "CoffeeBean",
ContextMenuStrip = new ContextMenu(screenLockPreventer)
};
Icon = new System.Drawing.Icon(System.Windows.Application.GetResourceStream(new Uri("/Icon/icon.ico", UriKind.Relative)).Stream),
Visible = true,
Text = "CoffeeBean",
ContextMenuStrip = new ContextMenu(_screenLockController)
};

// When application starts, the screen lock preventing functionality should be enabled by default, unless there are command line arguments saying otherwise.
screenLockPreventer.Enabled = true;
// When application starts, the screen lock preventing functionality should be enabled by default, unless there are command line arguments saying otherwise.
_screenLockController.Enabled = true;

var commandLineParametersAreCorrect = ProcessCommandLineArguments(e.CommandLine);
var commandLineParametersAreCorrect = ProcessCommandLineArguments(e.CommandLine);

if (commandLineParametersAreCorrect)
{
// Start the event loop
new System.Windows.Application().Run();
}
if (commandLineParametersAreCorrect)
{
// Start the event loop
new System.Windows.Application().Run();
}

// On shutdown
trayIcon.Dispose();
// On shutdown
trayIcon.Dispose();

return false;
}
return false;
}

protected override void OnStartupNextInstance(StartupNextInstanceEventArgs e)
{
_ = ProcessCommandLineArguments(e.CommandLine);
protected override void OnStartupNextInstance(StartupNextInstanceEventArgs e)
{
_ = ProcessCommandLineArguments(e.CommandLine);

e.BringToForeground = false;
}
e.BringToForeground = false;
}

private bool ProcessCommandLineArguments(IReadOnlyList<string> args)
private bool ProcessCommandLineArguments(IReadOnlyList<string> args)
{
try
{
try
{
var parsedArgs = CommandLineParser.Parse(args);
if (parsedArgs.IsScreenLockEnabled != null)
{
screenLockPreventer.Enabled = (bool)parsedArgs.IsScreenLockEnabled;
}
return true;
}
catch (Exception ex)
var parsedArgs = CommandLineParser.Parse(args);
if (parsedArgs.IsScreenLockEnabled != null)
{
ErrorDialog.Show($"{ex.Message}.\nUsage:\nCoffeeBean.exe [enable|disable]");
return false;
_screenLockController.Enabled = (bool)parsedArgs.IsScreenLockEnabled;
}
return true;
}
catch (Exception ex)
{
ErrorDialog.Show($"{ex.Message}.\nUsage:\nCoffeeBean.exe [enable|disable]");
return false;
}
}
}

internal static class EntryPoint
internal static class EntryPoint
{
[STAThread]
private static void Main(string[] args)
{
[STAThread]
private static void Main(string[] args)
{
var manager = new SingleInstanceManager();
manager.Run(args);
}
var manager = new SingleInstanceManager();
manager.Run(args);
}
}
12 changes: 5 additions & 7 deletions src/App/Utils/AssemblyInfoRetriever.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
using System.Diagnostics;
using System.Reflection;

namespace CoffeeBean.Utils
namespace CoffeeBean.Utils;

internal static class AssemblyInfoRetriever
{
internal static class AssemblyInfoRetriever
{
public static string InformationalVersion => Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
public static string ExecutableNameWithoutExtension => Process.GetCurrentProcess().ProcessName;
public static string ExecutableFullName => Process.GetCurrentProcess().MainModule.FileName;
}
public static string InformationalVersion => Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion;
public static string ExecutableFullName => Process.GetCurrentProcess().MainModule.FileName;
}
Loading

0 comments on commit d27c392

Please sign in to comment.