15 мая 2023 года "Исходники.РУ" отмечают своё 23-летие!
Поздравляем всех причастных и неравнодушных с этим событием!
И огромное спасибо всем, кто был и остаётся с нами все эти годы!

Главная Форум Журнал Wiki DRKB Discuz!ML Помощь проекту

Манипуляции с индикаторами на клавиатуре в Windows NT


Автор: Mark J. McGinty.

Требования: VC5, NT4 SP3-SP5

Этот пример демонстрирует управление индикаторами Num Lock, Caps Lock и Scroll Lock.
Несколько необходимых значений были позаимствованы из заголовков DDK, поэтому
для компиляции исходника нет необходимости иметь установленный DDK.

Всё, что делает эта программка - это открывает обработчик драйвера клавиатуры, а затем
вызывает DeviceIoControl, чтобы послать в него управляющие коды функций IOCTL.

Конкретно в этом примере запускается отдельный поток, который заставляет мигать
индикатор Scroll Lock.


/***********************************************************
** NTKbdLites.c                                           **
**                                                        **
**  Copyright 1999 Mark J. McGinty, All Rights Reserved   **
**   Free Usage granted to the public domain.             **
**                                                        **
***********************************************************/

#include <windows.h>
#include <winioctl.h>
#include "NTKbdLites.h"

// Code can be built as either a DLL or a static link library
//
#ifdef STATIC_LIBRARY
#define DECLSPEC 
#else
#define DECLSPEC __declspec(dllexport)
#endif

// FlashKeyboardLight
//
// Flashes the keyboard indicator, specified by LightFlag, one time, 
// at the rate indicated by Duration. All lights are left in their
// previous states when this call returns.
//
// Possible LightFlags:
//      KEYBOARD_CAPS_LOCK_ON   
//      KEYBOARD_NUM_LOCK_ON    
//      KEYBOARD_SCROLL_LOCK_ON

int DECLSPEC FlashKeyboardLight(HANDLE hKbdDev, UINT LedFlag, int Duration)
{
    KEYBOARD_INDICATOR_PARAMETERS InputBuffer;    // Input buffer for DeviceIoControl
    KEYBOARD_INDICATOR_PARAMETERS OutputBuffer;   // Output buffer for DeviceIoControl
    UINT                LedFlagsMask;
    BOOL                Toggle;
    ULONG               DataLength = sizeof(KEYBOARD_INDICATOR_PARAMETERS);
    ULONG               ReturnedLength; // Number of bytes returned in output buffer
    int             i;

    InputBuffer.UnitId = 0;
    OutputBuffer.UnitId = 0;

    // Сохраняем текущее состояние индикаторов
    //
    if (!DeviceIoControl(hKbdDev, IOCTL_KEYBOARD_QUERY_INDICATORS,
                &InputBuffer, DataLength,
                &OutputBuffer, DataLength,
                &ReturnedLength, NULL))
        return GetLastError();

    // Маскируем бит света, которым будем управлять
    //
    LedFlagsMask = (OutputBuffer.LedFlags & (~LedFlag));

    // Устанавливаем переменную переключателя, чтобы отразить текущее состояние.
    //
    Toggle = (OutputBuffer.LedFlags & LedFlag);

    for (i = 0; i < 2; i++)
    {
        Toggle ^= 1;
        InputBuffer.LedFlags = (LedFlagsMask | (LedFlag * Toggle));

        if (!DeviceIoControl(hKbdDev, IOCTL_KEYBOARD_SET_INDICATORS,
                    &InputBuffer, DataLength,
                    NULL,   0,  &ReturnedLength, NULL))
            return GetLastError();

        Sleep(Duration);
    }
    return 0;
}

HANDLE DECLSPEC OpenKeyboardDevice(int *ErrorNumber)
{
    HANDLE  hndKbdDev;
    int     *LocalErrorNumber;
    int     Dummy;

    if (ErrorNumber == NULL)
        LocalErrorNumber = &Dummy;
    else
        LocalErrorNumber = ErrorNumber;

    *LocalErrorNumber = 0;
    
    if (!DefineDosDevice (DDD_RAW_TARGET_PATH, "Kbd",
                "\\Device\\KeyboardClass0"))
    {
        *LocalErrorNumber = GetLastError();
        return INVALID_HANDLE_VALUE;
    }

    hndKbdDev = CreateFile("\\\\.\\Kbd", GENERIC_WRITE, 0,
                NULL,   OPEN_EXISTING,  0,  NULL);
    
    if (hndKbdDev == INVALID_HANDLE_VALUE)
        *LocalErrorNumber = GetLastError();

    return hndKbdDev;
}

int DECLSPEC CloseKeyboardDevice(HANDLE hndKbdDev)
{
    int e = 0;

    if (!DefineDosDevice (DDD_REMOVE_DEFINITION, "Kbd", NULL))
        e = GetLastError();

    if (!CloseHandle(hndKbdDev))                    
        e = GetLastError();

    return e;
}

// Процедура, которая будет запущена как поток, которая будет заставлять мигать индикатор.
//
DWORD WINAPI FlashKeyboardLightThd(LPVOID lpv)
{
    LPFLASH_KBD_THD_INIT pInit = (LPFLASH_KBD_THD_INIT)lpv;
    FLASH_KBD_THD_INIT Init = *pInit;
    HANDLE  hndKbdDev;
    HANDLE  heventCancel = OpenEvent(EVENT_ALL_ACCESS, FALSE, Init.EventName);

    if (heventCancel == NULL)
        ExitThread(-1);

    hndKbdDev = OpenKeyboardDevice(NULL);
    if (hndKbdDev == INVALID_HANDLE_VALUE)
    {
        CloseHandle(heventCancel);
        ExitThread(-1);
    }

    for (;;)
    {
        FlashKeyboardLight(hndKbdDev, Init.LightFlag, Init.Duration);
        
        if (WaitForSingleObject(heventCancel, Init.Duration) != WAIT_TIMEOUT)
            break;
    }

    Sleep(Init.Duration);

    CloseHandle(heventCancel);
    CloseKeyboardDevice(hndKbdDev);
    
    ExitThread(0);
    return 0;
}

// Создаём структуру и запускаем поток для мигания индикатора
//
HANDLE DECLSPEC FlashKeyboardLightInThread(UINT LightFlag, int Duration, LPSTR EventName)
{
    DWORD ThreadId;
    static FLASH_KBD_THD_INIT FlashInit;

    FlashInit.LightFlag = LightFlag;
    FlashInit.Duration = Duration;
    lstrcpyn(FlashInit.EventName, EventName, 128);

    return CreateThread(NULL, 0, FlashKeyboardLightThd, (LPVOID)&FlashInit, 0, &ThreadId);
 
}

/***********************************************************
** NTKbdLites.h                                           **
**                                                        **
**  Copyright 1999 Mark J. McGinty, All Rights Reserved   **
**   Free Usage granted to the public domain.             **
**                                                        **
***********************************************************/

#include <windows.h>

//
// Определяем индикаторы клавиатуры.
//

#define IOCTL_KEYBOARD_SET_INDICATORS        CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0002, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_KEYBOARD_QUERY_TYPEMATIC       CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0008, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_KEYBOARD_QUERY_INDICATORS      CTL_CODE(FILE_DEVICE_KEYBOARD, 0x0010, METHOD_BUFFERED, FILE_ANY_ACCESS)


typedef struct _KEYBOARD_INDICATOR_PARAMETERS {
    USHORT UnitId;          // Unit identifier.
    USHORT    LedFlags;     // LED indicator state.

} KEYBOARD_INDICATOR_PARAMETERS, *PKEYBOARD_INDICATOR_PARAMETERS;

#define KEYBOARD_CAPS_LOCK_ON     4
#define KEYBOARD_NUM_LOCK_ON      2
#define KEYBOARD_SCROLL_LOCK_ON   1

#ifdef STATIC_LIBRARY
#define DECLSPEC 
#else
#define DECLSPEC __declspec(dllexport)
#endif

int DECLSPEC FlashKeyboardLight(HANDLE hKbdDev, UINT LightFlag, int Duration);
HANDLE DECLSPEC OpenKeyboardDevice(int *ErrorNumber);
int DECLSPEC CloseKeyboardDevice(HANDLE hndKbdDev);
HANDLE DECLSPEC FlashKeyboardLightInThread(UINT, int, LPSTR);

typedef struct {
    UINT        LightFlag;
    int     Duration;
    char        EventName[128];
} FLASH_KBD_THD_INIT, *LPFLASH_KBD_THD_INIT;

/***********************************************************
** NTFlashScrollLight.c
**
**
**
** Copyright 1999 Mark J. McGinty, All Rights Reserved
**
** Free Usage granted to the public domain.
**
**
**
**
**
** A short test program, to excersize NTKbdLites.c
**
**
**
***********************************************************/

#include <windows.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "NTKbdLites.h"
#define CANCEL_EVENT_NAME "TestThreadedFlasherEvent"

void __cdecl main(int argc, char **argv)
{
HANDLE heventCancel = CreateEvent(NULL, FALSE, FALSE, CANCEL_EVENT_NAME);
HANDLE hThread = FlashKeyboardLightInThread(KEYBOARD_SCROLL_LOCK_ON, 250, CANCEL_EVENT_NAME);

printf("\r\n\r\nSample usage of IOCTL_KEYBOARD_SET_INDICATORS");
printf("\r\n\r\n (the Scroll Lock light should be flashing)");
printf("\r\n\r\n\r\npress any key to exit...");

getch();
printf("\r\n");

SetEvent(heventCancel);
WaitForSingleObject(hThread, 30000);
CloseHandle(heventCancel);
exit(0);
}

Downloads

Скачать демо проект - 24 Kb
Скачать исходник - 6 Kb