OnKeyPress = "=somefunction()" how function can receive the key pressed?

Posted on 2006-10-22
Last Modified: 2008-02-01
The event procedure for OnKeyPress starts:
Private Sub xxx_KeyPress(KeyAscii As Integer).

However when I change it to a function call:
OnKeyPress = "=somefunction()"
there does not seem to be a way to send the KeyAscii value to the function. Is there some way for the function to get the key pressed?

Why do I want this? To avoid having to write lots of keypress event subroutines. I have code that scans a form when it opens for certain comboboxes, and sets them up in certain ways. The only place I'm stuck is handling keypress.
Question by:ramrom
LVL 10

Expert Comment

by:Luke Chung
ID: 17784940
It sounds like you're trying to do something outside the "natural" behavior of Access' event model.  Subverting the natural behavior of Access keystrokes is dangerous because people who are used to the behavior in other instances of Access may end up fighting your application.  But that could quickly get into a religious argument, so I'll refrain.

Unfortunately, if you want to handle the keystrokes, you're going to need to use the Event Procedure, and pass that to your function. Good luck.

LVL 11

Expert Comment

ID: 17784969
Is this what umean?

in form  text box?

Private Sub FIELDNAME_KeyPress(KeyAscii As Integer)
testfunction (KeyAscii)

End Sub

in modules

Public Function testfunction(key As Integer)
MsgBox key
End Function

LVL 17

Author Comment

ID: 17785607
donaldmaloney: no. I want to avoid writing event procedures, and use a function instead.

LukeChung-FMS: I want my combo box to respond to ctrl-e. There is currently no action triggered by ctrl-e in combo boxes so I think I am safe.

Of course if I could intercept right click then I'd have no problem (I'd use that instead). But the only way to do that (again) is with a mouse event procedure, which I choose to avoid.
Complete VMware vSphere® ESX(i) & Hyper-V Backup

Capture your entire system, including the host, with patented disk imaging integrated with VMware VADP / Microsoft VSS and RCT. RTOs is as low as 15 seconds with Acronis Active Restore™. You can enjoy unlimited P2V/V2V migrations from any source (even from a different hypervisor)

LVL 44

Accepted Solution

Leigh Purvis earned 125 total points
ID: 17785619
<Warning - substantial post>
Hi ramrom - how goes it?
(I do like your questions ;-)

When you asked the question my first thought (apart from the point Luke raises - but you're an experienced developer, so I'm sure you'll be doing this for a good reason) was that you'll need to create a class (or two) to catch these keypresses.

First off - I'm assuming you really don't want to be making alterations to your existing functions.
For example sticking in a bunch of new code to whatever function calls might be going in to the Event properties - I'm assuming you want to avoid that.

So - back to the classes.
To successfully hook into a control's event - you'd need to have [Event Procedure] in the event property.
So - that kyboshes that one.
However the Form's keypress remains (hopefully!!) to be set to an [Event Procedure].
Is that a fair enough statement?
And if not - then is there a definite need for both control *and* form to have function calls in the keypress?  Could we live without one?

If the controls could be sacrificed then it's easier.
If not the we can still use the form - and I'll push on with that, as it's the more involved of the two (and you've mentioned controls specifically in your question).

A class which sinks the keypress event of the form.
Checks the current control of that form.
If it's one of the "certain comboboxes" then a class property makes available (through the parameter which it still receives) the ASCII character of the key that's just been pressed.
Of course the value needs to be retrieved by your functions somehow.
That could be simply by the form setting a public property of its own - or perhaps a global variable.

At a simple level - you could pass to the class a string delimited list of the controls which you're wanting to include (I assume they have some obvious identifier - perhaps a flag in the tag property or a common naming convention).
So they could always be enumerated at runtime - either in the code with which you pass the property to the class - or within the class itself once it has a form object to examine the controls of.

I'm sure this all sounds about as clear as mud.
Please feel free to post back why this wouldn't work (i.e. both keypress events are spoken for - which would be a shame) or if it's just not clear what I'm getting at.
And with more details too if you like - of how you identify the special combos for example.

I'll post here what I envisage the start of a class which should be enough to get back usable information.

Private WithEvents mfrmKey As Access.Form
Private mstrCtrlList As String
Private mintLastKey As Integer

Public Event BeenPressed()

Private Sub mfrmKey_KeyPress(KeyAscii As Integer)
    Dim strControl As String
    strControl = mfrmKey.ActiveControl.Name
    Debug.Print "In Class pressed " & KeyAscii & "  " & Chr(KeyAscii)
    'Check the current control is one we care about
    If InStr(1, mstrCtrlList, strControl) > 0 Then
        mintLastKey = KeyAscii
        mintLastKey = 0
    End If
    RaiseEvent BeenPressed
End Sub

Public Property Set CurFormKey(pfrm As Access.Form)
    Set mfrmKey = pfrm
End Property

Public Property Let ControlList(pstrList As String)

    mstrCtrlList = pstrList
End Property

Public Property Get LastKeyCode() As Integer

    LastKeyCode = mintLastKey
End Property

lol of course another possiblity could be to just use the control Keydown before the keypress to tell what would have been aquired.
(Or the form event more directly).
But why simplify matters when there's fun to be had.
I honestly don't think it would take long to set up.
And once done - it's done for use throughout... from then on. :-)
LVL 17

Author Comment

ID: 17786088
Yep. That's the approach I took. Nice to have it confirmed. Let me expound.

I wrote a Sub OpenForm which amongst other things calls docmd.openform, and a class (FormHelper) which contains code similar to what you posted.

User requests for forms are sent to OpenForm.

OpenForm checks to see if the form has an instance of the FormHelper class, and if not, writes "Dim Helper as New FormHelper" to the declarations of the form's module. It also ensures that the form's OnKeyUp = "[event procedure]" and keypreview = True.

It loops thru the form's controls looking for those of type combobox that have a tag. The tag contains directives used to set the combo box properties.

FormHelper watches for KeyUp events, examines the ActiveControl.tag, and acts as needed.

FWIW OpenForm also checks to see if the form has a Sub reinit(), and if not, writes the code for it to the form's module.
Subsequently it calls this method, passing up to 6 arguments (which are at the end of the argument list for OpenForm).

This totally overcomes the limitations of openargs.

The place I ran into trouble was that subforms did not benefit from this passage thru openform, as they are opened automatically. So I lacked a way to apply the above technology to the subforms. So I was looking to function call instead of eventy procedure to help.

I now work around that by having openform visit the subforms and update them as well.

I sure do miss the ease I had in FoxPro of just subclassing combobox. Sigh.

LVL 44

Expert Comment

by:Leigh Purvis
ID: 17788870
So you're using Keyup events in your class - and hence are free to have an "[Event Procedure]" there?
So no need for a form object?
Or do you do so to keep it simple (i.e. watching for the keyup on that form - rather than any of the controls.)

Another option would be to have a couple of classes (parent and child) where the child holds a combo object and watches for the events of your very particular controls - and the parent maintains a collection of those classes.

If you were adding controls then I suppose whether a form was a main or subform - then if it added the controls to the class itself it wouldn't matter.

But it's just semantics now - you're up and running :-)

Not that I've ever used Foxpro (or are ever likely to now) - but how does it subclass combos in a widespread way?
i.e. All combos?  You could subclass the entire combo type class? (Rather than an individual control at a time?)
LVL 17

Author Comment

ID: 17790867
In FoxPro one may:

DEFINE CLASS xxx AS combobox
  borderstyle = 1
  backcolor = 999
  PROCEDURE KeyPress(nKeyCode, nShiftAltCtrl)
    * code to act on KeyPress

Then add any number of controls to forms based on this class.

One may then define other classes based on combobox, or on xxx (subclassing).

  caption = "Foo"
  backcolor = 9989
  PROCEDURE LostFocus()
    * code to act on LostFocus

yyy "inherits" backstyle and KeyPress from xxx, creates some new things, and "overrides backcolor.

These definitions can also be made using a Visual Class Designer. Just like laying out a form! One may then drag-drop the visual class onto a form to create an instance of the class (control or whatever).

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Access custom database properties are useful for storing miscellaneous bits of information in a format that persists through database closing and reopening.  This article shows how to create and use them.
Did you know that more than 4 billion data records have been recorded as lost or stolen since 2013? It was a staggering number brought to our attention during last week’s ManageEngine webinar, where attendees received a comprehensive look at the ma…
In Microsoft Access, learn how to “cascade” or have the displayed data of one combo control depend upon what’s entered in another. Base the dependent combo on a query for its row source: Add a reference to the first combo on the form as criteria i…
In Microsoft Access, learn different ways of passing a string value within a string argument. Also learn what a “Type Mis-match” error is about.

685 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question