VERSION 5.00 Object = "{1F6AF2BA-798F-4586-8F76-CD0DB05515D9}#1.0#0"; "vb_SubClass.OCX" Begin VB.Form frmCanvas AutoRedraw = -1 'True BackColor = &H80000005& Caption = "Visual Basic Scrawl Sample" ClientHeight = 6150 ClientLeft = 165 ClientTop = 450 ClientWidth = 9990 Icon = "frmCanvas.frx":0000 LinkTopic = "Form1" ScaleHeight = 410 ScaleMode = 3 'Pixel ScaleWidth = 666 StartUpPosition = 2 'CenterScreen Begin vbSubClass.SubClasser subClass Left = 9360 Top = 60 _ExtentX = 900 _ExtentY = 873 End Begin VB.Image imgPencil Appearance = 0 'Flat Height = 480 Left = 0 Picture = "frmCanvas.frx":0442 Top = 0 Width = 480 End Begin VB.Menu mnuContext Caption = "none" Visible = 0 'False Begin VB.Menu mnuAbout Caption = "About..." End Begin VB.Menu Sep1 Caption = "-" End Begin VB.Menu mnuSpeed1 Caption = "Speed 1" End Begin VB.Menu mnuSpeed2 Caption = "Speed 2" End Begin VB.Menu mnuSpeed3 Caption = "Speed 3" End Begin VB.Menu Sep2 Caption = "-" End Begin VB.Menu mnuClear Caption = "Clear" End Begin VB.Menu Sep3 Caption = "-" End Begin VB.Menu mnuSuspend Caption = "Release Mouse" End End End Attribute VB_Name = "frmCanvas" Attribute VB_GlobalNameSpace = False Attribute VB_Creatable = False Attribute VB_PredeclaredId = True Attribute VB_Exposed = False ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' ' Copyright (C) 1999-2001 Microsoft Corporation. All Rights Reserved. ' ' File: frmCanvas.frm ' Content: This Form holds the DirectInput callback for mouse messages ' ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' Option Explicit Implements DirectXEvent8 Private Sub DirectXEvent8_DXCallback(ByVal eventid As Long) ' This is where we respond to any change in mouse state. Usually this will be an axis movement ' or button press or release, but it could also mean we've lost acquisition. ' Note: no event is signalled if we voluntarily Unacquire. Normally loss of acquisition will ' mean that the app window has lost the focus. Dim diDeviceData(1 To BufferSize) As DIDEVICEOBJECTDATA Dim NumItems As Integer Dim i As Integer Static OldSequence As Long ' Get data On Error GoTo INPUTLOST NumItems = objDIDev.GetDeviceData(diDeviceData, 0) On Error GoTo 0 ' Process data For i = 1 To NumItems Select Case diDeviceData(i).lOfs Case DIMOFS_X g_cursorx = g_cursorx + diDeviceData(i).lData * g_Sensitivity ' We don't want to update the cursor or draw a line is response to ' separate axis movements, or we will get a staircase instead of diagonal lines. ' A diagonal movement of the mouse results in two events with the same sequence number. ' In order to avoid postponing the last event till the mouse moves again, we always ' reset OldSequence after it's been tested once. If OldSequence <> diDeviceData(i).lSequence Then UpdateCursor OldSequence = diDeviceData(i).lSequence Else OldSequence = 0 End If Case DIMOFS_Y g_cursory = g_cursory + diDeviceData(i).lData * g_Sensitivity If OldSequence <> diDeviceData(i).lSequence Then UpdateCursor OldSequence = diDeviceData(i).lSequence Else OldSequence = 0 End If Case DIMOFS_BUTTON0 If diDeviceData(i).lData And &H80 Then Drawing = True ' Keep record for Line function CurrentX = g_cursorx CurrentY = g_cursory ' Draw a point in case button-up follows immediately PSet (g_cursorx, g_cursory) Else Drawing = False End If Case DIMOFS_BUTTON1 If diDeviceData(i).lData = 0 Then ' button up Popup End If End Select Next i Exit Sub INPUTLOST: ' Windows stole the mouse from us. DIERR_INPUTLOST is raised if the user switched to ' another app, but DIERR_NOTACQUIRED is raised if the Windows key was pressed. If (Err.Number = DIERR_INPUTLOST) Or (Err.Number = DIERR_NOTACQUIRED) Then SetSystemCursor Exit Sub End If End Sub Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer) Select Case KeyCode Case 93 ' AppMenu key Popup End Select End Sub Private Sub Form_Load() subClass.Hook Me.hWnd End Sub Private Sub Form_Unload(Cancel As Integer) ' Restore the default window procedure subClass.UnHook If EventHandle <> 0 Then objDX.DestroyEvent EventHandle End Sub Private Sub Form_MouseMove(Button As Integer, Shift As Integer, x As Single, y As Single) Dim didevstate As DIMOUSESTATE ' We want to force acquisition of the mouse whenever the context menu is closed, ' whenever we switch back to the application, or in any other circumstance where ' Windows is finished with the cursor. If a MouseMove event happens, ' we know the cursor is in our app window and Windows is generating mouse messages, therefore ' it's time to reacquire. ' Note: this event is triggered whenever the window gets the mouse, even when there's no mouse ' activity -- for example, when we have just Alt+Tabbed back, or cancelled out of the context ' menu with the Esc key. If Suspended Then Exit Sub ' Allow continued use of Windows cursor ' This event gets called again after we acquire the mouse. In order to prevent the cursor ' position being set to the middle of the window, we check to see if we've already acquired, ' and if so, we don't reposition our private cursor. The only way to find out if the mouse ' is acquired is to try to retrieve data. On Error GoTo NOTYETACQUIRED Call objDIDev.GetDeviceStateMouse(didevstate) On Error GoTo 0 Exit Sub NOTYETACQUIRED: Call AcquireMouse End Sub Sub AcquireMouse() Dim CursorPoint As POINTAPI ' Move private cursor to system cursor. Call GetCursorPos(CursorPoint) ' Get position before Windows loses cursor Call ScreenToClient(hWnd, CursorPoint) On Error GoTo CANNOTACQUIRE objDIDev.Acquire g_cursorx = CursorPoint.x g_cursory = CursorPoint.y UpdateCursor frmCanvas.imgPencil.Visible = True On Error GoTo 0 Exit Sub CANNOTACQUIRE: Exit Sub End Sub Private Sub Form_MouseUp(Button As Integer, Shift As Integer, x As Single, y As Single) ' Allows user to resume by clicking on the canvas. If Button = 1 Then Suspended = False End Sub Private Sub mnuAbout_Click() Call frmAbout.Show(vbModal, Me) End Sub Private Sub mnuClear_Click() Cls End Sub Private Sub mnuSpeed1_Click() g_Sensitivity = 1 mnuSpeed1.Checked = True mnuSpeed2.Checked = False mnuSpeed3.Checked = False End Sub Private Sub mnuSpeed2_Click() g_Sensitivity = 2 mnuSpeed2.Checked = True mnuSpeed1.Checked = False mnuSpeed3.Checked = False End Sub Private Sub mnuSpeed3_Click() g_Sensitivity = 3 mnuSpeed3.Checked = True mnuSpeed1.Checked = False mnuSpeed2.Checked = False End Sub Private Sub mnuSuspend_Click() Suspended = Not Suspended imgPencil.Visible = Not Suspended End Sub Public Sub UpdateCursor() ' Update the position of our private cursor If g_cursorx < 0 Then g_cursorx = 0 If g_cursorx >= frmCanvas.ScaleWidth Then g_cursorx = frmCanvas.ScaleWidth - 1 If g_cursory < 0 Then g_cursory = 0 If g_cursory >= frmCanvas.ScaleHeight Then g_cursory = frmCanvas.ScaleHeight - 1 frmCanvas.imgPencil.Left = g_cursorx frmCanvas.imgPencil.Top = g_cursory If Drawing Then Line -(g_cursorx, g_cursory) End If End Sub Public Sub Popup() objDIDev.Unacquire SetSystemCursor Call PopupMenu(mnuContext) End Sub Public Sub SetSystemCursor() ' Get the system cursor into the same position as the private cursor, ' and stop drawing Dim point As POINTAPI imgPencil.Visible = False Drawing = False point.x = g_cursorx point.y = g_cursory Call ClientToScreen(hWnd, point) Call SetCursorPos(point.x, point.y) End Sub Private Sub subClass_WindowsMessage(ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) ' This procedure intercepts Windows messages and looks for any that might encourage us ' to Unacquire the mouse. If (uMsg = WM_ENTERMENULOOP) And (Not Suspended) Then objDIDev.Unacquire SetSystemCursor End If End Sub