Переключить 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);
}