'; zhtm += ''; zhtm += '

' + pPage + ''; zhtm += ''; window.popUpWin.document.write(zhtm); window.popUpWin.document.close(); // Johnny Jackson 4/28/98 } //--> Using Visual Basic 6 -- Ch 15 -- Handling Keyboard and Mouse Input in Your Programs

Using Visual Basic 6

Previous chapterNext chapterContents

- 15 -
Handling Keyboard and Mouse Input
in Your Programs

Understanding Device Input

Microsoft supports device independence

In the Windows NT operating system, one part of the Executive Services is the Hardware Abstraction Layer (HAL). The presence of this distinct architecture element demonstrates the distinct support for device independence in the current Microsoft operating systems.

Windows is a device-independent operating system. The Windows operating system separates independent operating-system hardware (devices) such as the keyboard, mouse, monitor, and printer from the application programs. This separation--or abstraction, as it's called in object-oriented programming--enables programmers to work with general categories of hardware devices from which they can accept data and to which they can send data (see Figure 15.1). In other words, programmers never know the exact type of hardware connected to a given system; all they know is that a particular category of hardware is out there. Programmers code for a printer in general, not a specific model of printer. The same is true for the keyboard and mouse. What particular brand of input device is attached to a computer is the responsibility of the Windows operation system and the specific device drivers installed on the system. Device independence enables you to treat hardware devices as nothing more than event generators.

FIGURE 15.1 The device independence of Windows frees VB programmers from the difficult task of writing code for a particular piece of hardware.

Most Visual Basic controls support three keyboard input events--KeyPress(), KeyUp(), and KeyDown()--and five mouse events--(Click(), DblClick(), MouseUp(), MouseDown(), and MouseMove().

Working with the KeyPress Event

When users press a key within your program, Windows fires a KeyPress event to the form with the focus and then to the control with the focus. The KeyPress event has this syntax:

Private Sub ControlName_KeyPress(KeyAscii as Integer)

In this syntax,

Function keys don't generate a KeyPress event

Only numeric, alphabetic, and select command keys generate a KeyPress event. You can test which keys work with this event by using the sample program in the project KeyPress.vbp on the Web site devoted to this book.

KeyPress is associated with the character of the key being pressed. When the event is fired, Visual Basic passes the ASCII code of the character being input to the KeyAscii argument and thus makes it available to the event procedure for use. If having a parameter attached to an event handler is new to you, take a minute to think about it. You will be seeing many of these in the KeyPress, KeyDown, and KeyUp events.

An ASCII code is a number assigned, by formal convention, to each letter in the alphabet (separate numbers exist for uppercase and lowercase letters) as well as number characters and punctuation characters. Table 15.1 shows the more often used characters with their associated ASCII code numbers.

TABLE 15.1  The Popular ASCII Characters

Number Character
32 space
33 !
34 "
35 #
36 $
37 %
38 &
39 `
40 (
41 )
42 *
43 +
44 ,
45 -
46 .
47 /
48 0
49 1
50 2
51 3
52 4
53 5
54 6
55 7
56 8
57 9
58 :
59 ;
60 <z
61 =
62 >
63 ?
64 @
65 A
66 B
67 C
68 D
69 E
70 F
71 G
72 H
73 I
74 J
75 K
76 L
77 M
78 N
79 O
80 P
81 Q
82 R
83 S
84 T
85 U
86 V
87 W
88 X
89 Y
90 Z
91 [
92 \
93 ]
94 ^
95 _
96 ´
97 a
98 b
99 c
100 d
101 e
102 f
103 g
104 h
105 i
106 j
107 k
108 l
109 m
110 n
111 o
112 p
113 q
114 r
115 s
116 t
117 u
118 v
119 w
120 x
121 y
122 z
123 {
124 |
125 }
126 ~

Figure 15.2 shows you the output from a program that reports the value and the corresponding character of the KeyAscii parameter passed during the KeyPress event for a TextBox. Listing 15.1 shows the code for the KeyPress event procedure for the TextBox. In this case, the ASCII code number 103 was passed to the TextBox, along with the lowercase character g. You will find this is the correct value, as listed in Table 15.1.

FIGURE 15.2 The KeyPress event is associated with the character sent to the control.

You can find the code in Listing 15.1 in the project simplKey.VBP on the Web site devoted to this book (http://www.mcp. com/info). Also on this Web site is the sample project KeyPress.vbp, which you can use to test the key combinations in Table 15.2.

LISTING 15.1  15LIST01.txt--Converting a Character's ASCII Code into a String

01 Private Sub txtSimpl_KeyPress(KeyAscii As Integer)
02 Dim strKeyPressed As String `inputted character
03 Dim strAscii As String `Ascii number
04 Dim Msg As String `Message string
06 `Convert KeyAscii to a character
07 strKeyPressed = Chr(KeyAscii) `VB function Chr
09 `Convert the actual number to a string
10 strAscii = CStr(KeyAscii) `VB function CStr
12 `Build the Message display string
13 Msg = "ASCII Number: " & strAscii
14 Msg = Msg & ", " & "Character: " & strKeyPressed
15 MsgBox Msg
16 End Sub

The ASCII code convention also includes 32 special command or control codes that were extremely important in the era of character-based terminals (see Table 15.2). Several of these codes are still used for their original purpose in Visual Basic.

Select command keys generate KeyPress events

Under Windows 95, the Backspace, Enter, and Esc keys generate ASCII values that can be trapped by the KeyPress event's KeyAscii parameter. These values are 8, 13, and 27, respectively. You also can combine the Backspace and Enter keys with the Ctrl key to produce 127 and 10 for ACSII values. These key combinations are in addition to those listed in Table 15.2.

TABLE 15.2  The ASCII Control Characters

Number Key Combinations Control Code Control Name

0 Ctrl+Shift+@ NUL Null
1 Ctrl+A SOH Start of heading
2 Ctrl+B STX Start of text
3 Ctrl+C ETX End of text
4 Ctrl+D EOT End of transmit
5 Ctrl+E ENQ Inquiry
6 Ctrl+F ACK Acknowledgement
7 Ctrl+G BEL Bell
8 Ctrl+H BS Backspace
9 Ctrl+I HT Horizontal tab
10 Ctrl+J LF Line feed
11 Ctrl+K VT Vertical tab
12 Ctrl+L FF Form feed
13 Ctrl+M CR Carriage feed
14 Ctrl+N SO Shift out
15 Ctrl+O SI Shift in
16 Ctrl+P DLE Data line escape
17 Ctrl+Q DC1 Device control 1
18 Ctrl+R DC2 Device control 2
19 Ctrl+S DC3 Device control 3
20 Ctrl+T DC4 Device control 4
21 Ctrl+U NAK Negative acknowledgment
22 Ctrl+V SYN Synchronous idle
23 Ctrl+W ETB End of transmit block
24 Ctrl+X CAN Cancel
25 Ctrl+Y EM End of medium
26 Ctrl+Z SUB Substitute
27 Ctrl+[ ESC Escape
28 Ctrl+\ FS File separator
29 Ctrl+] GS Group separator
30 Ctrl+Shift+^ RS Record separator
31 Ctrl+Shift+_ US Unit separator

It's important that you be aware of these codes and their uses. Consider a program that needs to disable the entry of an escape command. Although you might remember to program your application to ignore the pressing of the Esc key, a user could also press Ctrl+[ and send the program an unwanted command. On the other hand, if a program disallowed the entry of any ASCII values less than 32, it might prevent the Tab and Enter keys from working properly.

Working with the KeyUp and KeyDown Events

Detection of keystrokes versus character codes

The important distinction between the KeyUp and KeyDown events and the KeyPress event is that KeyPress is associated with characters, whereas KeyUp and KeyDown are associated with keys on the keyboard. Remember, most keys can input one of two characters, depending on the state of the Shift key (a and A, for example). If it's important to your program to know which character has been input, use the KeyPress event. However, if it's important that you know which key has been pressed, use the KeyUp/KeyDown event.

Every time a user presses a key on the keyboard, a KeyDown event is fired to the control that has the focus. When the key is released, a KeyUp event is fired.

The KeyUp/KeyDown event procedures use this syntax:

Private Sub ControlName_KeyUp(KeyCode as Integer, _
                              Shift as Integer)
Private Sub ControlName_KeyDown(KeyCode as Integer, _
                                Shift as Integer)

In this syntax,

TABLE 15.3  The Different Values for the Shift Parameter

Combination Key(s) Held Down Value
Shift 1
Ctrl 2
Alt 4
Shift+Ctrl 3
Shift+Alt 5
Ctrl+Alt 6
Shift+Ctrl+Alt 7

The trick to using the KeyUp/KeyDown event handlers is working with the KeyCode and Shift parameters. In addition to reporting which alphabetic key has been struck, the KeyCode parameter also can report whether users pressed a function key (F1-F12), a key on the numeric keypad, the arrow keys, or any other key. When a key is pressed, Visual Basic sends a value to the KeyCode parameter that's reporting the key in question. The number sent to KeyCode is represented by a constant value, as shown in Table 15.4.

TABLE 15.4  Visual Basic 6.0 KeyCode Constants

Constant Key
vbKeyLButton Left mouse button
vbKeyRButton Right mouse button
vbKeyCancel Cancel
vbKeyMButton Middle mouse button
vbKeyBack Backspace
vbKeyTab Tab
vbKeyClear Clear
vbKeyReturn Enter
vbKeyShift Shift
vbKeyControl Ctrl

Help keys come in two flavors

Many applications use the F1 key as their Help key, because most keyboard manufactures don't provide a separate key labeled Help. Windows, however, supports a Help key, so you may want to support both in your applications. The actual keyboard BIOS scan codes for these two keys are vbKeyHelp = 0x2F and vbKeyF1 = 0x70.

Constant Key
vbKeyMenu Menu
vbKeyPause Pause
vbKeyCapital Caps Lock
vbKeyEscape Esc
vbKeySpace Spacebar
vbKeyPageUp Page Up
vbKeyPageDown Page Down
vbKeyEnd End
vbKeyHome Home
vbKeyLeft ®
vbKeyUp !=
vbKeyRight [Delta]
vbKeyDown ÿ
vbKeySelect Select
vbKeyPrint Print Screen
vbKeyExecute Execute
vbKeySnapshot Snapshot
vbKeyInsert Insert
vbKeyDelete Delete
vbKeyHelp Help
vbKeyNumlock Num Lock
vbKeyA through vbKeyZ Althrough Z, respectively
vbKey0 through vbKey9 0 (zero) through 9, respectively
vbKeyNumpad0 0 through 9 on number pad, respectively
through vbKeyNumpad9
vbKeyMultiply Multiplication sign (*) on number pad
vbKeyAdd Plus sign (+) on number pad
vbKeySeparator Enter on number pad
vbKeySubtract Minus sign (-) on number pad
Constant Key
vbKeyDecimal Decimal point (.) on number pad
vbKeyDivide Division sign (/) on number pad
vbKeyF1 through F1 through F16, respectively

Listing 15.2 shows a piece of code from the project KeyEvent.vbp, which you can find on the Web site dedicated to this book (http://www.mcp.com/info). This code reports which function key has been pressed. It also reports the state of the Shift, Ctrl, and Alt keys. Figure 15.3 shows the code in action.

LISTING 15.2  15List02.TXT--Checking Whether a Function Key Has Been

01 Private Sub Form_KeyDown(KeyCode As Integer, _
Shift As Integer)
02 Dim strKey As String `variable to hold key string
04 `Pass Keycode parameter through Case statement.
05 `If the key up/down is a function key, the case
06 `statement will catch it.
07 Select Case KeyCode
08 Case vbKeyF1
09 strKey = "F1"
10 Case vbKeyF2
11 strKey = "F2"
12 Case vbKeyF3
13 strKey = "F3"
14 Case vbKeyF4
15 strKey = "F4"
16 Case vbKeyF5
17 strKey = "F5"
18 Case vbKeyF6
19 strKey = "F6"
20 Case vbKeyF7
21 strKey = "F7"
22 Case vbKeyF8
23 strKey = "F8"
24 Case vbKeyF9
25 strKey = "F9"
26 Case vbKeyF10
27 strKey = "F10"
28 Case vbKeyF11
29 strKey = "F11"
30 Case vbKeyF12
31 strKey = "F12"
32 Case vbKeyF13
33 strKey = "F13"
34 Case vbKeyF14
35 strKey = "F14"
36 Case vbKeyF15
37 strKey = "F15"
38 Case vbKeyF16
39 strKey = "F16"
40 Case Else
41 strKey = "Some other key"
42 End Select
43 `Check to see if Shift, Ctrl or Alt key is down
44 Select Case Shift
45 Case 0
46 frmKeyEvent.Caption = "No key down"
47 Case 1
48 frmKeyEvent.Caption = "Shift down"
49 Case 2
50 frmKeyEvent.Caption = "Ctrl down"
51 Case 3
52 frmKeyEvent.Caption = "Shift and Ctrl down"
53 Case 4
54 frmKeyEvent.Caption = "Alt down"
55 Case 5
56 frmKeyEvent.Caption = "Shift and Alt down"
57 Case 6
58 frmKeyEvent.Caption = "Ctrl and Alt down"
59 Case 7
60 frmKeyEvent.Caption = "Shift,Ctrl,Alt down"
61 End Select
62 `Report which key is down
63 txtKeyEvent.Caption = "Key Down, Key: " & strKey
64 End Sub

FIGURE 15.3 The KeyUp/KeyDown event procedures enable access to all keys on the keyboard.

Using the KeyPreview Property

Sometimes you want a form to process keyboard input, even if a control on a form has the focus. You use the form's KeyPreview property to do this.

When you create a form, the default value of the KeyPreview property is False. Thus, any keyboard input that you send to a control on the form (a TextBox, for instance) goes directly to that control. If you set the value of KeyPreview property to True, however, the form intercepts all keyboard input. You can then access the input through the form's keyboard event procedures. After the form handles the input, it's passed to the control with the focus.

At http://www.mcp.com/info is a sample project, KeyPress.vbp, in which the form's KeyPress event procedure intercepts all keyboard input headed for a TextBox and manipulates it into a backward string, and then ASCII reads it out (see Figure 15.4). It then sends each respective string to its own TextBox control. The form can intercept and distribute all the keyboard input to the various TextBoxes because the value of the KeyPreview property is set to True. Listing 15.3 shows the code for the Form_KeyPress() event procedure.

FIGURE 15.4 If the value of the form's KeyPreview property were set to False, only the Forward TextBox would receive data.

LISTING 15.3  15LIST03.TXT--The Form's KeyPress Event Procedure

01 Private Sub Form_KeyPress(KeyAscii As Integer)
02 `Send the mouse cursor to the first textbox
03 txtForward.SetFocus
05 `Convert the KeyAscii parameter to a character and
06 `put it in front of the existing text
07 txtBackward.Text = Chr(KeyAscii) & txtBackward.Text
09 `Turn the KeyAscii value to a numeral and
10 `concatenate it to the end of the existing string
11 txtAscii.Text = txtAscii.Text & CStr(KeyAscii) & ",
12 End Sub

Understanding Mouse Input

Every time you do something with the mouse, a mouse event is fired in your Visual Basic application. If you click the mouse, a Click event is fired. When you double-click, a DblClick event is fired. When you press a mouse button down, a MouseDown event is fired, whereas letting the mouse button up causes a MouseUp event. Every time the mouse moves, a MouseMove event occurs. Where and when a given event occurs depends on the position of the mouse pointer.

Most controls support the event procedures just described. Some controls, however, such as the ComboBox, have no support for the MouseDown, MouseUp, and MouseMove events.

Sometimes one gesture with a mouse fires many events. When you click a mouse, not only is a Click event fired, but MouseDown and MouseUp events are also fired. Taking control of the interactions among all the different events requires some getting used to.

Using the Click Event

Program a click event procedure

1. Start a new project. Name the project and the form TClick and frmTClick, respectively. Add a TextBox to the form as shown in Figure 15.5.

FIGURE 15.5 The TextBox supports the click event procedure.

2. Assign a name to the TextBox, such as txtClick.

3. Double-click the TextBox to open the code window. Go to the event procedure drop-down list and change the event procedure from the Change event to the Click event (see Figure 15.6).

FIGURE 15.6 The default event procedure for the TextBox control is the Change event. Some people mistakenly program this event, thinking it's the click event.

4. In the Properties window, clear the value of txtClick's Text property from "Text1" to an empty string (see Figure 15.7).

5. Add the lines of code between Private Sub txtClick_Click() and End Sub (lines 2-21) in Listing 15.4 to the txtClick_Click() event procedure.

6. Compile and run the code (see Figure 15.8).

FIGURE 15.7 Deleting the Text property string value in the Properties window deletes text from the TextBox.

Download this code, too

The code for this exercise is in the project TClick.vbp, which you can find on the Web site dedicated to this book.

LISTING 15.4  15LIST4.TXT--Displaying a Message, in the TextBox, That Reports How Many Times You've Clicked It

01 Private Sub txtClick_Click()
02 `Make this static so it keeps its
03 `value from click to click
04 Static intCntr As Integer
06 `Make a variable to hold a message string
07 Dim Msg As String
09 `Begin a message
10 Msg = "This is click number "
12 `Convert the counter variable from an
13 `integer to a string and concatenate it
14 `to the preceding string
15 Msg = Msg & CStr(intCntr) & "."
17 `Display the string in the text box
18 txtClick.Text = Msg
20 `Increment the counter variable
21 intCntr = intCntr + 1
22 End Sub

FIGURE 15.8 Programming the click event in a TextBox control is atypical. Although meaningful for demonstration purposes, it confuses users when they try to input text.

As you can see, the Click event is a simple event procedure to program. In fact, you can follow the same process to program the DblClick event procedure. Remember, however, that variables declared in a Click event procedure go out of scope when the procedure is completed. Therefore, if you want to maintain a state or value from click to click, you're required to reference a Static variable or a variable from the parent form within the Click event procedure. Static variables are covered in Chapter 7, "Using Data Types, Constants, and Variables."

Working with MouseDown and MouseUp Events

The MouseDown and MouseUp event procedures use this syntax:

Private Sub ControlName_MouseDown(Button As Integer, _
            Shift As Integer, x As Single, y As Single)
Private Sub ControlName_MouseUp(Button As Integer, _
            Shift As Integer, x As Single, y As Single)

In this syntax,

TABLE 15.5  Mouse Button Values

Mouse Button(s) Pressed Button Parameter Value
Left 1
Right 2
Left and right 3
Middle 4
Left and middle 5
Right and middle 6
All 7

In many ways, working with the MouseDown and MouseUp event procedures is very similar to working with the KeyDown and KeyUp procedures. The difference is that MouseDown and MouseUp have a few different parameters passed into them. When a MouseDown event is fired, Visual Basic passes information about what mouse button was pressed and whether the Shift, Ctrl, or Alt key is being held down. VB also passes in the location of the mouse pointer within the control firing the event. The same is true when working with the MouseUp event.

Although you might think that the MouseDown and MouseUp events are a complication of the Click event procedure, you ought to consider them an enhancement. For instance, you can take advantage of the value of the Shift parameter of the MouseDown event procedure to do things that you can't do within a Click event procedure. Suppose that you want to have a secret way to display an Easter egg. Listing 15.5 shows how to use the Shift parameter with a form's MouseDown event procedure to accomplish this. Only someone holding down the Shift key, when the mouse is clicked, can display the message box and the hidden image of an Easter egg.

LISTING 15.5  15LIST05.TXT--If the Shift Parameter Is Equivalent to 1, the Shift Key Is Being Held Down

01 Private Sub Form_MouseDown(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
02 If Shift = 1 Then
03 imgEgg.Visible = True
04 MsgBox "I am a secret Easter Egg"
05 End If
06 imgEgg.Visible = False
07 End Sub

Examples available for download

The code for Listing 15.5 is in the project MouseBut.vbp, and the code for Listing 15.6 is in the project Mouse.vbp. Both projects are available for download from http:// www.mcp.com/info.

On the Web site set up for this book is the project Mouse.vbp, which demonstrates programming the MouseDown and MouseUp event procedures as well as the Click and DblClick event procedures. The project reports all the mouse activity that takes place within a PictureBox control named Picture1. When users press a mouse button (thus firing a MouseDown event), the MouseDown event procedure reports which button and which combination of Shift, Ctrl, and Alt have been pressed. The event procedure uses two Select Case statements to create a string that reports the status of the Shift and Button parameters. The event procedure also reports the position of the mouse pointer (see Figure 15.9). Listing 15.6 shows the code for the MouseDown and MouseUp event procedures.

LISTING 15.6  15LIST06--The MouseDown Event Procedure for the Picture1
PictureBox Control

01 Private Sub Picture1_MouseDown(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
02 Dim strButton As String `holds value of Button param
03 Dim strShift As String `holds value of Shift param
04 Dim strX As String `holds value of X param
05 Dim strY As String `holds value of Y param
07 `Convert X , Y parameters from integers to a string
08 strX = CStr(X)
09 strY = CStr(Y)
11 `Run the SHIFT parameter through a Select Case
12 `statement in order to figure out what combination
13 `of Shift, Ctrl or Alt keys are depressed.
15 `Assign the result to the Shift string variable
16 Select Case Shift
17 Case 0
18 strShift = ""
19 Case 1
20 strShift = "Shift"
21 Case 2
22 strShift = "Ctrl"
23 Case 3
24 strShift = "Shift + Ctrl"
25 Case 4
26 strShift = "Alt"
27 Case 5
28 strShift = "Shift + Alt"
29 Case 6
30 strShift = "Ctrl + Alt"
31 Case 7
32 strShift = "Shift + Ctrl + Alt"
33 End Select
35 `Run the BUTTON parameter through a Select Case
36 `statement to determine what combination of the
37 `Mouse Buttons have been pushed. Assign the
38 `result to the Button string variable
39 Select Case Button
40 Case 0
41 strButton = ""
42 Case 1
43 strButton = "Left"
44 Case 2
45 strButton = "Right"
46 Case 3
47 strButton = "Left + Right"
48 Case 4
49 strButton = "Middle"
50 Case 5
51 strButton = "Left + Middle"
52 Case 6
53 strButton = "Right + Middle"
54 Case 7
55 strButton = "All"
56 End Select
58 `Diplay the event fired
59 lblMouse.Caption = "Mouse Down"
61 `Display the combination of keys pressed
62 lblShift.Caption = strShift
64 `Display the mouse buttons pressed
65 lblButton.Caption = strButton
66 End Sub

FIGURE 15.9 The mouse click event fires Click, MouseDown, and MouseUp events.

Notice in Figure 15.9 that the position of the mouse pointer is reported in twips. This number might be confusing at times. If you need to report the position of the mouse in pixels, replace lines 7-9 of Listing 15.6 with the following code:

`Report the X and Y position in pixels by dividing the
`value of X and Y by the TwipsPerPixelX(Y) property of
`the Screen object. Convert the X and Y parameters from
`integers to a string
    strX = CStr(x/Screen.TwipsPerPixelX)
    strY = CStr(y/Screen.TwipsPerPixely)

Notice also that the following code for the MouseUp event is minimal compared with the MouseDown event. This minimalism is intentional. When users release a mouse button, the MouseUp and MouseMove events are both fired. If the code in each event procedure is trying to affect the same controls, you run into a conflict because you must ensure that each event procedure's scope of activity is relatively exclusive. In the Mouse.vbp project, the MouseUp event sets a Label control's caption, on line 3 below , whereas the MouseMove event reports the mouse pointer's position in another Label control and uses the Line method to draw on the PictureBox.

01 Private Sub Picture1_MouseUp(Button As Integer, _
           Shift As Integer, X As Single, Y As Single)
02     `Diplay the event fired
03     lblMouse.Caption = "Mouse Up"
04 End Sub

Working with the MouseMove Event

The syntax for the MouseMove event procedure is as follows:

Private Sub ControlName_MouseMove(Button As Integer, _
        Shift As Integer, x As Single, y As Single)

It's identical to the MouseDown and MouseUp event procedures. Whenever you move the mouse, a MouseMove event is fired.

The Mouse.vbp project used in the preceding section demonstrates programming the MouseMove event. This event procedure is programmed to report the location of the mouse within the PictureBox control (see Figure 15.10).

FIGURE 15.10 Most controls support the MouseMove event procedure.

As shown in Listing 15.7, the MouseMove event procedure of the Picture control takes the value of the x and y parameters passed to it and displays those values in a Label control. Every time the mouse moves, the new value is reported. Also, the parameters are used to draw lines in the PictureBox by using the Line method of that control. Line 10 in Listing 15.7 performs the drawing that's shown in Figure 15.10.

LISTING 15.7  15LIST07.TXT--Reporting the Mouse Pointer's Value with the
MouseMove Event Procedure

01 Private Sub Picture1_MouseMove(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
02 Dim strX As String `holds converted value of X
03 Dim strY As String `holds converted value of Y
05 `Convert X , Y parameters from integers to string
06 strX = CStr(X)
07 strY = CStr(Y)
09 `Draw line in the Sketch Pad
10 Picture1.Line -(X, Y)
12 `Display the mouse pointer position
13 lblCursor.Caption = "X: " & strX & ", " & "Y: " & strY
14 End Sub

When programming with the MouseMove event, remember that the event is fired every time the mouse moves. This might sound simplistic, but the implications are important. If the code you write in the MouseMove event handler takes longer to execute than the amount of time before the next MouseMoves is fired, your program will display some very strange, possibly fatal behaviors. In Listing 15.8, for example, every time the mouse moves, the code creates a new For...Next loop, thus creating a queue of loops waiting to execute. The loops could go on forever. This unanticipated behavior will affect the integrity of your program.

LISTING 15.8  15LIST08.TXT--Using the MouseMove Event Procedure with

01 Private Sub Form_MouseMove(Button As Integer, _
Shift As Integer, X As Single, Y As Single)
02 Dim intCntr As Integer
03 `Loop could go on forever under certain conditions
04 `depending on the frequency of mouse movement.
05 For intCntr = 0 To 10000
06 frmMouse.Caption = CStr(intCntr)
07 Next intCntr
08 End Sub

Recognizing VB's Limitations with Mouse Input

Visual Basic has two significant shortcomings when it comes to handling mouse input. The first is that the mouse event procedures are control specific. In other words, there's no easy way for a form's mouse-movement event procedures to override a contained child control's event procedure. If you have a PictureBox control on a form or a separate form in the same application and then move the mouse pointer over the PictureBox, the control's MouseMove event procedure is executed. The parent form's MouseMove event procedure is ignored, and control is passed to the PictureBox that now has focus. This is important because the event procedure's x and y mouse pointer location parameters are relative to the control on which the mouse pointer is being moved.

Going back to the PictureBox control scenario, if you place the mouse pointer in the upper left corner of the PictureBox control, the x and y parameters passed to the form's MouseMove event procedure are 0,0. If you put your mouse pointer in the upper left corner of the Picture, the x and y parameters passed to the PictureBox's MouseMove event procedure also are 0,0. (This assumes that the PictureBox isn't in the upper left corner of the form.) Although the Picture is a contained child to the form, it doesn't report back the coordinates of the form; instead, it reports back coordinates relative to its internal Top and Left 0,0 position (see Figure 15.11).

FIGURE 15.11 Keeping track of the mouse pointer's location relative to the form can be difficult.

Draping the mouse outside the form

Use the Mouse.exe application to find the relative offset of the SketchPad PictureBox from its parent form. You can check your answers by looking at the Top and Left properties of the SketchPad PictureBox in the sample Mouse.vbp application on the dedicated Web site.

The second shortcoming is that Visual Basic doesn't report the mouse pointer's location outside its application, unless the MouseDown event has been initiated while under the control of the application and held down during the MouseMove event. (This is often referred to as dragging the mouse.) While the mouse is being dragged, it continues to report its relative position to the control through the MouseMove event; however, you have one final chance to process this information. When the mouse button is released and the MouseUp event fires, you can process the last x and y values, remembering that these are relative to the initiating control's location. These values could easily be negative.

This all means that after the mouse pointer leaves your Visual Basic application, VB normally has no idea where it is. Thus, writing a program that needs to know the location of the mouse pointer anywhere onscreen at anytime is very difficult to accomplish. You can use Visual Basic to access functions in the Windows API (Application Programming Interface) that enable you to use an advanced programming technique called subclassing to accomplish this task. However, this type of API programming is very advanced and very delicate. An error in a Visual Basic application that implements subclassing can cause serious problems not only in the VB application but also throughout the entire system.

Previous chapterNext chapterContents

© Copyright, Macmillan Computer Publishing. All rights reserved.