Переключить NUMLOCK / CAPSLOCK / SCROLLLOCK, пока рабочая станция заблокирована?

Я пытаюсь переключить световые индикаторы на клавиатуре на Num Lock, Caps Lock и Scroll Lock. (Я просто хочу, чтобы они выключали их автоматически в ночное время.) Это тривиально, используя AutoHotkey или AutoIt. Тем не менее, скрипт не имеет эффекта, если рабочая станция заблокирована.

Во время исследования этого будет какой-то вызов DLL, я наткнулся на SetKeyboardState в user32.dll, К сожалению, согласно документации Центра разработки Windows, невозможно установить состояние клавиатуры этих трех клавиш (и каждая из них упоминается по имени), используя SetKeyboardState,

https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setkeyboardstate


Другой поток сказал просто использовать ControlSend в AutoIt. Это, как правило, очень надежно, даже когда нет активного сеанса графического интерфейса или когда клавиатура / мышь используются в интерактивном режиме.

Следующее прекрасно работает:

ControlSend("", "", "", "{NUMLOCK off}")

... но только когда есть активный сеанс GUI. Это не действует, когда экран заблокирован.


Я знаю, что это специальные клавиши: вместо того, чтобы управлять состоянием ввода программного потока, они являются частью физического состояния клавиатуры и управляют глобальным вводом для всей системы.

Есть ли варианты вообще? На каком языке?

0 ответов

По крайней мере, в Windows действительно кажется, что нет возможности переключать эти клавиши, когда рабочая станция заблокирована. Независимо от того, какой язык или фреймворк используется, все они должны проходить через базовый уровень ОС. Без интерактивного сеанса эти нажатия клавиш не отправляются.

Естественно, если вы стоите у клавиатуры и нажимаете эти клавиши, они нормально реагируют.

Итак, это МОЖНО сделать, управляя клавиатурой как подключенным периферийным устройством, таким как Arduino. Некоторые из этих моделей могут работать как USB-клавиатура / мышь. (Я пробовал это, используя как Arduino Leonardo, так и Spark Fun Pro Micro. Оба реагируют одинаково для этого варианта использования.)

ПРИМЕЧАНИЕ: даже когда клавиши переключения обновляются Arduino или человеком на терминале, состояния клавиш переключения НЕ обновляются в операционной системе, пока рабочая станция не будет разблокирована. В каком бы состоянии ни находилась клавиша переключения, когда рабочая станция заблокирована, независимо от того, что человек на заблокированном терминале делает с клавиатурой, эта клавиша будет продолжать отображаться в этом состоянии для любых запущенных сценариев до момента разблокировки рабочей станции. Это легко проверить с помощью приведенного ниже сценария AHK.


Ниже приведен минимальный пример сценария управления AutoHotKey (хотя подойдет любая программа, которая может отправлять данные через последовательное соединение), а также эскиз Arduino:

Скрипт управления AutoHotKey

Loop
{
  RS232_FileHandle := RS232_Initialize()
  if (RS232_FileHandle)
  {
    ; Turn them all off
    (1 = GetKeyState("NumLock", "T")) ? RS232_Write(RS232_FileHandle, "219") : NA
    Sleep, 750
    (1 = GetKeyState("CapsLock", "T")) ? RS232_Write(RS232_FileHandle, "193") : NA
    Sleep, 750
    (1 = GetKeyState("ScrollLock", "T")) ? RS232_Write(RS232_FileHandle, "207") : NA

    Sleep, 4000

    ; Turn them all on
    (0 = GetKeyState("NumLock", "T")) ? RS232_Write(RS232_FileHandle, "219") : NA
    Sleep, 750
    (0 = GetKeyState("CapsLock", "T")) ? RS232_Write(RS232_FileHandle, "193") : NA
    Sleep, 750
    (0 = GetKeyState("ScrollLock", "T")) ? RS232_Write(RS232_FileHandle, "207") : NA

    RS232_Close(RS232_FileHandle)
  }
  Sleep, 4000
}

RS232_LoadSettings()
{
  RS232_Port     := "COM3"
  RS232_Baud     := "9600"
  RS232_Parity   := "N"
  RS232_DataBits := "8"
  RS232_StopBits := "1"
  RS232_Timeout  := "Off"
  RS232_XonXoff  := "Off"
  RS232_CTS_Hand := "Off"
  RS232_DSR_Hand := "Off"
  RS232_DSR_Sens := "Off"
  RS232_DTR      := "Off"
  RS232_RTS      := "Off"

  ; MSDN Reference: https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mode
  RS232_Settings = %RS232_Port%:BAUD=%RS232_Baud% PARITY=%RS232_Parity% DATA=%RS232_DataBits% STOP=%RS232_StopBits% to=%RS232_Timeout% xon=%RS232_XonXoff% odsr=%RS232_DSR_Hand% octs=%RS232_CTS_Hand% dtr=%RS232_DTR% rts=%RS232_RTS% idsr=%RS232_DSR_Sens%
  return RS232_Settings
}

RS232_Initialize()
{
  ; Source adapted from: https://autohotkey.com/board/topic/26231-serial-com-port-console-script/
  RS232_Settings := RS232_LoadSettings()
  RS232_Port     := StrSplit(RS232_Settings, ":")[1]
  RS232_COM      := (4 <= StrLen(RS232_Port) ? "\\.\" : "") . RS232_Port
  StringTrimLeft, RS232_Settings, RS232_Settings, StrLen(RS232_Port)+1
  VarSetCapacity(DCB, 28)
  if (1 <> DllCall("BuildCommDCB","str",RS232_Settings,"UInt",&DCB))
  {
    return false
  }
  hCom := DllCall("CreateFile","Str",RS232_COM,"UInt",0xC0000000,"UInt",3,"UInt",0,"UInt",3,"UInt",0,"UInt",0,"Cdecl Int")
  if (hCom < 1)
  {
    return false
  }
  if (1 <> DllCall("SetCommState","UInt",hCom,"UInt",&DCB))
  {
    RS232_Close(hCom)
    return false
  }
  VarSetCapacity(Data, 20, 0)
  NumPut(0xffffffff, Data,  0, "UInt")
  NumPut(0x00000000, Data,  4, "UInt")
  NumPut(0x00000000, Data,  8, "UInt")
  NumPut(0x00000000, Data, 12, "UInt")
  NumPut(0x00000000, Data, 16, "UInt")
  if (1 <> DllCall("SetCommTimeouts","UInt",hCom,"UInt",&Data))
  {
    RS232_Close(hCom)
    return false
  }
  return hCom
}

RS232_Write(hCom, msg)
{
  SetFormat, Integer, DEC
  StringSplit, Byte, msg, `,
  Data_Length := Byte0
  VarSetCapacity(Data, Byte0, 0xFF)
  i := 1
  Loop %Byte0%
  {
    NumPut(Byte%i%, Data, (i-1) , "UChar")
    i++
  }

  Bytes_Sent := 0
  WF_Result := DllCall("WriteFile","UInt",hCom,"UInt",&Data,"UInt",Data_Length,"UInt*",Bytes_Sent,"Int","NULL")
  if (WF_Result <> 1 or Bytes_Sent <> Data_Length)
  {
    return false
  }
  return Bytes_Sent
}

RS232_Close(hCom)
{
  return (1 == DllCall("CloseHandle","UInt",hCom))
}

Эскиз Arduino

/* Pro Micro NumCapsScrollToggleDemo
   by: Jonathan David Arndt
   date: March 6, 2020

   This will allow the toggle of the Num Lock, Caps Lock, and Scroll Lock keys
   on the keyboard, via commands sent over USB serial
*/

#include <Keyboard.h>

// You could patch this into your Keyboard.h file, or just define it here
// Source: https://forum.arduino.cc/index.php?topic=173583.0 (attachment: USBAPI.h)
#define KEY_NUM_LOCK    0xDB
#define KEY_SCROLL_LOCK 0xCF

void pressAndRelease(int c);

void setup()
{
  Serial.begin(9600); // This pipes to the serial monitor
  delay(3000);        // Wait a moment for things to get setup
  Serial.println("Initialize Serial Monitor");
}

void loop()
{
  int c = 0;

  if (0 < Serial.available())
  {
    c = Serial.read();
    if (219 == c)
    {
      pressAndRelease(KEY_NUM_LOCK);
    }
    else if (193 == c)
    {
      pressAndRelease(KEY_CAPS_LOCK);
    }
    else if (207 == c)
    {
      pressAndRelease(KEY_SCROLL_LOCK);
    }
  }
}

void pressAndRelease(int c)
{
  Keyboard.press(c);
  Keyboard.release(c);
}
Другие вопросы по тегам