|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: /* Copyright (c) 1992 NeXT Computer, Inc. All rights reserved. ! 25: * ! 26: * KeyMap.m - Generic keymap string parser and keycode translator. ! 27: * ! 28: * HISTORY ! 29: * 19 June 1992 Mike Paquette at NeXT ! 30: * Created. ! 31: * 5 Aug 1993 Erik Kay at NeXT ! 32: * minor API cleanup ! 33: * 11 Nov 1993 Erik Kay at NeXT ! 34: * fix to allow prevent long sequences from overflowing the event queue ! 35: */ ! 36: ! 37: #import <machkit/NXLock.h> ! 38: #import <bsd/dev/event.h> ! 39: #import <driverkit/KeyMap.h> ! 40: ! 41: @implementation KeyMap: Object ! 42: ! 43: ! 44: /* ! 45: * Common KeyMap initialization ! 46: */ ! 47: - initFromKeyMapping :(const unsigned char *)mapping ! 48: length :(int)len ! 49: canFree :(BOOL)canFree ! 50: { ! 51: [super init]; ! 52: ! 53: if ( keyMappingLock == nil ) ! 54: keyMappingLock = [NXLock new]; ! 55: ! 56: if ( [self setKeyMapping:mapping length:len canFree:canFree] == nil ) ! 57: return [self free]; ! 58: return self; ! 59: } ! 60: ! 61: /* ! 62: * Load a new keymapping. Returns nil if the map is invalid. ! 63: */ ! 64: - setKeyMapping :(const unsigned char *)mapping ! 65: length :(int)len ! 66: canFree :(BOOL)canFree ! 67: { ! 68: NXParsedKeyMapping newMapping; ! 69: ! 70: if ([self _parseKeyMapping:mapping length:len into:&newMapping] == nil) ! 71: return nil; ! 72: ! 73: [keyMappingLock lock]; ! 74: if ( curMapping.mapping != (unsigned char *)NULL ! 75: && canFreeMapping == YES ) ! 76: { ! 77: IOFree( curMapping.mapping, curMapping.mappingLen ); ! 78: } ! 79: bcopy( &newMapping, &curMapping, sizeof curMapping ); ! 80: canFreeMapping = canFree; ! 81: [keyMappingLock unlock]; ! 82: return self; ! 83: } ! 84: ! 85: - (const unsigned char *)keyMapping:(int *)len ! 86: { ! 87: if ( len != (int *)0 ) ! 88: *len = curMapping.mappingLen; ! 89: return (const unsigned char *)curMapping.mapping; ! 90: } ! 91: ! 92: - (int)keyMappingLength ! 93: { ! 94: return curMapping.mappingLen; ! 95: } ! 96: ! 97: - free ! 98: { ! 99: id lock; ! 100: [keyMappingLock lock]; ! 101: lock = keyMappingLock; ! 102: keyMappingLock = nil; ! 103: if ( curMapping.mapping != (unsigned char *)NULL ! 104: && canFreeMapping == YES ) ! 105: { ! 106: IOFree( curMapping.mapping, curMapping.mappingLen ); ! 107: curMapping.mapping = (unsigned char *)NULL; ! 108: } ! 109: [lock unlock]; ! 110: [lock free]; ! 111: return [super free]; ! 112: } ! 113: ! 114: - setDelegate:(id)newDelegate ! 115: { ! 116: if ( [newDelegate conformsTo:@protocol(KeyMapDelegate)] ) ! 117: delegate = newDelegate; ! 118: else ! 119: IOLog( "KeyMap setDelegate: new delegate [%s] does not " ! 120: "implement KeyMapDelegate protocol.\n", ! 121: object_getClassName(newDelegate) ); ! 122: return self; ! 123: } ! 124: ! 125: - delegate ! 126: { ! 127: return delegate; ! 128: } ! 129: ! 130: // ! 131: // Perform the mapping of 'key' moving in the specified direction ! 132: // into events. ! 133: // ! 134: // On entry, the _kbdListLock should be held. ! 135: // ! 136: - doKeyboardEvent:(unsigned)key ! 137: direction:(BOOL)down ! 138: keyBits :(kbdBitVector)keyBits ! 139: { ! 140: unsigned char thisBits; ! 141: ! 142: [keyMappingLock lock]; ! 143: if ( curMapping.mapping == (unsigned char *)NULL ) ! 144: { ! 145: [keyMappingLock unlock]; ! 146: return self; // No map set up yet ! 147: } ! 148: /* Do mod bit update and char generation in useful order */ ! 149: thisBits = curMapping.keyBits[key]; ! 150: if ( down == YES ) ! 151: { ! 152: EVK_KEYDOWN( key, keyBits ); ! 153: if (thisBits & NX_MODMASK) ! 154: [self _doModCalc:key keyBits:keyBits]; ! 155: if (thisBits & NX_CHARGENMASK) ! 156: [self _doCharGen:key direction:down]; ! 157: } ! 158: else ! 159: { ! 160: EVK_KEYUP( key, keyBits ); ! 161: if (thisBits & NX_CHARGENMASK) ! 162: [self _doCharGen:key direction:down]; ! 163: if (thisBits & NX_MODMASK) ! 164: [self _doModCalc:key keyBits:keyBits]; ! 165: } ! 166: [keyMappingLock unlock]; ! 167: ! 168: return self; ! 169: } ! 170: ! 171: ! 172: // ! 173: // Support goop for parseKeyMapping. These routines are ! 174: // used to walk through the keymapping string. The string ! 175: // may be composed of bytes or shorts. If using shorts, it ! 176: // MUST always be aligned to use short boundries. ! 177: // ! 178: typedef struct _NewMappingData { ! 179: unsigned const char *bp; ! 180: unsigned const char *endPtr; ! 181: int shorts; ! 182: } NewMappingData; ! 183: ! 184: static unsigned int NextNum(NewMappingData *nmd) ! 185: { ! 186: if (nmd->bp >= nmd->endPtr) ! 187: return(0); ! 188: if (nmd->shorts) ! 189: return(*((unsigned short *)nmd->bp)++); ! 190: else ! 191: return(*((unsigned char *)nmd->bp)++); ! 192: } ! 193: ! 194: // ! 195: // perform the actual parsing operation on a keymap. ! 196: // Returns self, or nil on failure. ! 197: // ! 198: - _parseKeyMapping:(const unsigned char *)mapping ! 199: length:(int)mappingLen ! 200: into:(NXParsedKeyMapping *)newMapping ! 201: { ! 202: NewMappingData nmd; ! 203: int i, j, k, l, n; ! 204: unsigned int m; ! 205: int keyMask, numMods; ! 206: int maxSeqNum = -1; ! 207: ! 208: /* Initialize the new map. */ ! 209: bzero( newMapping, sizeof (NXParsedKeyMapping) ); ! 210: newMapping->maxMod = -1; ! 211: newMapping->numDefs = -1; ! 212: newMapping->numSeqs = -1; ! 213: ! 214: nmd.endPtr = mapping + mappingLen; ! 215: nmd.bp = mapping; ! 216: nmd.shorts = 1; // First value, the size, is always a short ! 217: ! 218: /* Start filling it in with the new data */ ! 219: newMapping->mapping = (unsigned char *)mapping; ! 220: newMapping->mappingLen = mappingLen; ! 221: newMapping->shorts = nmd.shorts = NextNum(&nmd); ! 222: ! 223: /* Walk through the modifier definitions */ ! 224: numMods = NextNum(&nmd); ! 225: for(i=0; i<numMods; i++) ! 226: { ! 227: /* Get bit number */ ! 228: if ((j = NextNum(&nmd)) >= NX_NUMMODIFIERS) ! 229: return nil; ! 230: ! 231: /* Check maxMod */ ! 232: if (j > newMapping->maxMod) ! 233: newMapping->maxMod = j; ! 234: ! 235: /* record position of this def */ ! 236: newMapping->modDefs[j] = (unsigned char *)nmd.bp; ! 237: ! 238: /* Loop through each key assigned to this bit */ ! 239: for(k=0,n = NextNum(&nmd);k<n;k++) ! 240: { ! 241: /* Check that key code is valid */ ! 242: if ((l = NextNum(&nmd)) >= NX_NUMKEYCODES) ! 243: return nil; ! 244: /* Make sure the key's not already assigned */ ! 245: if (newMapping->keyBits[l] & NX_MODMASK) ! 246: return nil; ! 247: /* Set bit for modifier and which one */ ! 248: newMapping->keyBits[l] |= NX_MODMASK | (j & NX_WHICHMODMASK); ! 249: } ! 250: } ! 251: ! 252: /* Walk through each key definition */ ! 253: newMapping->numDefs = NextNum(&nmd); ! 254: n = newMapping->numDefs; ! 255: for( i=0; i < NX_NUMKEYCODES; i++) ! 256: { ! 257: if (i < n) ! 258: { ! 259: newMapping->keyDefs[i] = (unsigned char *)nmd.bp; ! 260: if ((keyMask = NextNum(&nmd)) != (nmd.shorts ? 0xFFFF: 0x00FF)) ! 261: { ! 262: /* Set char gen bit for this guy: not a no-op */ ! 263: newMapping->keyBits[i] |= NX_CHARGENMASK; ! 264: /* Check key defs to find max sequence number */ ! 265: for(j=0, k=1; j<=newMapping->maxMod; j++, keyMask>>=1) ! 266: { ! 267: if (keyMask & 0x01) ! 268: k*= 2; ! 269: } ! 270: for(j=0; j<k; j++) ! 271: { ! 272: m = NextNum(&nmd); ! 273: l = NextNum(&nmd); ! 274: if (m == (nmd.shorts ? 0xFFFF: 0x00FF)) ! 275: if (((int)l) > maxSeqNum) ! 276: maxSeqNum = l; /* Update expected # of seqs */ ! 277: } ! 278: } ! 279: else /* unused code within active range */ ! 280: newMapping->keyDefs[i] = NULL; ! 281: } ! 282: else /* Unused code past active range */ ! 283: { ! 284: newMapping->keyDefs[i] = NULL; ! 285: } ! 286: } ! 287: /* Walk through sequence defs */ ! 288: newMapping->numSeqs = NextNum(&nmd); ! 289: /* If the map calls more sequences than are declared, bail out */ ! 290: if (newMapping->numSeqs <= maxSeqNum) ! 291: return nil; ! 292: ! 293: /* Walk past all sequences */ ! 294: for(i = 0; i < newMapping->numSeqs; i++) ! 295: { ! 296: newMapping->seqDefs[i] = (unsigned char *)nmd.bp; ! 297: /* Walk thru entries in a seq. */ ! 298: for(j=0, l=NextNum(&nmd); j<l; j++) ! 299: { ! 300: NextNum(&nmd); ! 301: NextNum(&nmd); ! 302: } ! 303: } ! 304: /* Install Special device keys. These override default values. */ ! 305: numMods = NextNum(&nmd); /* Zero on old style keymaps */ ! 306: if ( numMods > NX_NUMSPECIALKEYS ) ! 307: return nil; ! 308: if ( numMods ) ! 309: { ! 310: for ( i = 0; i < NX_NUMSPECIALKEYS; ++i ) ! 311: newMapping->specialKeys[i] = NX_NOSPECIALKEY; ! 312: for ( i = 0; i < numMods; ++i ) ! 313: { ! 314: j = NextNum(&nmd); /* Which modifier key? */ ! 315: l = NextNum(&nmd); /* Scancode for modifier key */ ! 316: if ( j >= NX_NUMSPECIALKEYS ) ! 317: return nil; ! 318: newMapping->specialKeys[j] = l; ! 319: } ! 320: } ! 321: else /* No special keys defs implies an old style keymap */ ! 322: { ! 323: return nil; /* Old style keymaps are guaranteed to do */ ! 324: /* the wrong thing on ADB keyboards */ ! 325: } ! 326: /* Install bits for Special device keys */ ! 327: for(i=0; i<NX_NUM_SCANNED_SPECIALKEYS; i++) ! 328: { ! 329: if ( newMapping->specialKeys[i] != NX_NOSPECIALKEY ) ! 330: { ! 331: newMapping->keyBits[newMapping->specialKeys[i]] |= ! 332: (NX_CHARGENMASK | NX_SPECIALKEYMASK); ! 333: } ! 334: } ! 335: ! 336: return self; ! 337: } ! 338: ! 339: ! 340: #undef NEXTNUM ! 341: #define NEXTNUM() (shorts ? *((short *)mapping)++ : \ ! 342: *((unsigned char *)mapping)++ ) ! 343: // ! 344: // Look up in the keymapping each key associated with the modifier bit. ! 345: // Look in the device state to see if that key is down. ! 346: // Return 1 if a key for modifier 'bit' is down. Return 0 if none is down ! 347: // ! 348: static inline int IsModifierDown(NXParsedKeyMapping *curMapping, ! 349: kbdBitVector keyBits, ! 350: int bit ) ! 351: { ! 352: int i, n; ! 353: char *mapping; ! 354: unsigned key; ! 355: short shorts = curMapping->shorts; ! 356: ! 357: if ( (mapping = curMapping->modDefs[bit]) != 0 ) { ! 358: for(i=0, n=NEXTNUM(); i<n; i++) ! 359: { ! 360: key = NEXTNUM(); ! 361: if ( EVK_IS_KEYDOWN(key, keyBits) ) ! 362: return 1; ! 363: } ! 364: } ! 365: return 0; ! 366: } ! 367: ! 368: - (void)_calcModBit :(int)bit ! 369: keyBits :(kbdBitVector)keyBits ! 370: { ! 371: int bitMask,i,n; ! 372: unsigned myFlags; ! 373: ! 374: bitMask = 1<<(bit+16); ! 375: ! 376: /* Initially clear bit, as if key-up */ ! 377: myFlags = [delegate deviceFlags] & (~bitMask); ! 378: /* Set bit if any associated keys are down */ ! 379: if ( IsModifierDown( &curMapping, keyBits, bit ) ) ! 380: myFlags |= bitMask; ! 381: ! 382: /* If this was the shift bit... */ ! 383: if (bit == NX_MODIFIERKEY_SHIFT) ! 384: { ! 385: /* ! 386: * And CMD is already down, and we don't have a Caps Lock key, ! 387: * and we don't have a NX_KEYTYPE_CAPS_LOCK special key... ! 388: * We check both the CAPS LOCK modifier and the CAPS LOCK ! 389: * special key since only one or the other might be in use. ! 390: * We use the CAPS LOCK special key by itself for keyboards on ! 391: * which the CAPS LOCK key does not lock. ! 392: */ ! 393: if ( (myFlags & NX_COMMANDMASK) != 0 ! 394: && !curMapping.modDefs[NX_MODIFIERKEY_ALPHALOCK] ! 395: && (curMapping.specialKeys[NX_KEYTYPE_CAPS_LOCK] == ! 396: NX_NOSPECIALKEY) ) ! 397: { ! 398: /* ! 399: * On the SHIFT key down, clear the active char key if any, ! 400: * and on SHIFT key up, if no char key has been pressed, ! 401: * toggle the state of the Alpha Lock. This lets us do upper- ! 402: * case command keys without toggling Alpha Lock. ! 403: */ ! 404: if ( myFlags & bitMask ) // SHIFT key down event ! 405: [delegate setCharKeyActive:NO]; ! 406: else if ( [delegate charKeyActive] == NO ) ! 407: [delegate setAlphaLock:([delegate alphaLock] == NO)]; ! 408: } ! 409: /* Set NX_ALPHASHIFTMASK based on alphaLock OR shift active */ ! 410: myFlags = (myFlags & ~NX_ALPHASHIFTMASK) ! 411: | (([delegate alphaLock]==YES)<<16) ! 412: | ((myFlags & NX_SHIFTMASK)>>1); ! 413: } ! 414: else if ( bit == NX_MODIFIERKEY_ALPHALOCK ) /* Caps Lock key */ ! 415: [delegate setAlphaLock:(myFlags & NX_ALPHASHIFTMASK) ? YES : NO]; ! 416: ! 417: [delegate setDeviceFlags:myFlags]; ! 418: } ! 419: ! 420: ! 421: // ! 422: // Perform flag state update and generate flags changed events for this key. ! 423: // ! 424: - (void)_doModCalc:(int)key keyBits:(kbdBitVector)keyBits ! 425: { ! 426: int thisBits; ! 427: thisBits = curMapping.keyBits[key]; ! 428: if (thisBits & NX_MODMASK) ! 429: { ! 430: [self _calcModBit:(thisBits & NX_WHICHMODMASK) ! 431: keyBits:keyBits]; ! 432: /* The driver generates flags-changed events only when there is ! 433: no key-down or key-up event generated */ ! 434: if (!(thisBits & NX_CHARGENMASK)) ! 435: { ! 436: /* Post the flags-changed event */ ! 437: [delegate keyboardEvent:NX_FLAGSCHANGED ! 438: flags:[delegate eventFlags] ! 439: keyCode:key ! 440: charCode:0 ! 441: charSet:0 ! 442: originalCharCode:0 ! 443: originalCharSet:0]; ! 444: } ! 445: else /* Update, but don't generate an event */ ! 446: [delegate updateEventFlags:[delegate eventFlags]]; ! 447: } ! 448: } ! 449: ! 450: ! 451: #undef NEXTNUM ! 452: #define NEXTNUM() (shorts ? *((short *)mapping)++ : \ ! 453: *((unsigned char *)mapping)++ ) ! 454: ! 455: // ! 456: // Perform character event generation for this key ! 457: // ! 458: - (void)_doCharGen:(int)keyCode ! 459: direction:(BOOL)down ! 460: { ! 461: int i, j, n, eventType, adjust, thisMask, shorts, modifiers, origflags; ! 462: unsigned charSet, origCharSet; ! 463: unsigned charCode, origCharCode; ! 464: unsigned char *mapping; ! 465: unsigned eventFlags; ! 466: ! 467: [delegate setCharKeyActive:YES]; // A character generating key is active ! 468: ! 469: eventType = (down == YES) ? NX_KEYDOWN : NX_KEYUP; ! 470: eventFlags = [delegate eventFlags]; ! 471: modifiers = eventFlags >> 16; // machine independent mod bits ! 472: ! 473: /* Get this key's key mapping */ ! 474: shorts = curMapping.shorts; ! 475: mapping = curMapping.keyDefs[keyCode]; ! 476: ! 477: if ( mapping ) ! 478: { ! 479: /* Build offset for this key */ ! 480: thisMask = NEXTNUM(); ! 481: if (thisMask && modifiers) ! 482: { ! 483: adjust = (shorts ? sizeof(short) : sizeof(char))*2; ! 484: for( i = 0; i <= curMapping.maxMod; ++i) ! 485: { ! 486: if (thisMask & 0x01) ! 487: { ! 488: if (modifiers & 0x01) ! 489: mapping += adjust; ! 490: adjust *= 2; ! 491: } ! 492: thisMask >>= 1; ! 493: modifiers >>= 1; ! 494: } ! 495: } ! 496: charSet = NEXTNUM(); ! 497: charCode = NEXTNUM(); ! 498: ! 499: /* construct "unmodified" character */ ! 500: mapping = curMapping.keyDefs[keyCode]; ! 501: modifiers = (eventFlags & (NX_ALPHASHIFTMASK | NX_SHIFTMASK)) >> 16; ! 502: ! 503: thisMask = NEXTNUM(); ! 504: if (thisMask && modifiers) ! 505: { ! 506: adjust = (shorts ? sizeof(short) : sizeof(char)) * 2; ! 507: for ( i = 0; i <= curMapping.maxMod; ++i) ! 508: { ! 509: if (thisMask & 0x01) ! 510: { ! 511: if (modifiers & 0x01) ! 512: mapping += adjust; ! 513: adjust *= 2; ! 514: } ! 515: thisMask >>= 1; ! 516: modifiers >>= 1; ! 517: } ! 518: } ! 519: origCharSet = NEXTNUM(); ! 520: origCharCode = NEXTNUM(); ! 521: ! 522: if (charSet == (shorts ? 0xFFFF : 0x00FF)) ! 523: { ! 524: // Process as a character sequence ! 525: // charCode holds the sequence number ! 526: mapping = curMapping.seqDefs[charCode]; ! 527: ! 528: origflags = eventFlags; ! 529: for(i=0,n=NEXTNUM();i<n;i++) ! 530: { ! 531: // every 10 characters, give the windowserver a chance to ! 532: // actually read the events out of the event queue ! 533: if ((i % 10) == 9) ! 534: (void) thread_block(); ! 535: if ( (charSet = NEXTNUM()) == 0xFF ) /* metakey */ ! 536: { ! 537: if ( down == YES ) /* down or repeat */ ! 538: { ! 539: eventFlags |= (1 << (NEXTNUM() + 16)); ! 540: [delegate keyboardEvent:NX_FLAGSCHANGED ! 541: flags:[delegate deviceFlags] ! 542: keyCode:keyCode ! 543: charCode:0 ! 544: charSet:0 ! 545: originalCharCode:0 ! 546: originalCharSet:0]; ! 547: } ! 548: else ! 549: NEXTNUM(); /* Skip over value */ ! 550: } ! 551: else ! 552: { ! 553: charCode = NEXTNUM(); ! 554: [delegate keyboardEvent:eventType ! 555: flags:eventFlags ! 556: keyCode:keyCode ! 557: charCode:charCode ! 558: charSet:charSet ! 559: originalCharCode:charCode ! 560: originalCharSet:charSet]; ! 561: } ! 562: } ! 563: /* Done with macro. Restore the flags if needed. */ ! 564: if ( eventFlags != origflags ) ! 565: { ! 566: [delegate keyboardEvent:NX_FLAGSCHANGED ! 567: flags:[delegate deviceFlags] ! 568: keyCode:keyCode ! 569: charCode:0 ! 570: charSet:0 ! 571: originalCharCode:0 ! 572: originalCharSet:0]; ! 573: eventFlags = origflags; ! 574: } ! 575: } ! 576: else /* A simple character generating key */ ! 577: { ! 578: [delegate keyboardEvent:eventType ! 579: flags:eventFlags ! 580: keyCode:keyCode ! 581: charCode:charCode ! 582: charSet:charSet ! 583: originalCharCode:origCharCode ! 584: originalCharSet:origCharSet]; ! 585: } ! 586: } /* if (mapping) */ ! 587: ! 588: /* ! 589: * Check for a device control key: note that they always have CHARGEN ! 590: * bit set ! 591: */ ! 592: if (curMapping.keyBits[keyCode] & NX_SPECIALKEYMASK) ! 593: { ! 594: for(i=0; i<NX_NUM_SCANNED_SPECIALKEYS; i++) ! 595: { ! 596: if ( keyCode == curMapping.specialKeys[i] ) ! 597: { ! 598: [delegate keyboardSpecialEvent:eventType ! 599: flags:eventFlags ! 600: keyCode:keyCode ! 601: specialty:i]; ! 602: /* ! 603: * Special keys hack for letting an arbitrary (non-locking) ! 604: * key act as a CAPS-LOCK key. If a special CAPS LOCK key ! 605: * is designated, and there is no key designated for the ! 606: * AlphaLock function, then we'll let the special key toggle ! 607: * the AlphaLock state. ! 608: */ ! 609: if ( i == NX_KEYTYPE_CAPS_LOCK ! 610: && !curMapping.modDefs[NX_MODIFIERKEY_ALPHALOCK] ! 611: && down == YES ) ! 612: { ! 613: unsigned myFlags = [delegate deviceFlags]; ! 614: BOOL alphaLock = ([delegate alphaLock] == NO); ! 615: // Set delegate's alphaLock state ! 616: [delegate setAlphaLock:alphaLock]; ! 617: // Update the delegate's flags ! 618: if ( alphaLock ) ! 619: myFlags |= NX_ALPHASHIFTMASK; ! 620: else ! 621: myFlags &= ~NX_ALPHASHIFTMASK; ! 622: [delegate setDeviceFlags:myFlags]; ! 623: [delegate keyboardEvent:NX_FLAGSCHANGED ! 624: flags:myFlags ! 625: keyCode:keyCode ! 626: charCode:0 ! 627: charSet:0 ! 628: originalCharCode:0 ! 629: originalCharSet:0]; ! 630: } ! 631: break; ! 632: } ! 633: } ! 634: } ! 635: } ! 636: ! 637: @end ! 638:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.