diff --git a/Ctrl2Cap/INSTALL/ctrl2cap.c b/Ctrl2Cap/INSTALL/ctrl2cap.c new file mode 100644 index 00000000..0f2be208 --- /dev/null +++ b/Ctrl2Cap/INSTALL/ctrl2cap.c @@ -0,0 +1,383 @@ +//---------------------------------------------------------------------- +// +// Ctrl2cap Installation Program +// +// This program installs and uninstalls the ctrl2cap keyboard +// filter driver. Its actions vary depending on whether running +// on NT 4 or Win2K. +// +//---------------------------------------------------------------------- +#include +#include + +// +// Registry keys we access +// +#define CTRL2CAP_DRIVER_KEY "System\\CurrentControlSet\\Services\\Ctrl2cap" +#define CTRL2CAP_FILTER_KEY "System\\CurrentControlSet\\Control\\Class\\{4D36E96B-E325-11CE-BFC1-08002BE10318}" + +//---------------------------------------------------------------------- +// +// SearchMultiSz +// +// Finds the specified string in a multiSz. +// +//---------------------------------------------------------------------- +char * +SearchMultiSz( + char *Value, + DWORD ValueLength, + char *String + ) +{ + DWORD len; + + if( ValueLength < strlen( String )) return NULL; + + len = ValueLength - strlen(String); + do { + + if( !stricmp( &Value[len], String )) return &Value[len]; + + } while( len-- ); + return NULL; +} + + +//---------------------------------------------------------------------- +// +// PrintError +// +// Presents an error as an easy to read message. +// +//---------------------------------------------------------------------- +void +PrintError( + DWORD Code + ) +{ + CHAR buffer[80] ; + DWORD count ; + + // + // Translate the Win32 error code into a useful message. + // + count = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + Code, + 0, + buffer, + sizeof (buffer), + NULL) ; + + // + // Make sure that the message could be translated. + // + if (count == 0) { + + printf("\nError could not be translated.\n Code: %d\n", Code) ; + return; + } + else { + + // + // Display the translated error. + // + printf("%s\n", buffer) ; + return; + } +} + + +//---------------------------------------------------------------------- +// +// Ctrl2capUninstall +// +// Uninstalls the ctrl2cap driver. +// +//---------------------------------------------------------------------- +void +Ctrl2capUninstall( + BOOLEAN Silent, + DWORD Version, + char *SystemDirectory + ) +{ + HKEY hKey; + DWORD error, type, length; + char filters[MAX_PATH], *ptr; + + // + // Delete the driver file. + // + if( !DeleteFile( SystemDirectory ) && !Silent) { + + printf("Error deleting \\system32\\drivers\\ctrl2cap.sys:\n"); + PrintError( GetLastError()); + } + + // + // Delete the driver Registry key. + // + RegDeleteKey( HKEY_LOCAL_MACHINE, CTRL2CAP_DRIVER_KEY"\\Security" ); + RegDeleteKey( HKEY_LOCAL_MACHINE, CTRL2CAP_DRIVER_KEY"\\Enum" ); + if(( error = RegDeleteKey( HKEY_LOCAL_MACHINE, CTRL2CAP_DRIVER_KEY )) != + ERROR_SUCCESS && !Silent ) { + + printf("Error deleting ctrl2cap driver key:\n"); + PrintError( error ); + } + + // + // Delete ctrl2cap from keyboard filter value + // + if( Version > 4 ) { + + if( (error = RegOpenKey( HKEY_LOCAL_MACHINE, + CTRL2CAP_FILTER_KEY, + &hKey )) != ERROR_SUCCESS ) { + + if( !Silent ) { + printf("Could not open Ctrl2cap filter Registry key:\n"); + PrintError( error ); + } + return; + } + + length = sizeof( filters ); + if( (error = RegQueryValueEx( hKey, "UpperFilters", 0, &type, filters, &length )) != + ERROR_SUCCESS ) { + + if( !Silent ) { + + error = GetLastError(); + printf("Could not query Ctrl2cap filter Registry key:\n"); + PrintError( error ); + RegCloseKey( hKey ); + } + return; + } + if( ptr = SearchMultiSz( filters, length, "ctrl2cap" )) { + + // + // Zap it. + // + memcpy( ptr, ptr + strlen("ctrl2cap")+1, + length - (ptr-filters) - strlen("ctrl2cap") -1 ); + length -= strlen("ctrl2cap")+1; + + if( (error = RegSetValueEx( hKey, "UpperFilters", 0, type, + filters, length )) != ERROR_SUCCESS ) { + + if( !Silent ) { + + printf("Could not reset Ctrl2cap filter Registry key:\n"); + PrintError( error ); + } + } + } + RegCloseKey( hKey ); + } + printf("Ctrl2cap uninstalled. You must reboot for this to take effect.\n\n"); +} + + +//---------------------------------------------------------------------- +// +// Ctrl2capInstall +// +// Installs the ctrl2cap driver. +// +//---------------------------------------------------------------------- +void +Ctrl2capInstall( + DWORD Version, + char *SystemDirectory + ) +{ + HKEY hKey; + DWORD error, value, type, length; + char filters[MAX_PATH]; + + // + // First, copy the driver file to the system directory. + // + if( Version > 4 ) { + + if( !CopyFile( "ctrl2cap.nt5.sys", SystemDirectory, FALSE )) { + + printf("Could not copy ctrl2cap.nt5.sys to \\system32\\drivers.:\n"); + PrintError( GetLastError()); + exit(1); + } + } else { + + if( !CopyFile( "ctrl2cap.nt4.sys", SystemDirectory, FALSE )) { + + printf("Could not copy ctrl2cap.nt4.sys to \\system32\\drivers.:\n"); + PrintError( GetLastError()); + exit(1); + } + } + + // + // Create the driver Registry key. + // + if( (error = RegCreateKey( HKEY_LOCAL_MACHINE, + CTRL2CAP_DRIVER_KEY, + &hKey )) != ERROR_SUCCESS ) { + + error = GetLastError(); + PrintError( error ); + Ctrl2capUninstall( TRUE, Version, SystemDirectory ); + exit(1); + } + + // + // Add the appropriate values. + // + value = 1; + RegSetValueEx( hKey, "Type", 0, REG_DWORD, (PCHAR) &value, sizeof(value)); + value = 1; + RegSetValueEx( hKey, "ErrorControl", 0, REG_DWORD, (PCHAR) &value, sizeof(value)); + + // + // On Win2K, add the driver as a keyboard filter. + // + if( Version > 4 ) { + + value = 3; + RegSetValueEx( hKey, "Start", 0, REG_DWORD, (PCHAR) &value, sizeof(value)); + RegCloseKey( hKey ); + if( (error = RegOpenKey( HKEY_LOCAL_MACHINE, + CTRL2CAP_FILTER_KEY, + &hKey )) != ERROR_SUCCESS ) { + + printf("Could not create Ctrl2cap filter Registry key:\n"); + goto error; + } + + length = sizeof( filters ); + if( (error = RegQueryValueEx( hKey, "UpperFilters", 0, &type, filters, &length )) != + ERROR_SUCCESS ) { + + error = GetLastError(); + printf("Could not open Ctrl2cap filter Registry key:\n"); + RegCloseKey( hKey ); + goto error; + } + + // + // Append ctrl2cap to the end. + // + if( !SearchMultiSz( filters, length, "ctrl2cap" )) { + + strcpy( &filters[length-1], "ctrl2cap"); + length = length + strlen("ctrl2cap"); + filters[ length ] = 0; + + if( (error = RegSetValueEx( hKey, "UpperFilters", 0, type, + filters, length + 1 )) != ERROR_SUCCESS ) { + + error = GetLastError(); + printf("Could not set Ctrl2cap filter Registry key:\n"); + RegCloseKey( hKey ); + goto error; + } + } + RegCloseKey( hKey ); + } else { + + value = 1; + RegSetValueEx( hKey, "Start", 0, REG_DWORD, (PCHAR) &value, sizeof(value)); + RegSetValueEx( hKey, "Group", 0, REG_SZ, "KeyboardClass", strlen("KeyboardClass")+1); + RegCloseKey( hKey ); + } + + printf("Ctrl2cap successfully installed. You must reboot for it to take effect.\n\n"); + return; + +error: + // + // Cleanup path when we have to uninstall stuff on the way out. + // + PrintError( error ); + Ctrl2capUninstall( TRUE, Version, SystemDirectory ); + exit(1); +} + + +//---------------------------------------------------------------------- +// +// Usage +// +// Tell the user the proper arguments. +// +//---------------------------------------------------------------------- +void +Usage( + char *name + ) +{ + printf("usage: %s [/install | /uninstall]\n\n", name ); + exit(1); +} + + +//---------------------------------------------------------------------- +// +// Main +// +// Just prints banner and calls the uninstall or install function. +// +//---------------------------------------------------------------------- +void +main( + int argc, + char *argv[] + ) +{ + DWORD version; + CHAR systemDirectory[MAX_PATH] ; + + // + // Print banner + // + printf("\nCtrl2cap Installation Applet\n"); + printf("Copyright (C) 1999 Mark Russinovich\n"); + printf("Systems Internals - http://www.sysinternals.com\n\n"); + if( argc != 2 || + (stricmp( argv[1], "/install") && stricmp( argv[1], "/uninstall") )) { + + Usage( argv[0] ); + } + + // + // Get NT version + // + version = GetVersion(); + if( version >= 0x80000000 ) { + + printf("This version of ctrl2cap works on NT 4 and Win2K.\n" + "Visit http://www.sysinternals.com for a version that works on Windows 9x\n\n"); + return; + } + + // + // Get the system directory + // + GetSystemDirectory( systemDirectory, sizeof (systemDirectory)) ; + strcat( systemDirectory, "\\drivers\\ctrl2cap.sys") ; + + // + // Do the install or uninstall routine. + // + if( !stricmp( argv[1], "/install" )) { + + Ctrl2capInstall( version & 0xFF, systemDirectory ); + + } else { + + Ctrl2capUninstall( FALSE, version & 0xFF, systemDirectory ); + } +} diff --git a/Ctrl2Cap/INSTALL/ctrl2cap.dsp b/Ctrl2Cap/INSTALL/ctrl2cap.dsp new file mode 100644 index 00000000..c91eda82 --- /dev/null +++ b/Ctrl2Cap/INSTALL/ctrl2cap.dsp @@ -0,0 +1,104 @@ +# Microsoft Developer Studio Project File - Name="ctrl2cap" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=ctrl2cap - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ctrl2cap.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ctrl2cap.mak" CFG="ctrl2cap - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ctrl2cap - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "ctrl2cap - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ctrl2cap - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\Release/ctrl2cap.exe" + +!ELSEIF "$(CFG)" == "ctrl2cap - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c +# SUBTRACT CPP /YX +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\release\ctrl2cap.exe" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ctrl2cap - Win32 Release" +# Name "ctrl2cap - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ctrl2cap.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/Ctrl2Cap/INSTALL/ctrl2cap.dsw b/Ctrl2Cap/INSTALL/ctrl2cap.dsw new file mode 100644 index 00000000..3e788360 --- /dev/null +++ b/Ctrl2Cap/INSTALL/ctrl2cap.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ctrl2cap"=.\ctrl2cap.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/Ctrl2Cap/README.TXT b/Ctrl2Cap/README.TXT new file mode 100644 index 00000000..45aed168 --- /dev/null +++ b/Ctrl2Cap/README.TXT @@ -0,0 +1,24 @@ + +Ctrl2cap Keyboard Filter + +Example keyboard filter driver for NT4 and Win2K +Copyright (C) 1996-1999 Mark Russinovich +http://www.sysinternals.com + +To install: + + - Run "ctrl2cap.exe /install" from install directory + - Reboot + +To uninstall: + - Run "ctrl2cap.exe /uninstall" from install directory + - Reboot + +To build source: + - Copy ddk\src\input\inc\ntddkbd.h to \sys directory + - Run buildnt4.bat under NT 4 DDK to build NT 4 driver + * symbols placed under symbols.nt4 + * driver produced as release\ctrl2cap.nt4.sys + - Run buildnt5.bat under Win2K DDK to build Win2K driver + * symbols placed under symbols.nt5 + * driver produced as release\ctrl2cap.nt5.sys diff --git a/Ctrl2Cap/RELEASE/README.TXT b/Ctrl2Cap/RELEASE/README.TXT new file mode 100644 index 00000000..45aed168 --- /dev/null +++ b/Ctrl2Cap/RELEASE/README.TXT @@ -0,0 +1,24 @@ + +Ctrl2cap Keyboard Filter + +Example keyboard filter driver for NT4 and Win2K +Copyright (C) 1996-1999 Mark Russinovich +http://www.sysinternals.com + +To install: + + - Run "ctrl2cap.exe /install" from install directory + - Reboot + +To uninstall: + - Run "ctrl2cap.exe /uninstall" from install directory + - Reboot + +To build source: + - Copy ddk\src\input\inc\ntddkbd.h to \sys directory + - Run buildnt4.bat under NT 4 DDK to build NT 4 driver + * symbols placed under symbols.nt4 + * driver produced as release\ctrl2cap.nt4.sys + - Run buildnt5.bat under Win2K DDK to build Win2K driver + * symbols placed under symbols.nt5 + * driver produced as release\ctrl2cap.nt5.sys diff --git a/Ctrl2Cap/RELEASE/ctrl2cap.nt4.sys b/Ctrl2Cap/RELEASE/ctrl2cap.nt4.sys new file mode 100644 index 00000000..7ce2a664 Binary files /dev/null and b/Ctrl2Cap/RELEASE/ctrl2cap.nt4.sys differ diff --git a/Ctrl2Cap/RELEASE/ctrl2cap.nt5.sys b/Ctrl2Cap/RELEASE/ctrl2cap.nt5.sys new file mode 100644 index 00000000..697b0b76 Binary files /dev/null and b/Ctrl2Cap/RELEASE/ctrl2cap.nt5.sys differ diff --git a/Ctrl2Cap/SYS/CTRL2CAP.H b/Ctrl2Cap/SYS/CTRL2CAP.H new file mode 100644 index 00000000..cc8434ba --- /dev/null +++ b/Ctrl2Cap/SYS/CTRL2CAP.H @@ -0,0 +1,92 @@ +//====================================================================== +// +// Ctrl2cap.h +// +// Copyright (C) 1996-1999 Mark Russinovich +// +// Hook onto the keyboard I/O path and massage the input stream +// converting caps-locks into controls. This example works on +// NT 4 and Win2K and the Win2K version is very losely based on the +// i8042 port filter driver sample, kbfiltr, from the Win2K DDK. +// +//====================================================================== + +// +// Define scan codes of interest here. For scan code tables, see +// "The Undocumented PC", by Frank Van Gullwe, Addison-Wesley 1994. +// + +#define KEY_UP 1 +#define KEY_DOWN 0 + +#define LCONTROL ((USHORT)0x1D) +#define CAPS_LOCK ((USHORT)0x3A) + +// +// Print macro that only turns on when checked builds are on +// +#if DBG +#define DbgPrint(arg) DbgPrint arg +#else +#define DbgPrint(arg) +#endif + +// +// Undocumented NT 4 function to print to the startup screen +// +NTSYSAPI +NTSTATUS +NTAPI +ZwDisplayString( PUNICODE_STRING String ); + + +// +// Our device extension definition +// +typedef struct _DEVICE_EXTENSION +{ + // + // The top of the stack before this filter was added. AKA the location + // to which all IRPS should be directed. + // + PDEVICE_OBJECT TopOfStack; + +} DEVICE_EXTENSION, *PDEVICE_EXTENSION; + +// +// Forwards +// +NTSTATUS DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); +NTSTATUS +Ctrl2capAddDevice( + IN PDRIVER_OBJECT Driver, + IN PDEVICE_OBJECT PDO + ); +NTSTATUS Ctrl2capPnP( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); +NTSTATUS Ctrl2capPower( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); +VOID +Ctrl2capUnload( + IN PDRIVER_OBJECT Driver + ); +NTSTATUS Ctrl2capInit( + IN PDRIVER_OBJECT DriverObject + ); +NTSTATUS Ctrl2capDispatchRead( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); +NTSTATUS Ctrl2capDispatchGeneral( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + + diff --git a/Ctrl2Cap/SYS/MAKEFILE b/Ctrl2Cap/SYS/MAKEFILE new file mode 100644 index 00000000..58189757 --- /dev/null +++ b/Ctrl2Cap/SYS/MAKEFILE @@ -0,0 +1,7 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the driver components of the Windows NT DDK +# + +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/Ctrl2Cap/SYS/SOURCES b/Ctrl2Cap/SYS/SOURCES new file mode 100644 index 00000000..3412ea64 --- /dev/null +++ b/Ctrl2Cap/SYS/SOURCES @@ -0,0 +1,6 @@ +C_DEFINES=/DWIN2K=1 +TARGETNAME=ctrl2cap +TARGETPATH=obj +TARGETTYPE=DRIVER + +SOURCES=ctrl2cap.c ctrl2cap.rc diff --git a/Ctrl2Cap/SYS/buildnt4.bat b/Ctrl2Cap/SYS/buildnt4.bat new file mode 100644 index 00000000..9bebfda9 --- /dev/null +++ b/Ctrl2Cap/SYS/buildnt4.bat @@ -0,0 +1,12 @@ +@echo off +md obj\i386\%DDKBUILDENV% +copy sources.nt4 sources +call build.exe -cZ +if exist obj\i386\%DDKBUILDENV%\ctrl2cap.sys copy obj\i386\%DDKBUILDENV%\ctrl2cap.sys ctrl2cap.nt4.sys +rebase -b 10000 -x symbols.nt4 -a ctrl2cap.nt4.sys +copy ctrl2cap.nt4.sys ..\release\. +del ctrl2cap.nt4.sys + + + + diff --git a/Ctrl2Cap/SYS/buildnt5.bat b/Ctrl2Cap/SYS/buildnt5.bat new file mode 100644 index 00000000..5fae2464 --- /dev/null +++ b/Ctrl2Cap/SYS/buildnt5.bat @@ -0,0 +1,12 @@ +@echo off +copy sources.nt5 sources +call build.exe -cZ +if exist obj%BUILD_ALT_DIR%\i386\ctrl2cap.sys copy obj%BUILD_ALT_DIR%\i386\ctrl2cap.sys ctrl2cap.nt5.sys +rebase -b 10000 -x symbols.nt5 -a ctrl2cap.nt5.sys +copy ctrl2cap.nt5.sys ..\release\. +del ctrl2cap.nt5.sys + + + + + diff --git a/Ctrl2Cap/SYS/ctrl2cap.c b/Ctrl2Cap/SYS/ctrl2cap.c new file mode 100644 index 00000000..717c1116 --- /dev/null +++ b/Ctrl2Cap/SYS/ctrl2cap.c @@ -0,0 +1,510 @@ +//====================================================================== +// +// Ctrl2cap +// +// Copyright (C) 1996-1999 Mark Russinovich +// +// Hook onto the keyboard I/O path and massage the input stream +// converting caps-locks into controls. This example works on +// NT 4 and Win2K and the Win2K version is very losely based on the +// i8042 port filter driver sample, kbfiltr, from the Win2K DDK. +// +// For every function I list whether the function gets called +// under NT 4, WIN2K, or both. +// +// File: ctrl2cap.c +// +//====================================================================== +#include "ntddk.h" +#include +#include "stdarg.h" +#include "stdio.h" +#include "ctrl2cap.h" +#include "ntddkbd.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text (INIT, DriverEntry) +#pragma alloc_text (PAGE, Ctrl2capDispatchGeneral) +#if WIN2K +#pragma alloc_text (PAGE, Ctrl2capAddDevice) +#pragma alloc_text (PAGE, Ctrl2capUnload) +#pragma alloc_text (PAGE, Ctrl2capPnP) +#pragma alloc_text (PAGE, Ctrl2capPower) +#endif // WIN2K +#endif // ALLOC_PRAGMA + + +//---------------------------------------------------------------------- +// +// DriverEntry +// +// Installable driver initialization. Here we just set ourselves up. +// +// Called: NT4, WIN2K +// +//---------------------------------------------------------------------- +NTSTATUS DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) +{ + ULONG i; + + DbgPrint (("Ctrl2cap.SYS: entering DriverEntry\n")); + + // + // Fill in all the dispatch entry points with the pass through function + // and the explicitly fill in the functions we are going to intercept + // + for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) { + + DriverObject->MajorFunction[i] = Ctrl2capDispatchGeneral; + } + + // + // Our read function is where we do our real work. + // + DriverObject->MajorFunction[IRP_MJ_READ] = Ctrl2capDispatchRead; + +#if WIN2K + // + // Power IRPs are the only ones we have to handle specially under + // Win2k since they require the special PoCallDriver and + // PoStartNextPowerIrp function calls. + // + DriverObject->MajorFunction [IRP_MJ_POWER] = Ctrl2capPower; + + // + // The only reason we need to handle PnP IRPs is to know when + // a device we've attached to disappears (is removed). + // + DriverObject->MajorFunction [IRP_MJ_PNP] = Ctrl2capPnP; + + // + // Under Win2K we get told about the presence of keyboard + // devices through our AddDevice entry point. + // + DriverObject->DriverUnload = Ctrl2capUnload; + DriverObject->DriverExtension->AddDevice = Ctrl2capAddDevice; + + return STATUS_SUCCESS; + +#else // WIN2K + + // + // Under NT 4 we go out and hook the keyboard class device for + // keyboard 0. + // + return Ctrl2capInit( DriverObject ); +#endif // WIN2K +} + + +//---------------------------------------------------------------------- +// +// Ctrl2capInit +// +// Hook onto the keyboard's path. Why does this routine return +// status success even if there's a problem? I've found that if it +// doesn't, the keyboard won't respond! +// +// Called: NT4 +// +//---------------------------------------------------------------------- +NTSTATUS Ctrl2capInit( + IN PDRIVER_OBJECT DriverObject + ) +{ + CCHAR ntNameBuffer[64]; + STRING ntNameString; + UNICODE_STRING ntUnicodeString; + PDEVICE_OBJECT device; + NTSTATUS status; + PDEVICE_EXTENSION devExt; + WCHAR messageBuffer[] = L"Ctrl2cap Initialized\n"; + UNICODE_STRING messageUnicodeString; + + // + // Only hook onto the first keyboard's chain. + // + sprintf( ntNameBuffer, "\\Device\\KeyboardClass0" ); + RtlInitAnsiString( &ntNameString, ntNameBuffer ); + RtlAnsiStringToUnicodeString( &ntUnicodeString, &ntNameString, TRUE ); + + // + // Create device object for the keyboard. + // + status = IoCreateDevice( DriverObject, + sizeof(DEVICE_EXTENSION), + NULL, + FILE_DEVICE_KEYBOARD, + 0, + FALSE, + &device ); + + if( !NT_SUCCESS(status) ) { + + DbgPrint(("Ctrl2cap: Keyboard hook failed to create device!\n")); + + RtlFreeUnicodeString( &ntUnicodeString ); + return STATUS_SUCCESS; + } + + RtlZeroMemory(device->DeviceExtension, sizeof(DEVICE_EXTENSION)); + + devExt = (PDEVICE_EXTENSION) device->DeviceExtension; + + // + // Keyboard uses buffered I/O so we must as well. + // + device->Flags |= DO_BUFFERED_IO; + device->Flags &= ~DO_DEVICE_INITIALIZING; + + // + // Attach to the keyboard chain. + // + status = IoAttachDevice( device, &ntUnicodeString, &devExt->TopOfStack ); + + if( !NT_SUCCESS(status) ) { + + DbgPrint(("Ctrl2cap: Connect with keyboard failed!\n")); + IoDeleteDevice( device ); + RtlFreeUnicodeString( &ntUnicodeString ); + return STATUS_SUCCESS; + } + + // + // Done! Just free our string and be on our way... + // + RtlFreeUnicodeString( &ntUnicodeString ); + DbgPrint(("Ctrl2cap: Successfully connected to keyboard device\n")); + + // + // This line simply demonstrates how a driver can print + // stuff to the bluescreen during system initialization. + // + RtlInitUnicodeString (&messageUnicodeString, + messageBuffer ); + ZwDisplayString( &messageUnicodeString ); + return STATUS_SUCCESS; +} + + +#if WIN2K +//---------------------------------------------------------------------- +// +// Ctrl2capAddDevice +// +// The PnP Manager calls us for each keyboard present on the system. +// We attach to each one so that we can flip caps lock to controls. +// +// Called: WIN2K +// +//---------------------------------------------------------------------- +NTSTATUS +Ctrl2capAddDevice( + IN PDRIVER_OBJECT Driver, + IN PDEVICE_OBJECT PDO + ) +{ + PDEVICE_EXTENSION devExt; + IO_ERROR_LOG_PACKET errorLogEntry; + PDEVICE_OBJECT device; + NTSTATUS status = STATUS_SUCCESS; + + // + // Create a filter device and attach it to the device stack. + // + status = IoCreateDevice(Driver, + sizeof(DEVICE_EXTENSION), + NULL, + FILE_DEVICE_KEYBOARD, + 0, + FALSE, + &device + ); + + if (!NT_SUCCESS(status)) { + + return (status); + } + + RtlZeroMemory(device->DeviceExtension, sizeof(DEVICE_EXTENSION)); + + devExt = (PDEVICE_EXTENSION) device->DeviceExtension; + devExt->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO); + + ASSERT(devExt->TopOfStack); + + device->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE); + device->Flags &= ~DO_DEVICE_INITIALIZING; + return status; +} + + +//---------------------------------------------------------------------- +// +// Ctrl2capPnP +// +// We have to handle PnP IRPs so that we detach from target +// devices when appropriate. +// +// Called: WIN2K +// +//---------------------------------------------------------------------- +NTSTATUS Ctrl2capPnP( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + PDEVICE_EXTENSION devExt; + PIO_STACK_LOCATION irpStack; + NTSTATUS status = STATUS_SUCCESS; + KIRQL oldIrql; + KEVENT event; + + devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; + irpStack = IoGetCurrentIrpStackLocation(Irp); + + switch (irpStack->MinorFunction) { + case IRP_MN_REMOVE_DEVICE: + + // + // Detach from the target device after passing the IRP + // down the devnode stack. + // + IoSkipCurrentIrpStackLocation(Irp); + IoCallDriver(devExt->TopOfStack, Irp); + + IoDetachDevice(devExt->TopOfStack); + IoDeleteDevice(DeviceObject); + + status = STATUS_SUCCESS; + break; + + case IRP_MN_SURPRISE_REMOVAL: + + // + // Same as a remove device, but don't call IoDetach or IoDeleteDevice. + // + IoSkipCurrentIrpStackLocation(Irp); + status = IoCallDriver(devExt->TopOfStack, Irp); + break; + + case IRP_MN_START_DEVICE: + case IRP_MN_QUERY_REMOVE_DEVICE: + case IRP_MN_QUERY_STOP_DEVICE: + case IRP_MN_CANCEL_REMOVE_DEVICE: + case IRP_MN_CANCEL_STOP_DEVICE: + case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: + case IRP_MN_STOP_DEVICE: + case IRP_MN_QUERY_DEVICE_RELATIONS: + case IRP_MN_QUERY_INTERFACE: + case IRP_MN_QUERY_CAPABILITIES: + case IRP_MN_QUERY_DEVICE_TEXT: + case IRP_MN_QUERY_RESOURCES: + case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: + case IRP_MN_READ_CONFIG: + case IRP_MN_WRITE_CONFIG: + case IRP_MN_EJECT: + case IRP_MN_SET_LOCK: + case IRP_MN_QUERY_ID: + case IRP_MN_QUERY_PNP_DEVICE_STATE: + default: + // + // Pass these through untouched + // + IoSkipCurrentIrpStackLocation(Irp); + status = IoCallDriver(devExt->TopOfStack, Irp); + break; + } + + return status; +} + + +//---------------------------------------------------------------------- +// +// Ctrl2capPower +// +// We have to handle Power IRPs specially. +// +// Called: WIN2K +// +//---------------------------------------------------------------------- +NTSTATUS Ctrl2capPower( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + PDEVICE_EXTENSION devExt; + + devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; + + // + // Let the next power IRP out of the gate + // + PoStartNextPowerIrp( Irp ); + + // + // Pass this power IRP to the keyboard class driver + // + IoSkipCurrentIrpStackLocation( Irp ); + + return PoCallDriver( devExt->TopOfStack, Irp ); +} + + +//---------------------------------------------------------------------- +// +// Ctrl2capUnload +// +// Our Win2K PnP unload function. We don't need to do anything. +// +// Called: WIN2K +// +//---------------------------------------------------------------------- +VOID +Ctrl2capUnload( + IN PDRIVER_OBJECT Driver + ) +{ + UNREFERENCED_PARAMETER(Driver); + + ASSERT(NULL == Driver->DeviceObject); +} +#endif // WIN2K + + +//---------------------------------------------------------------------- +// +// Ctrl2capReadComplete +// +// Gets control after a read operation has completed. +// +// Called: WIN2K, NT4 +// +//---------------------------------------------------------------------- +NTSTATUS Ctrl2capReadComplete( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp, + IN PVOID Context + ) +{ + PIO_STACK_LOCATION IrpSp; + PKEYBOARD_INPUT_DATA KeyData; + int numKeys, i; + + // + // Request completed - look at the result. + // + IrpSp = IoGetCurrentIrpStackLocation( Irp ); + if( NT_SUCCESS( Irp->IoStatus.Status ) ) { + + // + // Do caps-lock down and caps-lock up. Note that + // just frobbing the MakeCode handles both the up-key + // and down-key cases since the up/down information is specified + // seperately in the Flags field of the keyboard input data + // (0 means key-down, 1 means key-up). + // + KeyData = Irp->AssociatedIrp.SystemBuffer; + numKeys = Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA); + + for( i = 0; i < numKeys; i++ ) { + + DbgPrint(("ScanCode: %x ", KeyData[i].MakeCode )); + DbgPrint(("%s\n", KeyData[i].Flags ? "Up" : "Down" )); + + if( KeyData[i].MakeCode == CAPS_LOCK) { + + KeyData[i].MakeCode = LCONTROL; + } + } + } + + // + // Mark the Irp pending if required + // + if( Irp->PendingReturned ) { + + IoMarkIrpPending( Irp ); + } + return Irp->IoStatus.Status; +} + + +//---------------------------------------------------------------------- +// +// Ctrl2capDispatchRead +// +// Sets up to look at the read request completion so that we can +// massage the input queue on IO completion. +// +// Called: WIN2K, NT4 +// +//---------------------------------------------------------------------- +NTSTATUS Ctrl2capDispatchRead( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp ) +{ + PDEVICE_EXTENSION devExt; + PIO_STACK_LOCATION currentIrpStack; + PIO_STACK_LOCATION nextIrpStack; + + // + // Gather our variables. + // + devExt = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; + currentIrpStack = IoGetCurrentIrpStackLocation(Irp); + nextIrpStack = IoGetNextIrpStackLocation(Irp); + + // + // Push params down for keyboard class driver. + // + *nextIrpStack = *currentIrpStack; + + // + // Set the completion callback, so we can "frob" the keyboard data. + // + IoSetCompletionRoutine( Irp, Ctrl2capReadComplete, + DeviceObject, TRUE, TRUE, TRUE ); + + // + // Return the results of the call to the keyboard class driver. + // + return IoCallDriver( devExt->TopOfStack, Irp ); +} + + +//---------------------------------------------------------------------- +// +// Ctrl2capDispatchGeneral +// +// This handles several functions we are not interested in +// along to the keyboard class driver. +// +// Called: WIN2K, NT4 +// +//---------------------------------------------------------------------- +NTSTATUS Ctrl2capDispatchGeneral( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ) +{ + // + // Pass the IRP to the target without touching the IRP + // +#if WIN2K + IoSkipCurrentIrpStackLocation(Irp); +#else // WIN2K + // + // This is the equivalent of the IoSkipCurrentIrpStackLocation macro, + // which doesn't exist in the NT 4 DDK. + // + Irp->CurrentLocation++; + Irp->Tail.Overlay.CurrentStackLocation++; +#endif // WIN2K + return IoCallDriver(((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->TopOfStack, Irp); +} + diff --git a/Ctrl2Cap/SYS/ctrl2cap.rc b/Ctrl2Cap/SYS/ctrl2cap.rc new file mode 100644 index 00000000..3a2e8e31 --- /dev/null +++ b/Ctrl2Cap/SYS/ctrl2cap.rc @@ -0,0 +1,27 @@ +#include + +#define VER_DEBUG 0 +#define VER_PRERELEASE 0 +#define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#define VER_FILEOS VOS_NT_WINDOWS32 +#define VER_FILEFLAGS (VER_PRERELEASE|VER_DEBUG) + +#define VER_FILETYPE VFT_DRV +#define VER_FILESUBTYPE VFT2_DRV_SYSTEM + +#define VER_COMPANYNAME_STR "Systems Internals" +#define VER_PRODUCTNAME_STR "Ctrl2cap" +#define VER_LEGALCOPYRIGHT_YEARS "1996-1999" +#define VER_LEGALCOPYRIGHT_STR "Copyright (C) M. Russinovich" VER_LEGALCOPYRIGHT_YEARS +#define VER_LEGALTRADEMARKS_STR "Copyright (C) 1996-1999 Mark Russinovich" + +#define VER_PRODUCTVERSION 2,00,00,00 +#define VER_PRODUCTVERSION_STR "2.00" +#define VER_PRODUCTVERSION_W (0x02000) +#define VER_PRODUCTVERSION_DW (0x02000) +#define VER_FILEDESCRIPTION_STR "Windows NT Caps-lock Ctrl Swapper" +#define VER_INTERNALNAME_STR "ctrl2cap.sys" +#define VER_ORIGINALFILENAME_STR "ctrl2cap.Sys" + +#include "common.ver" + diff --git a/Ctrl2Cap/SYS/source.nt4 b/Ctrl2Cap/SYS/source.nt4 new file mode 100644 index 00000000..52a2407c --- /dev/null +++ b/Ctrl2Cap/SYS/source.nt4 @@ -0,0 +1,5 @@ +TARGETNAME=ctrl2cap +TARGETPATH=obj +TARGETTYPE=DRIVER + +SOURCES=ctrl2cap.c diff --git a/Ctrl2Cap/SYS/sources.nt4 b/Ctrl2Cap/SYS/sources.nt4 new file mode 100644 index 00000000..b03786e1 --- /dev/null +++ b/Ctrl2Cap/SYS/sources.nt4 @@ -0,0 +1,5 @@ +TARGETNAME=ctrl2cap +TARGETPATH=obj +TARGETTYPE=DRIVER + +SOURCES=ctrl2cap.c ctrl2cap.rc diff --git a/Ctrl2Cap/SYS/sources.nt5 b/Ctrl2Cap/SYS/sources.nt5 new file mode 100644 index 00000000..3412ea64 --- /dev/null +++ b/Ctrl2Cap/SYS/sources.nt5 @@ -0,0 +1,6 @@ +C_DEFINES=/DWIN2K=1 +TARGETNAME=ctrl2cap +TARGETPATH=obj +TARGETTYPE=DRIVER + +SOURCES=ctrl2cap.c ctrl2cap.rc