<<>> <> <> <> <> DIRECTORY CardTab, KeyMapping, KeyMappingPrivate, KeyMappingTypes, KeyTypes; KeyMappingImpl: CEDAR MONITOR IMPORTS CardTab EXPORTS KeyMapping, KeyMappingTypes ~ BEGIN OPEN KeyMapping; MappingRep: PUBLIC TYPE = KeyMappingPrivate.MappingRep; CountKeySyms: PUBLIC PROC [mapping: Mapping, keyCode: KeyCode] RETURNS [count: NAT ¬ 0] = { IF mapping#NIL AND keyCode<=mapping.maxCode THEN { keySyms: KeySyms ~ mapping.keyTable[keyCode]; IF keySyms#NIL THEN RETURN [keySyms.n] }; }; <<>> GetKeySym: PUBLIC PROC [mapping: Mapping, keyCode: KeyCode, i: NAT] RETURNS [keySym: KeySym ¬ [0]] = { IF mapping#NIL AND keyCode<=mapping.maxCode THEN { keySyms: KeySyms ~ mapping.keyTable[keyCode]; IF keySyms#NIL AND i> noKeySyms: KeySyms ~ NEW[KeySymsRep[0]]; GetKeySyms: PUBLIC PROC [mapping: Mapping, keyCode: KeyCode] RETURNS [keySyms: KeySyms] = { IF mapping#NIL AND keyCode<=mapping.maxCode THEN { keySyms ¬ mapping.keyTable[keyCode]; IF keySyms#NIL THEN RETURN [keySyms] }; RETURN [noKeySyms] }; <<>> noKeyCodes: KeyCodes ~ NEW[KeyCodesRep[0]]; KeyCodesFromKeySym: PUBLIC PROC [mapping: Mapping, keySym: KeySym] RETURNS [keyCodes: KeyCodes] = { val: CardTab.Val; found: BOOL ¬ FALSE; IF mapping#NIL THEN { IF mapping.inverseKeyTable=NIL THEN ComputeInverse[mapping]; [found, val] ¬ CardTab.Fetch[mapping.inverseKeyTable, keySym]; IF found THEN RETURN [ NARROW[val] ]; }; RETURN [noKeyCodes]; }; WalkKeySyms: PUBLIC PROC [mapping: Mapping, walkProc: WalkKeySymsProc] RETURNS [aborted: BOOL ¬ FALSE] = { ForEachKeySym: CardTab.EachPairAction = { keySym: KeySym ~ LOOPHOLE[key]; IF walkProc[keySym] THEN RETURN[TRUE]; }; IF mapping#NIL THEN { IF mapping.inverseKeyTable=NIL THEN ComputeInverse[mapping]; aborted ¬ CardTab.Pairs[mapping.inverseKeyTable, ForEachKeySym]; }; }; NewMapping: PUBLIC PROC [keyTable: KeyTable, maxCode: KeyCode ¬ KeyCode.LAST] RETURNS [mapping: Mapping] = { mapping ¬ NEW[MappingRep ¬ [ maxCode: maxCode, keyTable: keyTable, inverseKeyTable: NIL ]]; }; ComputeInverse: PROC [mapping: Mapping] = { inverse: CardTab.Ref ~ CardTab.Create[ORD[mapping.maxCode]*2+1]; firstSym, thisSym: KeySym; AddKeySym: PROC [keySym: KeySym, keyCode: KeyCode, index: NAT] = { keyVal: REF; found: BOOL ¬ FALSE; Update: CardTab.UpdateAction = { keys: REF KeyCodesRep; IF found THEN { oldKeys: REF KeyCodesRep ~ NARROW[val]; oldCount: NAT ~ oldKeys.n; keys ¬ NEW[KeyCodesRep[oldCount+1]]; FOR i: NAT IN [0..oldCount) DO keys[i] ¬ oldKeys[i]; ENDLOOP; keys[oldCount] ¬ [keyCode, index]; } ELSE { keys ¬ NEW[KeyCodesRep[1]]; keys[0] ¬ [keyCode, index]; }; new ¬ keys; op ¬ store; }; CardTab.Update[inverse, LOOPHOLE[keySym], Update]; }; keyTable: KeyTable ~ mapping.keyTable; FOR i: KeyCode IN [keycode0..mapping.maxCode] DO keySyms: KeySyms ~ keyTable[i]; IF keySyms#NIL AND keySyms.n>0 THEN { firstSym ¬ keySyms[0]; AddKeySym[firstSym, i, 0]; FOR j: NAT IN [0..keySyms.n) DO thisSym ¬ keySyms[j]; IF thisSym # firstSym THEN AddKeySym[thisSym, i, j]; ENDLOOP; }; ENDLOOP; <<>> <<--idempotent; locking not required>> mapping.inverseKeyTable ¬ inverse; }; END.