Re: msflexgrid with ctrl-pgup & ctrl-pgdn



On 9 May, 01:17, Rick <rick-pau...@xxxxxxxxx> wrote:

IMO, It seems like videosoft's msflexgrid is rather
greedy in taking all the navigation key combos,
many of which do the same thing.

Lots of controls eat various keys, either because of the nature of the
control or sometimes simply because it is a "Windows thing". For
example, unless there is only one control on your Form then the Tab
key will not get to the Form's KeyPreview unless all of their Tabstop
properties are set to False. It is still possible for your VB app to
get at all keys pressed by the user though, even the navigation keys
when your MSFlexGrid has the focus, but you need to use subclassing to
do it by setting up a keyboard hook. Such hooks can be system wide
(where your VB app can "see" all keypresses even when some other app
has the focus) or application wide (where your VB app can "see" all
keypresses only when a Form in your own app, or something on it, has
the focus). In almost all cases the latter is the best option, unless
you are doing something a bit unusual. You need to take the usual
"subclassing" precautions to avoid crashing the IDE of course,
specifically with respect to how you terminate your app when running
in the IDE (you should never use the Run / End menu for example
because it prevents the Form's Unload event from running) and the IDE
is likely to crash if your app generates an error while running in the
IDE, but running as a compiled exe is fine. There are some "safe
subclassing in the IDE" routines on vbaccelerator but personally I
don't use them myself and once I have got the subclassing working okay
I just disable it when performing other work on my app and enable it
again when I compile the exe.

Anyway, here's a simple example. There are two blocks of code, one for
a standard module and the other for your Form. When peforming
subclassing it is advisable for your code to get out of the subclassed
procedure fairly quickly and since I don't know how much work your own
code will be doing in response to the keys I have used a standard VB
Timer as a "one shot" so that the subclassed procedure ends very
quickly and your own code in response to the key can safely run in the
Timer event, which occurs about ten milliseconds after the key was
pressed. I can't remember now why I decided to use a Timer as a one
shot in this example, as opposed to the alternative of using
PostMessage to trigger an event, but I think there must have been a
good reason for it at the time. Also, when subclassing in this way you
get a choice as to what you want to do with the key when you have
picked it up and done what you want with it. You can either allow the
system (your VB app) to respond to the key in the normal way or you
can alternatively "eat" the key so that as far as the rest of your app
is concerned it was never pressed in the first place. In this example
I've "eaten" the key (the PageUp and the PageDown keys) in order to
prevent the MSFlexgrid responding to those keys in its normal way
(since that is what I assume you would prefer). But if you want to
change that behaviour you can do so (there is a short note in the code
explaining what to do if you want to make that change).

To try the example, first place an otherwise unused Timer Control on
the Form that contains your MSFlexGrid and add the following code into
your Form Load and Unload events (if your Timer is not called Timer1
then amend the code accordingly):

Private Sub Form_Load()
Timer1.Enabled = True
Timer1.Interval = 0
HookKeyboard Timer1
End Sub

Private Sub Form_Unload(Cancel As Integer)
UnHookKeyboard
End Sub

Then use the following code for your Timer event:

Private Sub Timer1_Timer()
Me.caption = Timer1.Tag ' just for test purposes
End Sub

Then add a standard Module and paste the following code into it. When
you run the project and click into your MSFlexGrid (Enabled set to
True as normal) you should find that it responds to all keys in its
normal way except that it does not respond at all to the PageUp or
PageDown keys (although, as explained above, you can allow it to
respond in its normal way to the PageUp and PageDown keys as well if
you wish). Each time you press down either the PageUp or PageDown key
the Timer1 event will fire. In this simple example that event merely
reports to keypress in the Form's Caption just for test purposes, and
any code you wish to execute when either of those keys are pressed
should be entered into the Timer event. One other thing, I'm in quite
a rush at the moment and so I've made only the essential modifications
to my "stock" code for doing these sort of things and at the moment
I've not had time to add the code to check the Ctrl key, so the code
as it stands responds to the PageUp and PageDown keys whether the Ctrl
key is held down or not. That extra function is quite easy to add
though and I'm fairly sure you will be able to do it yourself. Post
again if you have any problems with it. (Module code as below):

Mike

Option Explicit
Private Declare Function SetWindowsHookEx Lib "user32" _
Alias "SetWindowsHookExA" (ByVal idHook As Long, _
ByVal lpfn As Long, ByVal hmod As Long, _
ByVal dwThreadId As Long) As Long
Private Declare Function CallNextHookEx Lib "user32" _
(ByVal hHook As Long, ByVal ncode As Long, _
ByVal wParam As Long, lParam As Any) As Long
Private Declare Function UnhookWindowsHookEx Lib "user32" _
(ByVal hHook As Long) As Long
Private Const WH_KEYBOARD As Long = 2
Private Hook As Long, tMessage As Timer

Public Sub HookKeyboard(t1 As Timer)
Set tMessage = t1
Hook = SetWindowsHookEx(WH_KEYBOARD, _
AddressOf KeyboardProc, App.hInstance, App.ThreadID)
End Sub

Public Sub UnHookKeyboard()
UnhookWindowsHookEx Hook
End Sub

Public Function KeyboardProc(ByVal ncode As Long, _
ByVal wParam As Long, ByVal lParam As Long) As Long
Dim keyCode As Long
If ncode >= 0 Then
keyCode = wParam And &HFF&
If keyCode = vbKeyPageUp Or keyCode = vbKeyPageDown Then
If (lParam And &H80000000) = 0 Then ' key down
tMessage.Tag = CStr(keyCode)
tMessage.Interval = 10 ' ) one shot
tMessage.Interval = 0 ' ) timer
End If
' Return -1 if we want to kill this key,
' otherwise use CallNextHook
KeyboardProc = -1 ' kill the key
' KeyboardProc = CallNextHookEx(Hook, ncode, wParam, ByVal lParam)
End If
Else
KeyboardProc = CallNextHookEx(Hook, ncode, _
wParam, ByVal lParam)
End If
End Function






.



Relevant Pages

  • RE: Application Foreground "Timeout"
    ... "I'm sure the app is still running because pressing a programmed HotKey ... Me.BringToFront in my new timer routine. ... Private time As New Timer ... End Sub ...
    (microsoft.public.dotnet.framework.compactframework)
  • Re: Using Timer function in VB 6.0
    ... >> wondering how I can use the Timer or Time function to do that. ... Private Declare Function KillTimer Lib "user32" _ ... Public Sub TimerProc(ByVal hwnd As Long, ...
    (microsoft.public.vb.general.discussion)
  • Re: Running a scheduled task from VB
    ... Add a timer to the app. ... Timer1_Timersub to check the system date and if it's ... time to execute a procedure, ...
    (microsoft.public.vb.enterprise)
  • System.Timers.Timer.Elapsed event not firing
    ... countdown timer modal dialog. ... Public Sub New ... 'This call is required by the Windows Form Designer. ... Private Sub butCancel_Click(ByVal sender As System.Object, ...
    (microsoft.public.dotnet.languages.vb)
  • Re: On Time Bug?
    ... "Dave Peterson" wrote: ... throwing an error if the timer has already been cancelled. ... Public Sub cancel_timer ...
    (microsoft.public.excel.misc)