-- Em3270UserInputPack: 3270 Emulation Window -- Revised for Star 3.2IKlamath by Irani: 20-Dec-83 10:46:19 -- Owner: Lui -- Overview: -- This module handles all user initiated actions coming into the Emulator from the Notifier. DIRECTORY AreaDefs USING [Posn], CharDefs USING [Char, Roman], Em3270CmdProcessDefs USING [setBufferAddress], Em3270ComDefs USING [DoStreamPut], Em3270Defs, Em3270PrivDefs, Em3270BufferDefs USING [ BackSpaceKey, BackTabKey, ClearBuffer, DeleteKey, DisplayBuffer, DuplicateKey, EnumFields, EraseEOFKey, EraseInputKey, FieldMarkKey, GetCursor, HomeKey, NewLineKey, Release, Reserve, PutChar, SetCursor, TabKey, WriteError], Em3270CharTransDefs USING [EBCDICFromOISChar, ExpandLegalDeadchar], Em3270UserInputDefs, Em3270StatusDefs USING [ClearStatusArea, DisplayCode], GateStream USING [readModified3270, testRequest3270], MessageSwnDefs USING [DisplayMessage], McDefs USING [SetDefaultShape, SetStandardShape], NfrDefs USING [CancelMCS], NtDefs, RgnDefs USING [Aqrgn, FreeRest, Rgn, Sc], SchemaDefs USING [ AqrgnBkgdUtilStd, CancelMCS, GetRootCs, Lschema, lschemaNil, NewTrackUtilStd, PBRequest, ProcessButNopAbortMCSOnButtonUpStd, Pvprocessbut, Resolveresult, ResolveToChildExactly, Sel], SchemaUtilDefs USING [AddScs, AddScToPosn, ScInRgn], SelectionDefs USING [DeselectCs, selNil, SetCs], StandardDefs USING [Bv, Ch, Cv, String], Stream, TraitDefs USING [MyData], TreeEltDefs USING [ctxtNil], TxtDefs USING [Flow, flowNil, seldescNil, TextSegment, textSegmentNil], TxtEditDefs USING [ AdjustDeleteSpan, AlterCurrentSelection, Aqrehilitespec, AqTxtCtxt, BeginEdit, CopyTextSegment, Delete, DestroyTextSegment, EndEdit, LptSelDescription, Rehilite, SelectionDescription, Seldesc, seltypeText, TxtCtxt], TxtFlowDefs USING [AdvanceCharacter, CharacterCurrent, Create, Destroy], VDTDefs USING [ CharPos, GetCursorShape, LschemaVDT, SetCursorShape, TrackButton], WSCharDefs USING [Character], WSStringDefs USING [ Aqscanctxt, BeginForwardScan, CharCur, EndScan, ScanForward, Substring], ZoneMgrDefs USING [GetPredefinedZone]; Em3270UserInputPack: PROGRAM IMPORTS CharDefs, Em3270BufferDefs, Em3270CharTransDefs, Em3270ComDefs, Em3270PrivDefs, Em3270StatusDefs, McDefs, MessageSwnDefs, NfrDefs, RgnDefs, SchemaDefs, SchemaUtilDefs, SelectionDefs, TraitDefs, TxtEditDefs, TxtFlowDefs, VDTDefs, WSStringDefs, ZoneMgrDefs EXPORTS Em3270UserInputDefs SHARES SchemaDefs = BEGIN OPEN Em3270Defs, Em3270PrivDefs, Em3270UserInputDefs, StandardDefs; --=================== -- Types --=================== --=================== -- Signals and Errors --=================== --=================== -- Constants --=================== --=================== -- Global Variables --=================== bvStreamOn: Bv ← TRUE; -- for testing purposes without a stream connection +++ spredefinedZone: UNCOUNTED ZONE ← ZoneMgrDefs.GetPredefinedZone[short]; -- Set up 3270-unique key processor for all instances of the 3270 Emulator keyProcessor: KeyProcessor ← [ special3270Alpha: NoImpl, special3270AltCursor: AltCursor, special3270BackSpace: MoveCursor, special3270BackTab: MoveCursor, special3270Click: NoImpl, special3270Clear: Aid, special3270Copy: NoImpl, special3270CursorBlink: NoImpl, special3270CursorSel: Aid, special3270Delete: Delete, special3270Duplicate: Duplicate, special3270Enter: Aid, special3270EraseEOF: EraseEOF, special3270EraseInput: EraseInput, special3270FieldMark: FieldMark, special3270Home: MoveCursor, special3270Ident: NoImpl, special3270InsertMode: InsertMode, special3270NewLine: MoveCursor, special3270NumericDown: NoImpl, special3270NumericLockDown: NoImpl, special3270NumericLockUp: NoImpl, special3270NumericUp: NoImpl, special3270PA1: Aid, special3270PA2: Aid, special3270PF1: Aid, special3270PF2: Aid, special3270PF3: Aid, special3270PF4: Aid, special3270PF5: Aid, special3270PF6: Aid, special3270PF7: Aid, special3270PF8: Aid, special3270PF9: Aid, special3270PF10: Aid, special3270PF11: Aid, special3270PF12: Aid, special3270Reset: Reset, special3270ShiftDown: EnableShift, special3270ShiftLockDown: EnableShift, special3270ShiftLockUp: DisableShift, special3270ShiftUp: DisableShift, special3270SysReq: Aid, special3270Tab: MoveCursor, special3270TestReq: Aid]; -- Binary to EBCDIC Buffer address conversion table convertAddr: PACKED ARRAY [0..64) OF CHARACTER ← [ 100C, -- 40 Hex 301C, 302C, 303C, 304C, 305C, 306C, 307C, 310C, 311C, -- C1 to C9 Hex 112C, 113C, 114C, 115C, 116C, 117C, 120C, -- 4A to 4F, 50 Hex 321C, 322C, 323C, 324C, 325C, 326C, 327C, 330C, 331C, -- D1 to D9 Hex 132C, 133C, 134C, 135C, 136C, 137C, 140C, 141C, -- 5A to 5F, 60, 61 Hex 342C, 343C, 344C, 345C, 346C, 347C, 350C, 351C, -- E2 to E9 Hex 152C, 153C, 154C, 155C, 156C, 157C, -- 6A to 6F, Hex 360C, 361C, 362C, 363C, 364C, 365C, 366C, 367C, 370C, 371C, -- F0 to F9 Hex 172C, 173C, 174C, 175C, 176C, 177C]; -- 7A to 7F, Hex --=================== -- Private Procedures Define all the types of key processors here --=================== Aid: KeyProc = -- set up AID stream, inhibit input, send stream to host -- PROC[lschema:SchemaDefs.Lschema, key:NtDefs.Special3270Key]; BEGIN lptPutBuf: LptBufOfChar ← GetMDTStream[lschema].lptbuf; buffer: LptBufferData ← GetBufferHandle[lschema]; SetInputStatus[lschema, inputInhibited]; -- all AID keyes (except CLEAR) lock up the emulator Em3270StatusDefs.DisplayCode[lschema: lschema, code: time, bvOn: TRUE]; -- turn on wait status SELECT key FROM --special3270CursorSel=> DoCursorSel[lschema, buffer, lptPutBuf]; special3270Enter => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[enter]]; special3270PA1 => DoShortRd[lschema, lptPutBuf, AIDCodes[PA1]]; special3270PA2 => DoShortRd[lschema, lptPutBuf, AIDCodes[PA2]]; special3270PF1 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF1]]; special3270PF2 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF2]]; special3270PF3 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF3]]; special3270PF4 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF4]]; special3270PF5 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF5]]; special3270PF6 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF6]]; special3270PF7 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF7]]; special3270PF8 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF8]]; special3270PF9 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF9]]; special3270PF10 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF10]]; special3270PF11 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF11]]; special3270PF12 => DoReadMod[lschema, buffer, lptPutBuf, AIDCodes[PF12]]; special3270SysReq => DoTestReq[lschema, buffer, lptPutBuf]; special3270TestReq => DoTestReq[lschema, buffer, lptPutBuf]; special3270Clear => { Em3270BufferDefs.ClearBuffer[buffer]; Em3270BufferDefs.DisplayBuffer[buffer]; DoShortRd[lschema, lptPutBuf, AIDCodes[clear]]; }; ENDCASE => ERROR; -- should never get here; this is a non-AID key SetAIDStatus[lschema, FALSE]; -- set the AID. Can only be reset if the next WCC byte from host is unlock keyboard, or when user hit the RESET key. (use for Read modified commnads) -- Note that we do NOT clear input inhibited here because we assume the host will respond to the AID with a WCC bit set to clear it. Em3270StatusDefs.DisplayCode[lschema: lschema, code: insert, bvOn: FALSE]; -- turn off insert status (if present) END; -- of Aid AltCursor: KeyProc = -- toggles cursor between rectangle and underscore BEGIN display: VDTDefs.LschemaVDT ← GetDisplayHandle[lschema]; VDTDefs.SetCursorShape[display, (SELECT VDTDefs.GetCursorShape[display] FROM underscore => box, box => underscore, ghostunderscore => ghostbox, ghostbox => ghostunderscore, invisible => invisible, blinkunderscore => blinkbox, blinkbox => blinkunderscore, ENDCASE => box)]; -- toggle shape END; -- of AltCursor Delete: KeyProc = -- Delete the character pointed to by the cursor. -- If cursor is on an unprotected character -- THEN delete char, shifts left, fills with nulls, sets MDT, cursor does not move -- ELSE inhibit keyboard and issue message BEGIN bufstatus: Em3270BufferDefs.WriteError ← Em3270BufferDefs.DeleteKey[GetBufferHandle[lschema]]; -- do Delete IF bufstatus # okay THEN {SetInputInhibited[lschema]; DisplayBufferError[lschema, bufstatus]; }; END; -- of Delete Duplicate: KeyProc = -- puts a "unique code" into buffer at current cursor, performs Tab, sets MDT. -- Dup char displays as "*" (with an overscore if 3278 is dual-case). -- If cursor in protected field or attribute char, THEN inhibit keyboard and issue message BEGIN bufstatus: Em3270BufferDefs.WriteError ← Em3270BufferDefs.DuplicateKey[GetBufferHandle[lschema]]; -- do Dup Key IF bufstatus # okay THEN {SetInputInhibited[lschema]; DisplayBufferError[lschema, bufstatus]; }; END; -- of Duplicate EraseEOF: KeyProc = -- if cursor is on an unprotected character -- THEN clear from cursor to end of field, cursor doesn't move, MDT is set -- ELSE inhibit keyboard and issue message BEGIN bufstatus: Em3270BufferDefs.WriteError ← Em3270BufferDefs.EraseEOFKey[GetBufferHandle[lschema]]; -- do Erase Field IF bufstatus # okay THEN {SetInputInhibited[lschema]; DisplayBufferError[lschema, bufstatus]; }; END; -- of EraseEOF EraseInput: KeyProc = -- If formatted buffer -- THEN IF all protected fields, -- THEN only put cursor in home position -- ELSE clear ALL unprotected fields, reset all MDTs, put cursor in 1st unprotected location -- ELSE (unformatted) clear all buffer, put cursor in home position BEGIN Em3270BufferDefs.EraseInputKey[GetBufferHandle[lschema]]; END; -- of EraseInput FieldMark: KeyProc = -- puts a "unique code" into buffer at current cursor, sets MDT. -- FM char displays as ";" (with an overscore if 3278 is dual-case). -- If cursor in protected field or attribute char, THEN inhibit keyboard and issue message BEGIN bufstatus: Em3270BufferDefs.WriteError ← Em3270BufferDefs.FieldMarkKey[GetBufferHandle[lschema]]; -- do Field Mark Key IF bufstatus # okay THEN {SetInputInhibited[lschema]; DisplayBufferError[lschema, bufstatus]; }; END; -- of FieldMark InsertMode: KeyProc = -- Sets Insert mode. -- IF cursor is in a field with at least one null in it, -- THEN pressing any subsequent alphanumeric key inserts that character at the cursor and sets the MDT. Chars at cursor are shifted to the right one place and the field's ending null is removed. -- ELSE (no nulls or on a attribute) inhibit keyboard and issue message. -- Reset or any AID key exits insert mode. BEGIN SetInputStatus[lschema, insertMode]; -- set global emulator status to Insert Mode on Em3270StatusDefs.DisplayCode[lschema: lschema, code: insert, bvOn: TRUE]; -- turn on insert status END; -- of InsertMode MoveCursor: KeyProc = -- This routine is resonsible for positioning the cursor on the display according to the key value. -- Note that backspace, newline,and tab will not really come through MoveCursor but will given to 3270 through SkipCursor ala ProcessFunRepeat. They are left here for safety sake in case the keyboard interrupter decids to give us these notification thru Process3270Keyes BEGIN SELECT key FROM special3270BackSpace => Em3270BufferDefs.BackSpaceKey[my: GetBufferHandle[lschema]]; -- process BACKSPACE special3270BackTab => Em3270BufferDefs.BackTabKey[my: GetBufferHandle[lschema]]; -- process BACKTAB special3270Home => Em3270BufferDefs.HomeKey[my: GetBufferHandle[lschema]]; -- process HOME special3270NewLine => Em3270BufferDefs.NewLineKey[my: GetBufferHandle[lschema]]; -- process NEWLINE special3270Tab => Em3270BufferDefs.TabKey[my: GetBufferHandle[lschema]]; -- process TAB ENDCASE; END; -- of MoveCursor NoImpl: KeyProc = -- This key value is not currently supported BEGIN MessageSwnDefs.DisplayMessage[keyNotImplemented]; END; -- of NoImpl Reset: PUBLIC KeyProc = -- Resets Input Inhibited. Won't execute if: -- 1. polled AID till poll is done. Otherwise cancels AID. -- 2. a command is being executed. BEGIN SetInputStatus[lschema, systemAvailable]; -- set emulator globle status to available -- Reset the status area normal symbols Ready, Online, and MyJob Em3270StatusDefs.ClearStatusArea[lschema]; -- clear any status which could Inhibit Input Em3270StatusDefs.DisplayCode[lschema, Ready3276]; Em3270StatusDefs.DisplayCode[lschema, onlineA]; Em3270StatusDefs.DisplayCode[lschema, myJob]; -- Reset the AID status. (use for Read Modified) ResetAIDStatus[lschema]; -- => reset AID and free block END; -- of Reset EnableShift: KeyProc = -- Enters upper case mode. Clears shift lock. BEGIN Em3270StatusDefs.DisplayCode[lschema: lschema, code: upshift, bvOn: TRUE]; -- turn on shift status END; -- of Shift DisableShift: KeyProc = -- Sets shift lock. BEGIN Em3270StatusDefs.DisplayCode[lschema: lschema, code: upshift, bvOn: FALSE]; -- turn off shift status END; -- of ShiftLock --=================== -- Private Procedures Define all the indivigual "Do" processors here --=================== DoReadMod: PUBLIC PROCEDURE [ lschema: SchemaDefs.Lschema, buffer: LptBufferData, lptPutBuf: LptBufOfChar, aidCode: Ch, accessMode: AccessMode ← keyMode] = -- This routine will enumerate through all the modified fields in the 3270 Buffer and build the output stream in lptPutBuf. It first puts the given AID code in followed by the current cursor address into the stream, then proceeds to enumerate all the modified fields. It assumes the Buffer has been Reserved previously. BEGIN putBuf: MDTStream ← [lptPutBuf, 0]; -- initialize output stream block descriptor curAddr: VDTDefs.CharPos ← Em3270BufferDefs.GetCursor[buffer]; -- current cursor address -- First put the AID code for ENTER followed by the current cursor address into the output stream putBuf ← StoreByte[putBuf, aidCode]; -- EBCDIC AID header code putBuf ← StoreByte[putBuf, convertAddr[curAddr/64]]; -- convert and store cursor high-order address putBuf ← StoreByte[putBuf, convertAddr[curAddr MOD 64]]; -- convert and store cursor low-order address -- Enumerate through all the modified fields putBuf ← Em3270BufferDefs.EnumFields[ my: buffer, pvFieldHit: BuildFieldStream, clientData: putBuf, bvAll: FALSE, accessMode: accessMode]; -- enumerate all modified fields only -- Send entire "Read Modified" stream to host IF bvStreamOn THEN Em3270ComDefs.DoStreamPut[ my: GetComHandle[lschema], mdtStream: [lptPutBuf, putBuf.blkIx], sstType: GateStream.readModified3270]; SetMDTStream[lschema, [lptPutBuf, putBuf.blkIx]]; END; -- of DoReadMod DoShortRd: PROCEDURE [ lschema: SchemaDefs.Lschema, lptPutBuf: LptBufOfChar, aidCode: Ch] = -- This routine will perform a "Short Read", which means it will sent just the AID to the host. BEGIN putBuf: MDTStream ← [lptPutBuf, 0]; -- initialize output stream block descriptor -- Put given AID in stream buffer putBuf ← StoreByte[putBuf, aidCode]; -- EBCDIC AID header code IF bvStreamOn THEN Em3270ComDefs.DoStreamPut[ my: GetComHandle[lschema], mdtStream: [lptPutBuf, putBuf.blkIx], sstType: GateStream.readModified3270]; SetMDTStream[lschema, [lptPutBuf, putBuf.blkIx]]; END; -- of DoShortRd DoTestReq: PROCEDURE [ lschema: SchemaDefs.Lschema, buffer: LptBufferData, lptPutBuf: LptBufOfChar] = -- This routine will perform a "Test Request Read", which means it will sent just the modified data fields excluding the three-byte header (AID + cursor address) BEGIN putBuf: MDTStream ← [lptPutBuf, 0]; -- initialize output stream block descriptor Em3270StatusDefs.DisplayCode[lschema: lschema, code: test, bvOn: TRUE]; -- turn on wait status (WCC to turn it off) -- Enumerate through all the modified fields putBuf ← Em3270BufferDefs.EnumFields[ my: buffer, pvFieldHit: BuildFieldStream, clientData: putBuf, bvAll: FALSE]; -- enumerate all modified fields only -- Send entire "Read Modified" stream to host IF bvStreamOn THEN Em3270ComDefs.DoStreamPut[ my: GetComHandle[lschema], mdtStream: [lptPutBuf, putBuf.blkIx], sstType: GateStream.testRequest3270]; SetMDTStream[lschema, [lptPutBuf, putBuf.blkIx]]; END; -- of DoTestReq --=================== -- Utility Procedures --=================== BuildFieldStream: PvFieldHit = -- PROCEDURE[mainBuffer:VDTDefs.LptCharSeq, startPos:VDTDefs.CharPos, fLength:CARDINAL, clientData:MDTStream, bvIsNewField:Bv, lptToTransFile: BaseOISToEFile] -- RETURNS[MDTStream]; -- This routine is called once for each "run" of text in a modified field. A "run" is all text between two attributes and/or nulls. Therefore, it may take several calles to BuildFieldStream to aquire one modified field, depending on how many nulls are imbedded in it. Typically, however, the run will be all text between the attribute character and the first null. If bvIsNewField is TRUE, THEN we must put the SBA/FWA-of-field header in the stream (startPos is pointing at a attribute+1), ELSE, it points to the next non-null portion of the current field and we just keep on processing non-null text. BEGIN -- Process order and attribute portion of the output stream IF bvIsNewField THEN -- if called with the start of a new field BEGIN clientData ← StoreByte[clientData, Em3270CmdProcessDefs.setBufferAddress]; -- store Set Buffer Address Order clientData ← StoreByte[clientData, convertAddr[startPos/64]]; -- convert/store attribute+1 high-order address clientData ← StoreByte[clientData, convertAddr[startPos MOD 64]]; -- convert/store attribute+1 low-order address END; -- Process text/field portion of the output stream UNTIL fLength = 0 DO clientData ← StoreByte[ clientData, Em3270CharTransDefs.EBCDICFromOISChar[lptToTransFile, mainBuffer[startPos]]]; -- store text startPos ← startPos + 1; -- increment source pointer fLength ← fLength - 1; ENDLOOP; RETURN[clientData]; END; -- of BuildFieldStream SetInputInhibited: PROCEDURE [lschema: SchemaDefs.Lschema] = -- This routine will set the global emulator status to inputInhibited and display the systemLock sysbol. BEGIN SetInputStatus[lschema, inputInhibited]; Em3270StatusDefs.DisplayCode[lschema: lschema, code: systemLock, bvOn: TRUE]; -- turn on input inhibited status END; -- of SetInputInhibited StoreByte: PROCEDURE [to: MDTStream, byte: Ch] RETURNS [MDTStream] = -- This routine take care of storing the given byte into the output stream of bytes in ComBufIndexCt size chunks. When more storage is needed it calls GetNextBuf to get another ComBufIndexCt chunk and link it up. BEGIN IF to.blkIx >= maxComBufCt THEN { to.lptbuf ← GetNextBuf[to.lptbuf]; to.blkIx ← 0; }; to.lptbuf.hostData[to.blkIx] ← byte; -- store the byte to.blkIx ← to.blkIx + 1; RETURN[to]; END; -- of StoreByte GetNextBuf: PROCEDURE [putBufOld: LptBufOfChar] RETURNS [putBufNew: LptBufOfChar] = -- This rotuine will allocate another "PutBuf"'s worth of storage and link it into the given buffer chain BEGIN putBufNew ← spredefinedZone.NEW[BufOfChar]; putBufNew.nextBuf ← NIL; -- this new block now terminates the block chain IF putBufOld # NIL THEN putBufOld.nextBuf ← putBufNew; --link new buffer-block at end of chain END; -- of GetNextBuf FreeBuf: PROCEDURE [putBuf: LptBufOfChar] = -- This routine will free the entire Put Buffer Chain. -- This code duplicates the routine Em3270ComDefs.FreeBuffer. BEGIN nextBlk: LptBufOfChar ← putBuf.nextBuf; spredefinedZone.FREE[@putBuf]; -- free first block unconditionally UNTIL nextBlk = NIL DO putBuf ← nextBlk; nextBlk ← putBuf.nextBuf; spredefinedZone.FREE[@putBuf]; ENDLOOP; END; -- of FreeBuf --=================== -- Public Procedures --=================== DoProcessBut: PUBLIC SchemaDefs.Pvprocessbut = -- PROC[lschema:Lschema, pbrequest:PBRequest] --Handle legal button selections BEGIN MYdata: Lpttrt3270schemadata ← TraitDefs.MyData[lschema, trt3270schema]; lptdata: LONG POINTER TO EmHandle ← MYdata.lptEmState; charpos: VDTDefs.CharPos; posnSelf: AreaDefs.Posn = pbrequest.posnSchema; -- save my own tracking region rgnTrackSave: RgnDefs.Rgn = pbrequest.rgnTrack; -- save my own position resolveresult: SchemaDefs.Resolveresult; aqrgnBkgd: RgnDefs.Aqrgn ← [NIL, NIL]; bvBkgdComputed: Bv ← FALSE; bvDoneTracking: Bv ← FALSE; IF (pbrequest.button.buttype = butCopy OR pbrequest.button.buttype = butMove) AND SchemaDefs.GetRootCs[].sel.seltype # TxtEditDefs.seltypeText THEN { --we won't be able to process this ourselves SchemaDefs.ProcessButNopAbortMCSOnButtonUpStd[lschema, pbrequest]; RETURN}; -- While the button is in my interest region send it to a child or track in background UNTIL bvDoneTracking DO SchemaDefs.ResolveToChildExactly[lschema, pbrequest, @resolveresult]; -- is button in my schema? IF resolveresult.lschemaHit # SchemaDefs.lschemaNil THEN BEGIN -- send button to children pbrequest.rgnTrack ← @resolveresult.aqrgnTrackHit; -- tracking region for lschemaHit SchemaUtilDefs.AddScToPosn[resolveresult.scSchemaHit, @pbrequest.posnSchema]; -- position of lschemaHit (upper left hand corner) pbrequest.rgnTrack ← @resolveresult.aqrgnTrackHit; -- tracking region for lschemaHit pbrequest.button.sc ← resolveresult.scBut; -- but. pos. rel to lschemaHit IF resolveresult.lschemaHit = lptdata.display THEN BEGIN -- handle button in VDT area. Assumes VDT is my only child - all else is background! [charpos, pbrequest.button.sc, pbrequest.processbutctrl] ← VDTDefs.TrackButton[ lptdata.display, pbrequest.posnSchema, pbrequest.button.sc]; -- let VDT handle button while inside it IF pbrequest.processbutctrl = buttonup THEN DoButUpInDataArea[lschema, pbrequest, charpos] -- handle button up within main data area END; -- handle button in VDT area -- restore posnSchema, rgnTrack and scBut for parent (lschema) pbrequest.rgnTrack ← rgnTrackSave; RgnDefs.FreeRest[resolveresult.aqrgnTrackHit.rteFirst]; pbrequest.posnSchema ← posnSelf; -- restore position of lschema pbrequest.button.sc ← SchemaUtilDefs.AddScs[ pbrequest.button.sc, resolveresult.scSchemaHit]; -- make scBut lschema-relative END -- of send button to children ELSE --lschemaHit = lschemaNil; button processing in background (we're in the boarders) BEGIN -- processing background IF NOT bvBkgdComputed THEN BEGIN -- need to calculate backgroung region before testing bvBkgdComputed ← TRUE; aqrgnBkgd ← SchemaDefs.AqrgnBkgdUtilStd[ lschema, rgnTrackSave, posnSelf]; END; IF SchemaUtilDefs.ScInRgn[pbrequest.button.sc, @aqrgnBkgd] THEN BEGIN -- tracking in my background pbrequest.rgnTrack ← @aqrgnBkgd; SchemaDefs.NewTrackUtilStd[lschema, pbrequest]; SELECT pbrequest.button.buttype FROM butMove => SchemaDefs.CancelMCS[lschema, funMove]; butCopy => SchemaDefs.CancelMCS[lschema, funCopy]; butSameAs => SchemaDefs.CancelMCS[lschema, funSameAs]; ENDCASE => NULL; -- ignore select, adjust, convert, drawthrough pbrequest.rgnTrack ← rgnTrackSave; END -- of tracking in my background ELSE bvDoneTracking ← TRUE; -- neither in child nor in background END; -- processing background bvDoneTracking ← (pbrequest.processbutctrl = buttonup) OR (pbrequest.processbutctrl = cancel) OR NOT SchemaUtilDefs.ScInRgn[pbrequest.button.sc, rgnTrackSave]; ENDLOOP; IF bvBkgdComputed THEN RgnDefs.FreeRest[aqrgnBkgd.rteFirst]; END; -- of DoProcessBut DoButUpInDataArea: PROCEDURE [ lschema: SchemaDefs.Lschema, pbrequest: SchemaDefs.PBRequest, charpos: VDTDefs.CharPos] = BEGIN bvprocessOK: Bv ← TRUE; SELECT pbrequest.button.buttype FROM butSelect => { SelectCharPos[lschema, pbrequest, charpos]; SelectionDefs.DeselectCs}; -- pop the current selection butCopy, butMove => { SelectCharPos[lschema, pbrequest, charpos]; bvprocessOK ← DoMoveOrCopy[lschema, pbrequest.button.buttype = butMove]}; ENDCASE; --??? do anything here ???? IF bvprocessOK THEN -- set current selection to type 3270 if button processing ok VDTDefs.SetCursorShape[GetDisplayHandle[lschema], GetPrevCursorShape[lschema]]; SelectionDefs.SetCs[lschema, GetSelType[lschema], TreeEltDefs.ctxtNil]; END; -- of DoButUpInDataArea SelectCharPos: PROCEDURE [ lschema: SchemaDefs.Lschema, pbrequest: SchemaDefs.PBRequest, charpos: VDTDefs.CharPos] = BEGIN OPEN Em3270BufferDefs; buffer: LptBufferData ← GetBufferHandle[lschema]; Reserve[my: buffer]; -- lock for destructive function SetCursor[my: buffer, newCursor: charpos, bvDisplayCursor: FALSE]; -- set Release[my: buffer]; -- unlock buffer interlock END; -- of SelectCharPos DehiliteSeldesc: PROCEDURE [seldesc: TxtEditDefs.Seldesc] = BEGIN aqrehilitespec: TxtEditDefs.Aqrehilitespec; lptSelDescription: TxtEditDefs.LptSelDescription; [lptSelDescription: lptSelDescription] ← TxtEditDefs.SelectionDescription[seldesc]; -- de-hilite trial selection aqrehilitespec[primary][before] ← lptSelDescription.textSegment; aqrehilitespec[primary][after] ← TxtDefs.textSegmentNil; aqrehilitespec[secondary][before] ← TxtDefs.textSegmentNil; aqrehilitespec[secondary][after] ← TxtDefs.textSegmentNil; TxtEditDefs.Rehilite[@aqrehilitespec]; END; DoMoveOrCopy: PROCEDURE [lschema: SchemaDefs.Lschema, bvMove: Bv] RETURNS [ok: Bv ← TRUE] = --process COPY and MOVE into the 3270 window. If the operation fails due to some problem with the source, the MC is cancelled, the current selection is restored to the source, and ok is returned FALSE. If the operation fails due to a problem with the 3270 buffer, input inhibited is set, the appropriate status is displayed, and ok is returned TRUE; ie, the MC is considered successful from the Star point of view. BEGIN bvTextSelectionExists, bvWellFormed, bvAdjustmentMade: Bv; lschemaRoot: SchemaDefs.Lschema ← SchemaDefs.lschemaNil; seldescCS: TxtEditDefs.Seldesc ← TxtDefs.seldescNil; --of MC selection selRoot: SchemaDefs.Sel ← SelectionDefs.selNil; ts: TxtDefs.TextSegment ← TxtDefs.textSegmentNil; lptSelDescription: TxtEditDefs.LptSelDescription; -- If inputInhibited, ignore all input characters IF GetInputStatus[lschema] = inputInhibited THEN { SchemaDefs.CancelMCS[lschema, funCopy]; Em3270StatusDefs.DisplayCode[lschema: lschema, code: what, bvOn: TRUE]; -- turn on WHAT "?+" status RETURN[TRUE]; }; [lschema: lschemaRoot, sel: selRoot] ← SchemaDefs.GetRootCs[]; bvTextSelectionExists ← lschemaRoot # SchemaDefs.lschemaNil AND selRoot.seltype = TxtEditDefs.seltypeText; seldescCS ← LOOPHOLE[selRoot.seldesc.lptr]; IF ~bvTextSelectionExists THEN { --nothing to Copy or Move SchemaDefs.CancelMCS[lschema, IF bvMove THEN funMove ELSE funCopy]; RETURN[FALSE]}; [lptSelDescription: lptSelDescription] ← TxtEditDefs.SelectionDescription[seldescCS]; ts ← TxtEditDefs.CopyTextSegment[@lptSelDescription.textSegment]; McDefs.SetStandardShape[idHourGlass]; -- this may take a second or two IF bvMove THEN [bvWellFormed, bvAdjustmentMade] ← TxtEditDefs.AdjustDeleteSpan[ts] ELSE {bvWellFormed ← TRUE; bvAdjustmentMade ← FALSE}; IF NOT bvWellFormed THEN BEGIN -- cancel move or copy, restore old selection TxtEditDefs.AlterCurrentSelection[seldescCS]; MessageSwnDefs.DisplayMessage[ IF bvMove THEN keyCSCantMove ELSE keyCSCantCopy]; SchemaDefs.CancelMCS[lschema, IF bvMove THEN funMove ELSE funCopy]; TxtEditDefs.DestroyTextSegment[@ts]; McDefs.SetDefaultShape[]; RETURN[FALSE]; END ELSE BEGIN --actually do the copy or move. status: Em3270BufferDefs.WriteError ← okay; flow: TxtDefs.Flow ← TxtFlowDefs.Create[ ts.blockaddrFirst, ts.blockaddrLast]; buffer: Em3270PrivDefs.LptBufferData ← Em3270PrivDefs.GetBufferHandle[ lschema]; lptToTransFile: BaseOISToEFile ← Em3270PrivDefs.GetTransHandle[lschema]; Em3270BufferDefs.Reserve[buffer]; IF flow = TxtDefs.flowNil THEN status ← okay ELSE DO noChar: CharDefs.Char ← CharDefs.Roman[unused177B]; newChar1: CharDefs.Char ← CharDefs.Roman[unused177B]; newChar2: CharDefs.Char ← CharDefs.Roman[unused177B]; [newChar1, newChar2] ← GetNonTileCharFromFlow[lptToTransFile, flow]; IF newChar1 = noChar THEN EXIT; --no more characters IF (status ← Em3270BufferDefs.PutChar[buffer, newChar1]) # okay THEN GOTO reject; IF newChar2 # noChar THEN --it's the second part of a deadkey sequence IF (status ← Em3270BufferDefs.PutChar[buffer, newChar2]) # okay THEN GOTO reject; IF ~TxtFlowDefs.AdvanceCharacter[flow] THEN EXIT; REPEAT reject => DisplayBufferError[lschema, status]; ENDLOOP; Em3270BufferDefs.Release[buffer]; -- DehiliteSeldesc[seldescCS]; SelectionDefs.DeselectCs; TxtFlowDefs.Destroy[flow]; IF bvMove AND status = okay THEN BEGIN OPEN TxtEditDefs; --delete the (possibly) adjusted source segment txtCtxt: TxtCtxt ← @aqTxtCtxt; aqTxtCtxt: AqTxtCtxt; BeginEdit[txtCtxt, TRUE]; --consult user for things like anchors &c. Delete[txtCtxt, ts]; EndEdit[txtCtxt]; END; END; TxtEditDefs.DestroyTextSegment[@ts]; McDefs.SetDefaultShape[]; END; -- of DoMoveOrCopy GetNonTileCharFromFlow: PROCEDURE [lptToTransFile: BaseOISToEFile, flow: TxtDefs.Flow] RETURNS [char1, char2: CharDefs.Char] = --Returns with the next non-tile character in the flow, starting at the current position, or the news (char1 = Roman[unused177B]) that the flow is exhausted. ADD CODE to return a second CharDefs.Char # Roman[unused177B] if the character.aqplaincharacter.char is one that must decompose into a dead accent followed by a host; and to return a Roman[hyphen] if the character.aqplaincharacter.char is one that doesn't exist in the EBCDIC set under consideration at all. BEGIN character: WSCharDefs.Character; DO character ← TxtFlowDefs.CharacterCurrent[flow]; SELECT character.aqplaincharacter.representation FROM bit16 => { --here's where we'll have to check for decomposing dead characters (whew!) and transforming unrecognized NS characters to Roman hyphens. Note that when this is done we will NOT advance the flow, as it has no idea that we might have turned one character into two. [char1, char2] ← Em3270CharTransDefs.ExpandLegalDeadchar[lptToTransFile, character.aqplaincharacter.char]; RETURN[char1, char2]; }; ENDCASE => IF ~TxtFlowDefs.AdvanceCharacter[flow] THEN RETURN[CharDefs.Roman[unused177B], CharDefs.Roman[unused177B]]; ENDLOOP; END; --of GetCharFromFlow DisplayBufferError: PROCEDURE [lschema: SchemaDefs.Lschema, error:Em3270BufferDefs.WriteError] = -- This routine will take the given buffer error and translate it into a meaningful status character to be displayed in the lower Status area of the 3270 window. BEGIN Em3270StatusDefs.DisplayCode[lschema: lschema, bvOn: TRUE, code: SELECT error FROM attribute, protected => goElsewhere, noRoomInField => moreThan, alphaInNumericField => nonNumeric, ENDCASE => what]; END; -- of DisplayBufferError ProcessInputChar: PUBLIC PROCEDURE [ lschema: SchemaDefs.Lschema, string: String] = -- Process a normal alphanumeric characters from the main keyboard array. BEGIN aqscanctxt: WSStringDefs.Aqscanctxt; -- scan context for reading string bufstatus: Em3270BufferDefs.WriteError; -- buffer status returned while putting a char into the buffer BEGIN -- just needed for scope-of-definition on aqscanctxt/bufstatus status: InputStatus ← GetInputStatus[lschema]; -- get current emulator status -- If inputInhibited, ignore all input characters IF status = inputInhibited THEN { Em3270StatusDefs.DisplayCode[lschema: lschema, code: what, bvOn: TRUE]; -- turn on WHAT "?+" status RETURN;}; -- Initialize the scanctxt. Will then point to first character IF WSStringDefs.BeginForwardScan[ WSStringDefs.Substring[string], @aqscanctxt, characters] THEN -- string is not empty BEGIN buffer: LptBufferData ← GetBufferHandle[lschema]; -- Start reading characters for input and putting them into the buffer (usually this is only one character long) bufstatus ← Em3270BufferDefs.PutChar[my: buffer, -- display first char. unconditionally aChar: WSStringDefs.CharCur[@aqscanctxt], inputMode: status]; IF bufstatus # okay THEN GOTO buffererrors; -- handle any buffer errors WHILE WSStringDefs.ScanForward[@aqscanctxt] -- advance to next char DO bufstatus ← Em3270BufferDefs.PutChar[my: buffer, -- display all subsequent characters aChar: WSStringDefs.CharCur[@aqscanctxt], inputMode: status]; IF bufstatus # okay THEN GOTO buffererrors; -- handle any buffer errors ENDLOOP; END; WSStringDefs.EndScan[@aqscanctxt]; -- clean up scanctxt house EXITS buffererrors => {SetInputInhibited[lschema]; WSStringDefs.EndScan[@aqscanctxt]; DisplayBufferError[lschema, bufstatus]; }; END; -- scope-of-definition on aqscanctxt END; -- of ProcessInputChar Process3270Keyes: PUBLIC PROCEDURE [ lschema: SchemaDefs.Lschema, key: NtDefs.Special3270Key] = -- Process a 3270-unique character fron the virtual keyboard BEGIN -- If inputInhibited, only look at the RESET key, ignore all others IF GetInputStatus[lschema] = inputInhibited AND key # special3270Reset THEN { Em3270StatusDefs.DisplayCode[lschema: lschema, code: what, bvOn: TRUE]; -- turn on WHAT "?+" status RETURN; }; keyProcessor[key][lschema, key]; -- call 3270 key processing routine END; -- of Process3270Keyes ProcessFuntion: PUBLIC PROCEDURE [ lschema: SchemaDefs.Lschema, fun: NtDefs.Fun] = -- Process Star function keyes BEGIN SELECT fun FROM funCopy, funMove, funSameAs => { NfrDefs.CancelMCS[]; MessageSwnDefs.DisplayMessage[keyNotImplemented]; }; funHelp => MessageSwnDefs.DisplayMessage[keyNotImplemented]; ENDCASE => NULL; -- ignore all other function keyes END; -- of ProcessFuntion ProcessFunRepeat: PUBLIC PROCEDURE [ lschema: SchemaDefs.Lschema, cvFunrepeat: Cv, funrepeat: NtDefs.Funrepeat] = -- Process Function keyes which can repeat BEGIN THROUGH [1..cvFunrepeat] DO SELECT funrepeat FROM funTAB => MoveCursor[lschema: lschema, key: special3270Tab]; -- process TAB funBS, funBW => MoveCursor[lschema: lschema, key: special3270BackSpace]; -- process BACKSPACE funNewLine => MoveCursor[lschema: lschema, key: special3270NewLine]; -- process NEWLINE ENDCASE => EXIT; -- ignore all other repeat function keyes ENDLOOP; END; -- of ProcessFunRepeat Create: PUBLIC PROCEDURE [lschema: SchemaDefs.Lschema] = BEGIN MYdata: Lpttrt3270schemadata ← TraitDefs.MyData[lschema, trt3270schema]; emdata: LONG POINTER TO EmHandle ← MYdata.lptEmState; emdata.putMDTStream.lptbuf ← spredefinedZone.NEW[BufOfChar]; emdata.putMDTStream.blkIx ← 0; END; Destroy: PUBLIC PROCEDURE [lschema: SchemaDefs.Lschema] = BEGIN MYdata: Lpttrt3270schemadata ← TraitDefs.MyData[lschema, trt3270schema]; emdata: LONG POINTER TO EmHandle ← MYdata.lptEmState; firstPutBuf: LptBufOfChar ← emdata.putMDTStream.lptbuf; IF firstPutBuf.nextBuf = NIL THEN spredefinedZone.FREE[@firstPutBuf] -- free the first block only ELSE FreeBuf[firstPutBuf]; -- free all blocks emdata.putMDTStream ← [NIL, 0]; END; ResetAIDStatus: PUBLIC PROCEDURE [lschema: SchemaDefs.Lschema] = BEGIN -- reset the AID and free all blocks except for first block which is permanent till end of session. MYdata: Lpttrt3270schemadata ← TraitDefs.MyData[lschema, trt3270schema]; emdata: LONG POINTER TO EmHandle ← MYdata.lptEmState; firstPutBuf: LptBufOfChar ← emdata.putMDTStream.lptbuf.nextBuf; IF firstPutBuf # NIL THEN FreeBuf[firstPutBuf]; -- free all but the first block. emdata.putMDTStream.lptbuf.nextBuf ← NIL; SetAIDStatus[lschema,TRUE]; -- no-AID-generated RETURN; END; END. -- of Em3270UserInputPack LOG March 14, 1982 - Kernaghan - Created Em3270UserInputPack. March 20, 1982 - Kernaghan - Fix bug in BuildFieldStream whch was storing the attribute address instead of the attribute+1. March 26,1982 - Kernaghan - Removed keyboard interrputation stubs now that the actual 3270 virtual keyboards & Code are available. March 30 - Kernaghan - Rplaced SchemaDefs.CancelMCS with NfrDefs.CancelMCS inside of ProcessFuntion to properly handle the "ignoring" of *funCopy, funMove, funSameAs*. March 30 - Kernaghan - Added DisplayBufferError to handle buffer errors better and replaced code in various places that gets Em3270BufferDefs.WriteError returned to it. 23-Jun-82 18:11:50 - Lui - fixed abug in DoReadMod, was calling Em3270ComDefs.DoStreamPut with last buffer instead of pointer to head of chain. 24-Jun-82 9:47:50 - Lui - Added SchemaUtilDefs. 13-Jul-82 13:08:40 - Lui - removed TextHiliteDefs. 4-Aug-82 15:16:41 - Lui - fix buffer not reserved/released bug. removed Em3270BufferDefs.Reserve/Release from AID PROC. 4-Aug-82 15:30:11 - Lui - Added dded codes to DoButUpInDataArea for implementing ghost cursor. changed ALTCursor to incorporate all various cursor shape. 31-Aug-82 15:15:46 - Lui - Modified DoMoveOrCopy, and PvFieldHit to provide support multiNational. 9-Sep-82 17:53:11 - Lui - changed hostLang to lptToTransFile 29-Sep-82 15:08:32 - Lui - replaced seltype3270 with GetSelType. 14-Dec-82 17:05:24 - Lui - replaced NfrDefs.CancelMCS with SchemaDefs.CancelMCS 16-Dec-82 11:40:53 - Lui - undo previous action 18-Feb-83 12:19:55 - Lui - moved posting of message after called to NfrDefs.CancelMCS instead of before. 22-Feb-83 13:27:58 - Lui - removed called to DehiliteSeldesc in DoMoveOrCopy. AR 10780 9-Mar-83 11:06:19 - Lui - edited DoMoveOrCopy. AR #1354 30-Jun-83 14:09:16 - Lui - support for Read Modified. 5-Oct-83 16:52:02 - Lui - replace session zone with short zone.