Announcement

Collapse
No announcement yet.

DDT Keypress Capture for Graphic Control

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • DDT Keypress Capture for Graphic Control

    DDT style app.
    I am dynamically creating up to 81 Graphic Controls at runtime.
    I am using them to store chars.

    I want to update the graphic control’s text to whatever char the user pressed on the keyboard.

    What is the best way to do it?

    ------------------

  • #2
    If all you are displaying is text characters in response to keyboard input, the best way would be to use an edit control instead of a graphics control.

    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      >"I want to update the graphic control’s text to whatever char the user pressed on the keyboard."<

      By "whatever char" are you including to show keys such as Esc, Tab, etc. with symbols?

      Why 81 GC's seems like one big one could be made to do the work if you really want to do the above.

      ------------------
      Rick Angell
      Rick Angell

      Comment


      • #4
        A less known technique of trapping either keypresses
        or mouse movement (rather than subclass) is to trap them
        in the message loop. Rather than let DDT handle the
        message loop, write your own. All keyboard and mouse messages
        get sent to the message loop first, before they get passed on
        to the window procedures of controls (or the form).

        This way you can process all the key presses or mouse movement
        in one place, rather than subclass every window.



        ------------------
        Chris Boss
        Computer Workshop
        Developer of "EZGUI"
        http://cwsof.com
        Chris Boss
        Computer Workshop
        Developer of "EZGUI"
        http://cwsof.com
        http://twitter.com/EZGUIProGuy

        Comment


        • #5
          It sounds like this could be done in PBCC. Do you save
          all the window handles in an array and use something
          like the following to look for a key or mouse click?
          Code:
          Sub Getkey
           Do
            For i = 1 To NumberOfWindows
             GetMessage LPMSG, WindowHandle(i), WM_KEYFIRST, WM_KEYLAST
             ' if keystroke in LPMSG, process and Exit Do
             GetMessage LPMSG, WindowHandle(i), WM_MOUSEFIRST, WM_MOUSELAST
             ' if mouseclick in LPMSG process and Exit Do
            Next
           Loop
          End Sub


          [This message has been edited by Mark Hunter (edited June 18, 2006).]
          Politically incorrect signatures about immigration patriots are forbidden. Searching “immigration patriots” is forbidden. Thinking about searching ... well, don’t even think about it.

          Comment


          • #6
            I only want to trap 0 to 9, Aa to Zz, Arrow & Enter, and mouse activity.
            The reason I am using Graphic Control is so that I can adjust background color, and eventually replace with a nice tile image.
            In VB I would have taken care of it in Keypress event.

            Where do I call the Getkey sub?
            Do I create a one dimension array and store DlgHandle to NumberOfWindows?
            Do I have to set the input to null after being processed in GetKey (If I don’t want anything else to occur)?


            ------------------

            What is PBCC?

            [This message has been edited by Roger Sarlouis (edited June 18, 2006).]

            Comment


            • #7
              Roger,

              PB/CC is the PowerBasic Console Compiler. It only supports Graphic Windows, not Graphic Controls, in DDT however, although you could do pure SDK style there too. That however is different than your original request for a DDT solution.

              You indicate that you are using 81 Graphic Controls (GC), presumably this is a 9 x 9 array? How do you intend to move between or select them, just the mouse? Have you considered just one GC, where you draw the individual areas and only replace them as needed? This is possible to do using MS GDI API's with DDT.

              Subclassing the 81 GC's to use the same generic subclass callback is quite possible. An example of a generic subclass is found tin the Samples\DDD\Graphic\BoltCalc program, although it subclasses text boxes and has fewer handles to contend with.

              Do you understand what subclassing involves? Message loops?

              There should be no problem in sorting out these keys and then acting on them according to a generic process. It will be quite helpful though to make sure the control ID #'s are sequential, since this will allow you to do FOR/NEXT looping in managing the initial subclass and then resetting before the dialog is destroyed.





              ------------------
              Rick Angell
              Rick Angell

              Comment


              • #8
                >In VB I would have taken care of it in Keypress event.

                I don't know VB, but maybe someone could confirm one can processs a "keypress event" by responding to the WM_KEYDOWN notification.

                I am laboring under the impression that when using Microsoft Visual BASIC, all the "Events" are nothing more than a function which is called on receipt of a notification message.. a so-called "message cracker." Is this a good assumption on my part?


                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9

                  Michael,

                  Private Sub a_control_name_KeyPress(KeyAscii As Integer)


                  End Sub

                  yes , just a message cracker

                  A dozen what.

                  Comment


                  • #10
                    Michael,

                    VB does not use the Windows standard (or common) controls directly.
                    It superclasses them (different fro subclass for those who may not know).

                    By superclassing them, it has access to the window procedures for
                    all the controls, which allows it to process any standard window
                    message (such as key presses).

                    The VB controls class names all start with the word THUNDER.

                    So, yes VB controls are trapping standard window messages such
                    as WM_KEYPRESS for its events.

                    ------------------
                    Chris Boss
                    Computer Workshop
                    Developer of "EZGUI"
                    http://cwsof.com

                    [This message has been edited by Chris Boss (edited June 19, 2006).]
                    Chris Boss
                    Computer Workshop
                    Developer of "EZGUI"
                    http://cwsof.com
                    http://twitter.com/EZGUIProGuy

                    Comment


                    • #11
                      Roger,

                      Here's a small sample code with 3x3 GC 's, only one character printing currently supported just to illustrate some subclassing. No globals used in this example. This assumes that you are not really intending to display strings, but eventually display bitmaps in the GC 's. The sample here is just so you can get a feel for subclassed GW's

                      The example also handles TAB and Shifted movement keys.

                      It also illustrates that keeping all the GW control ID's sequential, column wise can be of great use to simplify some code writing needed to set and reset the subclassing as illustrated. However it could also be useful if you need to index a global or static array with the handles of bitmaps to draw in your program's GC controls.

                      Code:
                      #PBFORMS CREATED V1.51
                      #COMPILE EXE
                      #DIM ALL
                      
                      #PBFORMS BEGIN INCLUDES
                      %USEMACROS = 1
                      #IF NOT %DEF(%WINAPI)
                          #INCLUDE "WIN32API.INC"
                      #ENDIF
                      #IF NOT %DEF(%COMMCTRL_INC)
                          #INCLUDE "COMMCTRL.INC"
                      #ENDIF
                      #INCLUDE "PBForms.INC"
                      #PBFORMS END INCLUDES
                      
                      #PBFORMS BEGIN CONSTANTS
                      %IDD_DIALOG1  =  101
                      %IDC_GRAPHIC1 = 1001
                      %IDC_GRAPHIC2 = 1002
                      %IDC_GRAPHIC3 = 1003
                      %IDC_GRAPHIC4 = 1004
                      %IDC_GRAPHIC5 = 1005
                      %IDC_GRAPHIC6 = 1006
                      %IDC_GRAPHIC7 = 1007
                      %IDC_GRAPHIC8 = 1008
                      %IDC_GRAPHIC9 = 1009
                      #PBFORMS END CONSTANTS
                      
                      DECLARE CALLBACK FUNCTION GCSubClassProc()
                      DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
                      DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                      #PBFORMS DECLARATIONS
                      
                      FUNCTION PBMAIN()
                          PBFormsInitComCtls (%ICC_WIN95_CLASSES OR %ICC_DATE_CLASSES OR _
                              %ICC_INTERNET_CLASSES)
                          ShowDIALOG1 %HWND_DESKTOP
                      END FUNCTION
                      
                      CALLBACK FUNCTION ShowDIALOG1Proc()
                          LOCAL i&
                          LOCAL oldProc AS DWORD
                          LOCAL ncWidth!,ncHeight!,nWidth!, nHeight!
                      
                          SELECT CASE AS LONG CBMSG
                              CASE %WM_INITDIALOG
                                  DIALOG POST CBHNDL,%WM_USER+100,0,0
                      
                              CASE %WM_USER+100
                                   'initial GC setup
                                   FOR i& = 0 TO 8
                                      GRAPHIC ATTACH CBHNDL,(%IDC_GRAPHIC1 + i&)
                                      GRAPHIC FONT "Arial",20,1
                                      GRAPHIC COLOR %BLACK,%GREEN
                                      GRAPHIC CLEAR %GREEN
                                  NEXT i&
                                  CONTROL SET FOCUS CBHNDL,%IDC_GRAPHIC1
                                  FOR i& = 0 TO 8
                                      CONTROL SET USER CBHNDL,(%IDC_GRAPHIC1 + i&), 3, CBHNDL
                                      CONTROL SET USER CBHNDL,(%IDC_GRAPHIC1 + i&), 2, %IDC_GRAPHIC1 + i&
                                      CONTROL SET USER CBHNDL,(%IDC_GRAPHIC1 + i&), 1, _
                                          SetWindowLong(GetDlgItem(CBHNDL, (%IDC_GRAPHIC1 + i&)), %GWL_WNDPROC, CODEPTR(GCSubClassProc))
                                  NEXT i&
                                  DIALOG REDRAW CBHNDL
                                  DIALOG POST CBHNDL,%WM_USER+102,%IDC_GRAPHIC1,0
                      
                              CASE %WM_USER+101
                                  'text drawing code, but also where it would be appropos to do
                                  'the tile drawing when desired.  To still do multi-character printing
                                  'you will need to retrive the full string from static storage to
                                  'print.  The current case here uses CBWPARAM for the ID,and the
                                  'CBLPARAM for the typed charater.  That should give enough info to
                                  'key to an array and get a grahic handle to load as the background
                                  'as mentioned in your post.
                                  GRAPHIC ATTACH CBHNDL,CBWPARAM, REDRAW
                                  GRAPHIC CLEAR %GREEN
                                  GRAPHIC GET CLIENT  TO ncWidth!, ncHeight!
                                  GRAPHIC BOX (1,1)- (ncWidth!-1,ncHeight!-1),0,%RED
                                  GRAPHIC TEXT SIZE CHR$(CBLPARAM) TO nWidth!, nHeight!
                                  ncWidth!=   (ncWidth! - nWidth!)/2
                                  ncHeight! = (ncHeight!- nHeight!)/2
                                  GRAPHIC SET POS (ncWidth!,ncHeight!)
                                  GRAPHIC PRINT CHR$(CBLPARAM)
                                  GRAPHIC REDRAW
                      
                              CASE %WM_USER+102
                                  'draw a "focus rectangle"
                                  GRAPHIC ATTACH CBHNDL,CBWPARAM, REDRAW
                                  GRAPHIC GET CLIENT  TO ncWidth!, ncHeight!
                                  GRAPHIC BOX (1,1)- (ncWidth!-1,ncHeight!-1),0,%RED
                                  GRAPHIC REDRAW
                                           
                              CASE %WM_USER+103
                                  'erase a "focus rectangle"
                                  GRAPHIC ATTACH CBHNDL,CBWPARAM, REDRAW
                                  GRAPHIC GET CLIENT  TO ncWidth!, ncHeight!
                                  GRAPHIC BOX (1,1)- (ncWidth!-1,ncHeight!-1),0,%GREEN
                                  GRAPHIC REDRAW
                      
                              CASE %WM_NCACTIVATE
                                  STATIC hWndSaveFocus AS DWORD
                                  IF ISFALSE CBWPARAM THEN
                                      hWndSaveFocus = GetFocus()
                                  ELSEIF hWndSaveFocus THEN
                                      SetFocus(hWndSaveFocus)
                                      hWndSaveFocus = 0
                                  END IF
                      
                              CASE %WM_DESTROY
                                  'must un-subclass all subclassed controls here to exit without leaking!
                                  FOR i& = 0 TO 8
                                      CONTROL GET USER CBHNDL,(%IDC_GRAPHIC1 + i&),1 TO oldProc
                                      SetWindowLong GetDlgItem(CBHNDL, (%IDC_GRAPHIC1 + i&)), %GWL_WNDPROC, oldProc
                                  NEXT i&
                      
                              CASE %WM_COMMAND
                                  SELECT CASE AS LONG CBCTL
                                      CASE %IDC_GRAPHIC1
                      
                                      CASE %IDC_GRAPHIC2
                      
                                      CASE %IDC_GRAPHIC3
                      
                                      CASE %IDC_GRAPHIC4
                      
                                      CASE %IDC_GRAPHIC5
                      
                                      CASE %IDC_GRAPHIC6
                      
                                      CASE %IDC_GRAPHIC7
                      
                                      CASE %IDC_GRAPHIC8
                      
                                      CASE %IDC_GRAPHIC9
                      
                                  END SELECT
                          END SELECT
                      END FUNCTION
                      
                      FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
                          LOCAL lRslt AS LONG
                      
                      #PBFORMS BEGIN DIALOG %IDD_DIALOG1->->
                          LOCAL hDlg  AS DWORD
                      
                          DIALOG NEW hParent, "9 GRAPHIC CONTROLS", 407, 277, 144, 100, %WS_POPUP _
                              OR %WS_BORDER OR %WS_DLGFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                              %WS_CLIPSIBLINGS OR %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR _
                              %DS_NOFAILCREATE OR %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT _
                              OR %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
                      
                          CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC1, "", 5, 5, 40, 25, %WS_CHILD OR _
                              %WS_VISIBLE OR %WS_BORDER OR %WS_GROUP OR %WS_TABSTOP OR %SS_SUNKEN _
                              OR %SS_NOTIFY, %WS_EX_STATICEDGE
                          GRAPHIC ATTACH hDlg, %IDC_GRAPHIC1
                          GRAPHIC COLOR -1, %BLACK
                          GRAPHIC CLEAR
                          CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC2, "", 5, 35, 40, 25, %WS_CHILD OR _
                              %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %SS_SUNKEN OR _
                              %SS_NOTIFY, %WS_EX_STATICEDGE
                          GRAPHIC ATTACH hDlg, %IDC_GRAPHIC2
                          GRAPHIC COLOR -1, %BLACK
                          GRAPHIC CLEAR
                          CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC3, "", 5, 65, 40, 25, %WS_CHILD OR _
                              %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %SS_SUNKEN OR _
                              %SS_NOTIFY, %WS_EX_STATICEDGE
                          GRAPHIC ATTACH hDlg, %IDC_GRAPHIC3
                          GRAPHIC COLOR -1, %BLACK
                          GRAPHIC CLEAR
                          CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC4, "", 50, 5, 40, 25, %WS_CHILD OR _
                              %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %SS_SUNKEN OR %SS_NOTIFY
                          GRAPHIC ATTACH hDlg, %IDC_GRAPHIC4
                          GRAPHIC COLOR -1, %BLACK
                          GRAPHIC CLEAR
                          CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC5, "", 50, 35, 40, 25, %WS_CHILD _
                              OR %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %SS_SUNKEN OR _
                              %SS_NOTIFY, %WS_EX_STATICEDGE
                          GRAPHIC ATTACH hDlg, %IDC_GRAPHIC5
                          GRAPHIC COLOR -1, %BLACK
                          GRAPHIC CLEAR
                          CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC6, "", 50, 65, 40, 25, %WS_CHILD _
                              OR %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %SS_SUNKEN OR _
                              %SS_NOTIFY, %WS_EX_STATICEDGE
                          GRAPHIC ATTACH hDlg, %IDC_GRAPHIC6
                          GRAPHIC COLOR -1, %BLACK
                          GRAPHIC CLEAR
                          CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC7, "", 95, 5, 40, 25, %WS_CHILD OR _
                              %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %SS_SUNKEN OR _
                              %SS_NOTIFY, %WS_EX_STATICEDGE
                          GRAPHIC ATTACH hDlg, %IDC_GRAPHIC7
                          GRAPHIC COLOR -1, %BLACK
                          GRAPHIC CLEAR
                          CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC8, "", 95, 35, 40, 25, %WS_CHILD _
                              OR %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %SS_SUNKEN OR _
                              %SS_NOTIFY, %WS_EX_STATICEDGE
                          GRAPHIC ATTACH hDlg, %IDC_GRAPHIC8
                          GRAPHIC COLOR -1, %BLACK
                          GRAPHIC CLEAR
                          CONTROL ADD GRAPHIC, hDlg, %IDC_GRAPHIC9, "", 95, 65, 40, 25, %WS_CHILD _
                              OR %WS_VISIBLE OR %WS_BORDER OR %WS_TABSTOP OR %SS_SUNKEN OR _
                              %SS_NOTIFY, %WS_EX_STATICEDGE
                          GRAPHIC ATTACH hDlg, %IDC_GRAPHIC9
                          GRAPHIC COLOR -1, %BLACK
                          GRAPHIC CLEAR
                      #PBFORMS END DIALOG
                      
                          DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
                      
                      #PBFORMS BEGIN CLEANUP %IDD_DIALOG1
                      #PBFORMS END CLEANUP
                      
                          FUNCTION = lRslt
                      END FUNCTION
                      '==============================================================================
                      CALLBACK FUNCTION GCSubClassProc()
                      
                        LOCAL oldProc, hDlg AS DWORD
                        LOCAL IDGC AS LONG                         'will store current GC's ID number
                        STATIC lastIDGC AS LONG                    'used to move focus box when mousing
                      
                         
                        DIALOG GET USER CBHNDL, 1 TO oldProc       'old callback address
                        IF oldProc = 0 THEN EXIT FUNCTION
                      
                      
                        DIALOG GET USER CBHNDL, 3 TO hDlg          'this GC's parent dialog handle
                        DIALOG GET USER CBHNDL, 2 TO IDGC          'this GC's ID number
                      
                        '------------------------------------------------------------------
                        SELECT CASE AS LONG CBMSG
                      
                        '------------------------------------------------------------------
                            CASE %WM_LBUTTONDOWN, %WM_RBUTTONDOWN        'moused GC selection
                                IF lastIDGC = 0 THEN lastIDGC = %IDC_GRAPHIC1
                                CONTROL SET FOCUS hDlg,lastIDGC
                                DIALOG POST hDlg,%WM_USER+103,lastIDGC,0
                                CONTROL SET FOCUS hDlg,IDGC
                                DIALOG POST hDlg,%WM_USER+102,IDGC,0
                                lastIDGC = IDGC
                                
                            CASE %WM_KEYDOWN                              'focus change by keys
                                SELECT CASE CBWPARAM
                                  CASE %VK_RETURN,%VK_DOWN,%VK_TAB
                                      'test for shift key state, jump to reversing direction code
                                      IF GetAsyncKeyState(%VK_SHIFT)<> 0 THEN GOTO ShiftedVKs2
                                  ShiftedVKs1:
                                      SELECT CASE IDGC
                                          CASE %IDC_GRAPHIC1 TO %IDC_GRAPHIC8
                                              CONTROL SET FOCUS hDlg, IDGC + 1
                                              DIALOG POST hDlg,%WM_USER+102,IDGC + 1,0
                                          CASE %IDC_GRAPHIC9
                                              CONTROL SET FOCUS hDlg, %IDC_GRAPHIC1
                                              DIALOG POST hDlg,%WM_USER+102,%IDC_GRAPHIC1,0
                                      END SELECT
                                      DIALOG POST hDlg,%WM_USER+103,IDGC,0
                      
                                   CASE %VK_UP
                                       IF GetAsyncKeyState(%VK_SHIFT)<> 0 THEN GOTO ShiftedVKs1
                                   ShiftedVKs2:
                                       SELECT CASE IDGC
                                          CASE %IDC_GRAPHIC2 TO %IDC_GRAPHIC9
                                              CONTROL SET FOCUS hDlg, IDGC - 1
                                              DIALOG POST hDlg,%WM_USER+102,IDGC - 1,0
                                          CASE %IDC_GRAPHIC1
                                              CONTROL SET FOCUS hDlg, %IDC_GRAPHIC9
                                              DIALOG POST hDlg,%WM_USER+102,%IDC_GRAPHIC9,0
                                       END SELECT
                                       DIALOG POST hDlg,%WM_USER+103,IDGC,0
                      
                                  CASE %VK_LEFT
                                      IF GetAsyncKeyState(%VK_SHIFT)<> 0 THEN GOTO ShiftedVKs4
                                      ShiftedVKs3:
                                      SELECT CASE IDGC
                                          CASE %IDC_GRAPHIC1 TO %IDC_GRAPHIC3
                                              CONTROL SET FOCUS hDlg, IDGC + 6
                                              DIALOG POST hDlg,%WM_USER+102,IDGC + 6,0
                                          CASE %IDC_GRAPHIC4 TO %IDC_GRAPHIC9
                                              CONTROL SET FOCUS hDlg, IDGC - 3
                                              DIALOG POST hDlg,%WM_USER+102,IDGC - 3,0
                                      END SELECT
                                      DIALOG POST hDlg,%WM_USER+103,IDGC,0
                      
                                  CASE %VK_RIGHT
                                      IF GetAsyncKeyState(%VK_SHIFT)<> 0 THEN GOTO ShiftedVKs3
                                      ShiftedVKs4:
                                      SELECT CASE IDGC
                                          CASE %IDC_GRAPHIC1 TO %IDC_GRAPHIC6
                                              CONTROL SET FOCUS hDlg, IDGC + 3
                                              DIALOG POST hDlg,%WM_USER+102,IDGC + 3,0
                                          CASE %IDC_GRAPHIC7 TO %IDC_GRAPHIC9
                                              CONTROL SET FOCUS hDlg, IDGC - 6
                                              DIALOG POST hDlg,%WM_USER+102,IDGC - 6,0
                                      END SELECT
                                      DIALOG POST hDlg,%WM_USER+103,IDGC,0
                      
                                END SELECT
                      
                           CASE %WM_CHAR
                               'only the keys mentioned pass through to parent
                               'dialog callback for processing, or could do here
                               'nothing too dificult except if you want to write
                               'multicharacter strings you will need to provide
                               'string storage that can be modified and used when
                               'the GC is updated
                              SELECT CASE CBWPARAM
                                CASE 48 TO 57,65 TO 90,97 TO 122
                                    DIALOG POST hDlg,%WM_USER+101,IDGC,CBWPARAM
                              END SELECT
                      
                          CASE %WM_GETDLGCODE
                                    FUNCTION = %DLGC_WANTALLKEYS
                                    EXIT FUNCTION
                      
                        END SELECT
                      
                        '------------------------------------------------------------------
                        ' Pass on messages to original control procedure
                      
                        FUNCTION = CallWindowProc(oldProc, CBHNDL, CBMSG, CBWPARAM, CBLPARAM)
                      END FUNCTION

                      ------------------
                      Rick Angell
                      Rick Angell

                      Comment


                      • #12
                        Nice work Richard...
                        Also, if any interest, this one use a keyboard hook to do the job...

                        Pierre


                        Code:
                        #COMPILE EXE '#Win 8.01#
                        #DIM ALL
                        #INCLUDE "Win32Api.inc" '#2005-01-27#
                         
                        GLOBAL hDlg          AS DWORD
                        GLOBAL hKeyboardHook AS DWORD
                         
                        %Label1 = 101  
                        %Label2 = 102
                        %KeyMsg = 401 + %WM_USER 'Custom keyboard message
                        '________________________________________________________________________________________________________
                         
                        FUNCTION KeyboardHook(BYVAL HookCode AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS DWORD
                         LOCAL KeyName AS ASCIZ * 30
                         
                         FUNCTION = CallNextHookEx(hKeyboardHook, HookCode, wParam, lParam)
                         
                         IF HookCode = %HC_ACTION THEN
                           IF ISFALSE(lParam AND &H80000000) THEN 'Key up  
                         
                             GetKeyNameText lParam, BYVAL VARPTR(KeyName), SIZEOF(KeyName) 'Get text key name
                         
                             SELECT CASE wParam
                         
                               CASE %VK_A TO %VK_Z, _                        'Letter A to Z, 
                                    %VK_0 TO %VK_9, _                        'number 0 to 9,
                                    %VK_NUMPAD0 TO %VK_NUMPAD9, _            'number 0 to 9 on keypad,
                                    %VK_LEFT, %VK_UP, %VK_RIGHT, %VK_DOWN, _ 'Arrow
                                    %VK_RETURN                               'and [Enter]
                                      CONTROL SET TEXT hDlg, %Label1, KeyName & " is trapped"   
                                      PostMessage hDlg, %KeyMsg, wParam, lParam 
                                      FUNCTION = 1 'If function is true, key will not be forwarded to dialog
                         
                                CASE ELSE
                                  CONTROL SET TEXT hDlg, %Label1, KeyName & " is untrapped"           
                                  CONTROL SET TEXT hDlg, %Label2, ""
                         
                             END SELECT
                           END IF
                         END IF
                        END FUNCTION
                        '________________________________________________________________________________________________________
                         
                        CALLBACK FUNCTION DlgProc
                         LOCAL KeyName            AS ASCIZ * 30
                         LOCAL Buffer             AS STRING
                         DIM   KeyStateArray(256) AS BYTE
                         
                         SELECT CASE CBMSG
                         
                           CASE %WM_INITDIALOG
                             'Hook the keyboard with the KeyboardHook function
                             hKeyboardHook = SetWindowsHookEx(%WH_KEYBOARD, CODEPTR(KeyboardHook), 0, GetCurrentThreadId)
                         
                           CASE %KeyMsg 
                             Buffer = ""
                             'Detect the [Control], [Alt] and [Shift] keyboard status
                             IF ISTRUE(LOWRD(GetKeyState(%VK_CONTROL)) AND &H8000) THEN Buffer = Buffer & " Control "
                             IF ISTRUE(LOWRD(GetKeyState(%VK_MENU))    AND &H8000) THEN Buffer = Buffer & " Alt "
                             IF ISTRUE(LOWRD(GetKeyState(%VK_SHIFT))   AND &H8000) THEN Buffer = Buffer & " Shift "
                         
                             SELECT CASE CBWPARAM
                               CASE  %VK_A TO %VK_Z 'Letter A to Z
                                 Buffer = Buffer & "Letter: " & CHR$(CBWPARAM) & _
                                                   ", Chr: " & FORMAT$(CBWPARAM) 
                         
                               CASE %VK_0 TO %VK_9 'Number 0 to 9
                                 Buffer = Buffer & "Num: " & CHR$(CBWPARAM) & _
                                                   ", Chr: " & FORMAT$(CBWPARAM) 
                         
                               CASE %VK_NUMPAD0 TO %VK_NUMPAD9 'Number 0 to 9 on keypad
                                 GetKeyboardState BYVAL VARPTR(keyStateArray(0))
                                 IF KeyStateArray(%VK_NUMLOCK) THEN 'Check if [NumLock] is on
                                   Buffer = Buffer & "NumPad: " & CHR$(CBWPARAM - 48) & _
                                                     ", Chr: " & FORMAT$(CBWPARAM) & _
                                                     ", NumLock: On"
                                 END IF
                         
                               CASE %VK_LEFT, %VK_UP, %VK_RIGHT, %VK_DOWN
                                 Buffer = Buffer & "Arrow: " & CHOOSE$(CBWPARAM - 36, "Left", "Up", "Right", "Down")
                         
                               CASE %VK_RETURN
                                 Buffer = Buffer & "Return, Chr: " & FORMAT$(CBWPARAM) 
                         
                             END SELECT
                             CONTROL SET TEXT hDlg, %Label2, Buffer
                         
                           CASE %WM_DESTROY
                             'Remove hook before program end
                             UnhookWindowsHookEx hKeyboardHook
                         
                         END SELECT
                         
                        END FUNCTION
                        '________________________________________________________________________________________________________
                         
                        FUNCTION PBMAIN
                         
                         DIALOG NEW %HWND_DESKTOP, "Keyboard hook", , , 200, 50, %WS_CAPTION OR _
                                    %WS_MINIMIZEBOX OR %WS_SYSMENU, 0 TO hDlg
                         
                         CONTROL ADD LABEL, hdlg, %Label1 , "-", 10, 12, 180, 15
                         CONTROL ADD LABEL, hdlg, %Label2 , "Type any key (Alt, Ctrl and Shift are detected)", 10, 30, 180, 15
                         
                         DIALOG SHOW MODAL hdlg CALL DlgProc
                         
                        END FUNCTION
                        '________________________________________________________________________________________________________


                        [This message has been edited by Pierre Bellisle (edited June 19, 2006).]

                        Comment


                        • #13
                          Thanks, Pierre. Nice example of the basic extended KB hook on your part as well.

                          In my code I was attempting to confine the majority of the code to DDT constructs for Roger to quickly review, without needing to be adept at much API use. One thing the DDT version code does in the original post was to distinguish between the alphabetic character upper and lower cases by feeding all but the few directional keys and mouse buttons through a WM_CHAR filter. This can be accomplished in your example with the following replacement lines, other means may possible too, but this is just to show a small alteration possible.

                          One caveat though, to employ the KB hook in a non-subclassed GC's approach does mean that more code is needed to be developed to handle tracking the Graphic Control focus and its changes as well. most of this should be possible by maintaining a couple of static variables in the callback. The problem though might be if Roger plans to have many more controls in the dialog. In that case the key processing needs to also be aware that no GC has the focus or is getting the focus so the keys can be used elsewhere if desired. Just some thoughts for Roger to consider as to needs of the DDT+subclassing vs a basic KB hook example,

                          Replace existing lines in CALLBACK FUNCTION DlgProc from start to CASE %VK_0 TO %VK_9 'Number 0 to 9 to see how this works for helping decode a virtual key based hook, this only affects the reporting of alphabetic keys for their correct case, but the concept could be applied to keys that change direction as well, similar to the DDT example.
                          Code:
                          CALLBACK FUNCTION DlgProc
                           LOCAL KeyName            AS ASCIZ * 30
                           LOCAL Buffer             AS STRING
                           LOCAL SHIFTY             AS LONG
                           LOCAL CapsLock           AS LONG
                           DIM   KeyStateArray(256) AS BYTE
                           
                           SELECT CASE CBMSG
                           
                             CASE %WM_INITDIALOG
                               'Hook the keyboard with the KeyboardHook function
                               hKeyboardHook = SetWindowsHookEx(%WH_KEYBOARD, CODEPTR(KeyboardHook), 0, GetCurrentThreadId)
                           
                             CASE %KeyMsg
                               SHIFTY = %False
                               Buffer = ""
                               'Detect the [Control], [Alt] and [Shift] keyboard status
                               IF ISTRUE(LOWRD(GetKeyState(%VK_CONTROL)) AND &H8000) THEN Buffer = Buffer & " Control "
                               IF ISTRUE(LOWRD(GetKeyState(%VK_MENU))    AND &H8000) THEN Buffer = Buffer & " Alt "
                               IF ISTRUE(LOWRD(GetKeyState(%VK_SHIFT))   AND &H8000) THEN
                                   Buffer = Buffer & " Shift "
                                   SHIFTY = %True
                               END IF
                           
                           
                               SELECT CASE CBWPARAM
                                 CASE  %VK_A TO %VK_Z 'Letter A to Z
                                   CapsLock = GetKeyState(%VK_CAPITAL)
                                   IF ISTRUE(BIT(CapsLock,0)) THEN
                                       Buffer = Buffer & " CapsLock "
                                       IF SHIFTY = %True THEN  'detect Shift + CapsLock
                                          SHIFTY = %False
                                       ELSE
                                          SHIFTY = %True
                                       END IF
                                   END IF
                           
                                   IF ISFALSE(SHIFTY) THEN
                                       Buffer = Buffer & "Lower Case Letter: " & CHR$(CBWPARAM + 32) & _
                                                     ", Chr: " & FORMAT$(CBWPARAM+32)
                                   ELSE
                                       Buffer = Buffer & "Upper Case Letter : " & CHR$(CBWPARAM) & _
                                                         ", Chr: " & FORMAT$(CBWPARAM)
                                   END IF
                                 CASE %VK_0 TO %VK_9 'Number 0 to 9

                          ------------------
                          Rick Angell
                          Rick Angell

                          Comment


                          • #14
                            Originally posted by Roger Sarlouis:
                            The reason I am using Graphic Control is so that I can adjust background color, and eventually replace with a nice tile image.

                            You could also do that with a static control.

                            ------------------

                            Comment


                            • #15
                              Richard and Pierre thank you so much for the examples.
                              That is exactly what I am looking for.

                              The examples answered many questions.

                              Thank again.



                              ------------------

                              Comment


                              • #16
                                P.S.

                                Richard and Pierre do you use PowerBASIC IDE or one of the others like PwrDev, JellyFish, etc?



                                ------------------

                                Comment


                                • #17
                                  Roger,

                                  I use the PowerBasic IDE. For PB/Win programming I also use PB/Forms. The IDE today is significantly improved from PB/DLL days when I first brought their Windows programming products.

                                  I've tried some of the other's, but got familiar with the IDE and decided to keep it. I have tried Jellyfish and EZ_GUI, both very good products, and also looked as some of the others.

                                  For DDT style programming PB/Win and PB/Forms are a good combo, but if you want a RAD tool that does SDK then some of the third party offerings would be helpful. You can of course do either stle or a mix in the PB IDE.




                                  [This message has been edited by Richard Angell (edited June 20, 2006).]
                                  Rick Angell

                                  Comment


                                  • #18
                                    I also think that there is a lot of good
                                    IDE and editor for PowerBASIC.
                                    One have to try them to make a choice...

                                    On my side, I am addicted to UltraEdit, a sofisticated text editor.
                                    The drawback or should I say, the funny part, is that I had to write
                                    many utilitys to connect with the compiler the way I wanted.

                                    Pierre

                                    Comment


                                    • #19
                                      Rick:

                                      In your subclass callback function you use:
                                      Code:
                                        DIALOG GET USER CBHNDL, 1 TO oldProc       'old callback address
                                        IF oldProc = 0 THEN EXIT FUNCTION
                                      
                                      
                                        DIALOG GET USER CBHNDL, 3 TO hDlg          'this GC's parent dialog handle
                                        DIALOG GET USER CBHNDL, 2 TO IDGC          'this GC's ID number
                                      but I could not find where you set the dialog user variables. How did you do it?

                                      Walt Decker
                                      Walt Decker

                                      Comment


                                      • #20
                                        What is PBCC ?
                                        Roger, PBCC is the console compiler. It's similar in syntax to QuickBasic screen 0 (text) although the new version include the GRAPHIC and XPRINT statements.

                                        It's a true windows compiler but is programmed more like PB DOS or QB4.5
                                        with pbcc you can capture the keys with inkey$ and mouseX and MouseY will give you the mouse coordinates.
                                        Inkey$ will also give you the mouseclick info.
                                        Last edited by Fred Buffington; 2 Dec 2007, 09:33 PM.
                                        Client Writeup for the CPA

                                        buffs.proboards2.com

                                        Links Page

                                        Comment

                                        Working...
                                        X