From b0c58d03247bb73e61322b738aebed6536220bd1 Mon Sep 17 00:00:00 2001 From: achol Date: Tue, 19 Mar 2019 23:14:25 +0100 Subject: [PATCH] First commit: - working driver filter - switch console app - config app for installing driver, configuration persistence and tray launch - tray app for fast switch --- Config/KeybitorConfig.rc | Bin 0 -> 4100 bytes Config/Resource.h | 27 + Config/configurator.cpp | 653 ++++++++++++ Config/targetver.h | 8 + CtrlLib/include/Keybitor.h | 34 + CtrlLib/src/Keybitor.c | 288 ++++++ CtrlLib/src/Keybitor_internal.h | 0 Driver/Keybitor.inx | 148 +++ Driver/Trace.h | 54 + Driver/driver.rc | 12 + Driver/kbfiltr.c | 944 ++++++++++++++++++ Driver/kbfiltr.h | 205 ++++ Driver/public.h | 17 + Driver/rawpdo.c | 376 +++++++ Switch/cmd.c | 76 ++ Tray/KeybitorTray.rc | Bin 0 -> 4206 bytes Tray/PS2KeyboardTogglerTray.ico | Bin 0 -> 102229 bytes Tray/PS2KeyboardTogglerTray_Off.ico | Bin 0 -> 107549 bytes Tray/Resource.h | 28 + Tray/stdafx.cpp | 8 + Tray/stdafx.h | 21 + Tray/targetver.h | 8 + Tray/tray.cpp | 361 +++++++ Tray/tray.h | 3 + res/icon.ico | Bin 0 -> 102229 bytes res/icon_off.ico | Bin 0 -> 107549 bytes vsproject/Keybitor.sln | 322 ++++++ vsproject/Keybitor/Keybitor.vcxproj | 370 +++++++ vsproject/KeybitorCmd/KeybitorCmd.vcxproj | 162 +++ .../KeybitorConfig/KeybitorConfig.vcxproj | 174 ++++ .../KeybitorCtrlLib/KeybitorCtrlLib.vcxproj | 156 +++ .../KeybitorPackage/KeybitorPackage.vcxproj | 413 ++++++++ vsproject/KeybitorPackage/runsdvui.cmd | 2 + vsproject/KeybitorTray/KeybitorTray.vcxproj | 174 ++++ 34 files changed, 5044 insertions(+) create mode 100644 Config/KeybitorConfig.rc create mode 100644 Config/Resource.h create mode 100644 Config/configurator.cpp create mode 100644 Config/targetver.h create mode 100644 CtrlLib/include/Keybitor.h create mode 100644 CtrlLib/src/Keybitor.c create mode 100644 CtrlLib/src/Keybitor_internal.h create mode 100644 Driver/Keybitor.inx create mode 100644 Driver/Trace.h create mode 100644 Driver/driver.rc create mode 100644 Driver/kbfiltr.c create mode 100644 Driver/kbfiltr.h create mode 100644 Driver/public.h create mode 100644 Driver/rawpdo.c create mode 100644 Switch/cmd.c create mode 100644 Tray/KeybitorTray.rc create mode 100644 Tray/PS2KeyboardTogglerTray.ico create mode 100644 Tray/PS2KeyboardTogglerTray_Off.ico create mode 100644 Tray/Resource.h create mode 100644 Tray/stdafx.cpp create mode 100644 Tray/stdafx.h create mode 100644 Tray/targetver.h create mode 100644 Tray/tray.cpp create mode 100644 Tray/tray.h create mode 100644 res/icon.ico create mode 100644 res/icon_off.ico create mode 100644 vsproject/Keybitor.sln create mode 100644 vsproject/Keybitor/Keybitor.vcxproj create mode 100644 vsproject/KeybitorCmd/KeybitorCmd.vcxproj create mode 100644 vsproject/KeybitorConfig/KeybitorConfig.vcxproj create mode 100644 vsproject/KeybitorCtrlLib/KeybitorCtrlLib.vcxproj create mode 100644 vsproject/KeybitorPackage/KeybitorPackage.vcxproj create mode 100644 vsproject/KeybitorPackage/runsdvui.cmd create mode 100644 vsproject/KeybitorTray/KeybitorTray.vcxproj diff --git a/Config/KeybitorConfig.rc b/Config/KeybitorConfig.rc new file mode 100644 index 0000000000000000000000000000000000000000..3bbdce82ee3933c9de90a765aea12b042a290ee0 GIT binary patch literal 4100 zcmd6q(N7vd5XR@ZN&kl}zSOjVYM=V3pp+ER2%4Ih5CxB#s2DhFn)GjP`}=lTy~-U0 z?Zf4A%--(o?(EDr-z>j>)vRWFc4-5f*x07LiKXW3n7*mq*_mDORkwFM&PH}&H@p-2 zQ{<4o2~zX!XbosPzO>q<-J(;q*Y=7%YF@68y!gp87b!OJlp{ z{3+g%A9|enE59vHUFV$g#}56QyiX%CAA^J)z%W4!l;6&r-7E3`3%p%;tyP6#e`te&!?%e}+zO1oMz{?@=+tGxuOFyZhb3^ZjeD@}VSJ z6f$D*>6Xcdu#TeR?9E>pHng`OVi#(0hbzdbEDB_pGwvM`H%WvzALn>!NhvbpY~iyzR18BlDvUY+m}Tb+De0 zDz+5E3h$205yRg3thl9h<~dZnD$bkCbW>(JpHt#w<+nrgmgfqs0qqniYn=bi+7~(ZeW6`puPWXQ99DZcO&|Lbp6aY8RETIz7rx)}*qmQ6+w;Hn zl_$hV$x19*E<|UoiMWljsJ_H;$qk~HUxhTf4FZ}(zTzN{qb4xUUir3-6Td^xv<<#C}u!5d&<*})dbK?9&RP;98Re=xSpL)Lw9(3!{!bFu fEdHMqcgp&>JZ)K*#b(65EOa1x?C*5T{I~l9kD~Vg literal 0 HcmV?d00001 diff --git a/Config/Resource.h b/Config/Resource.h new file mode 100644 index 0000000..693997d --- /dev/null +++ b/Config/Resource.h @@ -0,0 +1,27 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by PS2KeyboardTogglerConfig.rc +// + +#define IDS_APP_TITLE 103 + +#define IDR_MAINFRAME 128 +#define IDI_PS2KEYBOARDTOGGLERCONFIG 107 +#define IDI_SMALL 108 +#define IDC_PS2KEYBOARDTOGGLERCONFIG 109 +#define IDC_MYICON 2 +#ifndef IDC_STATIC +#define IDC_STATIC -1 +#endif +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NO_MFC 130 +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif diff --git a/Config/configurator.cpp b/Config/configurator.cpp new file mode 100644 index 0000000..a791022 --- /dev/null +++ b/Config/configurator.cpp @@ -0,0 +1,653 @@ +// PS2KeyboardTogglerConfig.cpp : Defines the entry point for the application. +// + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + +// C RunTime Header Files +#include +#include +#include +#include +#include + +#include "resource.h" + +#include "Keybitor.h" + +#include "difxapi.h" +#include "newdev.h" +#include + +#include +#include + +//enable visual styles for common controls +#pragma comment(linker,"\"/manifestdependency:type='win32' \ +name='Microsoft.Windows.Common-Controls' version='6.0.0.0' \ +processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") + +static wchar_t DriverInfName [] = L"Keybitor.inf"; +static wchar_t TrayExeName [] = L"KeybitorTray.exe"; + + +DEFINE_GUID(GUID_DEVINTERFACE_KBFILTER, + 0x3fb7299d, 0x6847, 0x4490, 0xb0, 0xc9, 0x99, 0xe0, 0x98, 0x6a, 0xb8, 0x86); +// {3FB7299D-6847-4490-B0C9-99E0986AB886} + +#define MAX_LOADSTRING 100 + +#define CHECK_ELEV WM_USER+1 + +#ifdef _WIN64 +#define GWL_HINSTANCE_PTF GWLP_HINSTANCE +#else +#define GWL_HINSTANCE_PTF GWL_HINSTANCE +#endif +// Global Variables: +HINSTANCE hInst; // current instance +TCHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name + +// Forward declarations of functions included in this code module: +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); + +HWND hwndMainWindow; +HWND hwndInstallButton; +HWND hwndToggleButton; +HWND hwndPersistButton; +HWND hwndTrayButton; + + +void updateKeyboardToggleGUI(); +void updateDriverInstallGUI(); +void updatePersistenceGUI(); +void updateTraybarInstallGUI(); + +void checkNeedsElev(); +void toggleDeviceInternal(const wchar_t* device, void*); +void checkDeviceReachable(const wchar_t* dev, void* data); +void checkDeviceToggledOff(const wchar_t* dev, void* data); +bool checkDevicesToggledOff(); +bool isDriverInstalled(); +bool installDriver(); +bool uninstallDriver(); +void enablePersistence(); +void disablePersistence(); +bool isPersistenceEnabled(); +bool isTrayInstalled(); +void uninstallTray(); +void installTray(); +wchar_t* getLocalDriverInfFile(); +wchar_t* getLocalTrayExe(); +void notifyErrorMessage(DWORD); + +int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPTSTR lpCmdLine, + _In_ int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + // TODO: Place code here. + MSG msg; + HACCEL hAccelTable; + + // Initialize global strings + LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + LoadString(hInstance, IDC_PS2KEYBOARDTOGGLERCONFIG, szWindowClass, MAX_LOADSTRING); + MyRegisterClass(hInstance); + + // Perform application initialization: + if (!InitInstance (hInstance, nCmdShow)) + { + return FALSE; + } + + hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_PS2KEYBOARDTOGGLERCONFIG)); + + // Main message loop: + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return (int) msg.wParam; +} + + + +// +// FUNCTION: MyRegisterClass() +// +// PURPOSE: Registers the window class. +// +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PS2KEYBOARDTOGGLERCONFIG)); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = MAKEINTRESOURCE(IDC_PS2KEYBOARDTOGGLERCONFIG); + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); + + return RegisterClassEx(&wcex); +} + +// +// FUNCTION: InitInstance(HINSTANCE, int) +// +// PURPOSE: Saves instance handle and creates main window +// +// COMMENTS: +// +// In this function, we save the instance handle in a global variable and +// create and display the main program window. +// +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; // Store instance handle in our global variable + + hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, 300, 330, NULL, NULL, hInstance, NULL); + + if (!hWnd) + { + return FALSE; + } + + hwndMainWindow = hWnd; + + hwndToggleButton = CreateWindow( + L"BUTTON", L"Toggle keyboard", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, + 10, 30, 260, 80, + hWnd, NULL, (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE_PTF), NULL); + + HWND hwndConfigFrame = CreateWindow(L"BUTTON", L"Configuration", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_GROUPBOX , + 5, 120, 270, 166, + hWnd, NULL, (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE_PTF), NULL); + + /*HWND hwndConfigLabel = CreateWindow(L"STATIC", L"Configuration", WS_TABSTOP | WS_VISIBLE | WS_CHILD | SS_LEFTNOWORDWRAP, + 10, 115, 100, 20, + hWnd, NULL, (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE_PTF), NULL);*/ + SetWindowText(hwndConfigFrame, L"Configuration"); + + hwndInstallButton = CreateWindow( + L"BUTTON", L"Install driver", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, + 10, 140, 260, 40, + hWnd, NULL, (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE_PTF), NULL); + + hwndPersistButton = CreateWindow( + L"BUTTON", L"Enable persistence", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_CHECKBOX, + 10, 190, 260, 40, + hWnd, NULL, (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE_PTF), NULL); + + hwndTrayButton = CreateWindow( + L"BUTTON", L"Launch tray widget at startup", WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_CHECKBOX, + 10, 240, 260, 40, + hWnd, NULL, (HINSTANCE) GetWindowLong(hWnd, GWL_HINSTANCE_PTF), NULL); + + if (!(hwndToggleButton && hwndPersistButton && hwndTrayButton)) + { + return FALSE; + } + + updateKeyboardToggleGUI(); + updateDriverInstallGUI(); + updatePersistenceGUI(); + updateTraybarInstallGUI(); + + PostMessage(hWnd, CHECK_ELEV, 0, 0); + + + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + return TRUE; +} + +// +// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) +// +// PURPOSE: Processes messages for the main window. +// +// WM_COMMAND - process the application menu +// WM_PAINT - Paint the main window +// WM_DESTROY - post a quit message and return +// +// +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + PAINTSTRUCT ps; + HDC hdc; + + switch (message) + { + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + + if (((HWND) lParam) == hwndToggleButton){ + if (wmEvent == BN_CLICKED){ + foreachDevice(toggleDeviceInternal, NULL); + } + updateKeyboardToggleGUI(); + } + else if (((HWND) lParam) == hwndPersistButton){ + if (isPersistenceEnabled()){ + disablePersistence(); + } + else { + enablePersistence(); + } + } + else if (((HWND) lParam) == hwndInstallButton){ + if (isDriverInstalled()){ + uninstallDriver(); + } + else { + installDriver(); + } + } + else if (((HWND) lParam) == hwndTrayButton){ + if (isTrayInstalled()){ + uninstallTray(); + } + else { + installTray(); + } + } + return DefWindowProc(hWnd, message, wParam, lParam); + case CHECK_ELEV: + checkNeedsElev(); + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + // TODO: Add any drawing code here... + EndPaint(hWnd, &ps); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + +void updateKeyboardToggleGUI(){ + if (!isDriverInstalled()){ + Button_Enable(hwndToggleButton, FALSE); + } + else { + Button_Enable(hwndToggleButton, TRUE); + } + if (checkDevicesToggledOff()){ + Button_SetText(hwndToggleButton, L"Enable PS2 keyboards"); + } + else { + Button_SetText(hwndToggleButton, L"Disable PS2 keyboards"); + } +} + +void updateDriverInstallGUI(){ + if (isDriverInstalled()){ + Button_SetText(hwndInstallButton, L"Uninstall driver"); + } + else { + Button_SetText(hwndInstallButton, L"Install driver"); + } +} + +void updatePersistenceGUI(){ + if (!isDriverInstalled()){ + Button_Enable(hwndPersistButton, FALSE); + } + else { + Button_Enable(hwndPersistButton, TRUE); + } + if (isPersistenceEnabled()){ + Button_SetCheck(hwndPersistButton, BST_CHECKED); + } + else { + Button_SetCheck(hwndPersistButton, BST_UNCHECKED); + } +} + +void updateTraybarInstallGUI(){ + if (!isDriverInstalled()){ + Button_Enable(hwndTrayButton, FALSE); + } + else { + Button_Enable(hwndTrayButton, TRUE); + } + if (isTrayInstalled()){ + Button_SetCheck(hwndTrayButton, BST_CHECKED); + } + else { + Button_SetCheck(hwndTrayButton, BST_UNCHECKED); + } +} + + +void toggleDeviceInternal(const wchar_t* device, void* data){ + UNREFERENCED_PARAMETER(data); + + if (toggleDevice(device) < 0){ + MessageBox(hwndMainWindow, L"Device toggle didn't properly work.", L"Error", MB_OK); + + } +} + +void checkNeedsElev(){ + bool is_error = 0; + foreachDevice(checkDeviceReachable, (void*) &is_error); + if (is_error){ + MessageBox(hwndMainWindow, L"Could not read the device. Either the driver is not installed, or this software (and related) have to be \"Run as administrator\".", L"Error", MB_OK); + } +} + +void checkDeviceReachable(const wchar_t* dev, void* data){ + bool& error_flag = *((bool*) data); + error_flag |= isDeviceEnable(dev) < 0; +} + +void checkDeviceToggledOff(const wchar_t* dev, void* data){ + bool& flag = *((bool*) data); + flag |= !isDeviceEnable(dev); +} + +bool checkDevicesToggledOff(){ + bool toggledOff = false; + foreachDevice(checkDeviceToggledOff, (void*) &toggledOff); + return toggledOff; +} + +bool isDriverInstalled(){ + + wchar_t* InfPath = getLocalDriverInfFile(); + + DWORD NumOfChars = 0; + DWORD ReturnCode = ERROR_SUCCESS; + + ReturnCode = DriverPackageGetPath(InfPath, NULL, &NumOfChars); + + PTCHAR DriverStoreInfPath = (PTCHAR) LocalAlloc(LPTR, NumOfChars * sizeof(TCHAR)); + ReturnCode = DriverPackageGetPath(InfPath, DriverStoreInfPath, &NumOfChars); + + LocalFree(InfPath); + + if (ReturnCode == ERROR_SUCCESS){ + return true; + } + + return false; +} + +bool installDriver(){ + wchar_t* infFile = getLocalDriverInfFile(); + if (infFile == NULL){ + return false; + } + DWORD res = UpdateDriverForPlugAndPlayDevices(hwndMainWindow, L"*MSF0001", infFile, INSTALLFLAG_FORCE, NULL); + + if (res != ERROR_SUCCESS){ + notifyErrorMessage(res); + updateDriverInstallGUI(); + return false; + } + + updateDriverInstallGUI(); + + return true; +} + +bool uninstallDriver(){ + BOOL needReboot = false; + HDEVINFO dis = SetupDiGetClassDevs((LPGUID) &GUID_DEVINTERFACE_KBFILTER, NULL, NULL, (DIGCF_PRESENT |DIGCF_DEVICEINTERFACE)); + if (INVALID_HANDLE_VALUE == dis){ + notifyErrorMessage(GetLastError()); + return false; + } + + SP_DEVINFO_DATA did; + did.cbSize = sizeof(did); + int devIndex; + for (devIndex = 0; SetupDiEnumDeviceInfo(dis, devIndex, &did) && GetLastError() != ERROR_NO_MORE_ITEMS; ++devIndex){ + + BOOL localNeedReboot = false; + DWORD res = DiRollbackDriver(dis, &did, hwndMainWindow, 0, &localNeedReboot); + + if (!res){ + if (GetLastError() != ERROR_NO_MORE_ITEMS){ + notifyErrorMessage(GetLastError()); + } + else { + DWORD res = UpdateDriverForPlugAndPlayDevices(hwndMainWindow, L"*MSF0001", L"C:\\Windows\\inf\\keyboard.inf", INSTALLFLAG_FORCE, &needReboot); + } + } + + needReboot |= localNeedReboot; + } + + if (devIndex == 0){//no device enumerated + notifyErrorMessage(GetLastError()); + } + + wchar_t* InfPath = getLocalDriverInfFile(); + + DWORD NumOfChars = 0; + DWORD ReturnCode = ERROR_SUCCESS; + + ReturnCode = DriverPackageGetPath(InfPath, NULL, &NumOfChars); + + PTCHAR DriverStoreInfPath = (PTCHAR) LocalAlloc(LPTR, NumOfChars * sizeof(TCHAR)); + ReturnCode = DriverPackageGetPath(InfPath, DriverStoreInfPath, &NumOfChars); + + DWORD reqSize = 0; + SetupGetInfPublishedName(DriverStoreInfPath, NULL, 0, &reqSize); + WCHAR * buffer = (PTCHAR) LocalAlloc(LPTR, reqSize * sizeof(TCHAR)); + SetupGetInfPublishedName(DriverStoreInfPath, buffer, reqSize, NULL); + SetupUninstallOEMInf(buffer, 0, NULL); + + LocalFree(buffer); + LocalFree(DriverStoreInfPath); + LocalFree(InfPath); + if (needReboot){ + MessageBox(hwndMainWindow, L"The Keybitor driver has been removed.\nA reboot is required to load the previous driver back.", L"Reboot required", MB_OK); + } + + //clean registry + LSTATUS res = RegDeleteKeyEx(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\services\\Keybitor\\persist", KEY_WOW64_64KEY, 0); + if (res != 0){ + notifyErrorMessage(res); + } + + uninstallTray(); + + updateKeyboardToggleGUI(); + updateDriverInstallGUI(); + updatePersistenceGUI(); + updateTraybarInstallGUI(); + + return true; +} + +bool setPersistenceRegistry(bool enable, bool value){ + HKEY persistKeyHandle; + DWORD dispo; + LSTATUS res = RegCreateKeyEx(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\services\\Keybitor\\persist", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &persistKeyHandle, &dispo); + + if (res != ERROR_SUCCESS){ + notifyErrorMessage(res); + updatePersistenceGUI(); + return false; + } + + DWORD enableEntry = enable; + res = RegSetValueEx(persistKeyHandle, L"enable", 0, REG_DWORD, (BYTE*) &enableEntry, sizeof(DWORD)); + if (res != ERROR_SUCCESS){ + notifyErrorMessage(res); + updatePersistenceGUI(); + return false; + } + + DWORD valueEntry = value; + res = RegSetValueEx(persistKeyHandle, L"value", 0, REG_DWORD, (BYTE*) &valueEntry, sizeof(DWORD)); + if (res != ERROR_SUCCESS){ + notifyErrorMessage(res); + updatePersistenceGUI(); + return false; + } + + return true; +} + +void enablePersistence(){ + setPersistenceRegistry(true, checkDevicesToggledOff()); + updatePersistenceGUI(); +} + +void disablePersistence(){ + setPersistenceRegistry(false, false); + updatePersistenceGUI(); +} + +bool isPersistenceEnabled(){ + DWORD persistEnabled = 0; + DWORD valSize = sizeof(DWORD); + DWORD type; + LSTATUS res = RegGetValue(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\services\\Keybitor\\persist", L"enable", RRF_RT_REG_DWORD, &type, &persistEnabled, &valSize); + + if (res == ERROR_FILE_NOT_FOUND){ + return false; + } + + if (res != ERROR_SUCCESS){ + notifyErrorMessage(res); + return false; + } + + return persistEnabled==1; +} + +bool isTrayInstalled(){ + DWORD type; + std::vector data(300, '\0'); + DWORD valSize = (DWORD)data.size(); + LSTATUS res = RegGetValue(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", L"KibitorTray", RRF_RT_REG_SZ, &type, (void*) &data[0], &valSize); + + if (res == ERROR_FILE_NOT_FOUND){ + return false; + } + + while (res == ERROR_MORE_DATA){ + data.insert(data.end(), data.size(), '\0'); + valSize = (DWORD)data.size(); + res = RegGetValue(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", L"KibitorTray", RRF_RT_REG_SZ, &type, (void*) &data[0], &valSize); + } + + if (res != ERROR_SUCCESS){ + notifyErrorMessage(res); + return false; + } + + return true; +} + +void uninstallTray(){ + LSTATUS res = RegDeleteKeyValue(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", L"KibitorTray"); + + if (res != ERROR_SUCCESS){ + notifyErrorMessage(res); + } + updateTraybarInstallGUI(); +} + +void installTray(){ + LPCWSTR trayExeW = getLocalTrayExe(); + LSTATUS res = RegSetKeyValue(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", L"KibitorTray", REG_SZ, trayExeW, (DWORD)(wcslen(trayExeW)*sizeof(wchar_t))); + if (res != ERROR_SUCCESS){ + notifyErrorMessage(res); + } + updateTraybarInstallGUI(); +} + +template +wchar_t* getLocalFile(const wchar_t (&file)[Size]){ + TCHAR appFileName[MAX_PATH + 1]; + + if (GetModuleFileName(NULL, appFileName, MAX_PATH + 1) > (MAX_PATH + 1)){ + return false; + } + + DWORD pathSize = MAX_PATH + Size; + TCHAR* appPath = NULL; + LPWSTR filePart = NULL; + DWORD written = 0; + + appPath = (PTCHAR) malloc(pathSize * sizeof(TCHAR)); + memset(appPath, '\0', pathSize * sizeof(TCHAR)); + written = GetFullPathName(appFileName, pathSize, appPath, &filePart); + if (written > pathSize){ + free(appPath); + pathSize = written + Size + 2; + appPath = (PTCHAR) malloc(pathSize * sizeof(TCHAR)); + memset(appPath, '\0', pathSize * sizeof(TCHAR)); + written = GetFullPathName(appFileName, pathSize - 2, appPath, &filePart); + } + + memset(filePart, 0, wcslen(filePart)*sizeof(wchar_t)); + memcpy(filePart, file, Size*sizeof(wchar_t)); + + return appPath; +} + +wchar_t* getLocalDriverInfFile(){ + + return getLocalFile(DriverInfName); +} + +wchar_t* getLocalTrayExe(){ + + return getLocalFile(TrayExeName); +} + +void notifyErrorMessage(DWORD code = ERROR_SUCCESS){ + + if (code == ERROR_SUCCESS){ + code = GetLastError(); + if (code == 0) + return; + } + + LPWSTR messageBuffer = nullptr; + size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) &messageBuffer, 0, NULL); + + MessageBox(hwndMainWindow, messageBuffer, L"Error", MB_OK); + + LocalFree(messageBuffer); +} \ No newline at end of file diff --git a/Config/targetver.h b/Config/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/Config/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/CtrlLib/include/Keybitor.h b/CtrlLib/include/Keybitor.h new file mode 100644 index 0000000..4aaf925 --- /dev/null +++ b/CtrlLib/include/Keybitor.h @@ -0,0 +1,34 @@ + + +#ifdef __cplusplus +extern "C" { +#endif + + // check the presence of a device using the PS2KeyboardToggler driver filter + // returns : 0 if no device is present + // 1 if at least on device is present + // -1 on error + int hasDevice(); + + // executes a callback pssing each compatible device's path + // returns : 0 if no device is present + // 1 if at least on device is present + // -1 on error + int foreachDevice(void(*)(const wchar_t*, void*), void*); + + // returns whether the provided device is toggle on or off + // returns : 0 if the device is toggled off + // 1 if the device is toggled on + // -1 on error + int isDeviceEnable(const wchar_t*); + + // inverts the toggle state of the device and + // returns whether it is toggle on or off + // returns : 0 if the device is toggled off + // 1 if the device is toggled on + // -1 on error + int toggleDevice(const wchar_t*); + +#ifdef __cplusplus +} +#endif diff --git a/CtrlLib/src/Keybitor.c b/CtrlLib/src/Keybitor.c new file mode 100644 index 0000000..f5d158d --- /dev/null +++ b/CtrlLib/src/Keybitor.c @@ -0,0 +1,288 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +#pragma warning(disable:4201) + +#include +#include + +#pragma warning(default:4201) + +#include "../../driver/public.h" + +//----------------------------------------------------------------------------- +// 4127 -- Conditional Expression is Constant warning +//----------------------------------------------------------------------------- +#define WHILE(constant) \ +__pragma(warning(disable: 4127)) while(constant); __pragma(warning(default: 4127)) + +DEFINE_GUID(GUID_DEVINTERFACE_KBFILTER, + 0x3fb7299d, 0x6847, 0x4490, 0xb0, 0xc9, 0x99, 0xe0, 0x98, 0x6a, 0xb8, 0x86); +// {3FB7299D-6847-4490-B0C9-99E0986AB886} + +int hasDevice(){ + HDEVINFO hardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; + ULONG predictedLength = 0; + ULONG requiredLength = 0; + ULONG i = 0; + BOOL providedDeviceValid = 0; + int result = -1; + + // + // Open a handle to the device interface information set of all + // present toaster class interfaces. + // + + hardwareDeviceInfo = SetupDiGetClassDevs( + (LPGUID) &GUID_DEVINTERFACE_KBFILTER, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + if (INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + printf("SetupDiGetClassDevs failed: %x\n", GetLastError()); + return FALSE; + } + + deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + // + // Enumerate devices of keyboard class + // + + if (SetupDiEnumDeviceInterfaces(hardwareDeviceInfo, + 0, // No care about specific PDOs + (LPGUID) &GUID_DEVINTERFACE_KBFILTER, + 0, // + &deviceInterfaceData)) { + result = TRUE; + } + + if (ERROR_NO_MORE_ITEMS == GetLastError()){ + result = FALSE; + } + + SetupDiDestroyDeviceInfoList(hardwareDeviceInfo); + return result; +} + +int foreachDevice(void(*func)(const wchar_t*, void*), void* data){ + HDEVINFO hardwareDeviceInfo; + SP_DEVICE_INTERFACE_DATA deviceInterfaceData; + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; + ULONG predictedLength = 0; + ULONG requiredLength = 0; + ULONG i = 0; + BOOL providedDeviceValid = 0; + + // + // Open a handle to the device interface information set of all + // present toaster class interfaces. + // + + hardwareDeviceInfo = SetupDiGetClassDevs( + (LPGUID) &GUID_DEVINTERFACE_KBFILTER, + NULL, // Define no enumerator (global) + NULL, // Define no + (DIGCF_PRESENT | // Only Devices present + DIGCF_DEVICEINTERFACE)); // Function class devices. + if (INVALID_HANDLE_VALUE == hardwareDeviceInfo) + { + printf("SetupDiGetClassDevs failed: %x\n", GetLastError()); + return FALSE; + } + + deviceInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA); + + i = 0; + + // + // Enumerate devices of keyboard class + // + + do { + if (SetupDiEnumDeviceInterfaces(hardwareDeviceInfo, + 0, // No care about specific PDOs + (LPGUID) &GUID_DEVINTERFACE_KBFILTER, + i++, // + &deviceInterfaceData)) { + + if (deviceInterfaceDetailData) { + free(deviceInterfaceDetailData); + deviceInterfaceDetailData = NULL; + } + + // + // Allocate a function class device data structure to + // receive the information about this particular device. + // + + // + // First find out required length of the buffer + // + + if (!SetupDiGetDeviceInterfaceDetail( + hardwareDeviceInfo, + &deviceInterfaceData, + NULL, // probing so no output buffer yet + 0, // probing so output buffer length of zero + &requiredLength, + NULL)) { // not interested in the specific dev-node + if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) { + printf("SetupDiGetDeviceInterfaceDetail failed %d\n", GetLastError()); + SetupDiDestroyDeviceInfoList(hardwareDeviceInfo); + return -1; + } + + } + + predictedLength = requiredLength; + + deviceInterfaceDetailData = malloc(predictedLength); + + if (deviceInterfaceDetailData) { + deviceInterfaceDetailData->cbSize = + sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA); + } + else { + printf("Couldn't allocate %d bytes for device interface details.\n", predictedLength); + SetupDiDestroyDeviceInfoList(hardwareDeviceInfo); + return -1; + } + + + if (!SetupDiGetDeviceInterfaceDetail( + hardwareDeviceInfo, + &deviceInterfaceData, + deviceInterfaceDetailData, + predictedLength, + &requiredLength, + NULL)) { + printf("Error in SetupDiGetDeviceInterfaceDetail\n"); + SetupDiDestroyDeviceInfoList(hardwareDeviceInfo); + free(deviceInterfaceDetailData); + return -1; + } + func(deviceInterfaceDetailData->DevicePath, data); + } + else if (ERROR_NO_MORE_ITEMS != GetLastError()) { + free(deviceInterfaceDetailData); + deviceInterfaceDetailData = NULL; + continue; + } + else + break; + + } WHILE(TRUE); + + + SetupDiDestroyDeviceInfoList(hardwareDeviceInfo); + + if (!deviceInterfaceDetailData) + { + printf("No device interfaces present\n"); + return -1; + } + + return TRUE; +} + +int isDeviceEnable(const wchar_t* devicePath){ + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; + HANDLE file; + char discardingInputs; + ULONG bytes = 0; + + file = CreateFile(devicePath, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // No special attributes + NULL); + + if (INVALID_HANDLE_VALUE == file) { + printf("Error in CreateFile: %x", GetLastError()); + free(deviceInterfaceDetailData); + return -1; + } + + // + // Send an IOCTL to retrive the keyboard attributes + // These are cached in the kbfiltr + // + + if (!DeviceIoControl(file, + IOCTL_PS2KBDTGL_GET_STATE, + NULL, 0, + &discardingInputs, sizeof(discardingInputs), + &bytes, NULL)) { + printf("Retrieve Keyboard Attributes request failed:0x%x\n", GetLastError()); + free(deviceInterfaceDetailData); + CloseHandle(file); + return -1; + } + + free(deviceInterfaceDetailData); + CloseHandle(file); + + return !discardingInputs; +} + + +int toggleDevice(const wchar_t* devicePath){ + PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData = NULL; + HANDLE file; + char toggleStatus; + ULONG bytes = 0; + + file = CreateFile(devicePath, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, // no SECURITY_ATTRIBUTES structure + OPEN_EXISTING, // No special create flags + 0, // No special attributes + NULL); + + if (INVALID_HANDLE_VALUE == file) { + printf("Error in CreateFile: %x", GetLastError()); + free(deviceInterfaceDetailData); + return -1; + } + + // + // Send an IOCTL to retrive the keyboard attributes + // These are cached in the kbfiltr + // + + if (!DeviceIoControl(file, + IOCTL_PS2KBDTGL_TOGGLE_DISCARD, + NULL, 0, + &toggleStatus, sizeof(toggleStatus), + &bytes, NULL)) { + printf("Retrieve Keyboard Attributes request failed:0x%x\n", GetLastError()); + free(deviceInterfaceDetailData); + CloseHandle(file); + return -1; + } + + if (toggleStatus){ + printf("Device enabled : %s\n", devicePath); + } + + free(deviceInterfaceDetailData); + CloseHandle(file); + + return toggleStatus; +} + diff --git a/CtrlLib/src/Keybitor_internal.h b/CtrlLib/src/Keybitor_internal.h new file mode 100644 index 0000000..e69de29 diff --git a/Driver/Keybitor.inx b/Driver/Keybitor.inx new file mode 100644 index 0000000..f6abea8 --- /dev/null +++ b/Driver/Keybitor.inx @@ -0,0 +1,148 @@ +; Keybitor.inf +; +; Installation inf for the Device that needs filtering adapter. +; +; (c) Copyright 1999 Microsoft +; + +[Version] +Signature="$Windows NT$" +Provider=%DDK_Ex% +ClassGUID={4D36E96B-E325-11CE-BFC1-08002BE10318} +Class=Keyboard +; Uncomment the following line when you have a valid catalog file. +; If you use bogus catalog file installation will fail. +; Ignore the error from chkinf. +CatalogFile=Keybitor.cat + +DriverVer=03/03/2019, 0.0.0.1 + +[DestinationDirs] +DefaultDestDir = 12 + +; +; Driver information +; + +[Manufacturer] +%DDK_Ex% = DDK_Ex.Mfg,NTamd64 + +; For Win2K +[DDK_Ex.Mfg] +%DDK_Ex% = Keybitor, ACPI\MSF0001 + +; For XP and above +[DDK_Ex.Mfg.NTamd64] +%DDK_Ex% = Keybitor, ACPI\MSF0001,*PNP0303 + +; +; General installation section +; + +[Keybitor.NT] +; perform port related actions from keyboard.inf +Include=keyboard.inf +Needs=STANDARD_Inst + +; Copy the driver over +CopyFiles=Keybitor.CopyFiles + + +; +; File sections +; + +[Keybitor.CopyFiles] +Keybitor.sys + + +; +; Service Installation +; + +[Keybitor.NT.Services] +AddService = Keybitor, , Keybitor_Service_Inst +; Install the port driver and mouclass from keyboard.inf +Include=keyboard.inf +Needs=STANDARD_Inst.Services + +[Keybitor_Service_Inst] +DisplayName = %Keybitor.SvcDesc% +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 0 ; SERVICE_ERROR_IGNORE +LoadOrderGroup = Keyboard Port +ServiceBinary = %12%\Keybitor.sys + +[Keybitor.NT.HW] +; Add the device upper filter +AddReg = Keybitor.HW.AddReg + +; run the directives need by the port driver +Include=keyboard.inf +Needs=STANDARD_Inst.HW + +[Keybitor.HW.AddReg] +HKR,,"UpperFilters",0x00010000,"Keybitor" + + +; +; Source file information +; + + +[SourceDisksNames] +1 = %DiskId1%,,, + +[SourceDisksFiles] +Keybitor.sys = 1,, + +; +;--- Keybitor Coinstaller installation ------ +; + +[DestinationDirs] +Keybitor_CoInstaller_CopyFiles = 11 + +[Keybitor.NT.CoInstallers] +AddReg=Keybitor_CoInstaller_AddReg +CopyFiles=Keybitor_CoInstaller_CopyFiles + +[Keybitor_CoInstaller_AddReg] +HKR,,CoInstallers32,0x00010000, "WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll,WdfCoInstaller" + +[Keybitor_CoInstaller_CopyFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll + +[SourceDisksFiles] +WdfCoInstaller$KMDFCOINSTALLERVERSION$.dll=1 ; make sure the number matches with SourceDisksNames + +[Keybitor.NT.Wdf] +KmdfService = Keybitor, Keybitor_wdfsect +[Keybitor_wdfsect] +KmdfLibraryVersion = $KMDFVERSION$ + + + +[Strings] + +; +; Non-Localizable Strings +; + +REG_SZ = 0x00000000 +REG_MULTI_SZ = 0x00010000 +REG_EXPAND_SZ = 0x00020000 +REG_BINARY = 0x00000001 +REG_DWORD = 0x00010001 +SERVICEROOT = "System\CurrentControlSet\Services" + +; +; Localizable Strings +; + +DiskId1 = "Keybitor Disk #1 (Keyboard)" +DDK_Ex = "Keybitor" +; Make sure the service description is unique to avoid collision with another INF. +Keybitor.SvcDesc="Keybitor" + diff --git a/Driver/Trace.h b/Driver/Trace.h new file mode 100644 index 0000000..c3829d2 --- /dev/null +++ b/Driver/Trace.h @@ -0,0 +1,54 @@ +/*++ + +Module Name: + + Trace.h + +Abstract: + + Header file for the debug tracing related function defintions and macros. + +Environment: + + Kernel mode + +--*/ + +// +// Define the tracing flags. +// +// Tracing GUID - aff98593-0e6c-4bb9-b31c-100bd63333c6 +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + PS2KeyboardTogglerTraceGuid, (aff98593,0e6c,4bb9,b31c,100bd63333c6), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + WPP_DEFINE_BIT(TRACE_DRIVER) \ + WPP_DEFINE_BIT(TRACE_DEVICE) \ + WPP_DEFINE_BIT(TRACE_QUEUE) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \ + WPP_LEVEL_LOGGER(flags) + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ + (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); +// end_wpp +// diff --git a/Driver/driver.rc b/Driver/driver.rc new file mode 100644 index 0000000..b30615c --- /dev/null +++ b/Driver/driver.rc @@ -0,0 +1,12 @@ +#include + +#include + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM +#define VER_FILEDESCRIPTION_STR "Toggle PS2 Keyboard" +#define VER_INTERNALNAME_STR "PS2KeyboardToggler.sys" + +#include "common.ver" + + diff --git a/Driver/kbfiltr.c b/Driver/kbfiltr.c new file mode 100644 index 0000000..e9b859f --- /dev/null +++ b/Driver/kbfiltr.c @@ -0,0 +1,944 @@ +/*-- + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + +Module Name: + + kbfiltr.c + +Abstract: This is an upper device filter driver sample for PS/2 keyboard. This + driver layers in between the KbdClass driver and i8042prt driver and + hooks the callback routine that moves keyboard inputs from the port + driver to class driver. With this filter, you can remove or insert + additional keys into the stream. This sample also creates a raw + PDO and registers an interface so that application can talk to + the filter driver directly without going thru the PS/2 devicestack. + The reason for providing this additional interface is because the keyboard + device is an exclusive secure device and it's not possible to open the + device from usermode and send custom ioctls. + + If you want to filter keyboard inputs from all the keyboards (ps2, usb) + plugged into the system then you can install this driver as a class filter + and make it sit below the kbdclass filter driver by adding the service + name of this filter driver before the kbdclass filter in the registry at + " HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\ + {4D36E96B-E325-11CE-BFC1-08002BE10318}\UpperFilters" + + +Environment: + + Kernel mode only. + +--*/ + +#include "kbfiltr.h" + +#include "wdm.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, KbFilter_EvtDeviceAdd) +#pragma alloc_text (PAGE, KbFilter_EvtIoInternalDeviceControl) +#endif + +ULONG InstanceNo = 0; + +char gDiscardInput = 0; +char gPersistEnable = 0; + +enum PersistFlags{ + PersistEnable = 1, + PersistValue = 2 +}; +char getRegistryPersistConfig(); +void updateRegistryPersistValue(char persistValue); + +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Installable driver initialization entry point. + This entry point is called directly by the I/O system. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path, + to driver-specific key in the registry. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ +{ + WDF_DRIVER_CONFIG config; + NTSTATUS status; + + // + // Initialize driver config to control the attributes that + // are global to the driver. Note that framework by default + // provides a driver unload routine. If you create any resources + // in the DriverEntry and want to be cleaned in driver unload, + // you can override that by manually setting the EvtDriverUnload in the + // config structure. In general xxx_CONFIG_INIT macros are provided to + // initialize most commonly used members. + // + + WDF_DRIVER_CONFIG_INIT( + &config, + KbFilter_EvtDeviceAdd + ); + + // + // Create a framework driver object to represent our driver. + // + status = WdfDriverCreate(DriverObject, + RegistryPath, + WDF_NO_OBJECT_ATTRIBUTES, + &config, + WDF_NO_HANDLE); // hDriver optional + if (!NT_SUCCESS(status)) { + DebugPrint(("WdfDriverCreate failed with status 0x%x\n", status)); + } + + char persistConfig = getRegistryPersistConfig(); + gPersistEnable = (persistConfig & PersistEnable) >= 1 ? 1 : 0; + if (gPersistEnable){ + gDiscardInput = (persistConfig & PersistValue) >= 1 ? 1 : 0; + } + + return status; +} + +NTSTATUS +KbFilter_EvtDeviceAdd( + IN WDFDRIVER Driver, + IN PWDFDEVICE_INIT DeviceInit + ) +/*++ +Routine Description: + + EvtDeviceAdd is called by the framework in response to AddDevice + call from the PnP manager. Here you can query the device properties + using WdfFdoInitWdmGetPhysicalDevice/IoGetDeviceProperty and based + on that, decide to create a filter device object and attach to the + function stack. + + If you are not interested in filtering this particular instance of the + device, you can just return STATUS_SUCCESS without creating a framework + device. + +Arguments: + + Driver - Handle to a framework driver object created in DriverEntry + + DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure. + +Return Value: + + NTSTATUS + +--*/ +{ + WDF_OBJECT_ATTRIBUTES deviceAttributes; + NTSTATUS status; + WDFDEVICE hDevice; + WDFQUEUE hQueue; + PDEVICE_EXTENSION filterExt; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + + UNREFERENCED_PARAMETER(Driver); + + PAGED_CODE(); + + DebugPrint(("Enter FilterEvtDeviceAdd \n")); + + // + // Tell the framework that you are filter driver. Framework + // takes care of inherting all the device flags & characterstics + // from the lower device you are attaching to. + // + WdfFdoInitSetFilter(DeviceInit); + + WdfDeviceInitSetDeviceType(DeviceInit, FILE_DEVICE_KEYBOARD); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_EXTENSION); + + // + // Create a framework device object. This call will in turn create + // a WDM deviceobject, attach to the lower stack and set the + // appropriate flags and attributes. + // + status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &hDevice); + if (!NT_SUCCESS(status)) { + DebugPrint(("WdfDeviceCreate failed with status code 0x%x\n", status)); + return status; + } + + filterExt = FilterGetData(hDevice); + + // + // Configure the default queue to be Parallel. Do not use sequential queue + // if this driver is going to be filtering PS2 ports because it can lead to + // deadlock. The PS2 port driver sends a request to the top of the stack when it + // receives an ioctl request and waits for it to be completed. If you use a + // a sequential queue, this request will be stuck in the queue because of the + // outstanding ioctl request sent earlier to the port driver. + // + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, + WdfIoQueueDispatchParallel); + + // + // Framework by default creates non-power managed queues for + // filter drivers. + // + ioQueueConfig.EvtIoInternalDeviceControl = KbFilter_EvtIoInternalDeviceControl; + + status = WdfIoQueueCreate(hDevice, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + WDF_NO_HANDLE // pointer to default queue + ); + if (!NT_SUCCESS(status)) { + DebugPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); + return status; + } + + // + // Create a new queue to handle IOCTLs that will be forwarded to us from + // the rawPDO. + // + WDF_IO_QUEUE_CONFIG_INIT(&ioQueueConfig, + WdfIoQueueDispatchParallel); + + // + // Framework by default creates non-power managed queues for + // filter drivers. + // + ioQueueConfig.EvtIoDeviceControl = KbFilter_EvtIoDeviceControlFromRawPdo; + + status = WdfIoQueueCreate(hDevice, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &hQueue + ); + if (!NT_SUCCESS(status)) { + DebugPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); + return status; + } + + filterExt->rawPdoQueue = hQueue; + + // + // Create a RAW pdo so we can provide a sideband communication with + // the application. Please note that not filter drivers desire to + // produce such a communication and not all of them are contrained + // by other filter above which prevent communication thru the device + // interface exposed by the main stack. So use this only if absolutely + // needed. Also look at the toaster filter driver sample for an alternate + // approach to providing sideband communication. + // + status = KbFiltr_CreateRawPdo(hDevice, ++InstanceNo); + + return status; +} + +VOID +KbFilter_EvtIoDeviceControlFromRawPdo( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ + +Routine Description: + + This routine is the dispatch routine for device control requests. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDFDEVICE hDevice; + WDFMEMORY outputMemory; + PDEVICE_EXTENSION devExt; + size_t bytesTransferred = 0; + + UNREFERENCED_PARAMETER(InputBufferLength); + + DebugPrint(("Entered KbFilter_EvtIoDeviceControlFromRawPdo\n")); + + hDevice = WdfIoQueueGetDevice(Queue); + devExt = FilterGetData(hDevice); + + // + // Process the ioctl and complete it when you are done. + // + + switch (IoControlCode) { + case IOCTL_PS2KBDTGL_TOGGLE_DISCARD: + case IOCTL_PS2KBDTGL_GET_STATE: + + // + // Buffer is too small, fail the request + // + if (OutputBufferLength < sizeof(char)) { + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + status = WdfRequestRetrieveOutputMemory(Request, &outputMemory); + + if (!NT_SUCCESS(status)) { + DebugPrint(("WdfRequestRetrieveOutputMemory failed %x\n", status)); + break; + } + if (IoControlCode == IOCTL_PS2KBDTGL_TOGGLE_DISCARD){ + gDiscardInput = !gDiscardInput; + + if (gPersistEnable){ + DebugPrint(("event IOCTL_PS2KBDTGL_TOGGLE_DISCARD %x\n", gDiscardInput)); + updateRegistryPersistValue(gDiscardInput); + } + } + + status = WdfMemoryCopyFromBuffer(outputMemory, + 0, + &gDiscardInput, + sizeof(gDiscardInput)); + + if (!NT_SUCCESS(status)) { + DebugPrint(("WdfMemoryCopyFromBuffer failed %x\n", status)); + break; + } + + bytesTransferred = sizeof(gDiscardInput); + + break; + default: + status = STATUS_NOT_IMPLEMENTED; + break; + } + + WdfRequestCompleteWithInformation(Request, status, bytesTransferred); + + return; +} + +VOID +KbFilter_EvtIoInternalDeviceControl( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ + +Routine Description: + + This routine is the dispatch routine for internal device control requests. + There are two specific control codes that are of interest: + + IOCTL_INTERNAL_KEYBOARD_CONNECT: + Store the old context and function pointer and replace it with our own. + This makes life much simpler than intercepting IRPs sent by the RIT and + modifying them on the way back up. + + IOCTL_INTERNAL_I8042_HOOK_KEYBOARD: + Add in the necessary function pointers and context values so that we can + alter how the ps/2 keyboard is initialized. + + NOTE: Handling IOCTL_INTERNAL_I8042_HOOK_KEYBOARD is *NOT* necessary if + all you want to do is filter KEYBOARD_INPUT_DATAs. You can remove + the handling code and all related device extension fields and + functions to conserve space. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. + +Return Value: + + VOID + +--*/ +{ + PDEVICE_EXTENSION devExt; + PINTERNAL_I8042_HOOK_KEYBOARD hookKeyboard = NULL; + PCONNECT_DATA connectData = NULL; + NTSTATUS status = STATUS_SUCCESS; + size_t length; + WDFDEVICE hDevice; + BOOLEAN forwardWithCompletionRoutine = FALSE; + BOOLEAN ret = TRUE; + WDFCONTEXT completionContext = WDF_NO_CONTEXT; + WDF_REQUEST_SEND_OPTIONS options; + WDFMEMORY outputMemory; + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + + PAGED_CODE(); + + DebugPrint(("Entered KbFilter_EvtIoInternalDeviceControl\n")); + + hDevice = WdfIoQueueGetDevice(Queue); + devExt = FilterGetData(hDevice); + + switch (IoControlCode) { + + // + // Connect a keyboard class device driver to the port driver. + // + case IOCTL_INTERNAL_KEYBOARD_CONNECT: + // + // Only allow one connection. + // + if (devExt->UpperConnectData.ClassService != NULL) { + status = STATUS_SHARING_VIOLATION; + break; + } + + // + // Get the input buffer from the request + // (Parameters.DeviceIoControl.Type3InputBuffer). + // + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(CONNECT_DATA), + &connectData, + &length); + if(!NT_SUCCESS(status)){ + DebugPrint(("WdfRequestRetrieveInputBuffer failed %x\n", status)); + break; + } + + NT_ASSERT(length == InputBufferLength); + + devExt->UpperConnectData = *connectData; + + // + // Hook into the report chain. Everytime a keyboard packet is reported + // to the system, KbFilter_ServiceCallback will be called + // + + connectData->ClassDeviceObject = WdfDeviceWdmGetDeviceObject(hDevice); + +#pragma warning(disable:4152) //nonstandard extension, function/data pointer conversion + + connectData->ClassService = KbFilter_ServiceCallback; + +#pragma warning(default:4152) + + break; + + // + // Disconnect a keyboard class device driver from the port driver. + // + case IOCTL_INTERNAL_KEYBOARD_DISCONNECT: + + // + // Clear the connection parameters in the device extension. + // + // devExt->UpperConnectData.ClassDeviceObject = NULL; + // devExt->UpperConnectData.ClassService = NULL; + + status = STATUS_NOT_IMPLEMENTED; + break; + + // + // Attach this driver to the initialization and byte processing of the + // i8042 (ie PS/2) keyboard. This is only necessary if you want to do PS/2 + // specific functions, otherwise hooking the CONNECT_DATA is sufficient + // + case IOCTL_INTERNAL_I8042_HOOK_KEYBOARD: + + DebugPrint(("hook keyboard received!\n")); + + // + // Get the input buffer from the request + // (Parameters.DeviceIoControl.Type3InputBuffer) + // + status = WdfRequestRetrieveInputBuffer(Request, + sizeof(INTERNAL_I8042_HOOK_KEYBOARD), + &hookKeyboard, + &length); + if(!NT_SUCCESS(status)){ + DebugPrint(("WdfRequestRetrieveInputBuffer failed %x\n", status)); + break; + } + + NT_ASSERT(length == InputBufferLength); + + // + // Enter our own initialization routine and record any Init routine + // that may be above us. Repeat for the isr hook + // + devExt->UpperContext = hookKeyboard->Context; + + // + // replace old Context with our own + // + hookKeyboard->Context = (PVOID) devExt; + + if (hookKeyboard->InitializationRoutine) { + devExt->UpperInitializationRoutine = + hookKeyboard->InitializationRoutine; + } + hookKeyboard->InitializationRoutine = + (PI8042_KEYBOARD_INITIALIZATION_ROUTINE) + KbFilter_InitializationRoutine; + + if (hookKeyboard->IsrRoutine) { + devExt->UpperIsrHook = hookKeyboard->IsrRoutine; + } + hookKeyboard->IsrRoutine = (PI8042_KEYBOARD_ISR) KbFilter_IsrHook; + + // + // Store all of the other important stuff + // + devExt->IsrWritePort = hookKeyboard->IsrWritePort; + devExt->QueueKeyboardPacket = hookKeyboard->QueueKeyboardPacket; + devExt->CallContext = hookKeyboard->CallContext; + + status = STATUS_SUCCESS; + break; + + + case IOCTL_KEYBOARD_QUERY_ATTRIBUTES: + forwardWithCompletionRoutine = TRUE; + completionContext = devExt; + break; + + // + // Might want to capture these in the future. For now, then pass them down + // the stack. These queries must be successful for the RIT to communicate + // with the keyboard. + // + case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION: + case IOCTL_KEYBOARD_QUERY_INDICATORS: + case IOCTL_KEYBOARD_SET_INDICATORS: + case IOCTL_KEYBOARD_QUERY_TYPEMATIC: + case IOCTL_KEYBOARD_SET_TYPEMATIC: + break; + } + + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + return; + } + + // + // Forward the request down. WdfDeviceGetIoTarget returns + // the default target, which represents the device attached to us below in + // the stack. + // + + if (forwardWithCompletionRoutine) { + + // + // Format the request with the output memory so the completion routine + // can access the return data in order to cache it into the context area + // + + status = WdfRequestRetrieveOutputMemory(Request, &outputMemory); + + if (!NT_SUCCESS(status)) { + DebugPrint(("WdfRequestRetrieveOutputMemory failed: 0x%x\n", status)); + WdfRequestComplete(Request, status); + return; + } + + status = WdfIoTargetFormatRequestForInternalIoctl(WdfDeviceGetIoTarget(hDevice), + Request, + IoControlCode, + NULL, + NULL, + outputMemory, + NULL); + + if (!NT_SUCCESS(status)) { + DebugPrint(("WdfIoTargetFormatRequestForInternalIoctl failed: 0x%x\n", status)); + WdfRequestComplete(Request, status); + return; + } + + // + // Set our completion routine with a context area that we will save + // the output data into + // + WdfRequestSetCompletionRoutine(Request, + KbFilterRequestCompletionRoutine, + completionContext); + + ret = WdfRequestSend(Request, + WdfDeviceGetIoTarget(hDevice), + WDF_NO_SEND_OPTIONS); + + if (ret == FALSE) { + status = WdfRequestGetStatus (Request); + DebugPrint( ("WdfRequestSend failed: 0x%x\n", status)); + WdfRequestComplete(Request, status); + } + + } + else + { + + // + // We are not interested in post processing the IRP so + // fire and forget. + // + WDF_REQUEST_SEND_OPTIONS_INIT(&options, + WDF_REQUEST_SEND_OPTION_SEND_AND_FORGET); + + ret = WdfRequestSend(Request, WdfDeviceGetIoTarget(hDevice), &options); + + if (ret == FALSE) { + status = WdfRequestGetStatus (Request); + DebugPrint(("WdfRequestSend failed: 0x%x\n", status)); + WdfRequestComplete(Request, status); + } + + } + + return; +} + +NTSTATUS +KbFilter_InitializationRoutine( + IN PVOID InitializationContext, + IN PVOID SynchFuncContext, + IN PI8042_SYNCH_READ_PORT ReadPort, + IN PI8042_SYNCH_WRITE_PORT WritePort, + OUT PBOOLEAN TurnTranslationOn + ) +/*++ + +Routine Description: + + This routine gets called after the following has been performed on the kb + 1) a reset + 2) set the typematic + 3) set the LEDs + + i8042prt specific code, if you are writing a packet only filter driver, you + can remove this function + +Arguments: + + DeviceObject - Context passed during IOCTL_INTERNAL_I8042_HOOK_KEYBOARD + + SynchFuncContext - Context to pass when calling Read/WritePort + + Read/WritePort - Functions to synchronoulsy read and write to the kb + + TurnTranslationOn - If TRUE when this function returns, i8042prt will not + turn on translation on the keyboard + +Return Value: + + Status is returned. + +--*/ +{ + PDEVICE_EXTENSION devExt; + NTSTATUS status = STATUS_SUCCESS; + + devExt = (PDEVICE_EXTENSION)InitializationContext; + + // + // Do any interesting processing here. We just call any other drivers + // in the chain if they exist. Make sure Translation is turned on as well + // + if (devExt->UpperInitializationRoutine) { + status = (*devExt->UpperInitializationRoutine) ( + devExt->UpperContext, + SynchFuncContext, + ReadPort, + WritePort, + TurnTranslationOn + ); + + if (!NT_SUCCESS(status)) { + return status; + } + } + + *TurnTranslationOn = TRUE; + return status; +} + +BOOLEAN +KbFilter_IsrHook( + PVOID IsrContext, + PKEYBOARD_INPUT_DATA CurrentInput, + POUTPUT_PACKET CurrentOutput, + UCHAR StatusByte, + PUCHAR DataByte, + PBOOLEAN ContinueProcessing, + PKEYBOARD_SCAN_STATE ScanState + ) +/*++ + +Routine Description: + + This routine gets called at the beginning of processing of the kb interrupt. + + i8042prt specific code, if you are writing a packet only filter driver, you + can remove this function + +Arguments: + + DeviceObject - Our context passed during IOCTL_INTERNAL_I8042_HOOK_KEYBOARD + + CurrentInput - Current input packet being formulated by processing all the + interrupts + + CurrentOutput - Current list of bytes being written to the keyboard or the + i8042 port. + + StatusByte - Byte read from I/O port 60 when the interrupt occurred + + DataByte - Byte read from I/O port 64 when the interrupt occurred. + This value can be modified and i8042prt will use this value + if ContinueProcessing is TRUE + + ContinueProcessing - If TRUE, i8042prt will proceed with normal processing of + the interrupt. If FALSE, i8042prt will return from the + interrupt after this function returns. Also, if FALSE, + it is this functions responsibilityt to report the input + packet via the function provided in the hook IOCTL or via + queueing a DPC within this driver and calling the + service callback function acquired from the connect IOCTL + +Return Value: + + Status is returned. + +--*/ +{ + PDEVICE_EXTENSION devExt; + BOOLEAN retVal = TRUE; + + devExt = (PDEVICE_EXTENSION)IsrContext; + + if (devExt->UpperIsrHook) { + retVal = (*devExt->UpperIsrHook) ( + devExt->UpperContext, + CurrentInput, + CurrentOutput, + StatusByte, + DataByte, + ContinueProcessing, + ScanState + ); + + if (!retVal || !(*ContinueProcessing)) { + return retVal; + } + } + + *ContinueProcessing = TRUE; + return retVal; +} + +VOID +KbFilter_ServiceCallback( + IN PDEVICE_OBJECT DeviceObject, + IN PKEYBOARD_INPUT_DATA InputDataStart, + IN PKEYBOARD_INPUT_DATA InputDataEnd, + IN OUT PULONG InputDataConsumed + ) +/*++ + +Routine Description: + + Called when there are keyboard packets to report to the Win32 subsystem. + You can do anything you like to the packets. For instance: + + o Drop a packet altogether + o Mutate the contents of a packet + o Insert packets into the stream + +Arguments: + + DeviceObject - Context passed during the connect IOCTL + + InputDataStart - First packet to be reported + + InputDataEnd - One past the last packet to be reported. Total number of + packets is equal to InputDataEnd - InputDataStart + + InputDataConsumed - Set to the total number of packets consumed by the RIT + (via the function pointer we replaced in the connect + IOCTL) + +Return Value: + + Status is returned. + +--*/ +{ + if (gDiscardInput){ + *InputDataConsumed = (ULONG)(InputDataEnd - InputDataStart); + return; + } + + PDEVICE_EXTENSION devExt; + WDFDEVICE hDevice; + + hDevice = WdfWdmDeviceGetWdfDeviceHandle(DeviceObject); + + devExt = FilterGetData(hDevice); + + (*(PSERVICE_CALLBACK_ROUTINE)(ULONG_PTR) devExt->UpperConnectData.ClassService)( + devExt->UpperConnectData.ClassDeviceObject, + InputDataStart, + InputDataEnd, + InputDataConsumed); +} + +VOID +KbFilterRequestCompletionRoutine( + WDFREQUEST Request, + WDFIOTARGET Target, + PWDF_REQUEST_COMPLETION_PARAMS CompletionParams, + WDFCONTEXT Context + ) +/*++ + +Routine Description: + + Completion Routine + +Arguments: + + Target - Target handle + Request - Request handle + Params - request completion params + Context - Driver supplied context + + +Return Value: + + VOID + +--*/ +{ + WDFMEMORY buffer = CompletionParams->Parameters.Ioctl.Output.Buffer; + NTSTATUS status = CompletionParams->IoStatus.Status; + + UNREFERENCED_PARAMETER(Target); + + // + // Save the keyboard attributes in our context area so that we can return + // them to the app later. + // + if (NT_SUCCESS(status) && + CompletionParams->Type == WdfRequestTypeDeviceControlInternal && + CompletionParams->Parameters.Ioctl.IoControlCode == IOCTL_KEYBOARD_QUERY_ATTRIBUTES) { + + if( CompletionParams->Parameters.Ioctl.Output.Length >= sizeof(KEYBOARD_ATTRIBUTES)) { + + status = WdfMemoryCopyToBuffer(buffer, + CompletionParams->Parameters.Ioctl.Output.Offset, + &((PDEVICE_EXTENSION)Context)->KeyboardAttributes, + sizeof(KEYBOARD_ATTRIBUTES) + ); + } + } + + WdfRequestComplete(Request, status); + + return; +} + +char getRegistryPersistConfig(){ + NTSTATUS checkRes = RtlCheckRegistryKey(RTL_REGISTRY_SERVICES, L"Keybitor\\persist"); + if (STATUS_SUCCESS == checkRes){ + RTL_QUERY_REGISTRY_TABLE queries[3]; + int persistValue = 0; + int persistEnable = 0; + queries[0].QueryRoutine = NULL; + queries[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; + queries[0].Name = L"enable"; + queries[0].EntryContext = (PVOID) &persistEnable; + queries[0].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; + queries[0].DefaultData = REG_NONE; + queries[0].DefaultLength = 0; + queries[1].QueryRoutine = NULL; + queries[1].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_TYPECHECK; + queries[1].Name = L"value"; + queries[1].EntryContext = (PVOID) &persistValue; + queries[1].DefaultType = (REG_DWORD << RTL_QUERY_REGISTRY_TYPECHECK_SHIFT) | REG_NONE; + queries[1].DefaultData = REG_NONE; + queries[1].DefaultLength = 0; + queries[2].QueryRoutine = NULL; + queries[2].Name = NULL; + NTSTATUS res = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, L"Keybitor\\persist", queries, NULL, NULL); + + if (res == STATUS_SUCCESS){ + return (persistEnable ? PersistEnable : 0) + | (persistValue ? PersistValue : 0); + } + + DebugPrint(("RtlQueryRegistryValues failed: 0x%x\n", res)); + } + + DebugPrint(("RtlCheckRegistryKey failed: 0x%x\n", checkRes)); + + return 0; +} + +void updateRegistryPersistValue(char persistValue){ + DWORD pValue = persistValue > 0 ? 1 : 0; + NTSTATUS res = RtlWriteRegistryValue(RTL_REGISTRY_SERVICES, L"Keybitor\\persist", L"value", REG_DWORD, &pValue, sizeof(DWORD));//ignore result + DebugPrint(("RtlWriteRegistryValue failed: 0x%x\n", res)); +#if !DBG + UNREFERENCED_PARAMETER(res); +#endif +} diff --git a/Driver/kbfiltr.h b/Driver/kbfiltr.h new file mode 100644 index 0000000..00e149d --- /dev/null +++ b/Driver/kbfiltr.h @@ -0,0 +1,205 @@ +/*++ +Copyright (c) 1997 Microsoft Corporation + +Module Name: + + kbfilter.h + +Abstract: + + This module contains the common private declarations for the keyboard + packet filter + +Environment: + + kernel mode only + +--*/ + +#ifndef KBFILTER_H +#define KBFILTER_H + +#pragma warning(disable:4201) + +#include "ntddk.h" +#include "kbdmou.h" +#include +#include + +#pragma warning(default:4201) + +#include + +#define NTSTRSAFE_LIB +#include + +#include +#include + +#include "public.h" + +#define KBFILTER_POOL_TAG (ULONG) 'tlfK' + +#if DBG + +#define TRAP() DbgBreakPoint() + +#define DebugPrint(_x_) DbgPrint _x_ + +#else // DBG + +#define TRAP() + +#define DebugPrint(_x_) + +#endif + +#define MIN(_A_,_B_) (((_A_) < (_B_)) ? (_A_) : (_B_)) + +typedef struct _DEVICE_EXTENSION +{ + WDFDEVICE WdfDevice; + + // + // Queue for handling requests that come from the rawPdo + // + WDFQUEUE rawPdoQueue; + + // + // Number of creates sent down + // + LONG EnableCount; + + // + // The real connect data that this driver reports to + // + CONNECT_DATA UpperConnectData; + + // + // Previous initialization and hook routines (and context) + // + PVOID UpperContext; + PI8042_KEYBOARD_INITIALIZATION_ROUTINE UpperInitializationRoutine; + PI8042_KEYBOARD_ISR UpperIsrHook; + + // + // Write function from within KbFilter_IsrHook + // + IN PI8042_ISR_WRITE_PORT IsrWritePort; + + // + // Queue the current packet (ie the one passed into KbFilter_IsrHook) + // + IN PI8042_QUEUE_PACKET QueueKeyboardPacket; + + // + // Context for IsrWritePort, QueueKeyboardPacket + // + IN PVOID CallContext; + + // + // Cached Keyboard Attributes + // + KEYBOARD_ATTRIBUTES KeyboardAttributes; + +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_EXTENSION, + FilterGetData) + + +typedef struct _WORKER_ITEM_CONTEXT { + + WDFREQUEST Request; + WDFIOTARGET IoTarget; + +} WORKER_ITEM_CONTEXT, *PWORKER_ITEM_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(WORKER_ITEM_CONTEXT, GetWorkItemContext) + +// +// Prototypes +// +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_DRIVER_DEVICE_ADD KbFilter_EvtDeviceAdd; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL KbFilter_EvtIoDeviceControlForRawPdo; +EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL KbFilter_EvtIoDeviceControlFromRawPdo; +EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL KbFilter_EvtIoInternalDeviceControl; + +NTSTATUS +KbFilter_InitializationRoutine( + IN PVOID InitializationContext, + IN PVOID SynchFuncContext, + IN PI8042_SYNCH_READ_PORT ReadPort, + IN PI8042_SYNCH_WRITE_PORT WritePort, + OUT PBOOLEAN TurnTranslationOn + ); + +BOOLEAN +KbFilter_IsrHook( + PVOID IsrContext, + PKEYBOARD_INPUT_DATA CurrentInput, + POUTPUT_PACKET CurrentOutput, + UCHAR StatusByte, + PUCHAR DataByte, + PBOOLEAN ContinueProcessing, + PKEYBOARD_SCAN_STATE ScanState + ); + +VOID +KbFilter_ServiceCallback( + IN PDEVICE_OBJECT DeviceObject, + IN PKEYBOARD_INPUT_DATA InputDataStart, + IN PKEYBOARD_INPUT_DATA InputDataEnd, + IN OUT PULONG InputDataConsumed + ); + +EVT_WDF_REQUEST_COMPLETION_ROUTINE +KbFilterRequestCompletionRoutine; + + +// +// IOCTL Related defintions +// + +// +// Used to identify kbfilter bus. This guid is used as the enumeration string +// for the device id. +DEFINE_GUID(GUID_BUS_KBFILTER, +0xa65c87f9, 0xbe02, 0x4ed9, 0x92, 0xec, 0x1, 0x2d, 0x41, 0x61, 0x69, 0xfa); +// {A65C87F9-BE02-4ed9-92EC-012D416169FA} + +DEFINE_GUID(GUID_DEVINTERFACE_KBFILTER, +0x3fb7299d, 0x6847, 0x4490, 0xb0, 0xc9, 0x99, 0xe0, 0x98, 0x6a, 0xb8, 0x86); +// {3FB7299D-6847-4490-B0C9-99E0986AB886} + + +#define KBFILTR_DEVICE_ID L"{A65C87F9-BE02-4ed9-92EC-012D416169FA}\\KeyboardFilter\0" + + +typedef struct _RPDO_DEVICE_DATA +{ + + ULONG InstanceNo; + + // + // Queue of the parent device we will forward requests to + // + WDFQUEUE ParentQueue; + +} RPDO_DEVICE_DATA, *PRPDO_DEVICE_DATA; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(RPDO_DEVICE_DATA, PdoGetData) + + +NTSTATUS +KbFiltr_CreateRawPdo( + WDFDEVICE Device, + ULONG InstanceNo +); + + + +#endif // KBFILTER_H + diff --git a/Driver/public.h b/Driver/public.h new file mode 100644 index 0000000..d1ebee8 --- /dev/null +++ b/Driver/public.h @@ -0,0 +1,17 @@ +#ifndef _PUBLIC_H +#define _PUBLIC_H + +#define IOCTL_INDEX 0x800 + +#define IOCTL_PS2KBDTGL_TOGGLE_DISCARD CTL_CODE( FILE_DEVICE_KEYBOARD, \ + IOCTL_INDEX, \ + METHOD_BUFFERED, \ + FILE_READ_DATA) + +#define IOCTL_PS2KBDTGL_GET_STATE CTL_CODE( FILE_DEVICE_KEYBOARD, \ + IOCTL_INDEX+1, \ + METHOD_BUFFERED, \ + FILE_READ_DATA) + + +#endif diff --git a/Driver/rawpdo.c b/Driver/rawpdo.c new file mode 100644 index 0000000..5a1848b --- /dev/null +++ b/Driver/rawpdo.c @@ -0,0 +1,376 @@ +/*-- + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + + +Module Name: + + RawPdo.c + +Abstract: This module have the code enumerate a raw PDO for every device + the filter attaches to so that it can provide a direct + sideband communication with the usermode application. + + The toaster filter driver sample demonstrates an alternation + approach where you can create one control-device for all the + instances of the filter device. + +Environment: + + Kernel mode only. + +--*/ + +#include "kbfiltr.h" +#include "public.h" + +VOID +KbFilter_EvtIoDeviceControlForRawPdo( + IN WDFQUEUE Queue, + IN WDFREQUEST Request, + IN size_t OutputBufferLength, + IN size_t InputBufferLength, + IN ULONG IoControlCode + ) +/*++ + +Routine Description: + + This routine is the dispatch routine for device control requests. + +Arguments: + + Queue - Handle to the framework queue object that is associated + with the I/O request. + Request - Handle to a framework request object. + + OutputBufferLength - length of the request's output buffer, + if an output buffer is available. + InputBufferLength - length of the request's input buffer, + if an input buffer is available. + + IoControlCode - the driver-defined or system-defined I/O control code + (IOCTL) that is associated with the request. + +Return Value: + + VOID + +--*/ +{ + NTSTATUS status = STATUS_SUCCESS; + WDFDEVICE parent = WdfIoQueueGetDevice(Queue); + PRPDO_DEVICE_DATA pdoData; + WDF_REQUEST_FORWARD_OPTIONS forwardOptions; + + pdoData = PdoGetData(parent); + + UNREFERENCED_PARAMETER(OutputBufferLength); + UNREFERENCED_PARAMETER(InputBufferLength); + + DebugPrint(("Entered KbFilter_EvtIoDeviceControlForRawPdo\n")); + + // + // Process the ioctl and complete it when you are done. + // Since the queue is configured for serial dispatch, you will + // not receive another ioctl request until you complete this one. + // + + switch (IoControlCode) { + case IOCTL_PS2KBDTGL_TOGGLE_DISCARD: + WDF_REQUEST_FORWARD_OPTIONS_INIT(&forwardOptions); + status = WdfRequestForwardToParentDeviceIoQueue(Request, pdoData->ParentQueue, &forwardOptions); + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + } + break; + case IOCTL_PS2KBDTGL_GET_STATE: + WDF_REQUEST_FORWARD_OPTIONS_INIT(&forwardOptions); + status = WdfRequestForwardToParentDeviceIoQueue(Request, pdoData->ParentQueue, &forwardOptions); + if (!NT_SUCCESS(status)) { + WdfRequestComplete(Request, status); + } + break; + default: + WdfRequestComplete(Request, status); + break; + } + + return; +} + +#define MAX_ID_LEN 128 + +NTSTATUS +KbFiltr_CreateRawPdo( + WDFDEVICE Device, + ULONG InstanceNo + ) +/*++ + +Routine Description: + + This routine creates and initialize a PDO. + +Arguments: + +Return Value: + + NT Status code. + +--*/ +{ + NTSTATUS status; + PWDFDEVICE_INIT pDeviceInit = NULL; + PRPDO_DEVICE_DATA pdoData = NULL; + WDFDEVICE hChild = NULL; + WDF_OBJECT_ATTRIBUTES pdoAttributes; + WDF_DEVICE_PNP_CAPABILITIES pnpCaps; + WDF_IO_QUEUE_CONFIG ioQueueConfig; + WDFQUEUE queue; + WDF_DEVICE_STATE deviceState; + PDEVICE_EXTENSION devExt; + DECLARE_CONST_UNICODE_STRING(deviceId,KBFILTR_DEVICE_ID ); + DECLARE_CONST_UNICODE_STRING(hardwareId,KBFILTR_DEVICE_ID ); + DECLARE_CONST_UNICODE_STRING(deviceLocation,L"Keyboard Filter\0" ); + DECLARE_UNICODE_STRING_SIZE(buffer, MAX_ID_LEN); + + DebugPrint(("Entered KbFiltr_CreateRawPdo\n")); + + // + // Allocate a WDFDEVICE_INIT structure and set the properties + // so that we can create a device object for the child. + // + pDeviceInit = WdfPdoInitAllocate(Device); + + if (pDeviceInit == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto Cleanup; + } + + // + // Mark the device RAW so that the child device can be started + // and accessed without requiring a function driver. Since we are + // creating a RAW PDO, we must provide a class guid. + // + status = WdfPdoInitAssignRawDevice(pDeviceInit, &GUID_DEVCLASS_KEYBOARD); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // Since keyboard is secure device, we must protect ourselves from random + // users sending ioctls and creating trouble. + // + status = WdfDeviceInitAssignSDDLString(pDeviceInit, + &SDDL_DEVOBJ_SYS_ALL_ADM_ALL); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // Assign DeviceID - This will be reported to IRP_MN_QUERY_ID/BusQueryDeviceID + // + status = WdfPdoInitAssignDeviceID(pDeviceInit, &deviceId); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // For RAW PDO, there is no need to provide BusQueryHardwareIDs + // and BusQueryCompatibleIDs IDs unless we are running on + // Windows 2000. + // + if (!RtlIsNtDdiVersionAvailable(NTDDI_WINXP)) { + // + // On Win2K, we must provide a HWID for the device to get enumerated. + // Since we are providing a HWID, we will have to provide a NULL inf + // to avoid the "found new device" popup and get the device installed + // silently. + // + status = WdfPdoInitAddHardwareID(pDeviceInit, &hardwareId); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + } + + // + // We could be enumerating more than one children if the filter attaches + // to multiple instances of keyboard, so we must provide a + // BusQueryInstanceID. If we don't, system will throw CA bugcheck. + // + status = RtlUnicodeStringPrintf(&buffer, L"%02d", InstanceNo); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + status = WdfPdoInitAssignInstanceID(pDeviceInit, &buffer); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // Provide a description about the device. This text is usually read from + // the device. In the case of USB device, this text comes from the string + // descriptor. This text is displayed momentarily by the PnP manager while + // it's looking for a matching INF. If it finds one, it uses the Device + // Description from the INF file to display in the device manager. + // Since our device is raw device and we don't provide any hardware ID + // to match with an INF, this text will be displayed in the device manager. + // + status = RtlUnicodeStringPrintf(&buffer,L"Keyboard_Filter_%02d", InstanceNo ); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // You can call WdfPdoInitAddDeviceText multiple times, adding device + // text for multiple locales. When the system displays the text, it + // chooses the text that matches the current locale, if available. + // Otherwise it will use the string for the default locale. + // The driver can specify the driver's default locale by calling + // WdfPdoInitSetDefaultLocale. + // + status = WdfPdoInitAddDeviceText(pDeviceInit, + &buffer, + &deviceLocation, + 0x409 + ); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + WdfPdoInitSetDefaultLocale(pDeviceInit, 0x409); + + // + // Initialize the attributes to specify the size of PDO device extension. + // All the state information private to the PDO will be tracked here. + // + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&pdoAttributes, RPDO_DEVICE_DATA); + + // + // Set up our queue to allow forwarding of requests to the parent + // This is done so that the cached Keyboard Attributes can be retrieved + // + WdfPdoInitAllowForwardingRequestToParent(pDeviceInit); + + status = WdfDeviceCreate(&pDeviceInit, &pdoAttributes, &hChild); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // Get the device context. + // + pdoData = PdoGetData(hChild); + + pdoData->InstanceNo = InstanceNo; + + // + // Get the parent queue we will be forwarding to + // + devExt = FilterGetData(Device); + pdoData->ParentQueue = devExt->rawPdoQueue; + + // + // Configure the default queue associated with the control device object + // to be Serial so that request passed to EvtIoDeviceControl are serialized. + // A default queue gets all the requests that are not + // configure-fowarded using WdfDeviceConfigureRequestDispatching. + // + + WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE(&ioQueueConfig, + WdfIoQueueDispatchSequential); + + ioQueueConfig.EvtIoDeviceControl = KbFilter_EvtIoDeviceControlForRawPdo; + + status = WdfIoQueueCreate(hChild, + &ioQueueConfig, + WDF_NO_OBJECT_ATTRIBUTES, + &queue // pointer to default queue + ); + if (!NT_SUCCESS(status)) { + DebugPrint( ("WdfIoQueueCreate failed 0x%x\n", status)); + goto Cleanup; + } + + // + // Set some properties for the child device. + // + WDF_DEVICE_PNP_CAPABILITIES_INIT(&pnpCaps); + + pnpCaps.Removable = WdfTrue; + pnpCaps.SurpriseRemovalOK = WdfTrue; + pnpCaps.NoDisplayInUI = WdfTrue; + + pnpCaps.Address = InstanceNo; + pnpCaps.UINumber = InstanceNo; + + WdfDeviceSetPnpCapabilities(hChild, &pnpCaps); + + // + // TODO: In addition to setting NoDisplayInUI in DeviceCaps, we + // have to do the following to hide the device. Following call + // tells the framework to report the device state in + // IRP_MN_QUERY_DEVICE_STATE request. + // + WDF_DEVICE_STATE_INIT(&deviceState); + deviceState.DontDisplayInUI = WdfTrue; + WdfDeviceSetDeviceState(hChild, &deviceState); + + // + // Tell the Framework that this device will need an interface so that + // application can find our device and talk to it. + // + status = WdfDeviceCreateDeviceInterface( + hChild, + &GUID_DEVINTERFACE_KBFILTER, + NULL + ); + + if (!NT_SUCCESS (status)) { + DebugPrint( ("WdfDeviceCreateDeviceInterface failed 0x%x\n", status)); + goto Cleanup; + } + + // + // Add this device to the FDO's collection of children. + // After the child device is added to the static collection successfully, + // driver must call WdfPdoMarkMissing to get the device deleted. It + // shouldn't delete the child device directly by calling WdfObjectDelete. + // + status = WdfFdoAddStaticChild(Device, hChild); + if (!NT_SUCCESS(status)) { + goto Cleanup; + } + + // + // pDeviceInit will be freed by WDF. + // + return STATUS_SUCCESS; + +Cleanup: + + DebugPrint(("KbFiltr_CreatePdo failed %x\n", status)); + + // + // Call WdfDeviceInitFree if you encounter an error while initializing + // a new framework device object. If you call WdfDeviceInitFree, + // do not call WdfDeviceCreate. + // + if (pDeviceInit != NULL) { + WdfDeviceInitFree(pDeviceInit); + } + + if(hChild) { + WdfObjectDelete(hChild); + } + + return status; +} + diff --git a/Switch/cmd.c b/Switch/cmd.c new file mode 100644 index 0000000..085391f --- /dev/null +++ b/Switch/cmd.c @@ -0,0 +1,76 @@ +/*++ + +Copyright (c) Microsoft Corporation. All rights reserved. + + THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR + PURPOSE. + +Module Name: + + KBFTEST.C + +Abstract: + + +Environment: + + usermode console application + +--*/ + +#include +#include + + + +typedef struct { + wchar_t* requested_device; + int index; +} context; + +void display_device(const wchar_t* device, void* data){ + context* ctx = (context*) data; + + printf("%3d: %5s %s\n", ++(ctx->index), (isDeviceEnable(device)==1?"ON":"OFF"), device); + + if (ctx->requested_device == NULL || wcslen(ctx->requested_device) == 0 || wcscmp(device, ctx->requested_device) == 0){ + toggleDevice(device); + } +} + +int +_cdecl +main( + int argc, + char *argv[] + ) +{ + + wchar_t* providedDeviceId = NULL; + + if (argc > 1 && strlen(argv[1])>0){ + size_t devSize = strlen(argv[1]) + 1; + providedDeviceId = malloc(sizeof(WCHAR) * (devSize)); + if (mbstowcs(providedDeviceId, argv[1], devSize) == -1){ + free(providedDeviceId); + providedDeviceId = NULL; + } + } + + context ctx; + ctx.index = 0; + ctx.requested_device = providedDeviceId; + + printf("\nPS2KeyboardToggler : Switch PS2 Keyboard bypass state\n"); + printf("-------------------------------------------------------\n"); + printf("Device list:\n"); + printf("Index: DeviceId\n"); + + int i = 0; + + foreachDevice(display_device, (void*) &ctx); + + return 0; +} diff --git a/Tray/KeybitorTray.rc b/Tray/KeybitorTray.rc new file mode 100644 index 0000000000000000000000000000000000000000..9928672d73483d465f48fb6b2d403f02a0a4a524 GIT binary patch literal 4206 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 MToKncS06tA52p_O{r~^~ literal 0 HcmV?d00001 diff --git a/Tray/PS2KeyboardTogglerTray_Off.ico b/Tray/PS2KeyboardTogglerTray_Off.ico new file mode 100644 index 0000000000000000000000000000000000000000..c3bf95ba1f9338ca84cea2a807bc15cd9ce5cf8a GIT binary patch literal 107549 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 WpL4iI(*A0>9Zd;ULC$pmi1$A + +// C RunTime Header Files +#include +#include +#include +#include + + +// TODO: reference additional headers your program requires here diff --git a/Tray/targetver.h b/Tray/targetver.h new file mode 100644 index 0000000..87c0086 --- /dev/null +++ b/Tray/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/Tray/tray.cpp b/Tray/tray.cpp new file mode 100644 index 0000000..136ec90 --- /dev/null +++ b/Tray/tray.cpp @@ -0,0 +1,361 @@ +// PS2KeyboardTogglerTray.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "tray.h" + +#include +#include + +#include "Keybitor.h" + +#define MAX_LOADSTRING 100 +#define MY_TRAY_ICON_ID 1<<3; +#define MY_TRAY_ICON_MESSAGE WM_APP+1 +#define CTX_MENU_QUIT 1 +#define CTX_MENU_TOGGLE 2 +#define CTX_MENU_CONFIG 3 + +// Global Variables: +HINSTANCE hInst; // current instance +TCHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name + +HWND hWndMain; +NOTIFYICONDATA niData; +HMENU hwndMenu; +HICON iconOn; +HICON iconOff; + +// Forward declarations of functions included in this code module: +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); + +void toggleDevices(); +void updateIcon(); +void ShowContextMenu(); +void launchConfigApp(); + +int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, + _In_opt_ HINSTANCE hPrevInstance, + _In_ LPTSTR lpCmdLine, + _In_ int nCmdShow) +{ + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + + // TODO: Place code here. + MSG msg; + + // Initialize global strings + LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + LoadString(hInstance, IDC_PS2KEYBOARDTOGGLERTRAY, szWindowClass, MAX_LOADSTRING); + MyRegisterClass(hInstance); + + // Perform application initialization: + if (!InitInstance (hInstance, nCmdShow)) + { + return FALSE; + } + + // Main message loop: + while (GetMessage(&msg, NULL, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + return (int) msg.wParam; +} + + + +// +// FUNCTION: MyRegisterClass() +// +// PURPOSE: Registers the window class. +// +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_PS2KEYBOARDTOGGLERTRAY)); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = MAKEINTRESOURCE(IDC_PS2KEYBOARDTOGGLERTRAY); + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); + + return RegisterClassEx(&wcex); +} + +// +// FUNCTION: InitInstance(HINSTANCE, int) +// +// PURPOSE: Saves instance handle and creates main window +// +// COMMENTS: +// +// In this function, we save the instance handle in a global variable and +// create and display the main program window. +// +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + + + hInst = hInstance; // Store instance handle in our global variable + + hWndMain = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); + + if (!hWndMain) + { + return FALSE; + } + + iconOn = (HICON) LoadImage(hInstance, + MAKEINTRESOURCE(IDI_PS2KEYBOARDTOGGLERTRAY), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + iconOff = (HICON) LoadImage(hInstance, + MAKEINTRESOURCE(IDI_PS2KEYBOARDTOGGLERTRAYOFF), + IMAGE_ICON, + GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + LR_DEFAULTCOLOR); + + /* + notify_icon example code courtesy of Abraxas23: + https://www.codeproject.com/Articles/4768/Basic-use-of-Shell-NotifyIcon-in-Win32 + */ + + + + // zero the structure - note: Some Windows funtions + // require this but I can't be bothered to remember + // which ones do and which ones don't. + + + + ZeroMemory(&niData, sizeof(NOTIFYICONDATA)); + + niData.cbSize = sizeof(NOTIFYICONDATA); + + + // the ID number can be any UINT you choose and will + // be used to identify your icon in later calls to + // Shell_NotifyIcon + + + niData.uID = MY_TRAY_ICON_ID; + + + // state which structure members are valid + // here you can also choose the style of tooltip + // window if any - specifying a balloon window: + // NIF_INFO is a little more complicated + + + niData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; + + + // load the icon note: you should destroy the icon + // after the call to Shell_NotifyIcon + + + niData.hIcon = iconOn; + + // set the window you want to recieve event messages + + + niData.hWnd = hWndMain; + + + // set the message to send + // note: the message value should be in the + // range of WM_APP through 0xBFFF + + + niData.uCallbackMessage = MY_TRAY_ICON_MESSAGE; + + // NIM_ADD adds a new tray icon + Shell_NotifyIcon(NIM_ADD, &niData); + + updateIcon(); + + hwndMenu = CreatePopupMenu(); + InsertMenu(hwndMenu, 3, MF_BYPOSITION|MF_STRING, CTX_MENU_QUIT, L"Quit"); + InsertMenu(hwndMenu, 2, MF_STRING, CTX_MENU_TOGGLE, L"Toggle"); + InsertMenu(hwndMenu, 1, MF_STRING, CTX_MENU_CONFIG, L"Config"); + + //ShowWindow(hWndMain, nCmdShow); + UpdateWindow(hWndMain); + + return TRUE; +} + +// +// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM) +// +// PURPOSE: Processes messages for the main window. +// +// WM_COMMAND - process the application menu +// WM_PAINT - Paint the main window +// WM_DESTROY - post a quit message and return +// +// +LRESULT CALLBACK WndProc(HWND hWndMain, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + PAINTSTRUCT ps; + HDC hdc; + + switch (message) + { + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case CTX_MENU_QUIT: + Shell_NotifyIcon(NIM_DELETE, &niData); + PostMessage(hWndMain, WM_QUIT, 0, 0); + break; + case CTX_MENU_CONFIG: + launchConfigApp(); + break; + case CTX_MENU_TOGGLE: + toggleDevices(); + break; + default: + return DefWindowProc(hWndMain, message, wParam, lParam); + } + break; + case MY_TRAY_ICON_MESSAGE: + switch (lParam){ + case WM_LBUTTONDBLCLK: + toggleDevices(); + break; + case WM_RBUTTONDOWN: + ShowContextMenu(); + break; + } + break; + case WM_PAINT: + hdc = BeginPaint(hWndMain, &ps); + // TODO: Add any drawing code here... + EndPaint(hWndMain, &ps); + break; + case WM_DESTROY: + Shell_NotifyIcon(NIM_DELETE, &niData); + PostQuitMessage(0); + break; + default: + return DefWindowProc(hWndMain, message, wParam, lParam); + } + return 0; +} + + +void toggleDeviceInternal(const wchar_t* device, void* data){ + UNREFERENCED_PARAMETER(data); + + toggleDevice(device); +} + +void toggleDevices(){ + foreachDevice(toggleDeviceInternal, NULL); + updateIcon(); +} + + +void checkDeviceToggledOff(const wchar_t* dev, void* data){ + bool& flag = *((bool*) data); + flag |= !isDeviceEnable(dev); +} + +bool checkDevicesToggledOff(){ + bool toggledOff = false; + foreachDevice(checkDeviceToggledOff, (void*) &toggledOff); + return toggledOff; +} + +void updateIcon(){ + if (checkDevicesToggledOff()){ + niData.hIcon = iconOff; + bool res = Shell_NotifyIcon(NIM_MODIFY, &niData); + } + else { + niData.hIcon = iconOn; + Shell_NotifyIcon(NIM_MODIFY, &niData); + } + UpdateWindow(hWndMain); +} + +void ShowContextMenu(){ + SetForegroundWindow(hWndMain); + NOTIFYICONIDENTIFIER iconId; + iconId.cbSize = sizeof(NOTIFYICONIDENTIFIER); + iconId.hWnd = hWndMain; + iconId.uID = MY_TRAY_ICON_ID; + iconId.guidItem = GUID_NULL; + RECT iconPosition; + HRESULT res = Shell_NotifyIconGetRect(&iconId, &iconPosition); + TrackPopupMenu(hwndMenu, TPM_CENTERALIGN | TPM_BOTTOMALIGN | TPM_LEFTBUTTON | TPM_NOANIMATION, iconPosition.left, iconPosition.top, 0, hWndMain, NULL); + Shell_NotifyIcon(NIM_SETFOCUS, &niData); +} + +const wchar_t ConfigAppName[] = L"KeybitorConfig.exe"; + +void launchConfigApp(){ + TCHAR appFileName[MAX_PATH + 1]; + + if (GetModuleFileName(NULL, appFileName, MAX_PATH + 1) > (MAX_PATH + 1)){ + return; + } + + DWORD pathSize = MAX_PATH + sizeof(ConfigAppName); + TCHAR* appPath = NULL; + LPWSTR filePart = NULL; + DWORD written = 0; + + appPath = (PTCHAR) malloc(pathSize * sizeof(TCHAR)); + memset(appPath, '\0', pathSize * sizeof(TCHAR)); + written = GetFullPathName(appFileName, pathSize, appPath, &filePart); + if (written > pathSize){ + free(appPath); + pathSize = written + sizeof(ConfigAppName) + 2; + appPath = (PTCHAR) malloc(pathSize * sizeof(TCHAR)); + memset(appPath, '\0', pathSize * sizeof(TCHAR)); + written = GetFullPathName(appFileName, pathSize - 2, appPath, &filePart); + } + + memset(filePart, 0, wcslen(filePart)); + memcpy(filePart, ConfigAppName, sizeof(ConfigAppName)); + STARTUPINFO startupInfo; + ZeroMemory(&startupInfo, sizeof(STARTUPINFO)); + startupInfo.cb = sizeof(STARTUPINFO); + PROCESS_INFORMATION procInfo; + if (CreateProcess(appPath, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &procInfo) == 0){ + LPWSTR messageBuffer = nullptr; + size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) &messageBuffer, 0, NULL); + + MessageBox(hWndMain, messageBuffer, L"Error", MB_OK); + + LocalFree(messageBuffer); + } + +} \ No newline at end of file diff --git a/Tray/tray.h b/Tray/tray.h new file mode 100644 index 0000000..d00d47e --- /dev/null +++ b/Tray/tray.h @@ -0,0 +1,3 @@ +#pragma once + +#include "resource.h" diff --git a/res/icon.ico b/res/icon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e1f0a8dbe6b7245c63a445b5eb250933584ce8c1 GIT binary patch literal 102229 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 MToKncS06tA52p_O{r~^~ literal 0 HcmV?d00001 diff --git a/res/icon_off.ico b/res/icon_off.ico new file mode 100644 index 0000000000000000000000000000000000000000..c3bf95ba1f9338ca84cea2a807bc15cd9ce5cf8a GIT binary patch literal 107549 zcmeHQ2Rv2nA3xV7BeJs7Akk7Hg-Sz%QoSugkp@vpWT&JQmC{C2OOdv$6t5Jew~#`q zG|0$a&;R$h-CWnWD*uws^Z9)5bIv`__^oH0XB~o|5F7+{6he-;BtsC(;M(1tdauYu zAw*;eLPzK8{dj^Ht3V-!4yE3o=}!?Tp z`f(jywo`(-!RN$%l+L{3t!*fgdd>FCO7G=Z9%keqx zS&h#a;V9YpeCBs9p756P^30Q}iyfCaYkHaVXNAICYt9K*col_a@lVopP>eL+U-n;> zYNkbek-DP2**rsCt@4BA^-25CBAvBD+&Ta5~M?5X~Pg`siVK+;ktE&~ipwu^6YD{79^E`8thn5Mo^+)+jx9M(;u#WP) zY?FVG|Kk|n%H$(&%WDHX`SrJM)IHuu^O>K<`&YU4oXKPDD`#i+xf{Vhm^bpGd?|b8 z!3O@!>ka&={w{C%T`weQ?dDqh=y9C7C8te=lTn_*==pgC7j#ljOBKl~-{`3>qb~T~ z*S^;_=Tl#TU-o!Z>nv`_hP+Reth}OhCWmlp;96wj@#=8yDo(k#AHtvLXxJ}(#1X8u z+okw%?3CO&!IC_L{ML~y;yns$ChQkqmk=K(xz+gnbry%-OZ+D6-+17Coz_N)GekCf zHX+(CY!uqy5%H*G-0pZK!uMWU+2TzWnZ?7TgW?vx9TXdM%vNjNJ=a6`6$^$x4y6>c z4V7{F;`48xyWtNcv^g#&EQG}))*?nqG^@cvD>zP!r)VHqQDk1~6S z)B^91bst%E*kfd@)&;-p>3d=W*`8HhJwN45&l<`+GoNDQ9+MEm=g_OFSHPvnL(5V# zj}oKV-SZtecGu10D&xG!7ER%edon^hOwd8vfpUQJzs>VgkL1*C*|LRgoK8<&OR?j2 zzH^i&j(%yIIFO5FNw_#W`(ud@>iPeg4?k%*@W?84(ZswpuS?X!=U*AFWih;W+J|*1 zZa%v5ahjlmqN?|Bhgu35cJCy%3iSvu@ACuLgrb(`?S{0%9u zj+}^&)(T0@7bYMFRu10a;9xmJx3K90CQO{juDRi}RdGa#!x3L;&9n&1r8WynlQkyK zohy=c-A3WybhWDLio&cXH|;E+UnzOoyZprI(_Y4r_Td|fvN^O5PwDqQGeV&->$)FM z6YN}TuYci!`AVgGBmCYjb3ZhHN6xxW37hz(GbH^+>D^kKFO_7zhfh*%SJH?vXO`P? z^(3UHO?9yQV0deNk<8gq%a!)M&fk!o#2QmQ!!xMxd8p)mgM)XDY9q%Czj_Ub8WUY1 zf$VDwol8p+`CJ>$t-AQiOVY;teVCbSCBCbBnGO|TeC*r_>5Y(c>jqL*A<9|hVlbp6@||q zt8uM8H(AfDkMz{3^7H)o`}f}~Ec$NF)@$Q*YV8Y;e{q=_a_l&ZYyB$yg;%%B9V|<) zaw^}nt=FrxY201{A=V-KGZyXx0*q(yZ5gMt!)u<%T1l1>ANr2cS5BPTPu|FnSY(-U zN@mz`N6`^-l`#{?OkIEGqSuVWxi|B34_Ypdv6g)EXnjgjZk+9_Ew+y*7MEXIWDtDt zO^tDSY0#C$bLSQ})DGP+_=TMxyQkEEC6aUIuo>TqJ+=SN^=Nih&hcXoMSc7e$MWQuc{+R5sU!7lQVDk|zndP#?RQCIZ^Ey~m(27fgySm0VxJy5ET9 z$?3R%cblb;P~aibHvX3$f6dw!)fbm07bhv~DqWX$&C=jT!^Q(cDf(kYc)s+VeVxVq z3V&@yoKsPpNyCy}u36V>SJX|MsP;sAy^@jhup_oCS5}GHTicx`)KFLVu!52^%qMb>I9D#XiBjYE2>3@c;z&RzDvDs=B}{%k=%=Y^MoSn z?Wer4oP9qvM0AC>-L(sqJ|?k!{W2!W8holPkL|0Ix+d>{Lzea3(kmsNK#*>Exmvc{ z$AJfivDz1wrd2)3I9P9DHrY`jVTohq7#M+dmNhC?Bxq=D@R@a*y{X#r7DIVV?8pQthJGK8dfcJjuO3=v8U* zs{>1wk4+wQoRE9GFDYY@Yt6bIMDqUlXQ8h52M_d^bwb%Pr>Z32+IbN}V%PGi0}3-f zpPO5pgRJu!TxumuRx2;t>Go#Ijf#cp`BLv6_bqttHHo5gT;b?7)-fOe1J@-hBAvbO z1>eXRUQt&TV*7fVVrKyK4lQjPcz5H<5 z*#eGydF@lU)^~T`P%$|-FoIX-E^Sp=q->pj!tc(VEv{+n6ok|=H&kQ>gl@RY_5PVk z!ShMJEbf~X_FX>MuplD$*jCe*qqW~AUXbt-d`@`%k8p>dZ_S+6g+`2G-TtRid*_UOSnfb{#*4VyWf9+<7OKsSB z2}dY~RxH8VL+x|4YElnPEU2%v=8sJ@H<`6Ns$9X~+F=K$vPaY1_=Sm+3;Ma|h3g*b zwQALe+iOn+ZR){ewbte?SERp9Rq?VYFU=ev#ovc@tb4M@wpi|H9{qm7tL81ri>bHQ z%;-B=m!flM4&{+p)euvz-1T#`Y~@}!s~Xwu1TvRsu)D7t5dVBb&MB)bH6eC(Gwm-S zsr#mepSYkLk~+X&Pw9U0g8CFqGwq7}lY8{kT&wz&YXn;7M6D8&y|8F<&v4aG;3s}I zj?}6wxer)x>Jzt!jaczIB=l0UIdy>rcgI>=1Cm|=> zajV1T)f`j%`xj(i^;zdDcI-{roAUMR>pn-?-dq29n-Og8Ft&wK7iSfflK4KB6 z`D^_{Mi*Q-^KbRdY~!1IqMRxog)dDEldZQ?8Z;=g^x!mgeYONbjKwo7P-kh327hu= z4BLSSM^(;cDg8#;1g0lNm#<2{teyCUGg)-VveeHncdzQTe*OCY@(-x?3HH$Bf2}i2 z=EU_Y%h%-2F*T~NRCi6&KNZe)bXxfIs4sUeF2DPfa&^R!Me8 z!q9zWgAM%a8O9x(FqQR_$0+xC9_%`+dn{Z#LYR2t&88z6JjzyDlyFv_GWxYxPs89`mE6@A zYKuNZ%O;KUl=SdjkrU|8$@jYUdbUJGglp0{kwNpzp0B##Qu&fYThr<;*VM^7U;k$o zf5){T_3Zicd5?4IeL=j2i)KH`%}1bdGk~^R9J!8n(0%5(VE0HDODxB($F@`*ydKOl|c}9XCRo!Mm??dx`vg3-B zBS*AyifzVldEZ;oPkvqQt6+yQfnT%=J{_@;y6{DY?k`48=3V9&yF(tIA@d3VEOks+Cta=8z8jph`<7NL2I#X4t3tq29Gyx z+~#X8w0L7u+Pc)BqRthbVPS8Rw|+!ZGCS2UNAxW?~WB zVil#=M;Av`#q=6*rev}^i@Wo=(+Me0QGsRgyTf5Fk>zY-9Apo0D{s5E{O}aT85?vJ z3Gd9Cy|P`z-aYUTGr2N7N@no;Gn{I~lklT1S)T5*`vyEXIdV3!yzofGs+$2So(EM6 z$EQg7>p5G5XS_Q4F!oDqo{ot9%9+O}P=c=}n?pw@w}Lt^>PbLUJSN-TQ4C@gmM>++%524-6w zWe8DAq#D;;8^7PQ;7*mg!gq+iSWraPo>-y}F;T!98CvdD;`aiy#AhEfNSLfAb zMwq=C@0RQgow-NHhOUt}a_F<}Gw&MNOrk$851}$c$s&2%4uNE%&xKx1h+e+i z`g7(LZhood&Ns&qFC(F;`KY8`Y4rYm-baCL^6c);dy_J*WjlV!_0_bxoSObFa1#r3 zLY`F_s8i$v$_(q$Oh(B*JZu?Kz3f5psAO5Tp|)~HZe#0eW40PkSTTTyaFma2m~R=n zct&OaX{L$%Znf1uK82y$7Cbx39bfI&J<6gZqezTq_4g2zbDSKN+)e^G?>)ER&YR6E4Hk8ZV(Bc~G5m$k zGv}i_J*;o%Jj`+*UwVK=NB0WFmo8g8Km>4g*!PnouAXnk6a1`azyk!9a3$LU5 zgRCR`{uNUsHm}H1)x^y9~;QnMF*vN^5Ib>WqX-A?IzmD1t5tDjBXY1~%r)+Op&9LVedt5X-WqoY4!7MAWv+E8$5VR7s8A|;3^l5mZzk$Q* znzFD@75&fub0PRR?oh1Gy1eCH4>3b{XMO&KBO@hxcG`+tDvKs%vG*`7TsUNBjA(`g zo0WIsS*3w-*3UO*T|Slh@mlo>zl^%allfc+@6(Ssaa?{+P6#v>hO-t2KC#@ecYlO) z$&$2(J&pYCLMs8y$AEmfo{wVt4_;F+?YzEu9$Ut;z&sB(R(;M}8CC`YPk#a zwN||R7`A`>gjafY#KV(p;yaA@zvKgpx1k_`$X!pKSeT?uRU}4uj*G31ofFLY?0o4l z9tV*doKBz8y^LoiY4Q*=6upkV))WwDElV`WGhjumw>fSTR&0CTkJr~&3y*V6OMMM< zC1Vw>_6G^9k6n17B$e{d7UKm;t9XdOd+yif&qJc7in)DHosQ2gmGsc2*m;DS&HJY` zkj33n+9SeUcIj3}XFZlrVZo(+a{Hi5-Yo703QI$(2C$AD8xScnpQ}ztF+QMP*LfyU z{6@K8XzD?oA$4_2q>BfuJwal*y(AW=i)aY(5If=B9fn_?W=wahEQqmD-alogOPXH6 zhv)lh)U4lcx8Pbi!|<%|)46k%O>V2_tK_UT7bbiSc_oX2c&4)scpdVpm(RFaf(IMw z&)%+Cd5cf_KD%+`+Hn~o{Ba)jwV5}}Sd;fFm)MnTbKb@hJL{u&|Iarl>W?kspnBQW z=dP^N4y{C4fh~ pXXJf|eIO*g*w>Dw~{38^h{u^T)dJ50}}3|+pi2G&nDDa3d80YBNpEHiZZ8K_CVLsM)tj@A0S+6l@?tZ(ZeNqZBJ91nkQjW_4!K_ z`bmy`C&2RQbZXVLtCvsFp z`@rGsHD%n9=hC(V>370owN0lvhfoSj)_G}*Mo2o?+@MVIy|VY^p#uM&AF?Xhqr%r2 z_Xk7|VXmLaB^^d!BZf`y#-W~Vy7NLx#+EKf{-1@Xm zW2>$g3-PR~her`1W_r-+_Q1hjK0{#OSf5^2Vf*FLh26|xQ;O!RZt%1}mEGkVun$lQNunz=E6 zNHuk=9X@g5^Jjy0KRf3|Q0&Jg^2L@{={<9tDdZsGz@Pm3#IhmP!B5%T<*l^Q!&r@~ z$RmBZ3n;7EvRRelFP`~VaJdL2xW~0?+Jae``R7ZD*c&*;@LZr&oVY8p$7JC;!kg74 zJi$%oT1ZZ!gRJtne8XIk+)J_1VS@&(6<%mXDBejaHn^Km8x_W?rDeswIPv1!g`4?U zbxUXY@DVS=Euw==$5KoV+ei;(J^VJu`&QkaoP|b&;@yUrl>dx3>(=-xY9TA}|mux~0wGi=b!z_^QVF7}ALEFbuGJ>hMpP(7H^(EAg2 z)vmbgGB?U+j&qO9gRV?>lq6nflx7RZT26h~uXsQ)SFvHnKH(Kh9L0zwI*W4ctuEWR zCtj{x(#ypzOxjgm#dtA0C|W1i+3NBoG1pu5D++1zbd zayU3%6&;C+=Pw{c`rrC*E%lN+=3jjaXxyO~z?=T}=u za?9_Jz84m_Wuw^SqTHe(TUbLY=qxX{o4aeC$QIdkWRU%GWjLU@Yb9IqFfbaZrGuO}{9;3RXmqO$hE zac$Nr>9Aez#wLxj&DGiN7*t51eH7=kkC1LQV;$uAXcZL=kB&OMK`***( zoQP?!*GG%@t9}`DFML=-Pb(uWE*SJ*={`4hLPnO`2D>>^`f2y~7`w(QDN3y2`Kx)O z51g(Qm@hA2a{b*Y_k*$4^J^}?lPU6fbI>^Uwt5&vo%_94PF8r#N#SWPN{oY58?KeF zW|3iS5D4SzUm(0fr+*l4)e4p#M9jU7sUb@|VzZQth<Mtk(L+OUIj;b_K>=;Ze~%eW0js}Mv>_; zPwtcfLnro|Dpj_@HqtXRP@*9&$e90~`ujKX8xQE6oNG5UB`!#MujUj-t2#G3+Yryi z{7ZIc#4F3^%Gu6*ZMxl4Oxh~hKHX(R-AT_({?+!jdsZdPm?ob_aIWEWkv0k}43sS% zlkJugH#fy(B_UYSM>8`$F>Vg0jYGlbkjr`X7W`fsSvrdHvt9=WdDb2>y?p6GoPTC1 zrbu|Sc%JEQ&zFG;wE^l?`wNCIF{0@78!xra&NkdLU8p-rP&c>*bATaD)lR`YUtN;&7m)fK3}OgGON!0C2hzd}UA`jf~u z--691;hsh2>3OO$3bkq)4*$lz5BoGwers;Q%+#KoHcm1{`!%XO2Gr`xD@VSl{8W&3 z#Lvs*Fy8>Q_vp<3%!8)rN+}(i#H-GyyNdj9B zvD#+z@1q*#WyEs@Z6E#*tDVPwk5e8mQ&i*~bEi?{YCr0ajx-(RHRIz^Z{z$8#h+t0 z21_h@=frWi*l9>uZXbEa*MlNIrUbC~aSpI_tFb_{d)x2NE%Mms@$!L+{13Ra?e%WQ z#@u|oBhy<0CZY+wiTb)1$D3|agll*F2h39AX>6*a5b^v(BfkDYdZYwM36K&XB|u7m zlmICKQUas|NC}VP%-sga4q;B0gO6lysv~XrvMUwzglwLi+RKW`kVuJ55V<3quv?suRxfA z09bKMy6z(ZqzXE{(*gZsdw2<$1R%$Xx{U$g^4vHsd=dOA0AsnQzsL0i9yc}z^yoGs zAQ=G(AVI)(05coF_JGF`{Q%I0kgkhMfCcE21&jo!wGTNhf;iz%5Jk+!iLed8J7hi7 z8NQR-Pm@`m9~b3LF2z|00}AaC`c4kt70A@B&4`Jc}BLO`C9nZ(i%o3H9 zl%UGW$}R~^8>aDlc>1+rv2K}_HBJa4^aH?US`Y9TfOXuS9pL8~faw5HK*#bkH@87m zRn@4gI!qg;v7`L_`fymc|1bU1bT|m|xD4n>zYzBcHUO~g(Bil4llpI4HXV^4LHr8+ zV;b?h!45!2`h{O0-0rV&+UJkdfBW)bZUetc|Cml(uR8;Z0PVE}_!;gOo&^j9w9O-_ z|F&h*p4^(A{Yw2~T6+Pe0iFSvjTK=#cn+8VXuUlk_5Y{oAJdC8`;BwBaF2FWm z3J?P{=aEZe@s8F*DV1b0L*Lvw-co`u|zI z)5phSMcV*nfcEPGZf=AuEPlTYkou?BUuRt7K7kS7HB%d4WkpC`y$o&H5{Y*1-1l3s zZQE`%YScuawKI7Cf27eB-~T$orvb<`4bXnSkXlbXf^gFTt zTLo|h(2=pCVhFbqfZr>BR%YEP{-3OWtcSjU0{}cf*nXdYAg~SW0`viNCmsF_FMqoJ zG4GN9TR=zFmeoPH^8iJ_&&aL2#AUAko;^j8q2c0A!NiG%s7DXnk8dtNB_)lYOy3mE zniY)t_hPHy{m-YDmBR_2ziIP)@D^ zMMTu2>gw<3ZQs5lEqLhHPxYsHpvgHe?=6y-Zz-pB>s&i6kIR>@BQ~}k9nybijijWf zXM+A!TgcASb4O=ofes(Oia0nfLLS%-+V2wx3L@m?g< ze)~4RRsFAD@77MN?|T#xakE?M|M>AUh?7$R^y2|2VQK@gJqxW`h0wcq9hV=e|BlOw zKIE?`|5W|s_dF4RHQ*yt8^G{>af0p)X%r=Z4gO>vCcC@9)$<)>(NuLjL{;&I({|0~{O( zEnJAuix(}qBK6-=CLQ_bck3V12tyetG!!8j8Rj;C=MYDaZrLv+_1_U~w+z!2^iQKI zI~$>~V-dnSX4WUb^~ISp2-Ve5W0U%)N%8yquB3lVc}@;O#>NQ73z*x0xHv+7eh8J7 zAw=r``}9r=-PQDu>B4;iH#Y?1?aXZe*A+H42zhvr<9{@revjW3^^fVVh9hK7oIt2g zALcfI-yb9;Goj7E=M~}c1?u|+IsVJs61uAXG3B^zPe?#8KY?IgjF}zav7}T0UfV^r z0aE{ew*G0<<37QhIS8?^FtY*t9G_RT79a|9&*c0MO@?jxUAg?z)104=(CXD4>l0Ad z9&JYb`svaq@l)62{NIm@uW9~=+Ah=DXWVE19*6q`+qWZx_Y*LCKg4HUii^ji4kb*1$mf5!T+rnOTeMvRBHyX9JMyk_f1*0JF=V*UFs2mL<) zn`(bu5w0it_N{`sc)j^`zz{%J z(mRb7QvW}u7u>(l1K>VE`~5=dx}&EMZVrGZ_pahI*FRn(jMwLO#vV!^AAeYPJ+y@! z1`HV4Dd}Sx?d{zWH@8HKJPZv@IxP>J7FCy;;NJ$|a?Z>S-a)_a1lqc_V|!7tOc?D2 z%MQ!1GjxG<+L86&oSb~<^XHy{iDkm5e=IvJ!_IJ6r&zbl_J5H2Zz=8O`p0#- zG`w>7~)}>tA2~scktQUmvt%M^1;<72$ef!UTl= z`>$=jNd31hoA#dkF8$*+=h?I8=<#E!Zkdf2;^%l>(bcO6)zq})h}3^enRMiz->H9` zH+Fe>2*&;p>_cn6KY;52ysl{9J_O${YR(<0|K{@O=v`OPKc*Ev{RHcT5PbiOxeeex z!HN|K714FGN&R{&pq( zW7_eVq}Q(_G;knu8^C>n;lmNSe;*-I|KF>5YWS|Ee;OC>-y<|>66(+%G*MC9FTnek zo6lpD@BcJuw(WOS{bP#XzNNPFcz+qQ_JBgc^9x%6czlWaj!EjjZN1Z;bY=Zx8gZXs z*DeHOMa*r0I(Kj!^iTcX1*w0UmfQBby8bcc_ZO`rq8Rwv34gI`o(v|L>5PS`E~4{9mYX&I#Mz z_d47!G&Sv5zYw<>_`IUl#tXkUUsC_yE3u~VovDAEYC!=)8#f}v$H%-bz~e~{4(O-X z8k72O(&zVHb+-O-{&-sVzya!bFtc|9yf?+b03l{`i0$!3>c2hdwEyh?p?{ns-h+1c zE<(!6%=aH*8yGSKp}4rFed+B}-TY}s_0Pe$E&@T8!!AJaOJMI)2ozsHj8_9#q1fgB-}CBkRo( zI(rtsS5|*l-dLwtx6IamP+(9}944tGV6yUO(YtqV$djW*o}91&|7X*t#TO9~fwdSc zE%Fc$5a_f#a9WIV!+GMoX>|OoPu;`f3;8f#Q$nHCB4J@)$a`Ri^T#^Hx@F`8?(19m zueEUGf6!3>e`STwXWank$hT4Po&&rN4X=G{Rj=?rQ+l!PUvwZ`N75q0Fqd}+WW)wx z@LIq(0A}w8c&sQEfX_E)s_WLmVBPBjk^pZ2Z%K3o8L)sJMgmfbU`)87eLJ9z6~TJ* zDuQ5n*FpVZU1ObN-Ln8>0V4rwB)XCeyeC2Pd>-^)*S-zldZM@zzL~b4Amp_=phK){ ztaGe;(sgMGAa>CGc0eg}8$i_%W+yc zz%f7tfLUEo0AcI_JpiQix{U-77wB^>;4^@k4d8y^X+W=T!#>FfNC4OC$PkbXVAdYM zSRc9uP$5Ov-6VjtL9ZzQX7vDm9s}U(ZW8#r`2n>ONCXfHz;%6lc7Xc~^Zssmbw}=} z>1ELHksw_5!W$Jsc>1`1)HUWE_6@dm#+)|rpT{7BYPh!rumakO_s9HC$2&fskG&NP zfd3f3501}fI|S(2N_ci8DJcuzhu(^|ZQIr0>1|V&CmB16U#^G>F{BgPI6tN{-g2C=nDh?xIa(@ zXtD)iVT2+hJ4XOrn}3=-rUU=^&13+_p`+cqf9za;dddA6{9`$&0-E=g@b?YO&FkQM z2v1N#!u=mYe0(BOP*8)kX|n!V|3}*Yj^^11=)3@6>?_5?e@dOmLr3XpE!_W;f1IBv zzzfj4UL=Sd_^)|isq=K&8lP?b*OGs8^OYzhB(z-|I&=*2@=5~_LTJ#S(d~u}3Au>; z{NBL#0U2db3f~kDL#I!-p4XNwxDP?4+thRwlRQFEP|zvVqlZ*uoB;#Wn1;tZjv1p1 z;hXpW4<0;BU*)uV{pnKy5)zVc%xl~@gI2>Z{yBR#=I1$}scpdDNOo~SsJfalG(ySA zDUIo48SL3}uw?*-e@aWgAVEPYO`4ih7@oF%yJ*o8$m7@WKXExy;qm+Kf&~_h;c=X!M^7@1gToL6?#~|uVBI&#K}6&=3Jz}h z4vlHS>0{b3jm+M&F|UmM-;Enx+pTBt!v^@+v9z>GV_tpxLdUHG&d$!IF+8S^zWr+} zYE%D51iq_%wAH>+R8;fWm=>HqrVZ1`%wb-;KL0`p%MSA@D%xZN*dFk>(*FI_Z;fJJ zyEFfozvu8dX8fK&Ul#DV(yCPmm6dgW{;>=S3#ol2#`mX*6A_eq?QU!Tn0K1PeI-|@ zrttUyy)97NOzm!2{%O3^d|bWZ?}YO5GRmMB_;>7f^&gFIM*rbMT<)980NaI!N9*HC z^zr|s`k$U|#_Kn45E?%oH5*gG^~3!6EytDU~CxN#Ghu2t~%_C`H>;`ttS7zY$% z8Xm8I(9+Ur43FbjSy?lUgTv6)IpDa=)=;>(Y(qRe!4RkUc)O}<1FXR~*J^ysD_#3f zw+5v7m>^vk`tV)w8n4B{a%(;ZNB!31xc2D9ytlIc>5p2&^mQ#3UX$ejYqJ{gw{d`H z8p`3?0luxo25Z_{@P&ErX0Gu&LMcuBH_8F8CxjfNkO?K)j7e z-R$qiZ-{ILe(@S!y7GY1;eJ>*W3~-;@Y?OhHQabDH@yt-T5nkM{WmyZo4S@Cuj!|k z!NtFU`z9Xoo(_cfc3>Ga0Nk3M{Vi9G-wMNfeDGc$_|6pRNC}V-$FA<{xfKmC%G2m*e%#ml zS6}@Odw4_FP=G1m+c^>a$a5k<9Hb*9z#xIfZ*Yl1- ziAMZwt8aU>@%!63K+mS~QGmQAaJ?sp9Z(MNzOzO>z!>jI z&_xfrF!bSn>oukw=%fJH=)exw%K-HItZ%_R-d9B*jt${Cn`O(E{Sc`0J2-Dlz8my`Ce;$BVCSJldo_A>qd;B;|+Ww%!ap}|gzH3Y~Gx{-|Ljm^zG#-lJ z+6+M5)7kau$2`aa&H!k0fi-Zw6(EZK4Eiw-A^>*)-e-?>fq4l<$Bte9LF++{ynmm~ zG}$e6F191~LmvlU8vzOdRC^jeysmN0^N%p`YwVwqetbU`kok=Vyk9Z=erxjS$bTKJf7(l{H{>4xptW^)T_iq#0sr4# zyv}&mM1SwzQm}7nYpbxgcSjr?;)tDH46Rw?)Jhm{WNZ5j)-%%TCcNf59xY$qGQDZj z<~8!Arl#9UI@IuZZy4rXRCGX_VK!{=fc*F%9JTzas*Y^ac#Dfm5Feimtfi1b@7}#{ zGn|&zW=QWXfLgBm^+V{!O-;(W3`$GlrqAYyZvZ$9z0~jL?7qO+4Ve z?8}#j(pYTa|48}$x%!h@@5#yz0oe*6Tt_n2#Vb~9g>rD`Te-&j>}+h(A)I%Mus>3N zQu{)k(WbPQhB(lF5P;h_tPkuT07wAZi`Uk(ruIunNEG(i9crV^KipXVv#4QIoo)>Pp9@2^DPG=xk(*mne*@=%^TKV;-o1xgO$*bCX{Ocx zva<4Ro-2aa{o}Tfl~n{idzRV4UTJ^Kn}_%QwzPlRbL`XVPZbq=*yqtyCKME!+B%#E z&I{*>^KQ-Ia~m+tzl(m%>x&l%si`&b(5n}KX{VM6+z&hl^pEJ$_Cuo|``FAcTtHAJX*?h(zv(DDn?6+2byu+e zCTg0lQeYc0eOo6jjnJJtP0wjpjP&#J@*xWgi#ErgxVd>@EjBysX`R<*n7)1cgWlQD z*s)q|hQZHp7#y~(F|X;STK_PNAO6|vCmqZiZO zg zNe<5~HqJ5PxyEP!%su{T4%>a>dBC{NAss1!zghy+J`t3NM%U8!`}#k1p%OkF7&|=U zNA=y^sQ%w3M9g&q<*U5hzxuIX{oJp9$ydLz)uPG?|595qs;>xwlLP1gzOB=OmV*4A z4+x}7IV2C-yaX8id&okXkarCLx4mY7-#`YM4EYuUa32QFQb+8+kcd%`7v#Utnjo@i zeexSna;8xK$It$6zlm5$As}Y9n@!>oZN8MlWvEA!_wll@8i6& z!UX`d@jyI&wi|%o6Y;st^8rGrckh8P{tg51OdJk_!#1TyOPA5dc~a+Tn&(doX9>^o zcpx6nbcZwt{o?#F9TNf6xho-|TX1$n>*IFxBI!K-X>!140VV^e<8pa<^trXX?)>~Q z9e6DHbR!KC5)Ckxb^?Sz--yf_Oa+jsCX$CjC#CFayn*WBLsCYE4}JRhT0=t@(xKYl zg9mUp0G%r@uRz?~5^#1-2;INbOC=>|h*#9Ohkor^gzz{Wb`}=4NKX$ACu4A%Hf?V_ zXM*8x6dD@#gZXPf9bk_X6{)Sgo*qJJnM#Lq8_u&vST3EQBEh)bhQ;`1bC%t(M|X5XH7#Qya3 zX16Fy92{auU42rE|3yU=8qYRnEPo0Lcz*vK0MCzJfbnl?`NV19v>3zVJZbhH6&2G$ zZUO>wa2EB!7XObPJ*Cms86RMsC@9QCqef9}0{i&937iH_i_t|z#dLc9n6`=vgp7@; zG~l@yW8)*gG=Iz|ZYH;HM^J}hIw~Ol^^IfU_!-SbMg4#Hr=^emt5*@MhoF{^_3NAJ zD*P-e>RbNx!-uQ3=vT0@aezJ*Tl_B|AP93@(k=eS|KVqheH3~5X&?jKmqBRAkUV%k zr!fr96YLN7Kfd(Q)B=MfJ zTtF4zo5SN2cvFTP;M+I_jQ)21I0YI3HpdUy{GdZ75dSft|Bod=2_%S_83geO%D(jp zcrQC4EiH3m0-fN#G_E(F05-z9r@i0gNW1Xy@&6i*zTb`G(&FR) zWdYZafx%}~)l3_BEmiCB1qH?6d_@g3aG*MzQ7;SEn$QQ0Kyq^LU~SE6v}lnf($SfL zCQdYL42Rcg;P4py{30;NXxT_&O-&7)-D*Z77v@#BLOX-dg9ixBo454a{{{v|->&D) zo8M;qDO2Vme6|-(W8}zv-{LUF@7q_gk;a7!mo@gsF})c0EKKZApS~K-#eWR+UWIjX zmPkrUx$%GeOipe9%$1saOMB+bCfexpnKo@Pyc;2SPr?0R=!ATAIBrMc)6&|t3!nM@ z{M-6x99LLaIFM#5f`UTdY^JSiK0e12e0-IKii!>yIPQX!9mN79YpLWe%6U WpL4iI(*A0>9Zd;ULC$pmi1$A + + + + Win8.1 Debug + Win32 + + + Win8.1 Release + Win32 + + + Win8 Debug + Win32 + + + Win8 Release + Win32 + + + Win7 Debug + Win32 + + + Win7 Release + Win32 + + + Win8.1 Debug + x64 + + + Win8.1 Release + x64 + + + Win8 Debug + x64 + + + Win8 Release + x64 + + + Win7 Debug + x64 + + + Win7 Release + x64 + + + + + Document + + + + + {B408C7A8-AFD5-4C65-B5E5-303A2AD012E7} + {497e31cb-056b-4f31-abb8-447fd55ee5a5} + v4.5 + 11.0 + Win8.1 Debug + Win32 + Keybitor + driver + + + + WindowsV6.3 + true + WindowsKernelModeDriver8.1 + Driver + KMDF + + + WindowsV6.3 + false + WindowsKernelModeDriver8.1 + Driver + KMDF + + + Windows8 + true + WindowsKernelModeDriver8.1 + Driver + KMDF + + + Windows8 + false + WindowsKernelModeDriver8.1 + Driver + KMDF + + + Windows7 + true + WindowsKernelModeDriver8.1 + Driver + KMDF + + + Windows7 + false + WindowsKernelModeDriver8.1 + Driver + KMDF + + + WindowsV6.3 + true + WindowsKernelModeDriver8.1 + Driver + KMDF + + + WindowsV6.3 + false + WindowsKernelModeDriver8.1 + Driver + KMDF + + + Windows8 + true + WindowsKernelModeDriver8.1 + Driver + KMDF + + + Windows8 + false + WindowsKernelModeDriver8.1 + Driver + KMDF + + + Windows7 + true + WindowsKernelModeDriver8.1 + Driver + KMDF + + + Windows7 + false + WindowsKernelModeDriver8.1 + Driver + KMDF + 1 + + + + + + + + + + + DbgengKernelDebugger + Keybitor + + + DbgengKernelDebugger + Keybitor + + + DbgengKernelDebugger + Keybitor + + + DbgengKernelDebugger + Keybitor + + + DbgengKernelDebugger + Keybitor + + + DbgengKernelDebugger + Keybitor + + + DbgengKernelDebugger + Keybitor + true + true + + + DbgengKernelDebugger + Keybitor + true + true + + + DbgengKernelDebugger + Keybitor + true + true + + + DbgengKernelDebugger + Keybitor + true + true + + + DbgengKernelDebugger + Keybitor + true + true + + + DbgengKernelDebugger + Keybitor + true + true + + + + true + ../../Driver/trace.h + true + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + true + ../../Driver/trace.h + true + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + true + ../../Driver/trace.h + true + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + true + ../../Driver/trace.h + true + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + true + ../../Driver/trace.h + true + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + rtlver.lib;Ntstrsafe.lib;wdmsec.lib;%(AdditionalDependencies) + + + + + true + ../../Driver/trace.h + true + + + rtlver.lib;Ntstrsafe.lib;wdmsec.lib;%(AdditionalDependencies) + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + true + ../../Driver/trace.h + true + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + true + ../../Driver/trace.h + true + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + true + ../../Driver/trace.h + true + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + true + ../../Driver/trace.h + true + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + true + ../../Driver/trace.h + true + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + true + ../../Driver/trace.h + true + + + %(AdditionalDependencies);$(DDK_LIB_PATH)\wdmsec.lib;$(DDK_LIB_PATH)\ntstrsafe.lib;$(DDK_LIB_PATH)\rtlver.lib + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vsproject/KeybitorCmd/KeybitorCmd.vcxproj b/vsproject/KeybitorCmd/KeybitorCmd.vcxproj new file mode 100644 index 0000000..a3fedc3 --- /dev/null +++ b/vsproject/KeybitorCmd/KeybitorCmd.vcxproj @@ -0,0 +1,162 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {EABEAA07-984D-4630-897A-C38094F22CE5} + Win32Proj + KeybitorCmd + cmd + + + + Application + true + v120 + Unicode + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + true + KeybitorCmd + + + true + KeybitorCmd + + + false + KeybitorCmd + + + false + KeybitorCmd + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Console + true + setupapi.lib;libKeybitor.lib;%(AdditionalDependencies) + $(SolutionDir)$(Configuration)\ + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Console + true + setupapi.lib;libKeybitor.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration)\ + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Console + false + true + true + setupapi.lib;libKeybitor.lib;%(AdditionalDependencies) + $(SolutionDir)$(Configuration)\ + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Console + false + true + true + setupapi.lib;libKeybitor.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration)\ + + + + + + + + + \ No newline at end of file diff --git a/vsproject/KeybitorConfig/KeybitorConfig.vcxproj b/vsproject/KeybitorConfig/KeybitorConfig.vcxproj new file mode 100644 index 0000000..0c7301a --- /dev/null +++ b/vsproject/KeybitorConfig/KeybitorConfig.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {755BA52B-A8D6-4975-8A22-5B4995FCFEC6} + Win32Proj + KeybitorConfig + configurator + + + + Application + true + v120 + Unicode + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + true + KeybitorConfig + + + true + KeybitorConfig + + + false + KeybitorConfig + + + false + KeybitorConfig + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + Disabled + + + Windows + true + setupapi.lib;difxapi.lib;libKeybitor.lib;Newdev.lib;%(AdditionalDependencies) + $(SolutionDir)$(Configuration)\ + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Windows + true + setupapi.lib;difxapi.lib;libKeybitor.lib;Newdev.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration)\ + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + AnySuitable + + + Windows + false + true + true + setupapi.lib;difxapi.lib;libKeybitor.lib;Newdev.lib;%(AdditionalDependencies) + $(SolutionDir)$(Configuration)\ + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + AnySuitable + + + Windows + true + true + true + setupapi.lib;difxapi.lib;libKeybitor.lib;Newdev.lib;%(AdditionalDependencies) + $(SolutionDir)$(Platform)\$(Configuration)\ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vsproject/KeybitorCtrlLib/KeybitorCtrlLib.vcxproj b/vsproject/KeybitorCtrlLib/KeybitorCtrlLib.vcxproj new file mode 100644 index 0000000..322675e --- /dev/null +++ b/vsproject/KeybitorCtrlLib/KeybitorCtrlLib.vcxproj @@ -0,0 +1,156 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {667F9350-9111-4B45-B2C5-9FF78FCD7688} + Win32Proj + KeybitorCtrlLib + controllerlib + + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + true + v120 + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + StaticLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + libKeybitor + + + libKeybitor + + + libKeybitor + + + libKeybitor + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + E:\dev\cpp\PS2KeyboardToggler\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Windows + true + + + + + + + Level3 + Disabled + WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + E:\dev\cpp\PS2KeyboardToggler\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Windows + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + E:\dev\cpp\PS2KeyboardToggler\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + + + Level3 + + + MaxSpeed + true + true + WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + E:\dev\cpp\PS2KeyboardToggler\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Windows + true + true + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/vsproject/KeybitorPackage/KeybitorPackage.vcxproj b/vsproject/KeybitorPackage/KeybitorPackage.vcxproj new file mode 100644 index 0000000..d823bcb --- /dev/null +++ b/vsproject/KeybitorPackage/KeybitorPackage.vcxproj @@ -0,0 +1,413 @@ + + + + + Win8.1 Debug + Win32 + + + Win8.1 Release + Win32 + + + Win8 Debug + Win32 + + + Win8 Release + Win32 + + + Win7 Debug + Win32 + + + Win7 Release + Win32 + + + Win8.1 Debug + x64 + + + Win8.1 Release + x64 + + + Win8 Debug + x64 + + + Win8 Release + x64 + + + Win7 Debug + x64 + + + Win7 Release + x64 + + + + {94AAA065-4342-41A7-964D-4FC9078847F6} + {4605da2c-74a5-4865-98e1-152ef136825f} + v4.5 + 11.0 + Win8.1 Debug + Win32 + Keybitor_Package + package + + + + WindowsV6.3 + true + WindowsKernelModeDriver8.1 + Utility + Package + true + + + WindowsV6.3 + false + WindowsKernelModeDriver8.1 + Utility + Package + true + + + Windows8 + true + WindowsKernelModeDriver8.1 + Utility + Package + true + + + Windows8 + false + WindowsKernelModeDriver8.1 + Utility + Package + true + + + Windows7 + true + WindowsKernelModeDriver8.1 + Utility + Package + true + + + Windows7 + false + WindowsKernelModeDriver8.1 + Utility + Package + true + + + WindowsV6.3 + true + WindowsKernelModeDriver8.1 + Utility + Package + true + + + WindowsV6.3 + false + WindowsKernelModeDriver8.1 + Utility + Package + true + + + Windows8 + true + WindowsKernelModeDriver8.1 + Utility + Package + true + + + Windows8 + false + WindowsKernelModeDriver8.1 + Utility + Package + true + + + Windows7 + true + WindowsKernelModeDriver8.1 + Utility + Package + true + + + Windows7 + false + WindowsKernelModeDriver8.1 + Utility + Package + true + + + + + + + + + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + DbgengKernelDebugger + False + True + + + + False + False + True + + 133563 + true + + + + true + + + /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + /USELOCALTIME %(AdditionalOptions) + + + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + /v /s PrivateCertStore /n a-chol(Test) /t http://timestamp.globalsign.com/scripts/timstamp.dll %(AdditionalOptions) + + + + + + + + {b408c7a8-afd5-4c65-b5e5-303a2ad012e7} + + + + + + \ No newline at end of file diff --git a/vsproject/KeybitorPackage/runsdvui.cmd b/vsproject/KeybitorPackage/runsdvui.cmd new file mode 100644 index 0000000..9dcc9ba --- /dev/null +++ b/vsproject/KeybitorPackage/runsdvui.cmd @@ -0,0 +1,2 @@ +cd /d "E:\dev\cpp\PS2KeyboardToggler\vsproject\KeybitorPackage" &msbuild "KeybitorPackage.vcxproj" /t:sdvViewer /p:configuration="Win7 Debug" /p:platform=Win32 +exit %errorlevel% \ No newline at end of file diff --git a/vsproject/KeybitorTray/KeybitorTray.vcxproj b/vsproject/KeybitorTray/KeybitorTray.vcxproj new file mode 100644 index 0000000..46044b7 --- /dev/null +++ b/vsproject/KeybitorTray/KeybitorTray.vcxproj @@ -0,0 +1,174 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {BAF098D9-AD01-4211-B55F-B2984AD19157} + Win32Proj + KeybitorTray + tray + + + + Application + true + v120 + Unicode + + + Application + true + v120 + Unicode + + + Application + false + v120 + true + Unicode + + + Application + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + + true + KeybitorTray + + + true + KeybitorTray + + + false + KeybitorTray + + + false + KeybitorTray + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Windows + true + setupapi.lib;libKeybitor.lib;%(AdditionalDependencies) + $(SolutionDir)$(Configuration)\ + + + + + NotUsing + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Windows + true + $(SolutionDir)$(Platform)\$(Configuration)\ + setupapi.lib;libKeybitor.lib;%(AdditionalDependencies) + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Windows + false + true + true + setupapi.lib;libKeybitor.lib;%(AdditionalDependencies) + $(SolutionDir)$(Configuration)\ + + + + + Level3 + NotUsing + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + $(SolutionDir)\..\CtrlLib\include;%(AdditionalIncludeDirectories) + + + Windows + false + true + true + $(SolutionDir)$(Platform)\$(Configuration)\ + setupapi.lib;libKeybitor.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file