jscript.net

How to Listen Keys in JScript.Net


What I wish is to catch the keypress using JScript .NET, and compile the code using that jsc.exe. So, is there any equivalent of "addEventListener("keyDown", keyCheck)" from FLASH actionscript. Or GetAsyncKeyState() from C++. And what library do I have to use? Please be kind enough to share a small, simple example.


Solution

  • Here's a simple solution if you're writing a console app.

    import System;
    
    Console.Write("Press the M key... ");
    
    var key:ConsoleKeyInfo;
    
    while (1) {
        while (!Console.KeyAvailable) {
            System.Threading.Thread.Sleep(1);
        }
        key = Console.ReadKey(1);
        if (key.Key == ConsoleKey.M) break;
    }
    
    Console.Write("Accepted.");
    

    Read more about ConsoleKeyInfo.


    If you need GetAsyncKeyState(), it is possible to access the method in JScript.NET. A couple days ago I came across a JScript.NET function that exposes Win32 API methods via P/Invoke. Here it is, slightly modified for simpler syntax (allowing pass-through of arguments from API function definitions).

    import System;
    import System.Reflection;
    import System.Reflection.Emit;
    
    // Invoke a Win32 P/Invoke call.
    // credit: http://cx20.main.jp/blog/hello/2013/03/07/hello-win32-api-jscript-net-world/
    function InvokeWin32(dllName:String, returnType:Type, methodName:String, params:Object[]) {
    
        var paramTypes:Type[] = new Type[params.length];
        for (var i:int in params) {
            paramTypes[i] = params[i].GetType();
        }
    
        // Begin to build the dynamic assembly
        var domain = AppDomain.CurrentDomain;
        var name = new System.Reflection.AssemblyName('PInvokeAssembly');
        var assembly = domain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run);
        var module = assembly.DefineDynamicModule('PInvokeModule');
        var type = module.DefineType('PInvokeType',TypeAttributes.Public
            + TypeAttributes.BeforeFieldInit);
    
        // Define the actual P/Invoke method
        var method = type.DefineMethod(methodName, MethodAttributes.Public
            + MethodAttributes.HideBySig + MethodAttributes.Static +
            MethodAttributes.PinvokeImpl, returnType, paramTypes);
    
        // Apply the P/Invoke constructor
        var ctor = System.Runtime.InteropServices.DllImportAttribute.GetConstructor(
            [System.String]
        );
        var attr = new System.Reflection.Emit.CustomAttributeBuilder(ctor, [dllName]);
        method.SetCustomAttribute(attr);
    
        // Create the temporary type, and invoke the method.
        var realType = type.CreateType();
        return realType.InvokeMember(methodName, BindingFlags.Public + BindingFlags.Static
            + BindingFlags.InvokeMethod, null, null, params);
    }
    

    With this function, you can expose Win32 DLL methods with the following syntax. (See? Told you it was simpler.)

    // ShowWindowAsync(hWnd:IntPtr, nCmdShow:int);
    function ShowWindowAsync(... args:Object[]):boolean {
       return InvokeWin32("user32.dll", System.Boolean, "ShowWindowAsync", args);
    }
    
    // GetWindowLong(hWnd:IntPtr, nIndex:int);
    function GetWindowLong(... args:Object[]):int {
        return InvokeWin32("user32.dll", System.Int32, "GetWindowLong", args);
    }
    
    // FindWindowEx(parentHandle:IntPtr, childAfter:IntPtr,
    //      lclassName:IntPtr, windowTitle:String);
    function FindWindowEx(... args:Object[]):IntPtr {
        return InvokeWin32("user32.dll", System.IntPtr, "FindWindowEx", args);
    }
    

    And I've never used GetAsyncKeyState(); but since it's a user32.dll method, I'm guessing it'll work the same way. (Edit: It does.)

    // GetAsyncKeyState(vKey:int);
    function GetAsyncKeyState(... args:Object[]):short {
        return InvokeWin32("user32.dll", System.Int16, "GetAsyncKeyState", args);
    }
    

    Then for a trivial example:

    import System;               // for Console methods
    import System.Windows.Forms; // for Keys object constants
    
    Console.Write("Press the M key... ");
    
    // while the M key is not being pressed, sleep
    while (!GetAsyncKeyState(Keys.M)) {
        System.Threading.Thread.Sleep(1);
    }
    
    // flush input buffer
    while (Console.KeyAvailable) Console.ReadKey(1);
    
    Console.WriteLine("Accepted.");