The example program in this chapter uses SAPI and TAPI services to create a true "hands-free" telephone. With this program and a pc speaker phone, you can lookup and dial telephone numbers by simply giving voice commands to your pc. You'll be able to initiate database adds, edits, and deletes; issue a voice command that will search the database for a name; and tell the program to Dial Mike. The Voice Phone will locate the record in the database, pull up the phone number, place the call, and then prompt you to begin speaking.
As an added bonus, this program gives audible responses to help requests and speaks the names and telephone numbers of selected records in the database. Even the About box is "read" to you! Figure 35.1 shows a completed version of Voice Phone in action.
Figure 35.1 : The completed version of Voice Phone.
There is one main form for the project and three support forms:
In addition to the forms, there are four support modules for the Voice Phone project:
Before you begin coding the project, you'll need to make sure you have the following resources loaded available on your workstation:
When you first start this project, you'll need to make sure you have loaded the proper support libraries for Visual Basic. Select Tools | References and load the following:
Note |
If you don't have these libraries available from your References dialog box, you'll need to use the Browse button to find them. Usually they can be found in the SYSTEM folder of the WINDOWS directory. The Voice libraries can also be found on the CD-ROM that ships with this book. You probably have other resources loaded for your programs. That's fine. Just be sure you have the three resources listed above. |
The first step in the process of building the Voice Phone project is creating the library modules. Three of the modules exist to provide simple support for the Windows extension services (SAPI and TAPI). The fourth module holds most of the project code.
The AssistedTAPI module holds the Telephony API declarations, two type definitions, and two Visual Basic wrapper functions. With this one code module you can provide any Visual Basic or VBA-compatible program with basic TAPI services.
Tip |
You might think it a better idea to implement Assisted TAPI support using a Visual Basic class module instead of a simple code module. However, the code module can be loaded into any VBA-compatible environment (including Visual Basic 3.0). The class module could only be used for Visual Basic 4.0. |
Add a BAS module to your project (Insert | Module) and set its Name property to AssistedTAPI. Save the module as VTAPI.BAS. Now you're ready to start coding.
The first things to add to this module are the Assisted TAPI API declarations. Listing 35.1 shows the code that imports the tapiRequestMakeCall and tapiGetLocationInfo API calls.
Listing 35.1. Adding the Assisted Telephony API Declarations.
'
' declare assisted tapi functions
'
#If Win32 Then
Declare Function tapiRequestMakeCall Lib "TAPI32.DLL" (ByVal lpszDestAddress As ÂString, ByVal lpszAppName As String, ByVal lpszCalledParty As String, ByVal ÂlpszComment As String) As Long
Declare Function tapiGetLocationInfo Lib "TAPI32.DLL" (ByVal lpszCountryCode As ÂString, ByVal lpszCityCode As String) As Long
#Else
Declare Function tapiRequestMakeCall Lib "TAPI.DLL" (ByVal lpszDestAddress As ÂString, ByVal lpszAppName As String, ByVal lpszCalledParty As String, ByVal ÂlpszComment As String) As Long
Declare Function tapiGetLocationInfo Lib "TAPI.DLL" (ByVal lpszCountryCode As ÂString, ByVal lpszCityCode As String) As Long
#End If
Notice that the code in Listing 35.1 uses the conditional compilation directives along with the code for both 16- and 32-bit Visual Basic 4.0. This ensures that the code will work in either version of Visual Basic 4.0 that you use.
Next you need to add two user-defined types to the module. These types encapsulate the parameters needed for the two TAPI calls. Using UDTs in this way reduces the complexity of your code and makes it easier to read. Add the code shown in Listing 35.2 to the general section of the module.
Listing 35.2. Adding the user-defined types.
'
' TAPILocation Type
Type TAPILocation
Country As String * 1
City As String * 3
End Type
'
' TAPIMakeCall Type
Type TAPICall
Address As String
AppName As String
CalledParty As String
Comment As String
End Type
After declaring the API routines and defining the type variables, you're ready to add the wrapper functions that will encapsulate the API calls. Listing 35.3 shows the function that supports the tapiGetLocationInfo API call. Add this to your module.
Listing 35.3. Adding the TAPIGetLocation function.
Public Function TAPIGetLocation() As TAPILocation
'
' returns UDT w/ city and country
'
Dim lTapi As Long
Dim cCountry As String * 1
Dim cCity As String * 3
'
lTapi = tapiGetLocationInfo(cCountry, cCity)
If lTapi >= 0 Then
TAPIGetLocation.Country = cCountry
TAPIGetLocation.City = cCity
End If
'
End Function
Notice that this function returns a UDT that contains both the country code and the city code for the workstation.
Note |
The TAPIGetLocation function is not called in this project. It is included here for completeness. When you use this module for other TAPI projects, you'll have this function call already defined. |
The second API wrapper function is the TAPIMakeCall function. This function accepts the TAPICall user-defined type as input and places an outbound call. Listing 35.4 shows the code for this function.
Listing 35.4. Adding the TAPIMakeCall function.
Public Function TAPIMakeCall(tapiRec As TAPICall) As Long
'
' make an assisted TAPI call
' returns 0 if OK, <0 if error
'
TAPIMakeCall = tapiRequestMakeCall(tapiRec.Address, tapiRec.AppName, ÂtapiRec.CalledParty, tapiRec.Comment)
'
End Function
This function returns a value that indicates the results of the TAPI request. If the value is less than 0, you've got an error condition. Only the first parameter is required (Address).
Tip |
For a more detailed look at Assisted Telephony, refer to Chapter 29, "Writing TAPI-Assisted Applications." |
That is the end of the Assisted TAPI support module. Save this module (VTAPI.BAS) and the project (VPHONE.VBP) before continuing.
Since this project uses the SAPI Voice Command and Voice Text type libraries, you'll need to add a class module to your project for each of the two libraries. These classes were designed to allow high-level languages (like Visual Basic) to register services that require the use of notification callbacks. The callback module for the TTS engine will not be used in this project. However, you'll use the SR callback routines to trap and respond to spoken commands.
Warning |
The function names for these callbacks cannot be altered. The OLE libraries for SR and TTS services are looking for these specific function names. If you use some other names, the callbacks will not work and you will get an error report when you request TTS or SR services. |
First add the TTS callback functions. In this project, the functions will be empty, but you'll need to register them anyway. Add a class module to your project (Insert | Class Module). Set the class name to TTSCallBack, set its Instancing property to Creatable, MultiUse, and its Public property to TRUE. Now add the two functions from Listing 35.5 to the class.
Listing 35.5. Adding functions to the TTSCallBack class.
Option Explicit
Public Function SpeakingDone()
'
' this method will execute when the
' TTS engine stops speaking text
'
End Function
Public Function SpeakingStarted()
'
' this method will execute when the
' TTS engine starts speaking text
'
End Function
When you've completed the functions, save the module as TTSCBK.CLS.
Now add a second class module to the project. Set its Name property to SRCallBack, its Instancing property to Createable, MultiUse, and its Public property to TRUE. Now add the code shown in Listing 35.6 to the class.
Listing 35.6. Adding functions to the SRCallBack class.
Option Explicit
Function CommandRecognize(szCommand As String, dwID As Long)
'
' fires off each time a command goes by
'
Dim cToken As String
Dim cContent As String
Dim iSpace As Integer
Dim cReturn As String
'
szCommand = Trim(szCommand) & " "
iSpace = InStr(szCommand, " ")
cToken = UCase(Left(szCommand, iSpace - 1))
cContent = Mid(szCommand, iSpace + 1, 255)
'
Select Case cToken
Case "NEW"
AddRec 'frmVPhone.cmdPhone_Click 0
Case "EDIT"
EditRec cContent
Case "DELETE"
DeleteRec cContent
Case "PLACE"
PlaceCall frmVPhone.txtDial, ""
Case "FIND"
frmVPhone.txtDial = LookUp(cContent)
Case "DIAL"
cReturn = LookUp(cContent)
frmVPhone.txtDial = cReturn
PlaceCall cReturn, cContent
End Select
'
End Function
Function CommandOther(szCommand As String, szApp As String, szState As String)
End Function
You'll notice that the only routine used is the CommandRecognize function. This routine looks at each command that passes through the speech recognition engine, parses the input and, if it's a known command, executes the appropriate code.
The reason the command line must be parsed is that several of the voice commands will be in the form of lists. You may remember that you can register command lists with the SR engine without knowing the members of the list ahead of time. In your project, you'll fill these lists with the names of people in the user's phone directory at run-time.
After you've entered the code, save this module as SRCBK.CLS before continuing with the chapter.
The LibVPhone module contains most of the code for the project. It is here that you'll put the routines that initialize the speech engines, load the database engine, and handle the processes of adding, editing, and deleting records from the phone book.
First, add a code module to the project. Set its Name property to LibVPhone and save it as VPHONE.BAS. Next, add the project-level declarations shown in Listing 35.7 to the general declaration section of the module.
Listing 35.7. Adding the project-level declarations.
Option Explicit
'
' establish voice command objects
Public objVCmd As Object
Public objVMenu As Object
Public lVMenuIdx As Long
Public objVText As Object
Public iVType As Integer
Public cUserMsgs() As String
'
' spoken message handles
Public Const ttsHello = 0
Public Const ttsVPhone = 1
Public Const ttsList = 2
Public Const ttsExit = 3
Public Const ttsEdit = 4
'
' database objects
Public wsPhone As Workspace
Public dbPhone As Database
Public rsPhone As Recordset
The code here declares the required objects for SAPI and for database services. There are also several constants that will be used to point to text messages that will be spoken by the engine at requested times in the program.
Next add the routine that will start the SAPI service initialization. Add a subroutine called InitVCmd to the project and enter the code from Listing 35.8.
Listing 35.8. Adding the InitVCmd routine.
Public Sub InitVCmd()
'
' init voice command
Set objVCmd = CreateObject("Speech.VoiceCommand")
objVCmd.Register ""
objVCmd.Awake = True
objVCmd.Callback = App.EXEName & ".SRCallBack"
'
' init voice menu
BuildVMenu
objVMenu.Active = True
'
End Sub
This code initializes the voice command object that will be used to handle speech recognition services for the program. Notice the line that registers the SRCallBack class. The class name is prefixed with the application name. You must set this application name manually. To do this, select Tools | Options | Project and enter VPHONE in the Project Name field.
Warning |
You must update the Project Name field to match the App.EXEName value before you attempt to run the project. If you fail to do this, you will receive errors from the SR engine. |
The InitVCmd routine calls another routine to handle the creation of the command menu. Add a new subroutine to the module called BuildVMenu and enter the code shown in Listing 35.9.
Listing 35.9. Adding the BuildVMenu routine.
Public Sub BuildVMenu()
'
' build a voice menu
'
Dim iType As Integer
Dim cState As String
Dim lLangId As Long
Dim cDialect As String
Dim cAppName As String
Dim cVMenu(3) As String
Dim x As Integer
'
' set params
cAppName = App.EXEName
cState = "Voice Phone"
cDialect = ""
lLangId = 1033
iType = vcmdmc_CREATE_TEMP
'
' set menu commands
cVMenu(1) = "New Record"
cVMenu(2) = "Place Call"
cVMenu(3) = "Exit"
'
' now instance menu
Set objVMenu = objVCmd.MenuCreate( _
cAppName, cState, lLangId, cDialect, iType)
'
' add simple commands to menu
For x = 1 To 3
lVMenuIdx = lVMenuIdx + 1
objVMenu.Add lVMenuIdx, cVMenu(x), "Voice Phone Commands", "Voice Phone ÂCommands"
Next x
'
' create list commands
lVMenuIdx = lVMenuIdx + 1
objVMenu.Add lVMenuIdx, "Edit <Name>", "Edit Name", "Edit Name"
'
lVMenuIdx = lVMenuIdx + 1
objVMenu.Add lVMenuIdx, "Delete <Name>", "Delete Name", "Delete Name"
'
lVMenuIdx = lVMenuIdx + 1
objVMenu.Add lVMenuIdx, "Dial <Name>", "Dial Name", "Dial Name"
'
lVMenuIdx = lVMenuIdx + 1
objVMenu.Add lVMenuIdx, "Find <Name>", "Find Name", "Find Name"
'
End Sub
There's a lot going on in this routine. First, internal variables are declared and set to their respective values. Next, the menu object is created using the MenuCreate method. After the menu object is created, the Add method of the menu object is used to add simple voice commands to the menu. Finally, the list commands are added to the menu (Edit, Delete, Dial, and Find). All these list commands refer to the Name list. This list will be filled in at run-time.
Now add the routine that will fill in the name list for the voice commands. Create a new subroutine called LoadNameList and enter the code you see in Listing 35.10.
Listing 35.10. Adding the LoadNameList routine.
Public Sub LoadNameList()
'
' fill list of names for vCmd
'
Dim cNameList As String
Dim iNameCount As String
'
cNameList = ""
iNameCount = 0
rsPhone.MoveFirst
Do Until rsPhone.EOF
cNameList = cNameList & rsPhone.Fields("Name") & Chr(0)
iNameCount = iNameCount + 1
rsPhone.MoveNext
Loop
'
objVMenu.ListSet "Name", iNameCount, cNameList
'
End Sub
As you can see, the LoadNameList routine reads each record in the open database table and adds the names, separated by chr(0), to a single string. This string is the list that is registered with the menu object using the ListSet method.
Now you're ready to add the routines that will initialize the Voice Text object for TTS services. First, add a new subroutine called InitVTxt and enter the code shown in Listing 35.11.
Listing 35.11. Adding the InitVTxt routine.
Public Sub InitVTxt()
'
' init voice text
Set objVText = CreateObject("Speech.VoiceText")
objVText.Register "", App.EXEName
objVText.Enabled = True
objVText.Callback = App.EXEName & ".TTSCallBack"
'
End Sub
This looks a lot like the InitVCmd routine. Notice the callback registration here, too. Again, it is very important that the Project Title property (Tools | Options | Project | Project Title) is set to the same value as the application executable filename. If not, you won't be able to use TTS services in your application.
The only other TTS support routine you'll need is the one that builds a set of messages that will be spoken by the TTS engine at different times in the program. Add a new subroutine called LoadMsgs to the module and enter the code from Listing 35.12.
Listing 35.12. Adding the LoadMsgs routine.
Public Sub LoadMsgs()
'
' build a list of user messages
'
ReDim cUserMsgs(5)
'
cUserMsgs(0) = "Hello. Welcome to Voice Phone."
cUserMsgs(1) = "Press New, Edit, or Delete to modify the phone list."
cUserMsgs(2) = "Select a name from the list and press Place Call to dial the Âphone."
cUserMsgs(3) = "Press Exit to end this program."
cUserMsgs(4) = "Enter name and phone number, then press OK or cancel."
'
End Sub
The public constants declared at the top of this module will be used to point to each of these messages. This will make it easier to read the code.
Next you need to add several routines to initialize and support database services. First, add the InitDB subroutine to your project and enter the code shown in Listing 35.13.
Listing 35.13. Adding the InitDB routine.
Public Sub InitDB()
'
' set up db stuff
'
Dim cDBName As String
cDBName = App.Path & "\VPHONE.MDB"
On Error Resume Next
Open cDBName For Input As 1
If Err <> 0 Then
Close 1
BuildDatabase
Else
Close 1
End If
On Error GoTo 0
'
OpenDatabase
'
End Sub
Warning |
Using the App.Path property to set the location of the MDB file assumes that you have created a project directory. If you attempt to place the project and the MDB files in the root directory of a drive, you'll receive error messages. It's recommended that you create a project directory and store the MDB in that directory. |
The only real purpose of this routine is to check for the existence of the database file. If it is not found, the BuildDatabase routine is called before the OpenDatabase routine. Now add the BuildDatabase subroutine to your project as shown in Listing 35.14.
Listing 35.14. Adding the BuildDatabase routine.
Public Sub BuildDatabase()
'
' build new database
'
On Error GoTo LocalErr
'
Dim ws As Workspace
Dim db As Database
Dim cSQL(3) As String
Dim x As Integer
'
cSQL(1) = "CREATE TABLE VPHONE (Name TEXT(20),Phone TEXT(20));"
cSQL(2) = "INSERT INTO VPHONE VALUES ('Information','1-555-1212');"
cSQL(3) = "INSERT INTO VPHONE VALUES('SAMS Publishing','1-800-428-5331');"
'
Set ws = DBEngine.Workspaces(0)
Set db = CreateDatabase(App.Path & "\VPHONE.MDB", dbLangGeneral)
'
For x = 1 To 3
db.Execute cSQL(x), dbFailOnError
Next x
'
db.Close
Set db = Nothing
Set ws = Nothing
'
Exit Sub
'
LocalErr:
MsgBox Err.Description & Chr(13) & Err.Source, vbCritical, "BuildDatabase"
'
End Sub
The code here is quite handy. First, the database file is created. Then, three SQL statements are executed. The first one creates the new VPHONE table. The second two statements add two records to the new table.
Tip |
This is a great technique for building databases upon installation of a new application. This way, users don't have to worry about copying data files, confusing older versions of the data, and so on. Even better, if you need to start the database from scratch, all you need to do is remove the database file and start the program-it will create the initial database for you! |
After the BuildDatabase routine has been added, you need to add the code that will open the existing database and select the phone records. Create the OpenDatabase subroutine and enter the code from Listing 35.15.
Listing 35.15. Adding the OpenDatabase routine.
Public Sub OpenDatabase()
'
' open phone database
'
On Error GoTo LocalErr
'
Dim cSelect As String
'
cSelect = "SELECT * FROM VPHONE"
'
Set wsPhone = DBEngine.Workspaces(0)
Set dbPhone = wsPhone.OpenDatabase(App.Path & "\VPHONE.MDB")
Set rsPhone = dbPhone.OpenRecordset(cSelect, dbOpenDynaset)
'
Exit Sub
'
LocalErr:
MsgBox Err.Description & Chr(13) & Err.Source, vbCritical, "OpenDatabase"
'
End Sub
Nothing real fancy here. The database is opened and a single SQL SELECT statement is executed to create a Dynaset-type recordset for use in the program.
There are four remaining database service support routines:
The AddRec and EditRec routines use a secondary dialog form (frmVRec), which you'll build in the next section of this chapter.
Create a new subroutine called AddRec and enter the code from Listing 35.16.
Listing 35.16. Adding the AddRec routine.
Public Sub AddRec()
'
' add a new record
'
Load frmVRec
frmVRec.txtName = ""
frmVRec.txtPhone = ""
frmVRec.lblaction = "ADD"
frmVRec.Show vbModal
'
End Sub
Now add the EditRec subroutine and enter the code from Listing 35.17.
Listing 35.17. Adding the EditRec routine.
Public Sub EditRec(cName As String)
'
' edit an existing record
'
Dim iAns As Integer
'
cName = Trim(cName)
rsPhone.FindFirst "Name='" & cName & "'"
If rsPhone.NoMatch = False Then
Load frmVRec
frmVRec.txtName = rsPhone.Fields("Name")
frmVRec.txtPhone = rsPhone.Fields("Phone")
frmVRec.lblaction = "EDIT"
frmVRec.Show vbModal
End If
'
End Sub
The DeleteRec subroutine consists of a single message box confirmation and the delete action. Add the code in Listing 35.18 to the module.
Listing 35.18. Adding the DeleteRec routine.
Public Sub DeleteRec(cName As String)
'
' delete record from table
'
Dim iAns As Integer
'
cName = Trim(cName)
iAns = MsgBox(cName, vbExclamation + vbYesNo, "Delete Record")
If iAns = vbYes Then
rsPhone.FindFirst "Name = '" & cName & "'"
If rsPhone.NoMatch = False Then
rsPhone.Delete
rsPhone.MoveNext
End If
End If
'
End Sub
Finally, add a new function called LookUp to the module. This function takes one parameter (the Name) and returns the corresponding phone number. Enter the code from Listing 35.19.
Listing 35.19. Adding the LookUp function.
Public Function LookUp(cName As String) As String
'
' lookup a name in the list
' return the phone number
'
Dim cRtn As String
'
cName = Trim(cName)
rsPhone.FindFirst "Name = '" & cName & "'"
If rsPhone.NoMatch = True Then
cRtn = ""
Else
cRtn = rsPhone.Fields("Phone").Value
End If
'
LookUp = cRtn
'
End Function
Only two support routines are left. The PlaceCall routine is used to perform the Assisted TAPI service request. Listing 35.20 shows you the code for this routine.
Listing 35.20. Adding the PlaceCall routine.
Public Sub PlaceCall(cPhone As String, cName As String)
'
Dim tCall As TAPICall
Dim lRtn As Long
'
If Trim(cPhone) <> "" Then
tCall.Address = cPhone
tCall.AppName = App.EXEName
tCall.CalledParty = cName
tCall.Comment = ""
lRtn = TAPIMakeCall(tCall)
If lRtn < 0 Then
MsgBox lRtn, vbcritical, "TAPI Error!"
End If
End If
'
End Sub
The last routine is one that is used to center dialog boxes on the screen. Add the code from Listing 35.21 to your project.
Listing 35.21. Adding the CenterForm routine.
Public Sub CenterForm(frm As Form)
'
frm.Left = (Screen.Width - frm.Width) / 2
frm.Top = (Screen.Height - frm.Height) / 2
'
End Sub
That is the end of the LibVPhone module code. Save this module (VPHONE.BAS) and the project (VPHONE.VBP) before you move to the next section.
The Vphone form is the main dialog box of the project. The first step is to lay out the controls on the form. Then you can add the menu and the code behind the form. Refer to Figure 35.2 and Table 35.1 for details on the size and position of the controls on the form.
Figure 35.2 : Laying out the Vphone form.
Control | Property | Setting |
VB.Form | Name | frmVPhone |
BorderStyle | 3 'Fixed Dialog | |
Caption | "Form1" | |
Height | 3795 | |
Icon | "VPHONE.ICO" | |
Left | 1755 | |
MaxButton | 0 'False | |
MinButton | 0 'False | |
ShowInTaskbar | -1 'True | |
Top | 2160 | |
Width | 6720 | |
VB.CommandButton | Name | cmdPhone |
Caption | "&Help" | |
Height | 300 | |
Index | 4 | |
Left | 5280 | |
TabIndex | 7 | |
Top | 2580 | |
Width | 1200 | |
VB.CommandButton | Name | cmdPhone |
Caption | "E&xit" | |
Height | 300 | |
Index | 3 | |
Left | 5280 | |
TabIndex | 6 | |
Top | 2160 | |
Width | 1200 | |
VB.CommandButton | Name | cmdPhone |
Caption | "&Edit" | |
Height | 300 | |
Index | 2 | |
Left | 5280 | |
TabIndex | 5 | |
Top | 1740 | |
Width | 1200 | |
VB.CommandButton | Name | cmdPhone |
Caption | "&Delete" | |
Height | 300 | |
Index | 1 | |
Left | 5280 | |
TabIndex | 4 | |
Top | 1320 | |
Width | 1200 | |
VB.CommandButton | Name | cmdPhone |
Caption | "&New" | |
Height | 300 | |
Index | 0 | |
Left | 5280 | |
TabIndex | 3 | |
Top | 900 | |
Width | 1200 | |
VB.ListBox | Name | List1 |
Font | name="MS LineDraw" | |
size=8.25 | ||
Height | 2370 | |
Left | 120 | |
TabIndex | 2 | |
Top | 540 | |
Width | 4995 | |
VB.CommandButton | Name | cmdDial |
Caption | "&Place Call" | |
Height | 300 | |
Left | 120 | |
TabIndex | 1 | |
Top | 120 | |
Width | 1200 | |
VB.TextBox | Name | txtDial |
Height | 300 | |
Left | 1440 | |
TabIndex | 0 | |
Text | "Text1" | |
Top | 120 | |
Width | 3660 | |
VB.Image | Name | Image1 |
Height | 615 | |
Left | 5520 | |
Picture | "VPHONE.ICO" | |
Stretch | -1 'True | |
Top | 120 | |
Width | 675 |
Note |
The VPHONE.ICO icon file that is used in this project can be found on the CD-ROM that ships with the book. Be sure to copy that file to the application directory before you start the project. |
Along with the control layout, there is also a small menu that goes with the VPhone form. Refer to Figure 35.3 and Table 35.2 for details on laying out the Vphone menu.
Figure 35.3 : Laying out the Vphone menu.
Level | Property | Setting |
Top Level | Name | mnuFile |
Caption | "&File" | |
Level 2 | Name | mnuFileItem |
Caption | "&New..." | |
Index | 0 | |
Level 2 | Name | mnuFileItem |
Caption | "&Edit..." | |
Index | 1 | |
Level 2 | Name | mnuFileItem |
Caption | "&Delete" | |
Index | 2 | |
Level 2 | Name | mnuFileItem |
Caption | "-" | |
Index | 3 | |
Level 2 | Name | mnuFileItem |
Caption | "&Place Call" | |
Index | 4 | |
Level 2 | Name | mnuFileItem |
Caption | "-" | |
Index | 5 | |
Level 2 | Name | mnuFileItem |
Caption | "E&xit" | |
Index | 6 | |
Top Level | Name | mnuHelp |
Caption | "&Help" | |
Level 2 | Name | mnuHelpItem |
Caption | "Help..." | |
Index | 0 | |
Level 2 | Name | mnuHelpItem |
Caption | "&About..." | |
Index | 1 |
Note |
Be sure to lay out the menu using menu arrays. You'll add code to the menu array in the next section. |
After laying out the form, save it as VPHONE.FRM and the save the project as VPHONE.VBP before moving on to the next section.
There's not a lot of code for the VPhone form. Most of the important stuff was built in the LibVPhone module. However, you'll need to add code to the control events that call the LibVPhone routines.
First, add the code from Listing 35.22 to the Form_Load event.
Listing 35.22. Coding the Form_Load event.
Private Sub Form_Load()
'
' set form properties
Me.Caption = "Voice Phone"
Me.Icon = LoadPicture(App.Path & "\vphone.ico")
Image1.Picture = LoadPicture(App.Path & "\vphone.ico")
Image1.Stretch = True
CenterForm Me
'
' initialize objects
InitVCmd ' start SR engine
InitVTxt ' start TTS engine
InitDB ' state DB engine
LoadNameList ' fill SR list
LoadList ' fill onscreen list
LoadMsgs ' fill TTS list
'
' set variables
txtDial = ""
iVType = vtxtst_READING + vtxtsp_NORMAL
'
objVText.Speak cUserMsgs(ttsHello), iVType
'
End Sub
The code in Listing 35.22 sets up some basic form properties and then calls the initialization routines for the various services. Finally, the application sends out a greeting message to the user.
Next, add the code in Listing 35.23 to the Form_Unload event.
Listing 35.23. Coding the Form_Unload event.
Private Sub Form_Unload(Cancel As Integer)
'
' destroy objects
Set objVMenu = Nothing
Set objVCmd = Nothing
Set objVText = Nothing
Set rsPhone = Nothing
Set dbPhone = Nothing
Set wsPhone = Nothing
'
End Sub
This code destroys the programming objects created at startup. It's always a good idea to do this before exiting your application.
The Form_Load event calls a custom routine called LoadList. This subroutine fills the onscreen list box with the names and phone numbers from the database. Add the LoadList subroutine to your form and enter the code from Listing 35.24.
Listing 35.24. Adding the LoadList routine.
Public Sub LoadList()
'
' fill onscreen list with name/phone
'
Dim cLine As String
List1.Clear
'
' add header line first
List1.AddItem "NAME" & String(16, ".") & Space(5) & "PHONE" & String(15, ".")
'
' now add database items
rsPhone.MoveFirst
Do Until rsPhone.EOF
cLine = Space(50)
Mid(cLine, 1, 20) = Left(rsPhone.Fields("Name"), 20)
Mid(cLine, 26, 20) = Left(rsPhone.Fields("Phone"), 20)
List1.AddItem cLine
rsPhone.MoveNext
Loop
'
End Sub
Next, add the code from Listing 35.25 to handle the user selections on the main command button array (cmdPhone).
Listing 35.25. Coding the cmdPhone_Click event.
Private Sub cmdPhone_Click(Index As Integer)
'
' handle user selections
'
Dim cName As String
Dim iAns As Integer
Dim x As Integer
'
Select Case Index
Case 0 ' add a record
AddRec
Case 1 ' delete a record
If List1.ListIndex > 0 Then ' skip first line!
cName = Left(List1.List(List1.ListIndex), 20)
DeleteRec cName
End If
Case 2 ' edit a record
If List1.ListIndex > 0 Then
cName = Left(List1.List(List1.ListIndex), 20)
EditRec cName
End If
Case 3 ' help
objVText.Speak cUserMsgs(ttsVPhone), iVType
objVText.Speak cUserMsgs(ttsList), iVType
objVText.Speak cUserMsgs(ttsExit), iVType
Case 4 ' exit
Unload Me
End
End Select
'
' update lists
LoadList
LoadNameList
'
End Sub
Notice that help is delivered in the form of three spoken messages to the user.
You also need to code the cmdDial_Click event. This code fires each time the user presses the Place Call command button. Enter the code from Listing 35.26.
Listing 35.26. Coding the cmdDial_Click event.
Private Sub cmdDial_Click()
'
' try to place the call
'
If Trim(txtDial) <> "" Then
PlaceCall txtDial, "" ' call dialer
Else
If List1.ListIndex > 0 Then
List1_DblClick
PlaceCall txtDial, ""
Else
MsgBox "Select a Name from the List", vbExclamation, "Place a Call"
End If
End If
'
End Sub
The cmdDial_Click event will first check the txtDial control to see if a phone number is present. If it is, that number is used to place the call. If no number is present, the routine will see if the user has selected a name from the list box. If so, the routine first calls the List1_DblClick event to force the name into the txtDial text box, then calls the PlaceCall routine to make the call. Finally, if none of this works, a message is displayed telling the user to select a name from the list.
Now add code to the List1_DblClick event to move the phone number from the list box into the txtDial text box. Listing 35.27 shows how this is done.
Listing 35.27. Coding the List1_DblClick event.
Private Sub List1_DblClick()
'
' select name from the list
'
Dim cReturn As String
'
If List1.ListIndex > 0 Then
cReturn = Left(List1.List(List1.ListIndex), 20)
txtDial = LookUp(cReturn)
End If
'
End Sub
The only code left to create is the code to handle the menu arrays. Listing 35.28 shows the code for both the mnuFileItem_Click and the mnuHelpItem_Click events. Add these two code modules to your form.
Listing 35.28. Coding the menu array events.
Private Sub mnuFileItem_Click(Index As Integer)
'
' handle user clicks
'
Select Case Index
Case 0 ' new
cmdPhone_Click 0
Case 1 ' edit
cmdPhone_Click 1
Case 2 ' delete
cmdPhone_Click 2
Case 4 ' place call
cmdDial_Click
Case 6 ' exit
Unload Me
End Select
'
End Sub
Private Sub mnuHelpItem_Click(Index As Integer)
'
Select Case Index
Case 0 ' help screen
frmHelp.Show vbModal
Case 1 ' about
frmAbout.Show vbModal
End Select
'
End Sub
That's the end of the code for the VPhone form. Save the form (VPHONE.FRM) and the project (VPHONE.VBP) before continuing.
There are three small support forms for the VPhone project. The VRec form is used to handle adds and edits to the data table. The Vhelp form displays a set of help strings, and the VAbout dialog box just shows the standard program information.
The VRec form is used to handle adding new records to the data table and editing existing records. There are two text boxes, three label controls, and three command buttons on the form. Add a new form to the project and lay out the controls on the form as shown in Figure 35.4 and Table 35.3.
Figure.35.4 : Laying out the VRec form.
Control | Property | Setting |
VB.Form | Name | frmVRec |
Caption | "Form2" | |
Height | 1680 | |
Left | 1725 | |
Top | 2445 | |
Width | 5340 | |
VB.CommandButton | Name | cmdRec |
Caption | "&Help" | |
Height | 300 | |
Index | 2 | |
Left | 3900 | |
TabIndex | 7 | |
Top | 120 | |
Width | 1200 | |
VB.CommandButton | Name | cmdRec |
Caption | "Cancel" | |
Height | 300 | |
Index | 1 | |
Left | 3900 | |
TabIndex | 5 | |
Top | 840 | |
Width | 1200 | |
VB.CommandButton | Name | cmdRec |
Caption | "OK" | |
Height | 300 | |
Index | 0 | |
Left | 3900 | |
TabIndex | 4 | |
Top | 480 | |
Width | 1200 | |
VB.TextBox | Name | txtPhone |
Height | 300 | |
Left | 1380 | |
TabIndex | 3 | |
Text | "Text1" | |
Top | 480 | |
Width | 2400 | |
VB.TextBox | Name | txtName |
Height | 300 | |
Left | 1380 | |
TabIndex | 1 | |
Text | "Text1" | |
Top | 120 | |
Width | 2400 | |
VB.Label | Name | lblAction |
Caption | "lblAction" | |
Height | 255 | |
Left | 120 | |
TabIndex | 6 | |
Top | 900 | |
Visible | 0 'False | |
Width | 1155 | |
VB.Label | Name | lblPhone |
Caption | "Phone:" | |
Height | 300 | |
Left | 120 | |
TabIndex | 2 | |
Top | 480 | |
Width | 1200 | |
VB.Label | Name | lblName |
Caption | "Name:" | |
Height | 300 | |
Left | 120 | |
TabIndex | 0 | |
Top | 120 | |
Width | 1200 |
Notice that the lblAction label control is an invisible control. This control is used to pass information from the VPhone form to the VRec form, and is not used for direct display at run-time.
There is very little code needed for the VRec form. Listing 35.29 shows the code for the Form_Load and Form_Activate events. Add this code to your form.
Listing 35.29. Coding the Form_Load and Form_Activate events.
Private Sub Form_Activate()
'
' tell them!
'
If Len(txtName.Text) <> 0 Then
objVText.Speak txtName.Text, iVType
End If
If Len(txtPhone.Text) <> 0 Then
objVText.Speak txtPhone.Text, iVType
End If
'
End Sub
Private Sub Form_Load()
'
Me.Caption = "Add/Edit a Record"
CenterForm Me
'
txtName = "'"
txtPhone = ""
'
End Sub
Nothing fancy in the Form-Load event. The Form_Activate event contains code that will read the database record aloud to the user.
The only other code needed on the form is code for the cmdRec_Click event. Enter the code from Listing 35.30 into your project.
Listing 35.30. Coding the cmdRec_Click event.
Private Sub cmdRec_Click(Index As Integer)
'
' handle user selections
'
Select Case Index
Case 0 ' OK
If Len(Trim(txtName)) <> 0 Then
If lblaction = "ADD" Then
rsPhone.AddNew
Else
rsPhone.Edit
End If
'
rsPhone.Fields("Name") = txtName
rsPhone.Fields("Phone") = txtPhone
rsPhone.Update
End If
Unload Me
Case 1 ' cancel
Unload Me
Case 2 ' help
objVText.Speak cUserMsgs(ttsEdit), iVType
End Select
'
End Sub
You'll notice that this routine checks the contents of the invisible label control (lblAction) to see if this is an "add" or "edit" form. If this is an "add" form, the contents of the control are used to add a new record to the table.
That's it for this form. Save the form as VREC.FRM and update the project (VPHONE.VBP) before going on to the next section.
The VHelp form is a simple one-screen help box. This screen not only displays help tips on using the Voice Phone, it also speaks those tips to the user. Refer to Figure 35.5 and Table 35.4 for help in laying out the form.
Figure 35.5 : Laying out the Vhelp form.
Control | Property | Setting |
VB.Form | Name | frmHelp |
BorderStyle | 3 'Fixed Dialog | |
Caption | "Help on Voice Phone" | |
Height | 3375 | |
Left | 2745 | |
LinkTopic | "Form1" | |
MaxButton | 0 'False | |
MinButton | 0 'False | |
Top | 1875 | |
Width | 4230 | |
VB.CommandButton | Name | cmdOK |
Caption | "OK" | |
Default | -1 'True | |
Height | 300 | |
Left | 2760 | |
TabIndex | 1 | |
Top | 2520 | |
Width | 1200 | |
VB.Label | Name | Label1 |
BorderStyle | 1 'Fixed Single | |
Caption | "Label1" | |
Height | 2175 | |
Left | 120 | |
TabIndex | 0 | |
Top | 180 | |
Width | 3855 |
The only code needed for the form is the Form_Load event and the one-line cmdOK_Click event. Listing 35.31 shows both these routines. Add this code to your form.
Listing 35.31. Coding the Form_Load and cmdOK_Click events.
Private Sub cmdOK_Click()
Unload Me
End Sub
Private Sub Form_Load()
'
' setup help dialog
'
Dim x As Integer
'
Me.Caption = "Help on Voice Phone"
Me.Icon = LoadPicture(App.Path & "\vphone.ico")
CenterForm Me
'
Label1 = ""
For x = ttsHello To ttsExit
Label1 = Label1 & cUserMsgs(x) & Chr(13) & Chr(13)
Next x
'
objVText.Speak Label1.Caption, iVType
'
End Sub
That's it for the VHelp form. Save the form as VHELP.FRM and update the project (VPHONE.VBP) before moving on to the last coding section of the project.
The VAbout form shows the
standard application information. This information is read from
the properties of the App
object. You set these properties using the File
| Make EXE | Options menu selection. Table 35.5 shows
the App object properties
and their settings.
Property | Setting |
Auto Increment | Checked ON |
File Description | Demonstrates SAPI andTAPI |
Legal Copyright | Copyright 1998 MCA/Sams Publishing |
Product Name | Voice Phone |
After setting these properties, you're ready to lay out the form and add the code. Refer to Figure 35.6 and Table 35.6 for the size and position of the controls on the form.
Figure 35.6 : Laying out the VAbout form.
Control | Property | Setting |
VB.Form | Name | frmAbout |
BorderStyle | 3 'Fixed Dialog | |
Caption | "Form1" | |
Height | 2610 | |
Left | 2685 | |
MaxButton | 0 'False | |
MinButton | 0 'False | |
Top | 1890 | |
Width | 4980 | |
VB.CommandButton | Name | Command1 |
Caption | "&OK" | |
Height | 300 | |
Left | 3540 | |
TabIndex | 1 | |
Top | 1800 | |
Width | 1200 | |
VB.Image | Name | Image1 |
Height | 1455 | |
Left | 120 | |
Top | 180 | |
Width | 1395 | |
VB.Label | Name | Label1 |
Caption | "Label1" | |
Height | 1455 | |
Left | 1800 | |
TabIndex | 0 | |
Top | 180 | |
Width | 2895 |
After laying out the form, you need to add code to the Form_Load and Command1_Click events. Listing 35.32 shows all the code you need for the form.
Listing 35.32. Coding the Form_Load and Command1_Click events.
Private Sub Command1_Click()
Unload Me
End Sub
Private Sub Form_Load()
'
' set up about dialog
'
Dim cVersion As String
Me.Caption = "About " & App.ProductName
Me.Icon = LoadPicture(App.Path & "\vphone.ico")
Image1.Stretch = True
Image1.Picture = LoadPicture(App.Path & "\vphone.ico")
'
cVersion = "Version: " & CStr(App.Major) & "." & CStr(App.Minor) & "." & ÂCStr(App.Revision)
Label1 = App.ProductName & Chr(13) & Chr(13)
Label1 = Label1 & App.LegalCopyright & Chr(13) & Chr(13)
Label1 = Label1 & App.FileDescription & Chr(13) & Chr(13)
Label1 = Label1 & cVersion
'
CenterForm Me
'
objVText.Speak Label1.Caption, iVType
'
End Sub
Notice the use of the App object properties to fill in the Label control. This is a great way to provide up-to-date application version information for your projects.
Save the form as VABOUT.FRM and update the project file (VPHONE.VBP). That's the last of the coding for this project. Before moving on to the next section, compile the project and check for any errors. Once you're sure all the bugs have been ironed out, you're ready to test your Voice Phone.
When you first start Voice Phone, you'll get a short friendly greeting ("Hello. Welcome to Voice Phone."). Once the program has started, several voice commands have been registered with the Windows operating system. You can view these available commands by asking the workstation, "What can I say? "or by clicking the Microsoft Voice icon in the system tray and selecting "What can I say?" from the context menu. Figure 35.7 shows what your display should look like.
Figure 35.7 : Viewing the available Microsoft voice commands.
New data table records can be added by pressing the New button or by speaking the New Record command. You can also edit an existing record by selecting it from the list and pressing Edit or by speaking the command Edit <Name> where <Name> is the name of the person whose record you wish to edit (see Figure 35.8).
Figure 35.8 : Editing an existing Voice Phone records.
You can place a call by selecting a name from the list and pressing the Place Call button. Or you can simply tell Voice Phone to Dial <Name> where <Name> is the name of the person you wish to call. For example, if you wanted to call Susan, you'd speak the command "Dial Susan." Voice Phone will look up Susan's phone number, and place the call for you.
Since this project is using Assisted TAPI, the actual handling of the call is performed by the application on the workstation that is registered to handle Assisted TAPI requests. If you have Microsoft Phone installed on your workstation, you'll see Microsoft Phone appear and handle the call. If you have not installed any special telephony support applications, the default dialer, DIALER.EXE, will appear.
Finally, you can get help by pressing the Help button. This will force Voice Phone to speak helpful tips to you. If you want to view the help tips, select Help | Help from the menu (see Figure 35.9).
Figure 35.9: Viewing the Help screen.
In this chapter you built an application that combined SAPI and TAPI services to create a "hands-free" telephone interface. You learned how to register speech recognition and text-to-speech services, how to register Assisted TAPI services, and how to use both services to access database information and place telephone calls using the registered telephony application for handling Assisted TAPI service requests.
In the next chapter, you'll learn how to build an e-mail client that records audio messages instead of handling text messages.