// KeyFilter.cpp: implementation of the CKeyFilter class.
//
//////////////////////////////////////////////////////////////////////

#include "KeyFilter.h"
#include "KbFilter.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// CKeyFilter::CKeyFilter()
// 
// Open the device driver.
//////////////////////////////////////////////////////////////////////
CKeyFilter::CKeyFilter( CString DeviceName)
{


  //open the device driver
  m_pKbHandle = CreateFile( (LPCTSTR)DeviceName,
                            GENERIC_WRITE | GENERIC_READ,
                            FILE_SHARE_WRITE | FILE_SHARE_READ,
                            NULL,
                            OPEN_EXISTING,
                            0,
                            NULL);

  //assume auto remove blocking of keys
  AutoRemoveAll = false;

    //query for secure screen saver

  HKEY m_hkResult;
  m_dwVal = 0;

  if (RegOpenKeyEx( HKEY_CURRENT_USER, 
                    REGSTR_PATH_SCREENSAVE,
                    0,
                    KEY_ALL_ACCESS,
                    &m_hkResult) == ERROR_SUCCESS)
  {

    unsigned char val[ 40] = _T("0");
    DWORD dwSize=40; 


    //get the current value
    RegQueryValueEx( m_hkResult, REGSTR_VALUE_USESCRPASSWORD, 
                     NULL, NULL, val, &dwSize);
            
    m_dwVal = (*val == '0') ? 0: 1;
//     RegSetValueEx( m_hkResult, REGSTR_VALUE_USESCRPASSWORD,
//                    0, REG_SZ, _T("0"), 2); 

    RegCloseKey( m_hkResult);
  }
}


//////////////////////////////////////////////////////////////////////
// CKeyFilter::~CKeyFilter()
// 
// Close the device driver
//////////////////////////////////////////////////////////////////////
CKeyFilter::~CKeyFilter()
{

  //close the deivce driver
  if ((m_pKbHandle) && (m_pKbHandle != INVALID_HANDLE_VALUE))
  {

    if (AutoRemoveAll)
    {

      EnableAllKeys();

      HKEY m_hkResult;

      if (RegOpenKeyEx( HKEY_CURRENT_USER, 
                        REGSTR_PATH_SCREENSAVE,
                        0,
                        KEY_ALL_ACCESS,
                        &m_hkResult) == ERROR_SUCCESS)
      {

        DWORD dwSize=sizeof(m_dwVal); 
        CString pw;

        if (m_dwVal) pw = m_dwVal ? _T("1"): _T("0");
 
        RegSetValueEx( m_hkResult, REGSTR_VALUE_USESCRPASSWORD,
                       0, REG_SZ, (unsigned char *)((LPCTSTR)pw), 2); 

        RegCloseKey( m_hkResult);
      }
    }

    CloseHandle( m_pKbHandle);
  }
}


//////////////////////////////////////////////////////////////////////
// BOOL CKeyFilter::DisableKey( unsigned short ScanCode, BOOL Shift, 
//                              BOOL Alt, BOOL Control)
// 
// 
//////////////////////////////////////////////////////////////////////
BOOL CKeyFilter::DisableKey( unsigned short ScanCode, BOOL Shift, 
                             BOOL Alt, BOOL Control)
{

  EXCEPTION_KEY InputBuffer;    // Input buffer for DeviceIoControl
  ULONG DataLength;
  ULONG ReturnedLength;
  BOOL IoctlResult;


  //we need a valid handle for the driver
  if (m_pKbHandle == INVALID_HANDLE_VALUE) return FALSE;

  //fill in the user values
  InputBuffer.key = ScanCode;
  InputBuffer.shift = Shift ? 1: 0;
  InputBuffer.alt = Alt ? 1: 0;
  InputBuffer.ctrl = Control ? 1: 0;
  InputBuffer.replace = 0;
  DataLength = sizeof( InputBuffer);

  //disable the key
  IoctlResult = DeviceIoControl( m_pKbHandle,          // Handle to device
                                 IOCTL_KBF_SET_KEY,    // IO Control code for Write
                                 &InputBuffer,         // Buffer to driver.  Holds port & data.
                                 DataLength,           // Length of buffer in bytes.
                                 NULL,                 // Buffer from driver.   Not used.
                                 0,                    // Length of buffer in bytes.
                                 &ReturnedLength,      // Bytes placed in outbuf.  Should be 0.
                                 NULL);                // NULL means wait till I/O completes.

  return IoctlResult;
}


//////////////////////////////////////////////////////////////////////
// BOOL CKeyFilter::ReplaceKey( unsigned short ScanCode, BOOL Shift, 
//                              BOOL Alt, BOOL Control, USHORT Replacement)
// 
// 
//////////////////////////////////////////////////////////////////////
BOOL CKeyFilter::ReplaceKey( unsigned short ScanCode, BOOL Shift, 
                             BOOL Alt, BOOL Control, USHORT Replacement)
{

  EXCEPTION_KEY InputBuffer;    // Input buffer for DeviceIoControl
  ULONG DataLength;
  ULONG ReturnedLength;
  BOOL IoctlResult;


  //we need a valid handle for the driver
  if (m_pKbHandle == INVALID_HANDLE_VALUE) return FALSE;


  //check for ctrl+alt+del
  if ((Alt) && (Control) && ((ScanCode == KEY_DEL) || (ScanCode == KEY_DELNUM)))
  {

    HKEY m_hkResult;

    if (RegOpenKeyEx( HKEY_CURRENT_USER, 
                      REGSTR_PATH_SCREENSAVE,
                      0,
                      KEY_ALL_ACCESS,
                      &m_hkResult) == ERROR_SUCCESS)
    {

      DWORD dwSize=sizeof(m_dwVal); 
 
      RegSetValueEx( m_hkResult, REGSTR_VALUE_USESCRPASSWORD,
                     0, REG_SZ, (unsigned char *)_T("0"), 2); 

      RegCloseKey( m_hkResult);
    }
  }

  //fill in the user values
  InputBuffer.key = ScanCode;
  InputBuffer.shift = Shift ? 1: 0;
  InputBuffer.alt = Alt ? 1: 0;
  InputBuffer.ctrl = Control ? 1: 0;
  InputBuffer.replace = Replacement;
  DataLength = sizeof( InputBuffer);

  //disable the key
  IoctlResult = DeviceIoControl( m_pKbHandle,          // Handle to device
                                 IOCTL_KBF_SET_KEY,    // IO Control code for Write
                                 &InputBuffer,         // Buffer to driver.  Holds port & data.
                                 DataLength,           // Length of buffer in bytes.
                                 NULL,                 // Buffer from driver.   Not used.
                                 0,                    // Length of buffer in bytes.
                                 &ReturnedLength,      // Bytes placed in outbuf.  Should be 0.
                                 NULL);                // NULL means wait till I/O completes.

  return IoctlResult;
}


//////////////////////////////////////////////////////////////////////
// BOOL CKeyFilter::EnableKey(unsigned short ScanCode, BOOL Shift, BOOL Alt, BOOL Control)
// 
// 
//////////////////////////////////////////////////////////////////////
BOOL CKeyFilter::EnableKey(unsigned short ScanCode, BOOL Shift, BOOL Alt, BOOL Control)
{

  EXCEPTION_KEY InputBuffer;    // Input buffer for DeviceIoControl
  ULONG DataLength;
  ULONG ReturnedLength;
  BOOL IoctlResult;

  if (m_pKbHandle == INVALID_HANDLE_VALUE) return FALSE;

  InputBuffer.key = ScanCode;
  InputBuffer.shift = Shift ? 1: 0;
  InputBuffer.alt = Alt ? 1: 0;
  InputBuffer.ctrl = Control ? 1: 0;
  InputBuffer.replace = 0;
  DataLength = sizeof( InputBuffer);

  IoctlResult = DeviceIoControl( m_pKbHandle,          // Handle to device
                                 IOCTL_KBF_REMOVE_KEY, // IO Control code for Write
                                 &InputBuffer,         // Buffer to driver.  Holds port & data.
                                 DataLength,           // Length of buffer in bytes.
                                 NULL,                 // Buffer from driver.   Not used.
                                 0,                    // Length of buffer in bytes.
                                 &ReturnedLength,      // Bytes placed in outbuf.  Should be 0.
                                 NULL);                // NULL means wait till I/O completes.

  return IoctlResult;
}


//////////////////////////////////////////////////////////////////////
// BOOL CKeyFilter::EnableAllKeys()
// 
// 
//////////////////////////////////////////////////////////////////////
BOOL CKeyFilter::EnableAllKeys()
{

  ULONG ReturnedLength;
  BOOL IoctlResult;

  if (m_pKbHandle == INVALID_HANDLE_VALUE) return FALSE;

  IoctlResult = DeviceIoControl( m_pKbHandle,          // Handle to device
                                 IOCTL_KBF_REMOVE_ALL, // IO Control code for Write
                                 NULL,                 // Buffer to driver.  Holds port & data.
                                 0,                    // Length of buffer in bytes.
                                 NULL,                 // Buffer from driver.   Not used.
                                 0,                    // Length of buffer in bytes.
                                 &ReturnedLength,      // Bytes placed in outbuf.  Should be 0.
                                 NULL);                // NULL means wait till I/O completes.

  return IoctlResult;
}

//////////////////////////////////////////////////////////////////////
// unsigned short CKeyFilter::GetLastKeyDown()
// 
// 
//////////////////////////////////////////////////////////////////////
unsigned short CKeyFilter::GetLastKeyDown()
{

  ULONG OutputBuffer;    // Input buffer for DeviceIoControl
  ULONG ReturnedLength = 0;
  BOOL IoctlResult;

  if (m_pKbHandle == INVALID_HANDLE_VALUE) return FALSE;

  memset( (void *)&OutputBuffer, 0, sizeof( OutputBuffer));

  IoctlResult = DeviceIoControl( m_pKbHandle,          // Handle to device
                                 IOCTL_KBF_GET_LAST,   // IO Control code for Write
                                 &OutputBuffer,                 // Buffer to driver.  Holds port & data.
                                 sizeof( OutputBuffer),                    // Length of buffer in bytes.
                                 &OutputBuffer,        // Buffer from driver.   Not used.
                                 sizeof( OutputBuffer),// Length of buffer in bytes.
                                 &ReturnedLength,      // Bytes placed in outbuf.  Should be 0.
                                 NULL);                // NULL means wait till I/O completes.

  if (IoctlResult) return (unsigned short)OutputBuffer;
  else return (unsigned short)0;
}


//////////////////////////////////////////////////////////////////////
// BOOL CKeyFilter::IsKeyDisabled( unsigned short ScanCode, BOOL Shift,
//                                 BOOL Alt, BOOL Control)
// 
// 
//////////////////////////////////////////////////////////////////////
BOOL CKeyFilter::IsKeyDisabled( BOOL *Disabled, unsigned short ScanCode, 
                                BOOL Shift, BOOL Alt, BOOL Control)
{

  EXCEPTION_KEY InputBuffer;    //Input buffer for DeviceIoControl
  USHORT OutputBuffer = 0;      //Output buffer for DeviceIoControl
  ULONG DataLength;
  ULONG ReturnedLength = 0;
  BOOL IoctlResult;

  if (m_pKbHandle == INVALID_HANDLE_VALUE) return FALSE;

  InputBuffer.key = ScanCode;
  InputBuffer.shift = Shift ? 1: 0;
  InputBuffer.alt = Alt ? 1: 0;
  InputBuffer.ctrl = Control ? 1: 0;
  InputBuffer.replace = 0;
  DataLength = sizeof( InputBuffer);

  memset( (void *)&OutputBuffer, 0, sizeof( OutputBuffer));

  IoctlResult = DeviceIoControl( m_pKbHandle,          // Handle to device
                                 IOCTL_KBF_GET_LAST,   // IO Control code for Write
                                 &InputBuffer,         // Buffer to driver.  Holds port & data.
                                 DataLength,           // Length of buffer in bytes.
                                 &OutputBuffer,        // Buffer from driver.   Not used.
                                 sizeof( OutputBuffer),// Length of buffer in bytes.
                                 &ReturnedLength,      // Bytes placed in outbuf.  Should be 0.
                                 NULL);                // NULL means wait till I/O completes.

  return IoctlResult;
}


//////////////////////////////////////////////////////////////////////
// BOOL CKeyFilter::IsAttached()
// 
// 
//////////////////////////////////////////////////////////////////////
BOOL CKeyFilter::IsAttached()
{

  if (m_pKbHandle == INVALID_HANDLE_VALUE) return FALSE;

  return TRUE;
}
