Subject Re: Grid search
From Mervyn Bick <invalid@invalid.invalid>
Date Sat, 26 Sep 2020 14:59:16 +0200
Newsgroups dbase.getting-started
Attachment(s) trap_grid_keystokes.wfm

On 2020/09/25 15:37, Akshat Kapoor wrote:
> Good Evening Ronnie,
> Placing a entryfield near the grid and then searching is damn easier
> than grid having focus and searching.
> Grid doesnot have a onKey event.

I agree with you, using a separate entryfield for the search string, as
with seekerSQL, makes sense.  On the other hand if one REALLY wants a
pseudo onKey event for a grid one can emulate one using a keyboard hook.

Very few programmers seem to have embraced the CALLBACK command which is
a pity as it can help solve many problems.  The attached example is
meant more as a contribution to your "old geezers" collection rather
than to solve Robbie's problem.

In the example a keyboard hook is used to build a simulated onKey event
handler but the same principle can be used to extend the normal onKey
event which doesn't catch ALL keystrokes.

Mervyn.







clear
if __version__ < 8
    msgbox("This form will only run in dBase Pluse 8 or higher.","Error")
    return
endif
if file('test_trap_grid_keystokes.dbf')
//   drop table test_trap_grid_keystokes
endif

if not file('test_trap_grid_keystokes.dbf')
   create table test_trap_grid_keystokes  (id autoinc,d1 character(5),d2 numeric(5,2),;
     d3 character(5),d4 numeric(5,2))

   use test_trap_grid_keystokes
   generate 20
   use
endif


#include winuser.h
** END HEADER -- do not remove this line
//
// Generated on 2020-09-25
//
parameter bModal
local f
f = new trap_grid_keystrokesForm()
if (bModal)
   f.mdi = false // ensure not MDI
   f.readModal()
else
   f.open()
endif

class trap_grid_keystrokesForm of FORM
   with (this)
      onOpen = class::FORM_ONOPEN
      onClose = class::FORM_ONCLOSE
      height = 15.4545
      left = 10.2857
      top = 3.1364
      width = 69.8571
      text = ""
   endwith

   this.TEST_TRAP_GRID_KEYSTOKES1 = new QUERY(this)
   with (this.TEST_TRAP_GRID_KEYSTOKES1)
      left = 4.0
      width = 14.0
      height = 1.0
      sql = 'select * from "test_trap_grid_keystokes.DBF"'
      active = true
   endwith

   this.GRID1 = new GRID(this)
   with (this.GRID1)
      onGotFocus = class::GRID1_ONGOTFOCUS
      dataLink = form.test_trap_grid_keystokes1.rowset
      allowEditing = false
      height = 9.0
      left = 6.0
      top = 3.0
      width = 56.0
   endwith

   this.ENTRYFIELD1 = new ENTRYFIELD(this)
   with (this.ENTRYFIELD1)
      when = {||false}
      height = 1.0
      left = 6.0
      top = 13.0
      width = 22.0
      tabStop = false
      value = ""
   endwith

   this.ENTRYFIELD2 = new ENTRYFIELD(this)
   with (this.ENTRYFIELD2)
      height = 1.0
      left = 35.0
      top = 13.0
      width = 8.0
      value = "Entryfield2"
   endwith

   this.ENTRYFIELD3 = new ENTRYFIELD(this)
   with (this.ENTRYFIELD3)
      height = 1.0
      left = 50.0
      top = 13.0
      width = 8.0
      value = "Entryfield3"
   endwith

   this.rowset = this.test_trap_grid_keystokes1.rowset

   function form_onOpen
      if type("GetCurrentThreadId") # "FP"
         extern CULONG GetCurrentThreadId() kernel32 from "GetCurrentThreadId"
      endif
      if type("GetAsyncKeyState") # "FP"
              extern CSHORT GetAsyncKeyState(CINT) user32
                endif
      if type("GetKeyState") # "FP"
              extern CSHORT GetKeyState(CINT) user32
                endif
      if type("GetWindowLong") # "FP"
       extern CLONG GetWindowLong(CHANDLE, CINT) user32 from "GetWindowLongA"
      endif
       if type("SetWindowsHookEx") # "FP"
          extern CLONG SetWindowsHookEx(CINT, CPTR, CHANDLE, CULONG) user32 from "SetWindowsHookExA"
       endif
       if type("UnhookWindowsHookEx") # "FP"
          extern CLOGICAL UnhookWindowsHookEx(CHANDLE) user32
       endif
       if type("CallNextHookEx") # "FP"
          extern CLONG CallNextHookEx(CHANDLE, CINT, CUINT, CUINT) user32
       endif
       CALLBACK CLONG hookWndProc(CINT, CUINT, CUINT) OBJECT this
       form.hookProc = GetCallAddress(class::HOOKWNDPROC)
       form.hInst = GetWindowLong(this.hwnd, GWL_HINSTANCE)
       form.hook = SetWindowsHookEx(WH_KEYBOARD,form.hookProc,form.hInst, GetCurrentThreadId())
       form.mouse_on_grid = true
       return

   function hookWndproc(hCode, wParam, lParam)
      // wParam   virtual key code.
      // lParam   bit 31 = 0 keydown, bit 31 = 1 keyup
      if bitset(lParam,31)  = false  ;     //keydown
            and hCode = 3 and  (wParam = VK_BACK  or (wParam >= 0x30 and wParam <= 0x5A))
            if form.activeControl = form.grid1
               if wParam > 0x39
                   if GetAsyncKeyState(VK_SHIFT) <>0 or GetKeyState(VK_CAPITAL) <> 0
                         form.entryfield1.value += chr(wParam)
                   else
                        form.entryfield1.value += chr(wParam+0x20)
                   endif
               elseif wParam > 0x30  
                   form.entryfield1.value += chr(wParam)
               endif
            endif
         if wParam = VK_BACK
            form.entryfield1.value = substr(trim(form.entryfield1.value),1,len(trim(form.entryfield1.value))-1)
         endif
     //Code to trigger progressive search goes here.
      endif
      return CallNextHookEx(form.hook, hCode, wParam, lParam)

   function GRID1_onGotFocus()
       form.entryfield1.value = ''
      return

   function form_onClose
       UnhookWindowsHookEx(form.hook)
       return

endclass