32

I have a piece of server-ish software written in Java to run on Windows and OS X. (It is not running on a server, but just a normal user's PC - something like a torrent client.) I would like the software to signal to the OS to keep the machine awake (prevent it from going into sleep mode) while it is active.

Of course I don't expect there to be a cross platform solution, but I would love to have some very minimal C programs/scripts that my app can spawn to inform the OS to stay awake.

Any ideas?

chills42
  • 14,201
  • 3
  • 42
  • 77
Frank Krueger
  • 69,552
  • 46
  • 163
  • 208

18 Answers18

42

I use this code to keep my workstation from locking. It's currently only set to move the mouse once every minute, you could easily adjust it though.

It's a hack, not an elegant solution.

import java.awt.*;
import java.util.*;
public class Hal{

    public static void main(String[] args) throws Exception{
        Robot hal = new Robot();
        Random random = new Random();
        while(true){
            hal.delay(1000 * 60);
            int x = random.nextInt() % 640;
            int y = random.nextInt() % 480;
            hal.mouseMove(x,y);
        }
    }
}
ScArcher2
  • 85,501
  • 44
  • 121
  • 160
  • 7
    Why not just move the mouse 1 pixel as @Keng mentioned? This seems like it would drive the user nuts. – Frank Krueger Sep 10 '08 at 05:08
  • 2
    You could do that, but I didn't need to. I just posted the code I'm using. It took me like 2 minutes to write, and I haven't needed to change it. If you want to post a modified version to move it one pixel that would be cool. – ScArcher2 Sep 10 '08 at 14:19
  • I just made a "mousemover" like that some years ago: http://simu.wikidot.com/java:java#toc0 :-) – user85421 May 20 '09 at 18:20
  • 3
    This does not work if the headless version of Java is installed (Linux-only). – binwiederhier Jul 28 '14 at 18:27
  • You can also use `Toolkit.getDefaultToolkit().getScreenSize()` to obtain the screen size and use `screen.width` and `screen.height` instead of `640` and `480`. – bobasti May 20 '17 at 21:12
  • I've got inspired and made this a clickable batch solution. Check below answer! https://stackoverflow.com/a/54684339/3002336 – Anand Varkey Philips Oct 22 '19 at 05:57
  • The problem with this approach is that the mouse-moving will prevent the screen from powering down (which could cause ghosting or LED burn-in on some screens). In an ideal situation you would still want the screen to power down but prevent the OS itself from going into a sleep state. The [JNA solution](https://stackoverflow.com/a/65890299/475044) that was posted at the bottom of this question is a much more appropriate solution than this as it still allows for the screen to power down. – wcmatthysen Mar 18 '21 at 21:34
14

On Windows, use the SystemParametersInfo function. It's a Swiss army-style function that lets you get/set all sorts of system settings.

To disable the screen shutting off, for instance:

SystemParametersInfo( SPI_SETPOWEROFFACTIVE, 0, NULL, 0 );

Just be sure to set it back when you're done...

Matt Dillard
  • 14,677
  • 7
  • 51
  • 61
  • 3
    Very bad idea. If the program crashes then you've just changed user settings without permission. You should process the WM_POWERBROADCAST message instead. – Steve Hanov Nov 03 '08 at 13:31
  • 2
    This is definitely the danger of using this approach; this can be somewhat mitigated (in C++) by creating a class which makes this call in its constructor, and resets it in the destructor. Processing the WM_POWERBROADCAST event may also work, but only with certain flavors of Windows. – Matt Dillard Nov 03 '08 at 15:48
  • You don't need to go that route. You can create a power-request by calling `PowerCreateRequest`. The resulting handle then allows you to either increment the number of requests by calling `PowerSetRequest` or decrementing it by calling `PowerClearRequest`. If the number of requests are non-zero then the OS won't go to sleep. This is all documented in the Win32API docs. The other advantage is that if the handle is destroyed during JVM shutdown then the power-requests are removed. The [JNA solution](https://stackoverflow.com/a/65890299/475044) listed at the bottom follows this approach. – wcmatthysen Mar 18 '21 at 21:56
8

A much cleaner solution is use JNA to tap into the native OS API. Check your platform at runtime, and if it happens to be Windows then the following will work:

import com.sun.jna.Native;
import com.sun.jna.Structure;
import com.sun.jna.Structure.FieldOrder;
import com.sun.jna.platform.win32.WTypes.LPWSTR;
import com.sun.jna.platform.win32.WinBase;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinDef.ULONG;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.win32.StdCallLibrary;

/**
 * Power management.
 *
 * @see <a href="https://stackoverflow.com/a/20996135/14731">https://stackoverflow.com/a/20996135/14731</a>
 */
public enum PowerManagement
{
    INSTANCE;

    @FieldOrder({"version", "flags", "simpleReasonString"})
    public static class REASON_CONTEXT extends Structure
    {
        public static class ByReference extends REASON_CONTEXT implements Structure.ByReference
        {
        }

        public ULONG version;
        public DWORD flags;
        public LPWSTR simpleReasonString;
    }

    private interface Kernel32 extends StdCallLibrary
    {
        HANDLE PowerCreateRequest(REASON_CONTEXT.ByReference context);

        /**
         * @param powerRequestHandle the handle returned by {@link #PowerCreateRequest(REASON_CONTEXT.ByReference)}
         * @param requestType        requestType is the ordinal value of {@link PowerRequestType}
         * @return true on success
         */
        boolean PowerSetRequest(HANDLE powerRequestHandle, int requestType);

        /**
         * @param powerRequestHandle the handle returned by {@link #PowerCreateRequest(REASON_CONTEXT.ByReference)}
         * @param requestType        requestType is the ordinal value of {@link PowerRequestType}
         * @return true on success
         */
        boolean PowerClearRequest(HANDLE powerRequestHandle, int requestType);

        enum PowerRequestType
        {
            PowerRequestDisplayRequired,
            PowerRequestSystemRequired,
            PowerRequestAwayModeRequired,
            PowerRequestMaximum
        }
    }

    private final Kernel32 kernel32;
    private HANDLE handle = null;

    PowerManagement()
    {
        // Found in winnt.h
        ULONG POWER_REQUEST_CONTEXT_VERSION = new ULONG(0);
        DWORD POWER_REQUEST_CONTEXT_SIMPLE_STRING = new DWORD(0x1);

        kernel32 = Native.load("kernel32", Kernel32.class);
        REASON_CONTEXT.ByReference context = new REASON_CONTEXT.ByReference();
        context.version = POWER_REQUEST_CONTEXT_VERSION;
        context.flags = POWER_REQUEST_CONTEXT_SIMPLE_STRING;
        context.simpleReasonString = new LPWSTR("Your reason for changing the power setting");
        handle = kernel32.PowerCreateRequest(context);
        if (handle == WinBase.INVALID_HANDLE_VALUE)
            throw new AssertionError(Native.getLastError());
    }

    /**
     * Prevent the computer from going to sleep while the application is running.
     */
    public void preventSleep()
    {
        if (!kernel32.PowerSetRequest(handle, Kernel32.PowerRequestType.PowerRequestSystemRequired.ordinal()))
            throw new AssertionError("PowerSetRequest() failed");
    }

    /**
     * Allow the computer to go to sleep.
     */
    public void allowSleep()
    {
        if (!kernel32.PowerClearRequest(handle, Kernel32.PowerRequestType.PowerRequestSystemRequired.ordinal()))
            throw new AssertionError("PowerClearRequest() failed");
    }
}

Then when the user runs powercfg /requests they see:

SYSTEM:
[PROCESS] \Device\HarddiskVolume1\Users\Gili\.jdks\openjdk-15.0.2\bin\java.exe
Your reason for changing the power setting

You should be able to do something similar for macOS and Linux.

Gili
  • 86,244
  • 97
  • 390
  • 689
  • 1
    Crazy, I can't believe this is not the top-most voted answer as this is obviously the correct way to do it plus much more elegant than interfering with the user's mouse position. Also, this approach has the benefit of allowing the screen to power down while preventing the OS from going to sleep. – wcmatthysen Mar 18 '21 at 21:40
  • 2
    Just one thing that I've noticed, the `PowerSetRequest` method increments a counter. So, if you call that function twice you need two corresponding calls of `PowerClearRequest` to decrement the counter to 0 again to allow the OS to go to sleep. I prevented this by keeping a boolean flag that indicates that I've already called `PowerSetRequest`. Also, I have a cleanup method to free the handle. I do this by calling `kernel32.CloseHandle(handle)`. This required me to add a `boolean CloseHandle(HANDLE handle)` method to the `Kernel32` interface. – wcmatthysen Mar 18 '21 at 21:47
7

Adding to scarcher2's code snippet above and moving mouse by only 1 pixel. I have moved the mouse twice so that some change occurs even if pointer is on extremes:

while(true){
            hal.delay(1000 * 30);       
            Point pObj = MouseInfo.getPointerInfo().getLocation();
            System.out.println(pObj.toString() + "x>>" + pObj.x + "  y>>" + pObj.y);
            hal.mouseMove(pObj.x + 1, pObj.y + 1);  
            hal.mouseMove(pObj.x - 1, pObj.y - 1);
            pObj = MouseInfo.getPointerInfo().getLocation();
            System.out.println(pObj.toString() + "x>>" + pObj.x + "  y>>" + pObj.y);
        }
Ashok M A
  • 478
  • 6
  • 14
asloob
  • 1,308
  • 20
  • 34
5

I have a very brute-force technique of moving the mouse 1 point in the x direction and then back every 3 minutes.

There may me a more elegant solution but it's a quick fix.

Keng
  • 52,011
  • 32
  • 81
  • 111
5

Wouldn't all the suggestions moving the mouse back and forth drive the user crazy? I know I'd remove any app that would do that as soon as I can isolate it.

zigdon
  • 14,573
  • 6
  • 35
  • 54
  • 6
    moving it one pixel isn't noticable to anyone but cyborgs and cyborgs just devnull frustration anyway so your all good. – Keng Sep 10 '08 at 12:46
  • Jip, the better approach is to use JNA. Plus, moving the mouse will prevent the screen from shutting down whereas with the JNA solution the screen will power down but the OS will be prevented from going to sleep. – wcmatthysen Mar 18 '21 at 22:00
4

Here is completed Batch file that generates java code, compile it, cleans the generated files, and runs in the background.. (jdk is required on your laptop)

Just save and run this as a Bat File. (somefilename.bat) ;)

@echo off
setlocal

rem rem if JAVA is set and run from :startapp labeled section below, else the program exit through :end labeled section.
if not "[%JAVA_HOME%]"=="[]" goto start_app
echo. JAVA_HOME not set. Application will not run!
goto end


:start_app
echo. Using java in %JAVA_HOME%
rem writes below code to Energy.java file.
@echo import java.awt.MouseInfo; > Energy.java
@echo import java.awt.Point; >> Energy.java
@echo import java.awt.Robot; >> Energy.java
@echo //Mouse Movement Simulation >> Energy.java
@echo public class Energy { >> Energy.java
@echo     public static void main(String[] args) throws Exception { >> Energy.java
@echo         Robot energy = new Robot(); >> Energy.java
@echo         while (true) { >> Energy.java
@echo             energy.delay(1000 * 60); >> Energy.java
@echo             Point pObj = MouseInfo.getPointerInfo().getLocation(); >> Energy.java
@echo             Point pObj2 = pObj;  >> Energy.java
@echo             System.out.println(pObj.toString() + "x>>" + pObj.x + "  y>>" + pObj.y); >> Energy.java
@echo             energy.mouseMove(pObj.x + 10, pObj.y + 10); >> Energy.java
@echo             energy.mouseMove(pObj.x - 10, pObj.y - 10); >> Energy.java
@echo             energy.mouseMove(pObj2.x, pObj.y); >> Energy.java
@echo             pObj = MouseInfo.getPointerInfo().getLocation(); >> Energy.java
@echo             System.out.println(pObj.toString() + "x>>" + pObj.x + "  y>>" + pObj.y); >> Energy.java
@echo         } >> Energy.java
@echo     } >> Energy.java
@echo } >> Energy.java

rem compile java code.
javac Energy.java
rem run java application in background.
start javaw Energy
echo. Your Secret Energy program is running...
goto end

:end
rem clean if files are created.
pause
del "Energy.class"
del "Energy.java"
Anand Varkey Philips
  • 1,811
  • 26
  • 41
2

On OS X, just spawn caffeinate. This will prevent the system from sleeping until caffeinate is terminated.

norq
  • 1,404
  • 2
  • 18
  • 35
2

In Visual Studio create a simple form. From the toolbar, drag a Timer control onto the form. In the Init code, set the timer interval to 60 seconds (60000 ms.). Implement the timer callback with the following code "SendKeys.Send("{F15}");" Run the new program.

No mouse movement needed.

Edit: At least on my Army workstation, simply programmatically generating mouse and key messages isn't enough to keep my workstation logged in and awake. The early posters with the Java Robot class are on the right track. JAVA Robot works on or below the OS's HAL (Hardware Abstraction Layer) However I recreated and tested the Java/Robot solution and it did not work - until I added a Robot.keyPress(123) to the code.

Felinis
  • 47
  • 3
2

I've been using pmset to control sleep mode on my Mac for awhile now, and it's pretty easy to integrate. Here's a rough example of how you could call that program from Java to disable/enable sleep mode. Note that you need root privileges to run pmset, and therefore you'll need them to run this program.

import java.io.BufferedInputStream;
import java.io.IOException;

/**
 * Disable sleep mode (record current setting beforehand), and re-enable sleep
 * mode. Works with Mac OS X using the "pmset" command.
 */
public class SleepSwitch {

    private int sleepTime = -1;

    public void disableSleep() throws IOException {
        if (sleepTime != -1) {
            // sleep time is already recorded, assume sleep is disabled
            return;
        }

        // query pmset for the current setting
        Process proc = Runtime.getRuntime().exec("pmset -g");
        BufferedInputStream is = new BufferedInputStream(proc.getInputStream());
        StringBuffer output = new StringBuffer();
        int c;
        while ((c = is.read()) != -1) {
            output.append((char) c);
        }
        is.close();

        // parse the current setting and store the sleep time
        String outString = output.toString();
        String setting = outString.substring(outString.indexOf(" sleep\t")).trim();
        setting = setting.substring(7, setting.indexOf(" ")).trim();
        sleepTime = Integer.parseInt(setting);

        // set the sleep time to zero (disable sleep)
        Runtime.getRuntime().exec("pmset sleep 0");
    }

    public void enableSleep() throws IOException {
        if (sleepTime == -1) {
            // sleep time is not recorded, assume sleep is enabled
            return;
        }

        // set the sleep time to the previously stored value
        Runtime.getRuntime().exec("pmset sleep " + sleepTime);

        // reset the stored sleep time
        sleepTime = -1;
    }
}
David Crow
  • 16,077
  • 8
  • 42
  • 34
  • 1
    Good answer, but in this case I wouldn't dare ask for elevation. What's the point of security if every app asks for special privileges? – Frank Krueger Sep 10 '08 at 05:07
  • True, it is inconvenient to grant privileges for minor tasks. But if you wrap pmset in a suid script, that could solve the problem (the script can be executed as root without prompting). Of course, suid scripts can be potential security holes... – David Crow Sep 10 '08 at 07:26
2

To go with the solution provided by user Gili for Windows using JNA, here's the JNA solution for MacOS.

First, the JNA library interface:

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.platform.mac.CoreFoundation;
import com.sun.jna.ptr.IntByReference;

public interface ExampleIOKit extends Library {
    ExampleIOKit INSTANCE = Native.load("IOKit", ExampleIOKit.class);

    CoreFoundation.CFStringRef kIOPMAssertPreventUserIdleSystemSleep = CoreFoundation.CFStringRef.createCFString("PreventUserIdleSystemSleep");
    CoreFoundation.CFStringRef kIOPMAssertPreventUserIdleDisplaySleep = CoreFoundation.CFStringRef.createCFString("PreventUserIdleDisplaySleep");

    int kIOReturnSuccess = 0;

    int kIOPMAssertionLevelOff = 0;
    int kIOPMAssertionLevelOn = 255;

    int IOPMAssertionCreateWithName(CoreFoundation.CFStringRef assertionType,
                                    int assertionLevel,
                                    CoreFoundation.CFStringRef reasonForActivity,
                                    IntByReference assertionId);

    int IOPMAssertionRelease(int assertionId);
}

Here's an example of invoking the JNA method to turn sleep prevention on or off:

public class Example {
    private static final Logger _log = LoggerFactory.getLogger(Example.class);

    private int sleepPreventionAssertionId = 0;

    public void updateSleepPrevention(final boolean isEnabled) {
        if (isEnabled) {
            if (sleepPreventionAssertionId == 0) {
                final var assertionIdRef = new IntByReference(0);
                final var reason = CoreFoundation.CFStringRef.createCFString(
                    "Example preventing display sleep");
                final int result = ExampleIOKit.INSTANCE.IOPMAssertionCreateWithName(
                    ExampleIOKit.kIOPMAssertPreventUserIdleDisplaySleep,
                    ExampleIOKit.kIOPMAssertionLevelOn, reason, assertionIdRef);
                if (result == ExampleIOKit.kIOReturnSuccess) {
                    _log.info("Display sleep prevention enabled");
                    sleepPreventionAssertionId = assertionIdRef.getValue();
                }
                else {
                    _log.error("IOPMAssertionCreateWithName returned {}", result);
                }
            }
        }
        else {
            if (sleepPreventionAssertionId != 0) {
                final int result = ExampleIOKit.INSTANCE.IOPMAssertionRelease(sleepPreventionAssertionId);
                if (result == ExampleIOKit.kIOReturnSuccess) {
                    _log.info("Display sleep prevention disabled");
                }
                else {
                    _log.error("IOPMAssertionRelease returned {}", result);
                }
                sleepPreventionAssertionId = 0;
            }
        }
    }
}
2

You can use the program Caffeine caffiene to keep your workstation awake. You could run the program via the open command in os X.

Milhous
  • 14,473
  • 16
  • 63
  • 82
1

This code moves the pointer to the same location where it already is so the user doesn't notice any difference.

while (true) {
    Thread.sleep(180000);//this is how long before it moves
    Point mouseLoc = MouseInfo.getPointerInfo().getLocation();
    Robot rob = new Robot();
    rob.mouseMove(mouseLoc.x, mouseLoc.y);
}
1

Wouldn't it be easier to disable the power management on the server? It might be argued that servers shouldn't go into powersave mode?

zigdon
  • 14,573
  • 6
  • 35
  • 54
0

This will work:

public class Utils {
    public static void main(String[] args) throws AWTException {
        Robot rob = new Robot();
        PointerInfo ptr = null;
        while (true) {
            rob.delay(4000);  // Mouse moves every 4 seconds
            ptr = MouseInfo.getPointerInfo();
            rob.mouseMove((int) ptr.getLocation().getX() + 1, (int) ptr.getLocation().getY() + 1);
        }
    }
}
Santosh Jadi
  • 1,479
  • 6
  • 29
  • 55
0

Run a command inside a timer like pinging the server..

Gulzar Nazim
  • 51,744
  • 26
  • 128
  • 170
0

I'd just do a function (or download a freebie app) that moves the mouse around. Inelegant, but easy.

Paulj
  • 3,096
  • 3
  • 25
  • 30
-1

One simple way which i use to avoid "Windows desktop Auto lock" is "Switch On/Off NumLock" every 6 seconds.

Here a Java Program to Switch ON/OFF NumLock.

import java.util.*;
import java.awt.*;
import java.awt.event.*;

public class NumLock extends Thread {
  public void run() {
    try {
    boolean flag = true;
    do {
        flag = !flag;

        Thread.sleep(6000);
        Toolkit.getDefaultToolkit().setLockingKeyState(KeyEvent. VK_NUM_LOCK, flag);
    }
    while(true);
    }
    catch(Exception e) {}
  }

  public static void main(String[] args) throws Exception {
    new NumLock().start();
  }
}

Run this Java program in a separate command prompt; :-)

maris
  • 718
  • 7
  • 8