hi friends …

pretext
when i refer to activex controls i mean those which i test well, the richtextctrl, datetime picker and the month view.
(other activex controls like forms2 textbox got other issues too, tested partially)

activex keypress(), keydown(), keyup() choas
-------------------------------------------------------------------------

while i was developing a form in which i decided to use f5 function key as a shortcut key to refresh the form, as usual i set the keypreview property of the form to .t. to trap the key pressed and take an action … i placed a simple code to deal with the f5 key press.

* the keypress() of the form

lparameters nkeycode, nshiftaltctrl

with this
  do case

    case nkeycode=-4  && f5 .. refresh
      .myrefreshmethod()
     
nodefault

    case nkeycode= ............
     
*
      * ... etc
      *

  endcase
endwith


till now ok …

but what i noticed is that when the focus is in a datetimepicker on the form, the form will not be refreshed when i press f5.

this weird behavior lead me to test more … i found that:

  •     the keypress of the form was not receiving the key code … i.e. the keypreview setting is useless and the activex disrespect it and never passed the key to the form keypress.
  •     the keypress() of the activex contains this native code:

*** activex control event ***
lparameters keyascii

the twisted thing here is that … the key code passed to the keypress() of the activex is based on the ascii character codes charts (see below) … which gives some similar key codes to that we depend on (that is listed in the table of key codes in the inkey() section of vfp help) like the number keys codes and basic english letters codes …
but .. at the same time … keypress() of the activex didn't received the function keys pressed …. !!   because these are not included in the basic ascii character codes charts

the keypress() of the activex doesn't receive the modifier keys (shift, ctrl, alt) nor does it receive function keys .. but it receive some keys like the enter key, the backspace, the space and the esc key ..

and as you noticed there is no nshiftaltctrl parameter as that in the keypress() of the native vfp controls, so the keypress() of the activex will not reflect the condition of the modifier keys …

this is because it is ….. ascii code based … i.e. indicate which ascii character was passed whatever the key you pressed to invoke it … 🙂 …

  •     the activex has another two events to receive the key strokes …. :

keydown() and keyup() events.  .. let's talk about these …..

  •   keydown (as the name is clear) is fired when a keyboard key is pressed down, and keyup will fire when it is released to spring up …

the native code in these 2 events is:

* the code in the keyup and keydown events

*** activex control event ***
lparameters keycode, shift

  • the irony here is that .. this keycode here could have different values from that of the key codes in the keypress() of the activex and that of the native form …..

this is because … here, the keycode reflects the physical key pressed !!  and there is another table for these key codes .. see below (so you get 3 tables, one for ascii code, one for these physical key values, and one for the vfp native nkeycode value as shown in the inkey() function help document in vfp help)

so that keycode of the letter 'a' is the same as to its capital 'a'. the only difference is that shift value will indicate whether modifier keys were pressed or not, the value as follows:

shift value                  modifier key

      1                                 shift

      2                                 ctrl

      4                                   alt

and this value is additive, that mean if we press shift+ctrl, the value of shift is 3

but still in fact keyup() and keydown() in this case are not useful to detect which ascii key was pressed because the value returned by shift is not related to what is the setting of the caps key is !! …

in our example, if caps key was on and we press the keyboard key 'a' without shift, we are passing 'a' letter to the keyup and keydown events, the keycode value in keyup and keydown will be (65) according to the key codes table used by keyup and keydown, and shift will be 0.

but again, if caps key was off and we press the keyboard key 'a' without shift, we are passing 'a' letter to the keyup and keydown events, the keycode value in keyup and keydown will also be (65) according to the key codes table used by keyup and keydown, and shift will also be 0. !! … so, in this case we need to know the condition of the caps key to know what's going on ..

on the other hand, when we press the key '0', its key ascii in the keypress event is (48) whether we pressed the zero in the main keyboard numbers or in the numpad. while in the keyup and keydown, the keycode is (48) if the 0 key pressed in the main keyboard and it is (96) if the numpad 0 was pressed.

  •  therefore, msdn .. recommendation is:

" although the keydown and keyup events can apply to most keys, they're most often used for:

  •     extended character keys such as function keys.
  •     navigation keys.
  •     combinations of keys with standard keyboard modifiers.
  •     distinguishing between the numeric keypad and regular number keys.

"

  •  note here that … it is a native behavior of the keyboard to send repeated keys when you keep pressing down the key until you move your finger up. …. like this if i keep pressing the 'a' key :

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

in this case .. keydown will be fired with each one and keyup will be fired at the end only …

another (but) … if the key you pressed is processed by keypress() of the activex (if it is an ascii character), then the keypress() of the activex will be fired also 🙂 .. and the sequence of events will be like this for one rapid key press:

keydown ---> keypress ---> keyup

but for a press with a hold down say for 3 repeats, the event sequence will be like this:

keydown ---> keypress --->  keydown ---> keypress ---> keydown ---> keypress ---> keyup

a third (but) ….. if the key you are holding is not processed by the keypress (because it is not an ascii character), like the shift key or the ctrl key, the sequence of events will be:

keydown ---> keydown ---> keydown ---> keyup

this is important to be noticed if you want to put a code in these events since these will fire repeatedly .. especially the keydown() event that i thought it will fire once as do the keyup() event, but is not

  • if we have a command button with its default property is set to .t. or a command button with its cancel property set to .t., it is supposed that the activex control respects these settings (as the native vfp controls does) but … it doesn't !!

it doesn't … although in the msdn documentation of the keyup and keydown events it says that pressing enter key will not invoke these events if there is a commandbutton on the form with its default property set to .t. … and pressing esc key will not invoke these events if there is a commandbutton on the form with its cancel property set to .t. ………

this is not happening here in visual foxpro .. may be it is true in visual basic only !! i don't know.

  • and .. in msdn, it is said that tab key will not invoke the keyup and keydown events … but … by testing i found that:

if we press the tab key inside the activex .. we have different responses:

  • if there is another control that will receive the focus after the activex, then the event sequence will be as follows:

keydown() of the activex ---> keypress() of the parent form. ---> lostfocus() of the activex !!!

that's all .. no keypress() of the activex is fired (the ascii tab chr(9) fires it which can be produced by ctrl+i which inserts a tab space, like in the text part of the richtextctrl, not used to jump from a control to another)  … and .. no keyup() event.

  • if we used tab to move from a control on the form to the activex then the sequence of events will be:

gotfocus() of the activex ---> keyup() … and no keydown() event.

  • if there is no other active control that can receive the focus, then the sequence of events will be like this:

keydown() ---> keypress() of the form ---> lostfocus() of the activex ---> gotfocus() of the activex ---> keyup()

  • another nice funny note:

if we press just a modifier key once, lets take shift, inside the activex … the keypress() will not fire (of course .. not an ascii character)

the keydown() will be fired first with these values:

keycode=16 …. shift=1

then keyup() will be fired with these settings:

keycode=16 …. shift=0

in the keydown event, its like saying … " you pressed the shift key + shift key"

and in the keydup event, its like saying …" you pressed the shift key without the shift key"

funny and ironic 🙂

  • so, in foxpro .. activex key events are chaotic … when we look at it with the usual keypress event behavior we used to in vfp controls.

now to the struggle to overcome these puzzles ….

case no 1:

what i was trying to do in my form (as i said above) is that i want to use f5 key to call a custom refresh method in my form ….

the code i used in the keypress() event of the form is clear … (see it at the beginning of this article). and it works fine inside the form as far as i am away from the datetime picker .. so now how can we overcome that and let the f5 key works even in the activex control. ??

several options i tried:

1) using on key label:the use of on key label need careful control so that it will not interrupt a critical running code. so, we may use it within the confines of a modal form. defined in the init event and set to its default in the destroy event like this:

* init event of the form
on key label f5 execscript("_vfp.activeform.myrefresh")

* destroy event of the form
on key label f5

and the code i used in the keypress() event of the form to trap the f5 will be discarded. the code in myrefresh will be excuted directly with the f5 press.

or:

i keep my code in the keypress() of the form and just use on key label within the confines of the activex itself like this:

* gotfocus event of the activex
on key label f5 execscript("_vfp.activeform.myrefresh")

* lostfocus event of the activex
on key label f5

2) using bindevent():
 
i was expecting that using bindevent() will solve the problem .. by trapping the keypress() event of the activex or even the keyup() or keydown() events in a code like this:

* init event of the form
bindevent(thisform.olemyactivex, "keypress", thisform,;
 "keypress")

here … whether binding keypress, keydown, keyup .. of the activex to the keypress of the form (and whatever the flag is and whatever the type of keycode is) .. it doesn"t bind … it bind it to somewhere?!!

it looks like the activex is behaving like a standalone object … not respecting keypreview nor respecting any bindevent !! …

so, i said .. may be i should regard it as a window .. i tried this code to bind it using hwnd and windows message codes like this:

* init event of the form
#define wm_keyup   0x0101

bindevent(thisform.olemyactivex.hwnd,wm_keyup, thisform, "keypress")

it doesn"t bind too !! 🙁

notes:

- the activex hwnd property is not seen in the pem window but seen with intellisense!!

- i took the windows message value (wm_keyup   0x0101) from wmhandler.h available for download in msdn .. and i uploaded it here (change the extension to .h).

- i am not sure this last binding is logical or not, but it seems logical to me ..not sure!.

so, i failed with this method.

3) passing the keypress() or keyup() event key codes and shift values into keypress() of the form like this:

use keyup() to trap the function keys as far as these don't fire the keypress() of the activex.

* keyup() of the activex
*** activex control event ***

lparameters keycode, shift

do case
  case keycode=116  && f5
    thisform.keypress(-4,shift)
    nodefault
endcase

here the keycode need to be received as 116 and passed to the keypress() of the form as -4 … !! the tables that help us deal with these differences in keycodes are shown at the end of the article.

or we can send the keycode "as-is" and translate it in the form keypress() event.

case no. 2

if we like to use a richtextctrl control and want to work with it using the conventional shortcuts like: ctrl+b = bold, ctrl+i = italic, ctrl+u = underline. so that just selecting some text in the richtext control and pressing these shortcuts will format it accordingly.

the code i used to control this shortcut function is:

* keyup() of the richtextctrl
with this

do case
  case keycode=66 and shift=2 && ctrl+b
    .selbold=!.selbold
    nodefault
  case keycode=73 and shift=2 && ctrl+i
    .selitalic=!.selitalic
    nodefault
  case keycode=85 and shift=2 && ctrl+u
    .selunderline=!.selunderline
    nodefault
endcase

endwith

i faced some problems here ….

      1) if we run the form that contains the activex within the main vfp window (in-screen or in-top-level form), ctrl+b will call the breakpoints window.

      2) ctrl+i in the keypress event of the activex is interpreted as a tab space, chr(9) which is the standard ascii shortcut.

progress:

running the form as top level form .. solved the problem of breakpoints window. and the shortcut ctrl+b works fine.

ctrl+u is already working fine.

ctrl+i continued to produce tab spaces despite the assignment in the code above and the nodefault command.!!
even putting the code in the keydown() event that fires before the keypress didn't change this behavior.

so, what i did is i cancelled the original assignment of ctrl+i within the activex control and return it back when it loses the focus like this:

* gotfocus event of the activex
on key label ctrl+i *

* lostfocus event of the activex
on key label ctrl+i

when i use this approach, the code above that i put in the keyup() event will work fine whether put in the keyup() or keydown() event.

but ctrl+i will not work if i used the code in the keypress() event of the activex like this:

* keyup() of the richtextctrl
with this

do case

  case keyascii=2 && ^b
    .selbold=!.selbold
    nodefault

  case keyascii=9 && ^i
    .selitalic=!.selitalic
    nodefault

  case keyascii=21 && ^u
    .selunderline=!.selunderline
    nodefault

endcase

endwith

this is because the keypress() event will not receive ctrl+i anymore since it is no more an ascii character. but received by keyup() and keydown() as far as they represent a physical key combination as i explained above.

note:

we can add ctrl+b to the disabling code if we want to run the form in the main vfp window so the code will be:

* gotfocus event of the activex
on key label ctrl+i *
on key label ctrl+b *

* lostfocus event of the activex
on key label ctrl+i
on key label ctrl+b

now …. the key code tables ..

1) nkeycode values of the native visual foxpro controls are found in vfp help in the inkey() section.

2) ascii character codes chart 1 (0-127) (used in keypress event of the activex): http://msdn.microsoft.com/en-us/library/60ecse8t(vs.71).aspx

the picture below is to show the description of the codes from 0-31



3)
ascii character codes chart 2 (128-255) (used in keypress event of the activex):http://msdn.microsoft.com/en-us/library/9hxt0028(vs.71).aspx

"the characters that appear in windows above 127 depend on the selected typeface."

4) key code constants for keyup() and keydown():

http://msdn.microsoft.com/en-us/library/aa243025(vs.60).aspx

key codes

constant

value

description

vbkeylbutton

1

left mouse button

vbkeyrbutton

2

right mouse button

vbkeycancel

3

cancel key

vbkeymbutton

4

middle mouse button

vbkeyback

8

backspace key

vbkeytab

9

tab key

vbkeyclear

12

clear key

vbkeyreturn

13

enter key

vbkeyshift

16

shift key

vbkeycontrol

17

ctrl key

vbkeymenu

18

menu key

vbkeypause

19

pause key

vbkeycapital

20

caps lock key

vbkeyescape

27

esc key

vbkeyspace

32

spacebar key

vbkeypageup

33

page up key

vbkeypagedown

34

page down key

vbkeyend

35

end key

vbkeyhome

36

home key

vbkeyleft

37

left arrow key

vbkeyup

38

up arrow key

vbkeyright

39

right arrow key

vbkeydown

40

down arrow key

vbkeyselect

41

select key

vbkeyprint

42

print screen key

vbkeyexecute

43

execute key

vbkeysnapshot

44

snapshot key

vbkeyinsert

45

ins key

vbkeydelete

46

del key

vbkeyhelp

47

help key

vbkeynumlock

144

num lock key

 

keya through keyz are the same as their ascii equivalents: 'a'
through 'z'

constant

value

description

vbkeya

65

a key

vbkeyb

66

b key

vbkeyc

67

c key

vbkeyd

68

d key

vbkeye

69

e key

vbkeyf

70

f key

vbkeyg

71

g key

vbkeyh

72

h key

vbkeyi

73

i key

vbkeyj

74

j key

vbkeyk

75

k key

vbkeyl

76

l key

vbkeym

77

m key

vbkeyn

78

n key

vbkeyo

79

o key

vbkeyp

80

p key

vbkeyq

81

q key

vbkeyr

82

r key

vbkeys

83

s key

vbkeyt

84

t key

vbkeyu

85

u key

vbkeyv

86

v key

vbkeyw

87

w key

vbkeyx

88

x key

vbkeyy

89

y key

vbkeyz

90

z key

 

key0 through key9 are the same as their ascii equivalents: '0'
through '9

constant

value

description

vbkey0

48

0 key

vbkey1

49

1 key

vbkey2

50

2 key

vbkey3

51

3 key

vbkey4

52

4 key

vbkey5

53

5 key

vbkey6

54

6 key

vbkey7

55

7 key

vbkey8

56

8 key

vbkey9

57

9 key

 

keys on the numeric keypad

constant

value

description

vbkeynumpad0

96

0 key

vbkeynumpad1

97

1 key

vbkeynumpad2

98

2 key

vbkeynumpad3

99

3 key

vbkeynumpad4

100

4 key

vbkeynumpad5

101

5 key

vbkeynumpad6

102

6 key

vbkeynumpad7

103

7 key

vbkeynumpad8

104

8 key

vbkeynumpad9

105

9 key

vbkeymultiply

106

multiplication sign (*) key

vbkeyadd

107

plus sign (+) key

vbkeyseparator

108

enter (keypad) key

vbkeysubtract

109

minus sign (-) key

vbkeydecimal

110

decimal point(.) key

vbkeydivide

111

division sign (/) key

 

function keys

constant

value

description

vbkeyf1

112

f1 key

vbkeyf2

113

f2 key

vbkeyf3

114

f3 key

vbkeyf4

115

f4 key

vbkeyf5

116

f5 key

vbkeyf6

117

f6 key

vbkeyf7

118

f7 key

vbkeyf8

119

f8 key

vbkeyf9

120

f9 key

vbkeyf10

121

f10 key

vbkeyf11

122

f11 key

vbkeyf12

123

f12 key

vbkeyf13

124

f13 key

vbkeyf14

125

f14 key

vbkeyf15

126

f15 key

vbkeyf16

127

f16 key

download links:

  • a sample form to show the use of shortcuts, print with ctrl-p, format a richtext with ctrl+b, ctrl+i, ctrl+u. here
  • wmhandler.h (windows messaging handler h file): here (change its extension to .h)

some resources:

- ammar hadi ................ iraq

One Response to ActiveX keypress() Chaos

Leave a Reply

Your email address will not be published. Required fields are marked *