#define XK_MISCELLANY
#define XK_LATIN1
#define XK_LATIN2
#define XK_LATIN3
#define XK_LATIN4
#include "IntrinsicI.h"
#include <X11/keysymdef.h>
#ifdef XKB
#include <X11/XKBlib.h>
#endif
#define FLUSHKEYCACHE(ctx) \
bzero((char *)&ctx->keycache, sizeof(TMKeyCache))
#define FM(i) i >> (8 - TMKEYCACHELOG2)
static const unsigned char modmix[256] = {
FM(0x0f), FM(0x8f), FM(0x4f), FM(0xcf), FM(0x2f), FM(0xaf), FM(0x6f), FM(0xef),
FM(0x1f), FM(0x9f), FM(0x5f), FM(0xdf), FM(0x3f), FM(0xbf), FM(0x7f), FM(0xff),
FM(0x07), FM(0x87), FM(0x47), FM(0xc7), FM(0x27), FM(0xa7), FM(0x67), FM(0xe7),
FM(0x17), FM(0x97), FM(0x57), FM(0xd7), FM(0x37), FM(0xb7), FM(0x77), FM(0xf7),
FM(0x0b), FM(0x8b), FM(0x4b), FM(0xcb), FM(0x2b), FM(0xab), FM(0x6b), FM(0xeb),
FM(0x1b), FM(0x9b), FM(0x5b), FM(0xdb), FM(0x3b), FM(0xbb), FM(0x7b), FM(0xfb),
FM(0x03), FM(0x83), FM(0x43), FM(0xc3), FM(0x23), FM(0xa3), FM(0x63), FM(0xe3),
FM(0x13), FM(0x93), FM(0x53), FM(0xd3), FM(0x33), FM(0xb3), FM(0x73), FM(0xf3),
FM(0x0d), FM(0x8d), FM(0x4d), FM(0xcd), FM(0x2d), FM(0xad), FM(0x6d), FM(0xed),
FM(0x1d), FM(0x9d), FM(0x5d), FM(0xdd), FM(0x3d), FM(0xbd), FM(0x7d), FM(0xfd),
FM(0x05), FM(0x85), FM(0x45), FM(0xc5), FM(0x25), FM(0xa5), FM(0x65), FM(0xe5),
FM(0x15), FM(0x95), FM(0x55), FM(0xd5), FM(0x35), FM(0xb5), FM(0x75), FM(0xf5),
FM(0x09), FM(0x89), FM(0x49), FM(0xc9), FM(0x29), FM(0xa9), FM(0x69), FM(0xe9),
FM(0x19), FM(0x99), FM(0x59), FM(0xd9), FM(0x39), FM(0xb9), FM(0x79), FM(0xf9),
FM(0x01), FM(0x81), FM(0x41), FM(0xc1), FM(0x21), FM(0xa1), FM(0x61), FM(0xe1),
FM(0x11), FM(0x91), FM(0x51), FM(0xd1), FM(0x31), FM(0xb1), FM(0x71), FM(0xf1),
FM(0x00), FM(0x8e), FM(0x4e), FM(0xce), FM(0x2e), FM(0xae), FM(0x6e), FM(0xee),
FM(0x1e), FM(0x9e), FM(0x5e), FM(0xde), FM(0x3e), FM(0xbe), FM(0x7e), FM(0xfe),
FM(0x08), FM(0x88), FM(0x48), FM(0xc8), FM(0x28), FM(0xa8), FM(0x68), FM(0xe8),
FM(0x18), FM(0x98), FM(0x58), FM(0xd8), FM(0x38), FM(0xb8), FM(0x78), FM(0xf8),
FM(0x04), FM(0x84), FM(0x44), FM(0xc4), FM(0x24), FM(0xa4), FM(0x64), FM(0xe4),
FM(0x14), FM(0x94), FM(0x54), FM(0xd4), FM(0x34), FM(0xb4), FM(0x74), FM(0xf4),
FM(0x0c), FM(0x8c), FM(0x4c), FM(0xcc), FM(0x2c), FM(0xac), FM(0x6c), FM(0xec),
FM(0x1c), FM(0x9c), FM(0x5c), FM(0xdc), FM(0x3c), FM(0xbc), FM(0x7c), FM(0xfc),
FM(0x02), FM(0x82), FM(0x42), FM(0xc2), FM(0x22), FM(0xa2), FM(0x62), FM(0xe2),
FM(0x12), FM(0x92), FM(0x52), FM(0xd2), FM(0x32), FM(0xb2), FM(0x72), FM(0xf2),
FM(0x0a), FM(0x8a), FM(0x4a), FM(0xca), FM(0x2a), FM(0xaa), FM(0x6a), FM(0xea),
FM(0x1a), FM(0x9a), FM(0x5a), FM(0xda), FM(0x3a), FM(0xba), FM(0x7a), FM(0xfa),
FM(0x06), FM(0x86), FM(0x46), FM(0xc6), FM(0x26), FM(0xa6), FM(0x66), FM(0xe6),
FM(0x16), FM(0x96), FM(0x56), FM(0xd6), FM(0x36), FM(0xb6), FM(0x76), FM(0xf6),
FM(0x0e), FM(0x8e), FM(0x4e), FM(0xce), FM(0x2e), FM(0xae), FM(0x6e), FM(0xee),
FM(0x1e), FM(0x9e), FM(0x5e), FM(0xde), FM(0x3e), FM(0xbe), FM(0x7e), FM(0xfe)
};
#undef FM
#define MOD_RETURN(ctx, key) (ctx)->keycache.modifiers_return[key]
#define TRANSLATE(ctx,pd,dpy,key,mod,mod_ret,sym_ret) \
{ \
int _i_ = (((key) - (pd)->min_keycode + modmix[(mod) & 0xff]) & \
(TMKEYCACHESIZE-1)); \
if ((key) != 0 && \
(ctx)->keycache.keycode[_i_] == (key) && \
(ctx)->keycache.modifiers[_i_] == (mod)) { \
mod_ret = MOD_RETURN(ctx, key); \
sym_ret = (ctx)->keycache.keysym[_i_]; \
} else { \
XtTranslateKeycode(dpy, key, mod, &mod_ret, &sym_ret); \
(ctx)->keycache.keycode[_i_] = key; \
(ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \
(ctx)->keycache.keysym[_i_] = sym_ret; \
MOD_RETURN(ctx, key) = (unsigned char)mod_ret; \
} \
}
#define UPDATE_CACHE(ctx, pd, key, mod, mod_ret, sym_ret) \
{ \
int _i_ = (((key) - (pd)->min_keycode + modmix[(mod) & 0xff]) & \
(TMKEYCACHESIZE-1)); \
(ctx)->keycache.keycode[_i_] = key; \
(ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \
(ctx)->keycache.keysym[_i_] = sym_ret; \
MOD_RETURN(ctx, key) = (unsigned char)mod_ret; \
}
#define KEYCODE_ARRAY_SIZE 10
Boolean _XtComputeLateBindings(dpy, lateModifiers, computed, computedMask)
Display *dpy;
LateBindingsPtr lateModifiers;
Modifiers *computed,*computedMask;
{
int i,j,ref;
ModToKeysymTable* temp;
XtPerDisplay perDisplay;
Boolean found;
KeySym tempKeysym = NoSymbol;
perDisplay = _XtGetPerDisplay(dpy);
if (perDisplay == NULL) {
XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
"displayError","invalidDisplay",XtCXtToolkitError,
"Can't find display structure",
(String *)NULL, (Cardinal *)NULL);
return FALSE;
}
_InitializeKeysymTables(dpy, perDisplay);
for (ref=0; lateModifiers[ref].keysym; ref++) {
found = FALSE;
for (i=0;i<8;i++) {
temp = &(perDisplay->modsToKeysyms[i]);
for (j=0;j<temp->count;j++){
if (perDisplay->modKeysyms[temp->idx+j] ==
lateModifiers[ref].keysym) {
*computedMask = *computedMask | temp->mask;
if (!lateModifiers[ref].knot)
*computed |= temp->mask;
tempKeysym = lateModifiers[ref].keysym;
found = TRUE; break;
}
}
if (found) break;
}
if (!found && !lateModifiers[ref].knot)
if (!lateModifiers[ref].pair && (tempKeysym == NoSymbol))
return FALSE;
if (!lateModifiers[ref].pair) tempKeysym = NoSymbol;
}
return TRUE;
}
void _XtAllocTMContext(pd)
XtPerDisplay pd;
{
TMKeyContext ctx;
ctx = (TMKeyContext)_XtHeapAlloc(&pd->heap,
sizeof(TMKeyContextRec));
ctx->event = NULL;
ctx->serial = 0;
ctx->keysym = NoSymbol;
ctx->modifiers = 0;
FLUSHKEYCACHE(ctx);
pd->tm_context = ctx;
}
static unsigned int num_bits(unsigned long mask)
{
register unsigned long y;
y = (mask >> 1) &033333333333;
y = mask - y - ((y >>1) & 033333333333);
return ((unsigned int) (((y + (y >> 3)) & 030707070707) % 077));
}
Boolean _XtMatchUsingDontCareMods(typeMatch, modMatch, eventSeq)
TMTypeMatch typeMatch;
TMModifierMatch modMatch;
TMEventPtr eventSeq;
{
Modifiers modifiers_return;
KeySym keysym_return;
Modifiers useful_mods;
int i, num_modbits;
Modifiers computed = 0;
Modifiers computedMask = 0;
Boolean resolved = TRUE;
Display *dpy = eventSeq->xev->xany.display;
XtPerDisplay pd;
TMKeyContext tm_context;
if (modMatch->lateModifiers != NULL)
resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
&computed, &computedMask);
if (!resolved) return FALSE;
computed |= modMatch->modifiers;
computedMask |= modMatch->modifierMask;
if ( (computed & computedMask) ==
(eventSeq->event.modifiers & computedMask) ) {
pd = _XtGetPerDisplay(dpy);
tm_context = pd->tm_context;
TRANSLATE(tm_context, pd, dpy, (KeyCode)eventSeq->event.eventCode,
(unsigned)0, modifiers_return, keysym_return);
if ((keysym_return & typeMatch->eventCodeMask) == typeMatch->eventCode ) {
tm_context->event = eventSeq->xev;
tm_context->serial = eventSeq->xev->xany.serial;
tm_context->keysym = keysym_return;
tm_context->modifiers = (Modifiers)0;
return TRUE;
}
useful_mods = ~computedMask & modifiers_return;
if (useful_mods == 0) return FALSE;
switch (num_modbits = num_bits(useful_mods)) {
case 1:
case 8:
for (i = useful_mods; i > 0; i--) {
TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode,
(Modifiers)i, modifiers_return, keysym_return);
if (keysym_return ==
(typeMatch->eventCode & typeMatch->eventCodeMask)) {
tm_context->event = eventSeq->xev;
tm_context->serial = eventSeq->xev->xany.serial;
tm_context->keysym = keysym_return;
tm_context->modifiers = (Modifiers)i;
return TRUE;
}
}
break;
default:
{
static char pows[] = { 0, 1, 3, 7, 15, 31, 63, 127 };
Modifiers tmod, mod_masks[8];
int j;
for (tmod = 1, i = 0; tmod <= (Mod5Mask<<1); tmod <<= 1)
if (tmod & useful_mods) mod_masks[i++] = tmod;
for (j = (int) pows[num_modbits]; j > 0; j--) {
tmod = 0;
for (i = 0; i < num_modbits; i++)
if (j & (1<<i)) tmod |= mod_masks[i];
TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode,
tmod, modifiers_return, keysym_return);
if (keysym_return ==
(typeMatch->eventCode & typeMatch->eventCodeMask)) {
tm_context->event = eventSeq->xev;
tm_context->serial = eventSeq->xev->xany.serial;
tm_context->keysym = keysym_return;
tm_context->modifiers = (Modifiers)i;
return TRUE;
}
}
}
break;
}
}
return FALSE;
}
void XtConvertCase(dpy,keysym,lower_return,upper_return)
Display *dpy;
KeySym keysym;
KeySym *lower_return, *upper_return;
{
XtPerDisplay pd;
CaseConverterPtr ptr;
DPY_TO_APPCON(dpy);
LOCK_APP(app);
pd = _XtGetPerDisplay(dpy);
*lower_return = *upper_return = keysym;
for (ptr=pd->case_cvt; ptr; ptr = ptr->next)
if (ptr->start <= keysym && keysym <= ptr->stop) {
(*ptr->proc)(dpy, keysym, lower_return, upper_return);
return;
}
XConvertCase(keysym, lower_return, upper_return);
UNLOCK_APP(app);
}
Boolean _XtMatchUsingStandardMods (typeMatch, modMatch, eventSeq)
TMTypeMatch typeMatch;
TMModifierMatch modMatch;
TMEventPtr eventSeq;
{
Modifiers modifiers_return;
KeySym keysym_return;
Modifiers computed= 0;
Modifiers computedMask = 0;
Boolean resolved = TRUE;
Display *dpy = eventSeq->xev->xany.display;
XtPerDisplay pd = _XtGetPerDisplay(dpy);
TMKeyContext tm_context = pd->tm_context;
Modifiers translateModifiers;
modifiers_return = MOD_RETURN(tm_context, eventSeq->event.eventCode);
if (!modifiers_return) {
XtTranslateKeycode(dpy, (KeyCode)eventSeq->event.eventCode,
eventSeq->event.modifiers, &modifiers_return,
&keysym_return);
translateModifiers = eventSeq->event.modifiers & modifiers_return;
UPDATE_CACHE(tm_context, pd, eventSeq->event.eventCode,
translateModifiers, modifiers_return, keysym_return);
} else {
translateModifiers = eventSeq->event.modifiers & modifiers_return;
TRANSLATE(tm_context, pd, dpy, (KeyCode)eventSeq->event.eventCode,
translateModifiers, modifiers_return, keysym_return);
}
if ((typeMatch->eventCode & typeMatch->eventCodeMask) ==
(keysym_return & typeMatch->eventCodeMask)) {
if (modMatch->lateModifiers != NULL)
resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
&computed, &computedMask);
if (!resolved) return FALSE;
computed |= modMatch->modifiers;
computedMask |= modMatch->modifierMask;
if ((computed & computedMask) ==
(eventSeq->event.modifiers & ~modifiers_return & computedMask)) {
tm_context->event = eventSeq->xev;
tm_context->serial = eventSeq->xev->xany.serial;
tm_context->keysym = keysym_return;
tm_context->modifiers = translateModifiers;
return TRUE;
}
}
return FALSE;
}
void _XtBuildKeysymTables(dpy,pd)
Display *dpy;
register XtPerDisplay pd;
{
ModToKeysymTable *table;
int maxCount,i,j,k,tempCount,idx;
KeySym keysym,tempKeysym;
XModifierKeymap* modKeymap;
KeyCode keycode;
#define KeysymTableSize 16
FLUSHKEYCACHE(pd->tm_context);
if (pd->keysyms)
XFree( (char *)pd->keysyms );
pd->keysyms_serial = NextRequest(dpy);
pd->keysyms = XGetKeyboardMapping(dpy, pd->min_keycode,
pd->max_keycode-pd->min_keycode+1,
&pd->keysyms_per_keycode);
if (pd->modKeysyms)
XtFree((char *)pd->modKeysyms);
if (pd->modsToKeysyms)
XtFree((char *)pd->modsToKeysyms);
pd->modKeysyms = (KeySym*)__XtMalloc((Cardinal)KeysymTableSize*sizeof(KeySym));
maxCount = KeysymTableSize;
tempCount = 0;
table = (ModToKeysymTable*)__XtMalloc((Cardinal)8*sizeof(ModToKeysymTable));
pd->modsToKeysyms = table;
table[0].mask = ShiftMask;
table[1].mask = LockMask;
table[2].mask = ControlMask;
table[3].mask = Mod1Mask;
table[4].mask = Mod2Mask;
table[5].mask = Mod3Mask;
table[6].mask = Mod4Mask;
table[7].mask = Mod5Mask;
tempKeysym = 0;
modKeymap = XGetModifierMapping(dpy);
for (i=0;i<32;i++)
pd->isModifier[i] = 0;
pd->mode_switch = 0;
pd->num_lock = 0;
for (i=0;i<8;i++) {
table[i].idx = tempCount;
table[i].count = 0;
for (j=0;j<modKeymap->max_keypermod;j++) {
keycode = modKeymap->modifiermap[i*modKeymap->max_keypermod+j];
if (keycode != 0) {
pd->isModifier[keycode>>3] |= 1 << (keycode & 7);
for (k=0; k<pd->keysyms_per_keycode;k++) {
idx = ((keycode-pd->min_keycode)*
pd->keysyms_per_keycode)+k;
keysym = pd->keysyms[idx];
if ((keysym == XK_Mode_switch) && (i > 2))
pd->mode_switch |= 1 << i;
if ((keysym == XK_Num_Lock) && (i > 2))
pd->num_lock |= 1 << i;
if (keysym != 0 && keysym != tempKeysym ){
if (tempCount==maxCount) {
maxCount += KeysymTableSize;
pd->modKeysyms = (KeySym*)XtRealloc(
(char*)pd->modKeysyms,
(unsigned) (maxCount*sizeof(KeySym)) );
}
pd->modKeysyms[tempCount++] = keysym;
table[i].count++;
tempKeysym = keysym;
}
}
}
}
}
pd->lock_meaning = NoSymbol;
for (i = 0; i < table[1].count; i++) {
keysym = pd->modKeysyms[table[1].idx + i];
if (keysym == XK_Caps_Lock) {
pd->lock_meaning = XK_Caps_Lock;
break;
} else if (keysym == XK_Shift_Lock) {
pd->lock_meaning = XK_Shift_Lock;
}
}
XFreeModifiermap(modKeymap);
}
void XtTranslateKeycode (
Display *dpy,
_XtKeyCode keycode,
Modifiers modifiers,
Modifiers *modifiers_return,
KeySym *keysym_return)
{
XtPerDisplay pd;
DPY_TO_APPCON(dpy);
LOCK_APP(app);
pd = _XtGetPerDisplay(dpy);
_InitializeKeysymTables(dpy, pd);
(*pd->defaultKeycodeTranslator)(
dpy,keycode,modifiers,modifiers_return,keysym_return);
UNLOCK_APP(app);
}
void XtTranslateKey(
register Display *dpy,
_XtKeyCode keycode,
Modifiers modifiers,
Modifiers *modifiers_return,
KeySym *keysym_return)
#ifndef XKB
{
XtPerDisplay pd;
int per;
register KeySym *syms;
KeySym sym, lsym, usym;
DPY_TO_APPCON(dpy);
LOCK_APP(app);
pd = _XtGetPerDisplay(dpy);
*modifiers_return = (ShiftMask|LockMask) | pd->mode_switch | pd->num_lock;
if (((int)keycode < pd->min_keycode) || ((int)keycode > pd->max_keycode)) {
*keysym_return = NoSymbol;
UNLOCK_APP(app);
return;
}
per = pd->keysyms_per_keycode;
syms = &pd->keysyms[(keycode - pd->min_keycode) * per];
while ((per > 2) && (syms[per - 1] == NoSymbol))
per--;
if ((per > 2) && (modifiers & pd->mode_switch)) {
syms += 2;
per -= 2;
}
if ((modifiers & pd->num_lock) &&
(per > 1 && (IsKeypadKey(syms[1]) || IsPrivateKeypadKey(syms[1])))) {
if ((modifiers & ShiftMask) ||
((modifiers & LockMask) && (pd->lock_meaning == XK_Shift_Lock)))
*keysym_return = syms[0];
else
*keysym_return = syms[1];
} else if (!(modifiers & ShiftMask) &&
(!(modifiers & LockMask) || (pd->lock_meaning == NoSymbol))) {
if ((per == 1) || (syms[1] == NoSymbol))
XtConvertCase(dpy, syms[0], keysym_return, &usym);
else
*keysym_return = syms[0];
} else if (!(modifiers & LockMask) ||
(pd->lock_meaning != XK_Caps_Lock)) {
if ((per == 1) || ((usym = syms[1]) == NoSymbol))
XtConvertCase(dpy, syms[0], &lsym, &usym);
*keysym_return = usym;
} else {
if ((per == 1) || ((sym = syms[1]) == NoSymbol))
sym = syms[0];
XtConvertCase(dpy, sym, &lsym, &usym);
if (!(modifiers & ShiftMask) && (sym != syms[0]) &&
((sym != usym) || (lsym == usym)))
XtConvertCase(dpy, syms[0], &lsym, &usym);
*keysym_return = usym;
}
if (*keysym_return == XK_VoidSymbol)
*keysym_return = NoSymbol;
UNLOCK_APP(app);
}
#else
{
XkbLookupKeySym(dpy, keycode, modifiers, modifiers_return, keysym_return);
}
#endif
void XtSetKeyTranslator(dpy, translator)
Display *dpy;
XtKeyProc translator;
{
XtPerDisplay pd;
DPY_TO_APPCON(dpy);
LOCK_APP(app);
pd = _XtGetPerDisplay(dpy);
pd->defaultKeycodeTranslator = translator;
FLUSHKEYCACHE(pd->tm_context);
UNLOCK_APP(app);
}
void XtRegisterCaseConverter(dpy, proc, start, stop)
Display *dpy;
XtCaseProc proc;
KeySym start;
KeySym stop;
{
XtPerDisplay pd;
CaseConverterPtr ptr, prev;
DPY_TO_APPCON(dpy);
LOCK_APP(app);
pd = _XtGetPerDisplay(dpy);
ptr = (CaseConverterPtr) __XtMalloc(sizeof(CaseConverterRec));
ptr->start = start;
ptr->stop = stop;
ptr->proc = proc;
ptr->next = pd->case_cvt;
pd->case_cvt = ptr;
prev = ptr;
for (ptr=ptr->next; ptr; ptr=prev->next) {
if (start <= ptr->start && stop >= ptr->stop) {
prev->next = ptr->next;
XtFree((char *)ptr);
}
else prev = ptr;
}
FLUSHKEYCACHE(pd->tm_context);
UNLOCK_APP(app);
}
KeySym *XtGetKeysymTable(dpy, min_keycode_return, keysyms_per_keycode_return)
Display *dpy;
KeyCode *min_keycode_return;
int *keysyms_per_keycode_return;
{
XtPerDisplay pd;
KeySym* retval;
DPY_TO_APPCON(dpy);
LOCK_APP(app);
pd = _XtGetPerDisplay(dpy);
_InitializeKeysymTables(dpy, pd);
*min_keycode_return = pd->min_keycode;
*keysyms_per_keycode_return = pd->keysyms_per_keycode;
retval = pd->keysyms;
UNLOCK_APP(app);
return retval;
}
void XtKeysymToKeycodeList(dpy, keysym, keycodes_return, keycount_return)
Display *dpy;
KeySym keysym;
KeyCode **keycodes_return;
Cardinal *keycount_return;
{
XtPerDisplay pd;
unsigned keycode;
int per, match;
register KeySym *syms;
register int i, j;
KeySym lsym, usym;
unsigned maxcodes = 0;
unsigned ncodes = 0;
KeyCode *keycodes, *codeP = NULL;
DPY_TO_APPCON(dpy);
LOCK_APP(app);
pd = _XtGetPerDisplay(dpy);
_InitializeKeysymTables(dpy, pd);
keycodes = NULL;
per = pd->keysyms_per_keycode;
for (syms = pd->keysyms, keycode = (unsigned) pd->min_keycode;
(int)keycode <= pd->max_keycode;
syms += per, keycode++) {
match = 0;
for (j = 0; j < per; j++) {
if (syms[j] == keysym) {
match = 1;
break;
}
}
if (!match)
for (i = 1; i < 5; i += 2) {
if ((per == i) || ((per > i) && (syms[i] == NoSymbol))) {
XtConvertCase(dpy, syms[i-1], &lsym, &usym);
if ((lsym == keysym) || (usym == keysym)) {
match = 1;
break;
}
}
}
if (match) {
if (ncodes == maxcodes) {
KeyCode *old = keycodes;
maxcodes += KEYCODE_ARRAY_SIZE;
keycodes = (KeyCode*)__XtMalloc(maxcodes*sizeof(KeyCode));
if (ncodes) {
(void) memmove((char *)keycodes, (char *)old,
ncodes*sizeof(KeyCode) );
XtFree((char *)old);
}
codeP = &keycodes[ncodes];
}
*codeP++ = (KeyCode) keycode;
ncodes++;
}
}
*keycodes_return = keycodes;
*keycount_return = ncodes;
UNLOCK_APP(app);
}