none
Services and CapsLock RRS feed

  • Question

  • I am writing a windows service in c# that needs to check the state of the caps lock. The problem is GetAsyncKeyState will not work properly from inside a service. I have also tried Console.CapsLock as well as Control.IsKeyLocked. The caps lock seems to me like it should be a system wide setting. Why can I not access its state from a service? Also, the keybd_event function does not work from inside a service either. Is it just not possible to mess with caps lock from a service?

    Thanks,
    Tuesday, April 1, 2008 6:06 PM

Answers

  • Okay, that makes sense. The service doesn't have a desktop or keyboard, and it's possible that the person logged in is a terminal user.

     

    Can you go into the service manager and make the selection to "Allow service to interact with desktop" in the "Log On" tab of the service properties?

     

    Tuesday, April 1, 2008 8:22 PM

All replies

  • Try checking through win api:

     

    Code Snippet

     

    [DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true,
    CallingConvention=CallingConvention.Winapi)]
    public static extern short GetKeyState(int keyCode);

    bool isCapsLock = (((ushort) GetKeyState(0x14 /*VK_CAPITAL*/)) & 0xffff) != 0;
    bool isNumLock = (((ushort) GetKeyState(0x90 /*VK_NUMLOCK*/)) & 0xffff) != 0;

     

     

     

    Tuesday, April 1, 2008 6:17 PM
  • Well I didn't try GetKeyState because of this:

    The key status returned from this function changes as a thread reads key messages from its message queue. The status does not reflect the interrupt-level state associated with the hardware. Use the GetAsyncKeyState function to retrieve that information.

    GetAsyncKeyState doesn't work either though because of this:

    The return value is zero for the following cases:
    • The current desktop is not the active desktop
    • The foreground thread belongs to another process and the desktop does not allow the hook or the journal record.

    Tuesday, April 1, 2008 7:43 PM
  • Okay, that makes sense. The service doesn't have a desktop or keyboard, and it's possible that the person logged in is a terminal user.

     

    Can you go into the service manager and make the selection to "Allow service to interact with desktop" in the "Log On" tab of the service properties?

     

    Tuesday, April 1, 2008 8:22 PM
  • --GetAsyncKeyState doesn't work either though because of this:
    Did you try it and get this result?

    --The current desktop is not the active desktop
    What exactly you mean by "current desktop"?

    Thursday, April 3, 2008 6:44 AM
  • We are changing the issue type to “Comment” because you have not followed up with the necessary information. If you have more time to look at the issue and provide more information, please feel free to change the issue type back to “Question” by editing your initial post and changing the radio button at the top of the post editor window. If the issue is resolved, we will appreciate it if you can share the solution so that the answer can be found and used by other community members having similar questions. 

    Thank you!
    Monday, April 7, 2008 3:24 AM
  • Thank you Chris, that did the trick. Once that option is turned on Console.CapsLock, Control.IsKeyLocked, and GetAsyncKeyState all function properly. That brings up the question, however, of how I can get that option turned on automatically during the installation of the service.

    As to Feng Chen's question, I am not completely sure what current and active desktop mean, but I assumed the result was that the service couldn't interact with the desktop. That was a quote from the MSDN.

    Also, I was reading about that option and it seems like some people think it is not a good idea, and it is in fact no longer available in vista. What is the preferred model for a service like application that needs to access keyboard information?

    Thanks
    Monday, April 7, 2008 6:37 PM
  • Just for future reference, here is a method for turning on interact with desktop during the installation.

    Code Snippet

    [RunInstaller(true)]

          public partial class ProjectInstaller : Installer

          {

                public ProjectInstaller()

                {

                      InitializeComponent();

     

                      this.serviceInstaller1.Committed += new InstallEventHandler(ProjectInstaller_Committed);

                }

     

                void ProjectInstaller_Committed(object sender, InstallEventArgs e)

                {

                      ManagementBaseObject inParams = null;

                      ManagementObject srvc = new ManagementObject(

                            "Win32_Service=" + '"' + this.serviceInstaller1.ServiceName + '"');

                      inParams = srvc.GetMethodParameters("Change");

                      inParams["DesktopInteract"] = true; // Enable Interact With Desktop

                      ManagementBaseObject outParams = srvc.InvokeMethod("Change", inParams, null);

                      //if ((ret = Convert.ToInt32(outParams.Properties["ReturnValue"].Value)) != 0)

                      //    Console.WriteLine("Failed to set option: {0}", ret);

                      //else

                      //    Console.WriteLine("Option set");

                }

          }



    Tuesday, April 8, 2008 10:35 PM