Tk Source Code

Check-in [769f555d]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Another rewrite of tkProcessKeyEvent to repair and clarify the logic of when to use the TextInputClient and when to send an XEvent.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | bug-585584ad66
Files: files | file ages | folders
SHA3-256: 769f555de32d10d4e7448576e71ece0d91a0e3c739898297eaa9a41275a9e9eb
User & Date: marc_culler 2020-04-20 17:14:40
References
2020-04-20
19:02 Ticket [585584ad] Aqua: `event generate` not working for function keys status still Open with 3 other changes artifact: 3d3b1190 user: chrstphrchvz
Context
2020-04-20
19:18
Fix two typos and a bug -- thanks to Christopher Chavez. check-in: f4ee810c user: culler tags: bug-585584ad66
17:14
Another rewrite of tkProcessKeyEvent to repair and clarify the logic of when to use the TextInputClient and when to send an XEvent. check-in: 769f555d user: marc_culler tags: bug-585584ad66
2020-04-19
23:43
Another major overhaul: more code cleanup; make event generate work for Home, End, ...; distinguish left and right mod keys. check-in: 7e861e1e user: marc_culler tags: bug-585584ad66
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to macosx/tkMacOSXKeyEvent.c.

19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48




49
50
51

52


53
54
55
56
57
58
59



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93

94

95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

143
144
145
146
147
148

149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174

175
176

177

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227


228






229









230







231






232


233




234






235
236
237
238
239
240
241

/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_KEYBOARD
#endif
*/
#define NS_KEYLOG 0

static Tk_Window keyboardGrabWinPtr = NULL; /* Current keyboard grab window. */
static NSWindow *keyboardGrabNSWindow = nil; /* Its underlying NSWindow.*/
static NSModalSession modalSession = nil;
static BOOL processingCompose = NO;
static Tk_Window composeWin = NULL;
static int caret_x = 0, caret_y = 0, caret_height = 0;
static TkWindow *caret_win = NULL;

static void setupXEvent(XEvent *xEvent, Tk_Window tkwin, NSUInteger modifiers);

#pragma mark TKApplication(TKKeyEvent)

@implementation TKApplication(TKKeyEvent)

- (NSEvent *) tkProcessKeyEvent: (NSEvent *) theEvent
{
#ifdef TK_MAC_DEBUG_EVENTS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
#endif
    unsigned int keyCode = [theEvent keyCode];
    NSWindow *w = [theEvent window];
    TkWindow *winPtr = TkMacOSXGetTkWindow(w);




    NSUInteger modifiers = ([theEvent modifierFlags] &
			    NSDeviceIndependentModifierFlagsMask);
    NSString *characters = nil;

    NSString *charactersIgnoringModifiers = nil;


    UniChar keychar = 0;
    static NSUInteger savedModifiers = 0;
    static NSMutableArray *nsEvArray;

    if (nsEvArray == nil) {
        nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
        processingCompose = NO;



    }

    /*
     * Control-Tab and Control-Shift-Tab are used to switch tabs in a tabbed
     * window.  We do not want to generate an Xevent for these since that might
     * cause the deselected tab to be reactivated.
     */

    if (keyCode == 48 && (modifiers & NSControlKeyMask) == NSControlKeyMask) {
	return theEvent;
    }

    if (!winPtr) {
	return theEvent;
    }

    /*
     * If a local grab is in effect, key events for windows in the
     * grabber's application are redirected to the grabber.  Key events
     * for other applications are delivered normally.  If a global
     * grab is in effect all key events are redirected to the grabber.
     */

    Tk_Window tkwin = (Tk_Window) winPtr;
    TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr;
    if (grabWinPtr) {
	if (winPtr->dispPtr->grabFlags ||  /* global grab */
	    grabWinPtr->mainPtr == winPtr->mainPtr){ /* same application */
	    tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
	}
    }

    NSEventType type = [theEvent type];
    BOOL has_modifiers = NO;

    XEvent xEvent;


    if (type == NSKeyUp || type == NSKeyDown) {
	characters = [theEvent characters];
	keychar = [characters length] > 0 ? [characters characterAtIndex:0] : 0;
	charactersIgnoringModifiers = [theEvent charactersIgnoringModifiers];
	
#if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1
	TKLog(@"-[%@(%p) %s] r=%d mods=%u '%@' '%@' keyCode=%u c=%d %@ %d",
	      [self class], self, _cmd, (type == NSKeyDown) && [theEvent isARepeat],
	      modifiers, characters, charactersIgnoringModifiers, keyCode,
	      ([charactersIgnoringModifiers length] == 0) ? 0 :
	      [charactersIgnoringModifiers characterAtIndex: 0], w, type);
#endif

    }
    if (type == NSKeyDown) {
	has_modifiers = xEvent.xkey.state &
	    (ControlMask | Mod1Mask | Mod3Mask | Mod4Mask);
    }

    /*
     * Build the XEvent.

     */

    setupXEvent(&xEvent, tkwin, modifiers);

    /*
     * Check whether this key event belongs to the caret window.
     */

    Bool has_caret = (TkFocusKeyEvent(winPtr, &xEvent) == caret_win);

    /*
     * A KeyDown event received for the caret window which is not a function key
     * and has no modifiers other than Shift or Option will be processed with the
     * TextInputClient protocol below.  All other key events are handled here
     * by queueing the XEvent created above.
     */

    if (!processingCompose || !has_caret) {
	xEvent.xkey.keycode = (keyCode << 16) | keychar;
	switch (type) {
	case NSFlagsChanged:

	    /*
	     * If the highest bit where they differ was set then this is a press.
	     */


	    xEvent.xany.type = modifiers > savedModifiers ? KeyPress : KeyRelease;

	    /*
	     * The value -1 signals a modifier keycode to the function TkpGetKeySym
	     * defined in tkMacOSXKeyboard.c.
	     */


	    xEvent.xany.send_event = -1;

	    /*
	     * Update savedModifiers for NSFlagsChanged events and no others,
	     * since some non-modifier keys (e.g. function keys) have modifier
	     * flags set
	     */

            savedModifiers = modifiers;
	    break;
	case NSKeyUp:
	    xEvent.xany.type = KeyRelease;
	    break;
	case NSKeyDown:
	    xEvent.xany.type = KeyPress;
	    break;
	default:
	    return theEvent; /* Unrecognized key event. */
	}

        if (type != NSKeyDown ||
	    !has_caret        ||
	    has_modifiers     ||
	    ((keychar >= 0xF700) && (keychar <= 0xF8FF))) {
	    if (type == NSKeyDown && [theEvent isARepeat]) {


		/*

		 * Insert a KeyRelease XEvent before a repeated KeyPress.

		 */

		xEvent.xany.type = KeyRelease;
		Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
		xEvent.xany.type = KeyPress;
            }

	    /*
	     * Queue the XEvent and return.
	     */

            Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
            return theEvent;
	}
    }

    /*
     * Either we are processing a composition or this is a normal KeyDown event
     * for the caret window. Either way the event should be passed to
     * interpretKeyEvents.  But we only need to send KeyDown events.
     */

    switch (type) {
    case NSKeyDown:
	if (NS_KEYLOG) {
	    TKLog(@"keyDown: %s compose sequence.\n",
		  processingCompose == YES ? "Continue" : "Begin");

	}

	/*
	 * Call the interpretKeyEvents method to handle the event as a
	 * TextInputClient.  When the composition sequence is complete, our
	 * implementation of insertText: replacementRange will be called.  that
	 * method generates a key down XEvent with the selected character.  In
	 * IME when multiple characters have the same composition sequence and
	 * the selected character is not the default it may be necessary to hit
	 * the Enter key multiple times before the character is accepted and
	 * rendered. So we repeatedly send Enter key events until inputText has
	 * cleared the processingCompose flag.
	 */

	processingCompose = YES;
	while(processingCompose) {
	    [nsEvArray addObject: theEvent];
	    [[w contentView] interpretKeyEvents: nsEvArray];
	    [nsEvArray removeObject: theEvent];
	    if ([theEvent keyCode] != 36) {
		break;
	    }
	}


	break;






    case NSFlagsChanged:









	savedModifiers = modifiers;







	break;






    default:


	break;




    }






    return theEvent;
}
@end


@implementation TKContentView








|



















<


>
>
>
>


<
>
|
>
>


|




>
>
>












<
<
<
<



|



<
<







<
<
>
|
>


|
<
<
|
<
<
<
<
<
<
<
|
|
<
<
<
<
<
|
<
>
|
<
<
<
<
<
<

<
|
<
<
<
<
<
<
|
<
<
<
<
|
<
<
<
|
>
|
|
<
<
<
<
>
|
<

|
|
|
|
|

<
<
<
<
<
<
<
<
<
<
<
|
<
<
|
<
<
>

|
>
|
>
|
<
<
<
<
|
|
<
<
<
|
<
<
<
<
|
<
<
<
<
<
|
|
<
|
|
|
>
|
<

|

|
|



|
|











>
>
|
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>

>
>
>
>
>
>
>

>
>
>
>
>
>

>
>
|
>
>
>
>
|
>
>
>
>
>
>







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45

46
47
48
49
50
51
52
53

54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79




80
81
82
83
84
85
86


87
88
89
90
91
92
93


94
95
96
97
98
99


100







101
102





103

104
105






106

107






108




109



110
111
112
113




114
115

116
117
118
119
120
121
122











123


124


125
126
127
128
129
130
131




132
133



134




135





136
137

138
139
140
141
142

143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219

/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_KEYBOARD
#endif
*/
#define NS_KEYLOG 0
#define XEVENT_MOD_MASK (ControlMask | Mod1Mask | Mod3Mask | Mod4Mask)
static Tk_Window keyboardGrabWinPtr = NULL; /* Current keyboard grab window. */
static NSWindow *keyboardGrabNSWindow = nil; /* Its underlying NSWindow.*/
static NSModalSession modalSession = nil;
static BOOL processingCompose = NO;
static Tk_Window composeWin = NULL;
static int caret_x = 0, caret_y = 0, caret_height = 0;
static TkWindow *caret_win = NULL;

static void setupXEvent(XEvent *xEvent, Tk_Window tkwin, NSUInteger modifiers);

#pragma mark TKApplication(TKKeyEvent)

@implementation TKApplication(TKKeyEvent)

- (NSEvent *) tkProcessKeyEvent: (NSEvent *) theEvent
{
#ifdef TK_MAC_DEBUG_EVENTS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, theEvent);
#endif

    NSWindow *w = [theEvent window];
    TkWindow *winPtr = TkMacOSXGetTkWindow(w);
    Tk_Window tkwin = (Tk_Window) winPtr;
    TkWindow *grabWinPtr = winPtr->dispPtr->grabWinPtr;
    NSEventType type = [theEvent type];
    NSUInteger keyCode = [theEvent keyCode];
    NSUInteger modifiers = ([theEvent modifierFlags] &
			    NSDeviceIndependentModifierFlagsMask);

    XEvent xEvent;
    Bool has_modifiers = NO;
    Bool has_caret = NO;
    Bool use_text_input = NO;
    UniChar keychar = 0;
    static NSUInteger savedModifiers = 0;
    static NSMutableArray *nsEvArray = nil;

    if (nsEvArray == nil) {
        nsEvArray = [[NSMutableArray alloc] initWithCapacity: 1];
        processingCompose = NO;
    }
    if (!winPtr) {
	return theEvent;
    }

    /*
     * Control-Tab and Control-Shift-Tab are used to switch tabs in a tabbed
     * window.  We do not want to generate an Xevent for these since that might
     * cause the deselected tab to be reactivated.
     */

    if (keyCode == 48 && (modifiers & NSControlKeyMask) == NSControlKeyMask) {
	return theEvent;
    }





    /*
     * If a local grab is in effect, key events for windows in the
     * grabber's application are redirected to the grabber.  Key events
     * for <other applications are delivered normally.  If a global
     * grab is in effect all key events are redirected to the grabber.
     */



    if (grabWinPtr) {
	if (winPtr->dispPtr->grabFlags ||  /* global grab */
	    grabWinPtr->mainPtr == winPtr->mainPtr){ /* same application */
	    tkwin = (Tk_Window) winPtr->dispPtr->focusPtr;
	}
    }



    /*
     * Extract the unicode character from KeyUp and KeyDown events.
     */

    if (type == NSKeyUp || type == NSKeyDown) {
	if ([[theEvent characters] length] > 0) {


	    keychar = [[theEvent characters] characterAtIndex:0];







	} else {






	    /*

	     * This is a dead key, so it should go to the TextInputClient.
	     */








	    use_text_input = YES;






	}




#if defined(TK_MAC_DEBUG_EVENTS) || NS_KEYLOG == 1



	TKLog(@"-[%@(%p) %s] repeat=%d mods=%x char=%x code=%lu c=%d type=%d",
	      [self class], self, _cmd,
	      (type == NSKeyDown) && [theEvent isARepeat], modifiers, keychar,
	      keyCode, w, type);




#endif
    }


    /*
     * Build a skeleton XEvent.  We need to build it here, even if we will not
     * send it, so we can pass it to TkFocusKeyEvent to determine whether the
     * target windows has the caret.
     */












    setupXEvent(&xEvent, tkwin, modifiers);


    has_modifiers = xEvent.xkey.state & XEVENT_MOD_MASK;


    has_caret = (TkFocusKeyEvent(winPtr, &xEvent) == caret_win);

    /*
     * A KeyDown event targetting the caret window and having alphanumeric
     * keychar should be processed by our TextInputClient.  The XEvent will not
     * be sent in this case.
     */





    if (type == NSKeyDown && has_caret && !has_modifiers &&



	(keychar >= 0x0020) && (keychar <= 0x00FF)) {




	use_text_input = YES;





    }
    if (use_text_input) {

#if (NS_KEYLOG)
	TKLog(@"keyDown: %s compose sequence.\n",
	      processingCompose == YES ? "Continue" : "Begin");
#endif


	/*
	 * Call our interpretKeyEvents method to handle the event as a
	 * TextInputClient.  When the composition sequence is complete, our
	 * implementation of insertText: replacementRange will be called.  That
	 * method generates a keyPress XEvent with the selected character.  In
	 * IME when multiple characters have the same composition sequence and
	 * the selected character is not the default it may be necessary to hit
	 * the Enter key multiple times before the character is accepted and
	 * rendered. So we repeatedly send Enter key events until the inputText
	 * method has cleared the processingCompose flag.
	 */

	processingCompose = YES;
	while(processingCompose) {
	    [nsEvArray addObject: theEvent];
	    [[w contentView] interpretKeyEvents: nsEvArray];
	    [nsEvArray removeObject: theEvent];
	    if ([theEvent keyCode] != 36) {
		break;
	    }
	}
	return theEvent;
    }

    /*
     * We need to send an XEvent.  Finish constructing it.
     */

    xEvent.xkey.keycode = (keyCode << 16) | keychar;
    switch (type) {
    case NSFlagsChanged:

	/*
	 * We simulate KeyPress and KeyRelease events whenever a modifier flag
	 * change is reported.  To determine the type, note that the highest
	 * bit where the flags differ is 1 if and only if it is a KeyPress.
	 * Remember the modifiers for the next flag change.
	 */

	xEvent.xany.type = modifiers > savedModifiers ? KeyPress : KeyRelease;
	savedModifiers = modifiers;

	/*
	 * The value -1 signals a modifier keycode to the function TkpGetKeySym
	 * (see tkMacOSXKeyboard.c).
	 */

	xEvent.xany.send_event = -1;
	break;
    case NSKeyUp:
	xEvent.xany.type = KeyRelease;
	break;
    case NSKeyDown:
	xEvent.xany.type = KeyPress;
	break;
    default:
	return theEvent; /* Unrecognized key event. */
    }

    /*
     * Finally we can queue an XEvent, inserting a KeyRelease before a
     * repeated KeyPress.
     */

    if (type == NSKeyDown && [theEvent isARepeat]) {
	xEvent.xany.type = KeyRelease;
	Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
	xEvent.xany.type = KeyPress;
    }
    Tk_QueueWindowEvent(&xEvent, TCL_QUEUE_TAIL);
    return theEvent;
}
@end


@implementation TKContentView

Changes to macosx/tkMacOSXKeyboard.c.

71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88
    {97,	XK_F6,		NSF6FunctionKey},
    {98,	XK_F7,		NSF7FunctionKey},
    {99,	XK_F3,		NSF3FunctionKey},
    {100,	XK_F8,		NSF8FunctionKey},
    {101,	XK_F9,		NSF9FunctionKey},
    {103,	XK_F11,		NSF11FunctionKey},
    {105,	XK_F13,		NSF13FunctionKey},

    {107,	XK_F14,		NSF14FunctionKey},
    {109,	XK_F10,		NSF10FunctionKey},
    {105,	XK_F13,		NSF13FunctionKey},
    {106,	XK_F16,		NSF16FunctionKey},
    {111,	XK_F12,		NSF12FunctionKey},
    {113,	XK_F15,		NSF15FunctionKey},
    {114,	XK_Help,	NSHelpFunctionKey},
    {115,	XK_Home,	NSHomeFunctionKey},     /* Fn Left */
    {116,	XK_Page_Up,	NSPageUpFunctionKey},   /* Fn Up */
    {117,	XK_Delete,	NSDeleteFunctionKey},   /* Fn Deleete */
    {118,	XK_F4,		NSF4FunctionKey},







>


<
<







71
72
73
74
75
76
77
78
79
80


81
82
83
84
85
86
87
    {97,	XK_F6,		NSF6FunctionKey},
    {98,	XK_F7,		NSF7FunctionKey},
    {99,	XK_F3,		NSF3FunctionKey},
    {100,	XK_F8,		NSF8FunctionKey},
    {101,	XK_F9,		NSF9FunctionKey},
    {103,	XK_F11,		NSF11FunctionKey},
    {105,	XK_F13,		NSF13FunctionKey},
    {106,	XK_F16,		NSF16FunctionKey},
    {107,	XK_F14,		NSF14FunctionKey},
    {109,	XK_F10,		NSF10FunctionKey},


    {111,	XK_F12,		NSF12FunctionKey},
    {113,	XK_F15,		NSF15FunctionKey},
    {114,	XK_Help,	NSHelpFunctionKey},
    {115,	XK_Home,	NSHomeFunctionKey},     /* Fn Left */
    {116,	XK_Page_Up,	NSPageUpFunctionKey},   /* Fn Up */
    {117,	XK_Delete,	NSDeleteFunctionKey},   /* Fn Deleete */
    {118,	XK_F4,		NSF4FunctionKey},
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
};

/*
 * X11 keysyms for modifier keys, in order.
 */

#define NUM_MOD_KEYCODES 14
static KeyCode modKeyArray[NUM_MOD_KEYCODES] = {
    XK_Shift_L,
    XK_Shift_R,
    XK_Control_L,
    XK_Control_R,
    XK_Caps_Lock,
    XK_Shift_Lock,
    XK_Meta_L,
    XK_Meta_R,
    XK_Alt_L,
    XK_Alt_R,
    XK_Super_L,
    XK_Super_R,
    XK_Hyper_L,
    XK_Hyper_R,
};

static int initialized = 0;
static int keyboardChanged = 1;
static Tcl_HashTable virtual2keysym;	/* Maps Mac keyCode to X11 keysym. */
static Tcl_HashTable keysym2keycode;	/* Maps X11 keysym to Mac keycode. */
static int latin1Table[LATIN1_MAX+1];	/* Reverse mapping table for Latin-1. */

/*
 * Prototypes for static functions used in this file.
 */







|
















|
|







97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
};

/*
 * X11 keysyms for modifier keys, in order.
 */

#define NUM_MOD_KEYCODES 14
static const KeyCode modKeyArray[NUM_MOD_KEYCODES] = {
    XK_Shift_L,
    XK_Shift_R,
    XK_Control_L,
    XK_Control_R,
    XK_Caps_Lock,
    XK_Shift_Lock,
    XK_Meta_L,
    XK_Meta_R,
    XK_Alt_L,
    XK_Alt_R,
    XK_Super_L,
    XK_Super_R,
    XK_Hyper_L,
    XK_Hyper_R,
};

static BOOL initialized = NO;
static BOOL keyboardChanged = YES;
static Tcl_HashTable virtual2keysym;	/* Maps Mac keyCode to X11 keysym. */
static Tcl_HashTable keysym2keycode;	/* Maps X11 keysym to Mac keycode. */
static int latin1Table[LATIN1_MAX+1];	/* Reverse mapping table for Latin-1. */

/*
 * Prototypes for static functions used in this file.
 */
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

@implementation TKApplication(TKKeyboard)
- (void) keyboardChanged: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
    keyboardChanged = 1;
}
@end

#pragma mark -

/*
 *----------------------------------------------------------------------







|







138
139
140
141
142
143
144
145
146
147
148
149
150
151
152

@implementation TKApplication(TKKeyboard)
- (void) keyboardChanged: (NSNotification *) notification
{
#ifdef TK_MAC_DEBUG_NOTIFICATIONS
    TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification);
#endif
    keyboardChanged = YES;
}
@end

#pragma mark -

/*
 *----------------------------------------------------------------------
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
	hPtr = Tcl_CreateHashEntry(&virtual2keysym, INT2PTR(kPtr->virtual),
				   &dummy);
	Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym));
	hPtr = Tcl_CreateHashEntry(&keysym2keycode, INT2PTR(kPtr->keysym),
				   &dummy);
	Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keychar | (kPtr->virtual << 16)));
    }
    initialized = 1;
}

/*
 *----------------------------------------------------------------------
 *
 * InitLatin1Table --
 *







|







177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
	hPtr = Tcl_CreateHashEntry(&virtual2keysym, INT2PTR(kPtr->virtual),
				   &dummy);
	Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keysym));
	hPtr = Tcl_CreateHashEntry(&keysym2keycode, INT2PTR(kPtr->keysym),
				   &dummy);
	Tcl_SetHashValue(hPtr, INT2PTR(kPtr->keychar | (kPtr->virtual << 16)));
    }
    initialized = YES;
}

/*
 *----------------------------------------------------------------------
 *
 * InitLatin1Table --
 *