4

I'm trying to prevent the screensaver from kicking-in. I've tried Sending keystrokes but they all require to grab a window by title. If there is no open window on the desktop, there is nothing to grab.

So I have found something that might work but I'm no C# wizard. It's based on Simulating a keypress AND keyrelease in another application?

The code below is supposed to send a 1 but I'm missing something. I get no errors until I call the new type from Powershell. After this works, I want to make it send an F15 to reset the screensaver countdown but not modify stuff on the screen. (But I gotta crawl first by sending 1s)

Add-Type @"
using System.Runtime.InteropServices;

namespace ConsoleApplication1 
{
    public static class PressKeyForMe 
    { 
        [DllImport("user32.dll")] 
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

        //public static void Main(string[] args)
        public static void Main()
        {            
            //This code will press and hold the '1' button for 3 secs, and then will release for 1 second
            //VK_F15 0x7E
            keybd_event((byte)0x31, (byte)0x02, 0, UIntPtr.Zero);
            Thread.Sleep(3000);

            keybd_event((byte)0x31, (byte)0x82, (uint)0x2, UIntPtr.Zero);
            Thread.Sleep(1000);
        }
    }

}
"@
cls

#all of these give me: Unable to find type
[void] [PressKeyForMe]::Main()
[void] [ConsoleApplication1]::PressKeyForMe()
[void] [PressKeyForMe.Main]
[void] [ConsoleApplication1.Main]
[void] [ConsoleApplication1.PressKeyForMe]::Main()
Community
  • 1
  • 1
Mr. Annoyed
  • 541
  • 3
  • 18

2 Answers2

5

Seems like you're missing a few using-statements in that type definition:

Add-Type @"
using System;
using System.Threading;
using System.Runtime.InteropServices;

namespace ConsoleApplication1 
{
    public static class PressKeyForMe 
    { 
        [DllImport("user32.dll")] 
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

        //public static void Main(string[] args)
        public static void Main()
        {            
            //This code will press and hold the '1' button for 3 secs, and then will release for 1 second
            //VK_F15 0x7E
            keybd_event((byte)0x31, (byte)0x02, 0, UIntPtr.Zero);
            Thread.Sleep(3000);

            keybd_event((byte)0x31, (byte)0x82, (uint)0x2, UIntPtr.Zero);
            Thread.Sleep(1000);
        }
    }

}
"@

This should work now:

[ConsoleApplication1.PressKeyForMe]::Main()

You could also add just the methods and assign the auto-generated type to a variable:

$KeyPresser = Add-Type -MemberDefinition @"
[DllImport("user32.dll")]
static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

public static void PressOne(int press, int release)
{
    //This code will press and hold the '1' button for 3 secs, and then will release for 1 second
    //VK_F15 0x7E
    keybd_event((byte)0x31, (byte)0x02, 0, UIntPtr.Zero);
    Thread.Sleep(press);

    keybd_event((byte)0x31, (byte)0x82, (uint)0x2, UIntPtr.Zero);
    Thread.Sleep(release);
}

public static void PressOne()
{
    PressOne(3000, 1000);
}
"@ -Name PressKeyForMe -UsingNamespace System.Threading -PassThru

Now you can call the method without the full type name:

PS C:\> $KeyPresser::PressOne() 
PS C:\> $KeyPresser::PressOne(400,120) # you really need to press 3 seconds?
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
  • Thank you Mathias! This works. And No, I didn't need to hold that key down for an insane 3 seconds. I just wasn't sure what I could change before things broke. – Mr. Annoyed Nov 10 '15 at 20:56
  • @Mr.Annoyed Cool :) If this solved your problem, please mark the answer as "accepted" by clicking the checkmark on the left – Mathias R. Jessen Nov 10 '15 at 21:09
  • Here I was looking for a big green box that says "Accept this solution" for a month or so.. – Mr. Annoyed Nov 12 '15 at 16:29
0

Thank you Mathias for fixing my code above. I was able to finish my script!

For the curious, below is how I got the F15 key thing to work. Just use [ScreenSpender.PressKeyForMe]::Main() every few minutes to keep the screen saver at bay. Thanks to John Savard for helping out on the Keyboard Scan Code.

#The following is an attempt to prevent the SceenSaver from kicking-in during installation
#We call it using this
#[ScreenSpender.PressKeyForMe]::Main()

Add-Type @"
using System;
using System.Threading;
using System.Runtime.InteropServices;

namespace ScreenSpender 
{
    public static class PressKeyForMe 
    { 
        [DllImport("user32.dll")] 
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, UIntPtr dwExtraInfo);

        //public static void Main(string[] args)
        public static void Main()
        {
            //bScan = PS/2 scan code. (We happen to be using Set 1)
            // Make  = when you press the key
            // Break = when you release the key
            //VK_F15 0x7E
            //SC_F15 0x5D   (Scan code set 1) (or 0x64) (http://www.quadibloc.com/comp/scan.htm  - by John Savard)
            //private const int KEYEVENTF_KEYUP = 0x02;
            //This code will press and hold the 'F15' key for 250 Milliseconds, and then will release for 200 Milliseconds
            keybd_event((byte)0x7E, (byte)0x5D, 0, UIntPtr.Zero);
            Thread.Sleep(250);

            // Release for 200 Milliseconds
            keybd_event((byte)0x7E, (byte)0x5D, (uint)0x2, UIntPtr.Zero);
            Thread.Sleep(200);
        }
    }
}
"@
Mr. Annoyed
  • 541
  • 3
  • 18