1

I'm trying to write a code that "blinks" the lock key leds really fast (using -comObject to sendkeys). The code run really slow on Powershell (from CMD) and miss some keypress, but seems to work great on Powershell_ise.

The code reads a file to binary and then transfer each bit to num/scroll lock. This needs to run really fast - as fast as I can.

This is the code:

$wsh = New-Object -ComObject "WScript.Shell"
$bytes = [Byte[]] (Get-Content  $env:temp\temp1536.txt -Encoding Byte -ReadCount 0) | ForEach-Object {[System.Convert]::ToString($_,2)}
##($i=0; $i -le $byte.length; $i++){

 foreach ($byte in $bytes) {
 #$byte;
   while($byte.length -ne 1 ){
    if($byte[1] -eq '1'){
        #echo "1";
        $wsh.SendKeys('{SCROLLLOCK}');
        [System.Threading.Thread]::Sleep(40);   
        $wsh.SendKeys('{SCROLLLOCK}');
    } Else {
        #echo "0";
        $wsh.SendKeys('{NUMLOCK}');
        [System.Threading.Thread]::Sleep(40);
        $wsh.SendKeys('{NUMLOCK}');
    }
    $byte=$byte.Substring(1);
    [System.Threading.Thread]::Sleep(50);


   }
   #echo " ";
   #echo "1";

   $wsh.SendKeys('{CAPSLOCK}');
   [System.Threading.Thread]::Sleep(55);

   $wsh.SendKeys('{CAPSLOCK}');
   [System.Threading.Thread]::Sleep(20);

 }

Anyone knows why this happens?

EDIT: I added a video showing the lag of the lock key blinking on Powershell Console Vs. Powershell_ISE http://youtu.be/OnOmr50OBhs

I tried this on Powershell V3.0/4.0 on Windows 7

I used this text file name -'temp1536.txt' in %temp% folder The file is imported to binary and then light the led accordingly.

$bytes = [Byte[]] (Get-Content  $env:temp\temp1536.txt -Encoding Byte -ReadCount 0) | ForEach-Object {[System.Convert]::ToString($_,2)}
oriez
  • 11
  • 4

2 Answers2

0

I couldn't get your code working (it never steps into if($byte[1] -eq '1')), but here is the version using keybd_event\GetKeyState Win32 API that works fine in my ISE and console. Adapted from code posted here.

$Keyboard = @'
using System.Runtime.InteropServices;

namespace My
{
    public class Keyboard
    {
        private const byte VK_SCROLL = 0x91;
        private const byte VK_NUMLOCK = 0x90;
        private const byte VK_CAPITAL = 0x14;
        private const uint KEYEVENTF_KEYUP = 0x2;

        [DllImport("user32.dll", EntryPoint = "keybd_event", SetLastError = true)]
        static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);

        [DllImport("user32.dll", EntryPoint = "GetKeyState", SetLastError = true)]
        static extern short GetKeyState(uint nVirtKey);

        // SCROLLLOCK
        public static void SetScrollLockKey(bool newState)
        {
            bool scrollLockSet = GetKeyState(VK_SCROLL) != 0;
            if (scrollLockSet != newState)
            {
                keybd_event(VK_SCROLL, 0, 0, 0);
                keybd_event(VK_SCROLL, 0, KEYEVENTF_KEYUP, 0);
            }
        }
        public static bool GetScrollLockState()
        {
            return GetKeyState(VK_SCROLL) != 0;
        }

        // NUMLOCK
        public static void SetNumLockKey(bool newState)
        {
            bool scrollLockSet = GetKeyState(VK_NUMLOCK) != 0;
            if (scrollLockSet != newState)
            {
                keybd_event(VK_NUMLOCK, 0, 0, 0);
                keybd_event(VK_NUMLOCK, 0, KEYEVENTF_KEYUP, 0);
            }
        }

        public static bool GetNumLockState()
        {
            return GetKeyState(VK_NUMLOCK) != 0;
        }

        // CAPSLOCK
        public static void SetCapsLockKey(bool newState)
        {
            bool scrollLockSet = GetKeyState(VK_NUMLOCK) != 0;
            if (scrollLockSet != newState)
            {
                keybd_event(VK_CAPITAL, 0, 0, 0);
                keybd_event(VK_CAPITAL, 0, KEYEVENTF_KEYUP, 0);
            }
        }

        public static bool GetCapsLockState()
        {
            return GetKeyState(VK_CAPITAL) != 0;
        }
    }
}
'@

Add-Type -TypeDefinition $Keyboard -ErrorAction Stop

$Bytes = Get-Content -Path '.\led.txt' -Encoding Byte

foreach ($byte in $Bytes) {
    if($byte)
    {
        [My.Keyboard]::SetScrollLockKey($true)
        [System.Threading.Thread]::Sleep(40)
        [My.Keyboard]::SetScrollLockKey($false)
    }
    else
    {
        [My.Keyboard]::SetNumLockKey($true)
        [System.Threading.Thread]::Sleep(40)
        [My.Keyboard]::SetNumLockKey($false)
    }

    [My.Keyboard]::SetCapsLockKey($true)
    [System.Threading.Thread]::Sleep(55)

    [My.Keyboard]::SetNumLockKey($false)
    [System.Threading.Thread]::Sleep(20)
}
beatcracker
  • 6,714
  • 1
  • 18
  • 41
  • thanks. can you see different performance in console and ISE? When I run this on console it is running really slow... I can see the leds blink slowly and also when running 'Measure-Command' – oriez May 25 '15 at 11:37
  • @oriez You mean my code runs slow in console? Just checked it on another PC using `Measure-Command`, still no issues: it's runs as fast as in ISE. Check this question, maybe it doesn't have anything to do with code itself: [It seems like updates described in the KB3057134 make PowerShell to start slow](http://serverfault.com/questions/691873/it-seems-like-updates-described-in-the-kb3057134-make-powershell-to-start-slow) – beatcracker May 25 '15 at 11:50
  • @oriez Btw, what version of PowerShell are you using? This could be realted to STA\MTA modes: [Difference between PowerShell Console and PowerShell ISE](http://stackoverflow.com/questions/20022976/difference-between-powershell-console-and-powershell-ise). Try running PS console with `-sta` and `-mta` switches and see if it helps. – beatcracker May 25 '15 at 13:21
  • I tried also the latest version running both on -sta , maybe it is just my machine – oriez May 26 '15 at 08:10
  • I tried different Windows machine with powershell V6.1 that also running on -sta/-mta run really slow on console – oriez May 26 '15 at 13:05
  • @oriez `powershell V6.1` ? Latest version is v5 and it's still in beta. Anyway, could you update your question with example file (the one with 0 & 1), so I could test it on the my PCs? – beatcracker May 26 '15 at 18:00
  • sorry V3.0 and V4.0. I added more info. – oriez May 26 '15 at 19:29
  • I added more info to the question. There is no 0 & 1 file. I placed a text file on "%temp%\temp1536.txt". The text is then converted to binary using this line: $bytes = [Byte[]] (Get-Content $env:temp\temp1536.txt -Encoding Byte -ReadCount 0) | ForEach-Object {[System.Convert]::ToString($_,2)} Just place a file in this path - "%temp%\temp1536.txt" – oriez May 26 '15 at 19:38
0

It seems to be a problem in some PCs only. Can't really understand why. But I got it to work fine on some computers.

oriez
  • 11
  • 4