Wednesday, September 26, 2012

[ MFC ] - Check Shift, ctrl, alt and Toggle keystate in onkeydown (WM_KEYDOWN Message Handler)


1. Introduction


We know that keyboard and mouse are very basic hardware interface supported by almost all the computer operating system. When the user presses the Keyboard key the device driver for the keyboard processes that input by making use of the interrupts. Windows OS knows about these kinds of hardware actions in the form of a message structure. The hardware fills this structure with the information it has processed and places that in the Operating system message queue.

The operating system message queue then places the message in the corresponding application and from the application queue; the message is delivered to the target window for responding back.

In this article, we will see how can we check various keyboard events with a simple example.



2. Create an SDI Application


The sample is a simple SDI Application.  To create the application on your own,
1. Create a new project and chose MFC Application under the Visual C++ category. Then provide the project name as shown in Fig.1
Fig.1


2. Then click ok to the above dialog. This will open a wizard now. Accept the default for the pages except the one shown in Fig.2 below:

Fig.2


The SDI Application is ready to check the different kinds of keyboard input.



3. Before we code


When a key is pressed by the user, the target window will receive the below-specified windows messages. The messages and its details are shown in Fig.3:

Fig.3


From the above table, we can conclude that KeyDown and KeyUp will be fired for any type of keyboard keys. Therefore, this event is the combination of System key as well as the character keystrokes. Let us say that you typed the alphabet letter ‘K’ in a notepad. The hardware interprets that as a two events. One is KeyDown and the other one is KeyUp. So we get three messages WM_KEYDOWN, WM_KEYUP and WM_CHAR as the typed keystroke is not a  system key.

There some special keys that we should be aware. These are categorized as Shift Keys as well as Toggle keys. Examples for shift keys are ctrl, shift and Alt. Similarly, Toggle key changes it’s key state in between on & off. One best example for toggle key is Caps Lock.

We will use the sample created in section 2 to demonstrate the WM_KEYDOWN event. You can handle other events similar to this.



4. Implement the WM_KEYDOWN event


First, we need to provide the handler for the WM_KEYDOWN message. The steps are shown in Fig.4. Go to class view and select properties for the class CKeyBoardInputView. We are going to handle our keyboard events in the view class. Next, provide the handler function for WM_KEYDOWN windows message. To do this click on the message icon, then double click on the grid column for the WM_KEYDOWN.

Fig.4


The signature of the empty handler is shown below:
void CKeyBoardInputView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
}

In this article, we are going to deal with the first parameter only. The first parameter represents the key code that you can compare with the keyboard constants to decide the keystroke.



5. Looking for Alphanumeric Key


The alphanumeric keystroke can be compared directly with character constants. In the below code we are looking for the English letter M or the numeric digit 3.

//01. Numbers and Charactors
if (nChar == 'M')
        AfxMessageBox(_T("M Pressed"));
if (nChar == '3')
        AfxMessageBox(_T("Three Pressed"));



6. Looking for the System Key


System keys should be compared with the pre-defined constant values defined in the WinUser.h header file.  The below code shows how we ensure that the typed keystroke is either an F5 key or an End key. These two keys are system keys and do not fall in the alphabets or numeric keys.

//02. Process System Keys
if (nChar == VK_F5)
        AfxMessageBox(_T("F5 Function Key Pressed"));
if (nChar == VK_END)
        AfxMessageBox(_T("END Key Pressed"));



7. Looking for the Shift key combination


Sometimes we will end up in a situation where we need to check the alphanumeric keystroke in combination with the shift keys like ctrl, shift etc. The below example will check for the ctrl+A and the Shift+S combination of the keys. When converting the 8000 from hexadecimal to binary we get 16 digits with the high bit set to one. The GetKeyState returns a negative number when the shift key is kept down. So you can either check the return value is negative or check the high order bit with the Bitwise AND operator ‘&’. The code listed uses the bit-wise operator to make the comparison:

//03. Numbers and Char keys with Shift key combination
if (nChar == 'A')
{
        if (GetKeyState(VK_CONTROL ) & 0x8000  )
               AfxMessageBox(_T("Ctrl+A is pressed"));
}

if (nChar == 'S')
{
        //Shift Keys [Alt, Shift, Ctrl]
        if (GetKeyState(VK_SHIFT) & 0x8000  )
               AfxMessageBox(_T("Shift+S is pressed"));
}



8. Looking for the Toggle key state




The toggle key like Insert and CapsLock will change their state between ON and OFF. When the toggle key is pressed it current state is inverted. In the previous section, we saw the importance of the High order bit of the nChar (First parameter of the event handler) to decide the state (Hold down) of the shift key. The low order bit is used to check the toggle key status. When the low order bit is set, the toggle key is turned on. The below code informs you whenever the CAPSLOCK key is turned-ON. Similarly, the code below will also show a message box when the NumLock is turned-Off.

//04. Checking toggle keys
if (nChar == VK_CAPITAL)
{
        if (GetKeyState(VK_CAPITAL) & 0x01 )
               AfxMessageBox(_T("Caps Key On"));
}

if (nChar == VK_NUMLOCK)
{
        if (!(GetKeyState(VK_NUMLOCK) & 0x01) )
               AfxMessageBox(_T("Num Key Off"));     
}


Source Code: Download

Monday, September 17, 2012

[ C# ] - Monitor File System Recursively using FileSystemWatcher component

1. Introduction to FileSystemWatcher

"FileSystemWatcher Component" will track the changes in the file system. The changes include file creation, deletion, Modification and renaming a file. In this article, we will create a sample that can spy on your file system based on the folder path that you specify.

Whenever a change is encountered in the file system, it notifies the listening application through the events like File changed.

2. About the File System Monitor Sample

The below screenshot shows the sample application:


Figure 1. Sample Application


The top screen will show the Spied content. This wide white screen is a multi-line text box. Folder Picker button will enable you to pick a folder path to be monitored. Once a folder is picked, the folder name will be displayed in the Folder Path to Monitor text box. The Recursive check box tells that we want to monitor the sob-folders of the folder picked by the folder picker dialog. Say, for example, if we picked C:\ through folder picked and checked the Recursive checkbox, then the entire C:\ partition or drive will be monitored.

Start Monitor button will start the monitoring process. There is no much validation done here, so the sequence is:


  1.     Specify the Folder path to monitor
  2.   If you want to monitor recursively, place a check mark on the Recursive checkbox
  3.     Decide the kind of action
  4.     Then click the monitor button

Clear Content button will erase the spied content displayed on the output screen at any time. Close button… Do you need an explanation for it? The four checkbox filters are useful for specifying what kind of action you want to track. It is simple to create this sample as much of the work is done by the component.


3. Preparing the Form for FileSystemWatcher Example

From fig.1 you can easily place the required controls to the form. I used basic only basic controls in the form. So it is not a big deal to design such form. To prepare the sample we need two components. One is "FolderBrowserDialog Component" and the another one is "FileSystemWatcher Component". FileSystemWatcher is the key component that is going to spy the file system on the folder that you specify. Fig.2 shows from where you can drag drop these components.

Figure 2. Components required


In our sample, FolderB is the name given to the FolderBrowserDialog and FileMon is the name given to the FileSystemWatcher component. Once the components are dropped, we need to provide four events handler for the FileSystemWatcher (FileMon) component dropped on the form. Fig.3 shown below describes the event handler provided for the FileMon.


Figure 3. FileSystemWatcher Events




4. Source Code Explanation

1) First, the required variables are declared. We will see the use of it when we progress through the coding.

//Sample 01: Declarations.
private string content = "";
private string last_event_filename = "";

2) Event handler provided for the close and Clear Content is straightforward. The code for that is given below:

//Sample 02: Close the form
private void btnClose_Click(object sender, EventArgs e)
{
    fileMon.EnableRaisingEvents = false;
    this.Close();
}
//Sample 03: Clear Text Content
private void btnClear_Click(object sender, EventArgs e)
{
    txtDisplay.Clear();
}  

3) The FileSystemWatcher component will spy the files under a given path. To spy the files inside the sub-folder we should set "IncludeSubdirectories Property" to true. We can set this property only when we have a valid path and it is set through the Path property. In our sample, we provided a checkbox that will set IncludeSubdirectories property to true or false based on its check state. Below is the code:

//Sample 04: Do it recursively
private void chkRecursive_CheckedChanged(object sender, EventArgs e)
{
    if (chkRecursive.Checked == true )
        fileMon.IncludeSubdirectories = true;
    else
        fileMon.IncludeSubdirectories = false;
}

4) In the previous step we shown the code that set the IncludeSubdirectories and this property of the component become meaningful only when we have a valid path to monitor. The "Path Property" of the component will be used to specify from where exactly we want to monitor the files. To set this Path property, we used FolderBrowserDialog component from the dialogs group. When the … button is clicked, we make use of the folder browser dialog to read the Folder Path to monitor from the user of the sample. And the Recursive checkbox will tell we need to monitor this selected path recursively or not. Below is the piece code:

//Sample 05: Set the Path to Spy using Folder Browser Dialog
private void btnPickFolder_Click(object sender, EventArgs e)
{
    if (FolderB.ShowDialog() == DialogResult.OK)
    {
        txtFolderPath.Text = FolderB.SelectedPath;
        fileMon.Path = txtFolderPath.Text;
    }
}

5) The FileSystemWatcher component will actually start raising the events (Fig.3) when its "EnableRaisingEvents Property" is set to true. Once it starts raising the events, we will get the spied events in the corresponding handler functions. So we set this property when Start Monitor button is clicked. Below is piece of code:

//Sample 06: Enable capturing file system events
private void btnMonitor_Click(object sender, EventArgs e)
{
    fileMon.Path = txtFolderPath.Text;
    fileMon.EnableRaisingEvents = true;
}

6) The recursive checkbox will set the IncludeSubdirectories property of the component. We will get an application exception when we set this property to true when the Path property does not contain any valid path to monitor. So below is the piece of code which safeguards this situation:

//Sample 07: Enable capturing file system events
private void txtFolderPath_TextChanged(object sender, EventArgs e)
{
    if (string.IsNullOrEmpty(txtFolderPath.Text))
        chkRecursive.Enabled = false;
    else
        chkRecursive.Enabled = true;
}

7) Next, all the four events shown in Fig.3 are handled. In each handler, we will get the file name from the FileSystemEventArgs, which is passed to the handler as a parameter. As we already inside the handler we know the corresponding action say whether it is a file deletion or Rename etc. On each handler, we will check the status of the Filter checkboxes and display the information only when the corresponding check box is checked. Say for example, before displaying the file renamed action, it will check whether the filter is applied. Below is the code:

//Sample 08: Monitor all the File Events
private void fileMon_Changed(object sender, System.IO.FileSystemEventArgs e)
{
    //!under_modification: Avoids repeated consecutive ourput of Files changed per file
    if (chkModified.CheckState == CheckState.Checked && last_event_filename != e.FullPath)
    {
        content = "File Changed: " + e.FullPath + Environment.NewLine;
        txtDisplay.AppendText(content);
    }
    last_event_filename = e.FullPath;
}

private void fileMon_Created(object sender, System.IO.FileSystemEventArgs e)
{
    if (chkCreated.CheckState == CheckState.Checked)
    {
        content = "File Created: " + e.FullPath + Environment.NewLine;
        txtDisplay.AppendText(content);
    }
    last_event_filename = e.FullPath;
}

private void fileMon_Deleted(object sender, System.IO.FileSystemEventArgs e)
{
    if (chkDeleted.CheckState == CheckState.Checked)
    {
        content = "File Deleted: " + e.FullPath + Environment.NewLine;
        txtDisplay.AppendText(content);
    }
    last_event_filename = e.FullPath;
}

private void fileMon_Renamed(object sender, System.IO.RenamedEventArgs e)
{
    if (chkRenamed.CheckState == CheckState.Checked)
    {
        content = "File Renamed: New Name - "+  e.FullPath + " Old Name : " + e.OldFullPath
            + Environment.NewLine;
        txtDisplay.AppendText(content);
    }
    last_event_filename = e.FullPath;
}

5. Sample in Action

The recorded video shows spying the directory D:\Temp. First, the files are copied from C:\Temp to D:\Temp. Then a file is renamed from the D:\Temp. Then we rename a file name from Siva to Damodaran. Finally, we delete the list of files from the D:\Temp.



You can use this sample to spy your entire C:\ drive. Just Select C:\ then click on the recursive button, and the sample is now tracking entire c:\ drive. It is very useful when you are working big projects and want to know the file system that is affected by the particular workflow. 

Source Code: Download

Like this site? Tell it to your Firend :)