clear if file('test_grid_callback.dbf') drop table test_grid_callback endif if not file('test_grid_callback.dbf') create table test_grid_callback (job_no character(5),customer character(15),address1 character(15),address2 character(15),address3 character(15)) use test_grid_callback generate 10 go top for n = 1 to 10 replace job_no with '1'+str(N,3,0,'0') SKIP next go top replace customer with 'Abel' SKIP replace customer with 'Baker' SKIP replace customer with 'Charlie' SKIP replace customer with 'Delta' SKIP replace customer with 'Echo' SKIP use endif ** END HEADER -- do not remove this line // // Generated on 2018/02/12 // parameter bModal local f f = new test_rid_callback2Form() if (bModal) f.mdi = false // ensure not MDI f.readModal() else f.open() endif class test_rid_callback2Form of FORM with (this) canClose = class::FORM_CANCLOSE onOpen = class::FORM_ONOPEN onClose = class::FORM_ONCLOSE height = 26.7273 left = 44.2857 top = 3.2273 width = 134.8571 text = "" scrollBar = 2 // Auto endwith this.TEST_GRID_CALLBACK1 = new QUERY(this) with (this.TEST_GRID_CALLBACK1) left = 2.0 top = 1.0 width = 14.0 height = 1.0 sql = 'select * from "test_grid_callback.DBF"' active = true endwith with (this.TEST_GRID_CALLBACK1.rowset) with (fields["address1"]) readOnly = true endwith with (fields["address2"]) readOnly = true endwith with (fields["address3"]) readOnly = true endwith endwith this.GRID1 = new GRID(this) with (this.GRID1) onLeftMouseUp = class::GRID1_ONLEFTMOUSEUP dataLink = form.test_grid_callback1.rowset height = 15.5 left = 12.0 top = 6.0 width = 103.0 endwith this.rowset = this.test_grid_callback1.rowset function form_onClose() form.test_grid_callback1.active = false return function form_onOpen() clear #include winuser.h if type("dBGetCurrentThreadId") # "FP" extern CULONG dBGetCurrentThreadId() kernel32 from "GetCurrentThreadId" endif if type("dBGetWindowLong") # "FP" extern CLONG dBGetWindowLong(CHANDLE, CINT) user32 from "GetWindowLongW" endif if type("dBSetWindowsHookEx") # "FP" extern CLONG dBSetWindowsHookEx(CINT, CPTR, CHANDLE, CULONG) user32 from "SetWindowsHookExW" endif if type("dBUnhookWindowsHookEx") # "FP" extern CLOGICAL dBUnhookWindowsHookEx(CHANDLE) user32 from "UnhookWindowsHookEx" endif if type("dBCallNextHookEx") # "FP" extern CLONG dBCallNextHookEx(CHANDLE, CINT, CUINT, CUINT) user32 from "CallNextHookEx" endif // if type("GetAsyncKeyState") # "FP" // extern CSHORT GetAsyncKeyState(CSHORT) user32 // endif CALLBACK CLONG hookWndProc(CINT, CUINT, CUINT) OBJECT this this.hookProc = GetCallAddress(class::HOOKWNDPROC) this.hInst = dBGetWindowLong(this.hwnd, GWL_HINSTANCE) this.hook = dBSetWindowsHookEx(WH_KEYBOARD, this.hookProc, this.hInst, dBGetCurrentThreadId()) form.grid1.setFocus() return function GRID1_onLeftMouseUP(flags, col, row) keyboard '{tab}' keyboard '{home}' return function form_canClose //detach the hook. dBUnhookWindowsHookEx(this.hook) return true function doOnEnter if form.test_grid_callback1.rowset.atlast() form.test_grid_callback1.rowset.beginAppend() else form.test_grid_callback1.rowset.next() endif keyboard '{home}' return function hookWndproc(hCode, wParam, lParam) cReturn = dBCallNextHookEx(this.hook, hCode, wParam, lParam) if (wParam = VK_RETURN or wParam = VK_TAB) and hcode = 0 and not bitset(lparam,31) if upper(form.activeControl.name) = 'GRID1' and form.grid1.currentcolumn = 2 //tab or return in column 1 is ignored here and passed on to Windows like any other keystroke if form.test_grid_callback1.rowset.state = 3 and form.grid1.currentcolumn = 2 form.test_grid_callback1.rowset.save() endif class::doOnEnter() //Deal with tab or return in coulmn 2 cReturn = 1 // Don't call next hook. This prevents Enter or Tab from moving cursor to next field endif endif return cReturn endclass