/*++ Copyright (c) 1989 Microsoft Corporation Module Name: kbdrqust.c Abstract: This module contains the Kbd requests thread and the handler for Kbd requests. Author: Michael Jarus (mjarus) 23-Oct-1991 Environment: User Mode Only Revision History: --*/ #define WIN32_ONLY #include "os2ses.h" #include "trans.h" #include "event.h" #include "kbd.h" #include "os2win.h" #include #define OS2_SCAN_INSERT_0 0x52 #define OS2_SCAN_END_1 0x4F #define OS2_SCAN_CTRL_END_1 0x75 #define OS2_SCAN_DOWN_2 0x50 #define OS2_SCAN_LEFT_4 0x4B #define OS2_SCAN_CTRL_LEFT_4 0x73 #define OS2_SCAN_RIGHT_6 0x4D #define OS2_SCAN_CTRL_RIGHT_6 0x74 #define OS2_SCAN_HOME_7 0x47 #define OS2_SCAN_CTRL_HOME_7 0x77 #define OS2_SCAN_UP_8 0x48 #define OS2_SCAN_DEL 0x53 DWORD Ow2GetOs2KbdEventIntoQueue(); DWORD Ow2VioUpdateCurPos( IN COORD CurPos ); DWORD Ow2VioReadCurPos( ); DWORD Ow2VioReadCurType(); VOID KbdSetTable( IN ULONG KbdCP ); #if DBG BYTE KbdEchoCharToConsoleStr[] = "KbdEchoCharToConsole"; BYTE KbdEchoCharStr[] = "KbdEchoChar"; BYTE KbdEchoStringToConsoleStr[] = "KbdEchoStringToConsole"; BYTE KbdEchoAStringStr[] = "KbdEchoAString"; BYTE KbdEchoBSAndFillSpacesStr[] = "KbdEchoBSAndFillSpaces"; BYTE KbdEchoESCStr[] = "KbdEchoESC"; BYTE KbdCueMoveToRightStr[] = "KbdCueMoveToRight"; #endif #define KEYBOARD_NEW_MASK (USHORT)(KEYBOARD_2B_TURNAROUND | KEYBOARD_SHIFT_REPORT) #define KEYBOARD_ECHO (USHORT)(KEYBOARD_ECHO_ON | KEYBOARD_ECHO_OFF) #define KEYBOARD_INPUT (USHORT)(KEYBOARD_ASCII_MODE | KEYBOARD_BINARY_MODE) #define KEYBOARD_BINARY_SHIFT (KEYBOARD_BINARY_MODE | KEYBOARD_SHIFT_REPORT) #define MODE_BINARY_SHIFT (SHIFT_REPORT_MODE | BINARY_MODE) #define KEYBOARD_SHIFT_ASCII_INPUT (USHORT)(KEYBOARD_ASCII_MODE | KEYBOARD_SHIFT_REPORT) #define KEYBOARD_INPUT_RESERVED \ ~( KEYBOARD_ECHO_ON | KEYBOARD_ECHO_OFF | KEYBOARD_BINARY_MODE | \ KEYBOARD_ASCII_MODE | KEYBOARD_MODIFY_STATE | KEYBOARD_MODIFY_INTERIM | \ KEYBOARD_MODIFY_TURNAROUND | KEYBOARD_2B_TURNAROUND | KEYBOARD_SHIFT_REPORT ) #define KbdBuffSize 256 #define KBD_BUFFER_ADDRESS ((PUCHAR)KbdAddress) // used for ECHO to console #define KBD_BUFFER_SIZE OS2_KBD_PORT_MSG_SIZE #define ALPHANUM_CHAR(BuffIndex) \ ((((Char = LineInputBuff[BuffIndex].Char) >= '0') && \ (Char <= '9')) || \ ((Char >= 'a') && (Char <= 'z')) || \ ((Char >= 'A') && (Char <= 'Z'))) \ #define GET_CURRENT_COORD (SesGrp->WinCoord) typedef struct _LINE_EDIT_KBD { UCHAR Char; SHORT X_Pos; // Used as X Coordinate for edit // Used as offset for CUE } LINE_EDIT_KBD; typedef enum { CharMode, AsciiMode, BinaryMode } KBDMODE; //CONSOLE_SCREEN_BUFFER_INFO KbdConsoleInfo; KBDMODE KbdState; // state for HandleKeyboardInput ULONG KbdWaitFlag; // flags for KbdCheckPackage and // arg to GetKeyboardInput /* (from event.h) CharIn Peek String Read ------ ---- ------ ---- WAIT_MASK 0x01 User NOWAIT User WAIT (0 IO_WAIT, 1 IO_NOWAIT) ENABLE_SHIFT_KEY 0x02 ENABLE_NON_ASCII_KEY 0x04 + + ENABLE_LN_EDITOR_KEY 0x08 ENABLE_KEYS_ON_KEY 0x10 */ #define ENABLE_SHIFT_KEY 0x02 /* enable shift report keys (and break for them) */ /* * for Command line editing */ PUCHAR KbdCueBuffer = NULL; // 64K CUE buffer for KEYS ON // This is a cyclic bufffer and all // pointers are index of type USHORT. BOOL KbdLineWasEdited; // TRUE if user edited the current line USHORT KbdNextLinePointer; // where to put next input line USHORT KbdCurrentLine; // index of current line in KbdCueBuffer USHORT KbdIndexInLine; // index of current char in input line BOOL KbdCueUpRowIsCurrent; // flag set after CR to indicate UP arrow // returns the current line /* * for GetOs2KbdRead */ USHORT KbdBuffNextPtr; // when string typed was longer the size (ASCII read only) // it points to the remain string USHORT KbdBuffNextLen; // remaining bytes in the string /* * for for HandleKeyboardInput.CharMode: */ BOOL KbdPeekFlag; // called by CharIn (0) or Peek(1) /* * for for HandleKeyboardInput.Ascii/BinaryMode: */ USHORT KbdInputLength; // the current string length (num of chars // already in input buffer for the user) ULONG KbdMaxLength; // maximun input length (String.cb // for StringIn, KbdBuffSize for Read) USHORT KbdLength; // On enter: the requested length, // On exit: the returned string length USHORT KbdEndLength; // length of Turn Around string /* * for for HandleKeyboardInput.AsciiMode: */ LINE_EDIT_KBD LineInputBuff[KbdBuffSize]; // the current input buffer UCHAR KbdLastBuff[KbdBuffSize]; // holds the previous "Buff" USHORT KbdLastBuffPtr; // points to the char in KbdLastBuff to take (if F1) USHORT LastStringLength; // length of the previous "Buff" USHORT KbdEditFlag; // support EDIT line (F1 .. F4, ->, <-, Ins, Del) USHORT KbdReadMode; // called by StringIn (0) or Read(1) USHORT KbdFxWaitForChar; // waiting for char after F2(1) or F4(2) BOOL KbdEchoFlag; // set if ECHO ON BOOL KbdInsertOn; // INSERT key current state (1 - ON) BOOL KbdEchoString; // copy string from last buffer (F2 and F3) USHORT KbdTurnAroundChar; // turn around char to look for BOOLEAN KbdTurnAroundCharTwo; // 2-byte turn around char (KEYBOARD_2B_TURNAROUND) USHORT KbdDelIndex; SHORT KbdFirstColumn; // first column for this input request SHORT KbdStartOfLine; // first column on this line BOOLEAN KbdSetupTurnAroundCharTwo; // KbsSetStatus of KbdTurnAroundCharTwo: // before new read KbdTurnAroundCharTwo // is updated from this. #ifdef JAPAN // MSKK May.07.1993 V-AkihiS /* * for KBDGetKbdType */ extern USHORT KbdType, KbdSubType; extern BYTE OemId, OemSubType; #endif /* * internal functions */ DWORD GetOs2KbdKey( IN BOOL PeekFlag, IN USHORT WaitFlag, OUT PKBDKEYINFO KeyInfo, IN PVOID pMsg, OUT PULONG pReply ); DWORD GetOs2KbdString( IN USHORT WaitFlag, IN OUT PKBDREQUEST PReq, IN PVOID pMsg, OUT PULONG pReply ); DWORD GetOs2KbdRead( IN PULONG Length, IN PVOID pMsg, OUT PULONG pReply ); VOID KbdNewSetup( IN PKBDINFO LastSetup ); DWORD GetOs2KbdStringRead( IN USHORT WaitFlag, IN USHORT EditFlag, IN USHORT ReadMode, IN ULONG MaxLength, IN OUT PUSHORT Length, IN PVOID pMsg, OUT PULONG pReply ); DWORD HandleKeyboardInput( IN PKEYEVENTINFO pKbd ); DWORD Ow2KbdSetStatus( IN PKBDREQUEST PReq ); BOOL KbdKeyIsTurnAround( IN UCHAR Char, IN UCHAR Scan ); /* * Echo functions for KbdStringIn/Read (ASCII) */ DWORD KbdEchoNL( IN ULONG Count ); DWORD KbdEchoESC( IN ULONG Count, IN ULONG HorzMove ); DWORD KbdEchoBSAndFillSpaces( IN ULONG BSCount, IN ULONG SpaceCount ); DWORD KbdEchoBeep( IN ULONG Count ); DWORD KbdEchoChar( IN UCHAR Char, IN ULONG Count ); DWORD KbdEchoAString( IN PUCHAR String, IN ULONG Length ); /* * CUE functions */ VOID KbdCueEraseAndDisplayLine( IN ULONG NewLineIndex ); VOID KbdCueMoveToRight( IN ULONG StartIndex, IN ULONG StringLength, IN ULONG UpdateLVB ); VOID KbdCueMoveToLeft( IN ULONG StartIndex, IN ULONG MoveLength ); VOID KbdCueUpdateBufferOffset( IN ULONG StartIndex, IN ULONG StringLength, IN ULONG StartOffset ); VOID KbdCueDeleteCharAndShift( IN ULONG StartIndex, IN ULONG NumChar ); VOID KbdCueHandleChar( IN UCHAR Char, IN ULONG Count ); VOID KbdCueSetCurTypeToHalf(); VOID KbdCueSetCurTypeToQuater(); DWORD KbdInit(IN VOID) { KBDINFO LastSetup; if (InitQueue(&KbdQueue)) { return(TRUE); } KbdMonQueue = PhyKbdQueue = KbdQueue; KbdQueue->Setup.cb = sizeof(KBDINFO); KbdQueue->Setup.fsMask = KEYBOARD_ECHO_ON | KEYBOARD_ASCII_MODE; KbdQueue->Setup.chTurnAround = 0x0D; /* default: / */ KbdQueue->Setup.fsInterim = 0; KbdQueue->Setup.fsState = 0; KbdQueue->bNlsShift = 0; KbdQueue->LastKeyFlag = FALSE; LastSetup.fsMask = KEYBOARD_BINARY_MODE; KbdNewSetup(&LastSetup); KbdAddress = ((PCHAR)Os2SessionCtrlDataBaseAddress) + KBD_OFFSET; Ow2KbdXlateVars.OtherFlags = InterruptTime; return(FALSE); } DWORD KbdInitAfterSesGrp(IN VOID) { if (SesGrp->KeysOnFlag) { KbdCueBuffer = HeapAlloc(HandleHeap, 0, 64 * 1024); if ( KbdCueBuffer == NULL ) { #if DBG KdPrint(("OS2SES(KbdRequset): unable to allocate Cue buffer\n")); #endif return ERROR_KBD_NO_MORE_HANDLE; } } return(FALSE); } BOOL ServeKbdRequest(IN PKBDREQUEST PReq, OUT PVOID PStatus, IN PVOID pMsg, OUT PULONG pReply) { DWORD Rc; KBDINFO LastSetup; PKEY_EVENT_QUEUE TempKbdQueue; KEYEVENTINFO In; Rc = 0; TempKbdQueue = (PKEY_EVENT_QUEUE) PReq->hKbd; #if DBG if (( PReq->Request != KBDNewFocus ) && ( PReq->Request != KBDNewCountry ) && ( PReq->Request != KBDOpen ) && (KbdQueue != TempKbdQueue)) { KdPrint(("OS2SES(KbdRequest-%u): illegal handle\n", PReq->Request)); } #endif switch (PReq->Request) { case KBDOpen: if((Rc = InitQueue(&TempKbdQueue)) == NO_ERROR) { PReq->hKbd = TempKbdQueue; } break; case KBDClose: if (( TempKbdQueue != PhyKbdQueue) && TempKbdQueue->Count ) { if ( !--TempKbdQueue->Count ) { HeapFree(HandleHeap, 0, (LPSTR) TempKbdQueue->MonHdr.MemoryStartAddress); } } break; case KBDDupLogHandle: if (TempKbdQueue != PhyKbdQueue) { TempKbdQueue->Count++ ; } break; case KBDReadStdIn: if (!hStdInConsoleType) { #if DBG KdPrint(("OS2SES(KbdRequest-KbdReadStdIn): illegal request\n")); #endif Rc = ERROR_INVALID_HANDLE; break; } // falls into KBDRead case KBDRead: Rc = GetOs2KbdRead(&PReq->Length, pMsg, pReply); break; case KBDCharIn: Rc = GetOs2KbdKey(0, /* CharIn/Peek flag */ (USHORT)PReq->fWait, &PReq->d.KeyInfo, pMsg, pReply); break; case KBDStringIn: Rc = GetOs2KbdString((USHORT)PReq->fWait, PReq, pMsg, pReply); break; case KBDPeek: Rc = GetOs2KbdKey(1, /* CharIn/Peek flag */ IO_NOWAIT, &PReq->d.KeyInfo, pMsg, pReply); break; case KBDFlushBuffer: In.wRepeatCount = 0x7FFF; while (TRUE) { KbdQueue->LastKeyFlag = FALSE; KbdQueue->Out == KbdQueue->In; Rc = GetKeyboardInput( IO_NOWAIT, &In, pMsg, pReply); if ( !Rc ) /* no char & NO_WAIT */ break; } break; case KBDGetStatus: if (PReq->d.KbdInfo.cb < 10 ) { Rc = ERROR_KBD_INVALID_LENGTH; break; } Ow2GetOs2KbdEventIntoQueue(); PReq->d.KbdInfo = KbdQueue->Setup; #ifdef DBCS // MSKK May.18.1992 KazuM GetNlsMode(&KbdQueue->Setup); #endif PReq->d.KbdInfo.fsState &= KBDINFO_STATE_MASK; break; case KBDSetStatus: Rc = Ow2KbdSetStatus(PReq); break; case KBDFreeFocus: LastSetup = KbdQueue->Setup; KbdQueue = PhyKbdQueue; NewKbdQueue(KbdQueue); KbdNewSetup(&LastSetup); break; case KBDNewFocus: LastSetup = KbdQueue->Setup; KbdQueue = TempKbdQueue; NewKbdQueue(KbdQueue); KbdNewSetup(&LastSetup); break; // BUGBUG?? - do the following requests working on the current/last-focused // logical keyboard, on the physical keyboard or on a logical // keyboard passed as a parameter case KBDGetInputMode: switch (KbdQueue->Setup.fsMask & KEYBOARD_BINARY_SHIFT) { case KEYBOARD_BINARY_SHIFT: PReq->d.InputMode = MODE_BINARY_SHIFT; break; case KEYBOARD_BINARY_MODE: PReq->d.InputMode = BINARY_MODE; break; default: PReq->d.InputMode = ASCII_MODE; break; } break; case KBDGetInterimFlag: #ifdef DBCS // MSKK May.18.1992 KazuM GetNlsMode(&KbdQueue->Setup); #endif PReq->d.Interim = (UCHAR)(KbdQueue->Setup.fsInterim & (CONVERSION_REQUEST | INTERIM_CHAR)); break; case KBDGetKbdType: #ifdef JAPAN // MSKK May.07.1993 V-AkihiS if (KbdType == KBD_TYPE_JAPAN && OemId == SUB_KBD_TYPE_MICROSOFT) { switch(OemSubType) { case MICROSOFT_KBD_101_TYPE: PReq->d.KbdType[0] = 0x0001; PReq->d.KbdType[1] = 0x0000; PReq->d.KbdType[2] = 0x0000; break; case MICROSOFT_KBD_AX_TYPE: PReq->d.KbdType[0] = 0x0010; PReq->d.KbdType[1] = 0x0000; PReq->d.KbdType[2] = 0x0001; break; case MICROSOFT_KBD_106_TYPE: PReq->d.KbdType[0] = 0x0001; PReq->d.KbdType[1] = 0x82B3; PReq->d.KbdType[2] = 0x0032; break; case MICROSOFT_KBD_002_TYPE: PReq->d.KbdType[0] = 0x0006; PReq->d.KbdType[1] = 0x82B3; PReq->d.KbdType[2] = 0x0032; break; default: PReq->d.KbdType[0] = 0x0001; PReq->d.KbdType[1] = 0x0000; PReq->d.KbdType[2] = 0x0000; #if DBG KdPrint(("OS2SES(Kbd) This keyboard isn't supported yet.\n")); #endif } } else { PReq->d.KbdType[0] = 0x0001; PReq->d.KbdType[1] = 0x0000; PReq->d.KbdType[2] = 0x0000; #if DBG KdPrint(("OS2SES(Kbd) This keyboard isn't supported yet.\n")); #endif } #else PReq->d.KbdType = 0x0001; // BUGBUG #endif break; case KBDGetHotKey: // BUGBUG PReq->d.HotKey = /* if ((*pParm != HOTKEY_MAX_COUNT) && (*pParm != HOTKEY_CURRENT_COUNT)) { } #define HOTKEY_MAX_COUNT 0x0000 #define HOTKEY_CURRENT_COUNT 0x0001 */ break; case KBDGetShiftState: #ifdef DBCS // MSKK Oct.20.1992 V-AkihiS GetNlsMode(&KbdQueue->Setup); PReq->d.Shift.fNLS = HIBYTE(KbdQueue->Setup.fsInterim); #else PReq->d.Shift.fNLS = KbdQueue->bNlsShift; #endif PReq->d.Shift.fsState = KbdQueue->Setup.fsState; break; case KBDSetInputMode: LastSetup = KbdQueue->Setup; KbdQueue->Setup.fsMask = (USHORT) ((KbdQueue->Setup.fsMask & ~(KEYBOARD_INPUT | KEYBOARD_SHIFT_REPORT)) | ((PReq->d.InputMode & SHIFT_REPORT_MODE) ? KEYBOARD_SHIFT_REPORT : 0) | ((PReq->d.InputMode & BINARY_MODE ) ? KEYBOARD_BINARY_MODE : KEYBOARD_ASCII_MODE)); KbdNewSetup(&LastSetup); break; case KBDSetShiftState: LastSetup = KbdQueue->Setup; KbdQueue->Setup.fsState = PReq->d.Shift.fsState; // BUGBUG : SHIFTSTATE.fbNLS PReq->d.Shift.fNLS #ifdef DBCS // MSKK Oct.20.1992 V-AkihiS KbdQueue->Setup.fsInterim = MAKEWORD( KbdQueue->Setup.fsInterim, PReq->d.Shift.fNLS ); SetNlsMode(KbdQueue->Setup); #endif KbdNewSetup(&LastSetup); break; case KBDSetTypamaticRate: Rc = !SystemParametersInfo( SPI_SETKEYBOARDDELAY, PReq->d.RateDelay.usDelay, NULL, 0); if (!Rc) { Rc = !SystemParametersInfo( SPI_SETKEYBOARDSPEED, PReq->d.RateDelay.usRate, NULL, 0 ); } break; case KBDSetInTerimFlag: LastSetup = KbdQueue->Setup; #ifdef DBCS // MSKK Mar.03.1993 V-AkihiS KbdQueue->Setup.fsInterim = MAKEWORD( PReq->d.Interim, HIBYTE(KbdQueue->Setup.fsInterim) ); SetNlsMode(KbdQueue->Setup); #else KbdQueue->Setup.fsInterim = (USHORT)PReq->d.Interim; #endif KbdNewSetup(&LastSetup); break; case KBDGetCp: PReq->d.CodePage = SesGrp->KbdCP; break; case KBDSetCp: Rc = KbdNewCp(PReq->d.CodePage); break; case KBDNewCountry: SesGrp->KeyboardCountry = PReq->d.CodePage; //Hack - Not Really CodePage KbdSetTable(SesGrp->KbdCP); *pReply = 0; break; case KBDXlate: /* { KBD_XLATE_VARS XlateVars; KBD_MON_PACKAGE KeyInfo[3]; PKBDTRANS pKbdXlate = &PReq->d.KbdTrans; RtlZeroMemory(&XlateVars, sizeof(KBD_XLATE_VARS)); if (pKbdXlate->fsShift != 0) { // continue translation //? = pKbdXlate->fsShift; } RtlZeroMemory(&Os2KeyInfo[0], 3 * sizeof(KBD_MON_PACKAGE)); //KeyInfo[0].MonitorFlag = pKbdXlate->...; //KeyInfo[0].DeviceFlag = pKbdXlate->...; KeyInfo[0].KeyInfo.chChar = pKbdXlate->chChar; KeyInfo[0].KeyInfo.chScan = pKbdXlate->chScan; KeyInfo[0].KeyInfo.fbStatus = pKbdXlate->fbStatus; KeyInfo[0].KeyInfo.bNlsShift = pKbdXlate->bNlsShift; KeyInfo[0].KeyInfo.fsState = pKbdXlate->fsState; KeyInfo[0].KeyBoardFlag = pKbdXlate->fsDD; KeyInfo[0].KeyInfo.fbStatus = 0x40; //? XlateVars.XlateFlags |= SecPrefix; // Have seen E0 prefix Rc = Ow2KbdXlate( pKbdXlate->chScan, // ScanCode, &XlateVars, // pFlagArea, &KeyInfo[0], // pMonitorPack, Ow2KbdScanTable // pTransTable ); //? which packet - KeyInfo[?] pKbdXlate->chChar = KeyInfo[0].KeyInfo.chChar; pKbdXlate->chScan = KeyInfo[0].KeyInfo.chScan; pKbdXlate->fbStatus = KeyInfo[0].KeyInfo.fbStatus; pKbdXlate->bNlsShift = KeyInfo[0].KeyInfo.bNlsShift; pKbdXlate->fsState = KeyInfo[0].KeyInfo.fsState; pKbdXlate->fsDD = KeyInfo[0].KeyBoardFlag; //? pKbdXlate->fsXlate = ; //? pKbdXlate->fsShift = ; } */ case KBDSetCustXt: /* from ??? */ default: Rc = (DWORD)-1L; //STATUS_INVALID_PARAMETER; #if DBG IF_OD2_DEBUG2( KBD, OS2_EXE ) KdPrint(("OS2SES(KbdRequest): Unknown Kbd request = %X\n", PReq->Request)); #endif } if ( Rc == 1 ) { Rc = GetLastError(); } *(PDWORD) PStatus = Rc; return(TRUE); // Continue } DWORD Ow2KbdSetStatus(IN PKBDREQUEST PReq) { KBDINFO LastSetup, *pKbdSetup; USHORT KbdMask, Mask; /* * check legalty of parameters: * * 1. sizeof structure * 2. reserved bits * 3. mutuex bits (ECHO_ON & ECHO_OFF, ASCII & BINARY, ASCII & SHIFT) */ LastSetup = KbdQueue->Setup; if (PReq->d.KbdInfo.cb != 10 ) { return ERROR_KBD_INVALID_LENGTH; } KbdMask = PReq->d.KbdInfo.fsMask; pKbdSetup = &KbdQueue->Setup; if (KbdMask & KEYBOARD_INPUT_RESERVED) { return ERROR_KBD_INVALID_INPUT_MASK; } if ((KbdMask & KEYBOARD_ECHO ) == KEYBOARD_ECHO) { return ERROR_KBD_INVALID_ECHO_MASK; } if ((KbdMask & KEYBOARD_INPUT) == KEYBOARD_INPUT) { return ERROR_KBD_INVALID_INPUT_MASK; } if ((KbdMask & KEYBOARD_SHIFT_ASCII_INPUT) == KEYBOARD_SHIFT_ASCII_INPUT) { return ERROR_KBD_INVALID_INPUT_MASK; } /* * check modified bits and set the flags according: * * 1. STATE - set fsState * 2. INTERIM - set fsInterim * 3. TURNAROUND - set chTurnAround */ #ifdef DBCS // MSKK Jul.1993 V-AKihiS if (KbdMask & KEYBOARD_MODIFY_STATE) { pKbdSetup->fsState = PReq->d.KbdInfo.fsState; pKbdSetup->fsInterim = MAKEWORD( LOBYTE(pKbdSetup->fsInterim), HIBYTE(PReq->d.KbdInfo.fsInterim) ); SetNlsMode(*pKbdSetup); } if (KbdMask & KEYBOARD_MODIFY_INTERIM) pKbdSetup->fsInterim = MAKEWORD( LOBYTE(PReq->d.KbdInfo.fsInterim), HIBYTE(pKbdSetup->fsInterim) ); #else if (KbdMask & KEYBOARD_MODIFY_STATE) pKbdSetup->fsState = PReq->d.KbdInfo.fsState; if (KbdMask & KEYBOARD_MODIFY_INTERIM) pKbdSetup->fsInterim = PReq->d.KbdInfo.fsInterim; #endif if (KbdMask & KEYBOARD_MODIFY_TURNAROUND) pKbdSetup->chTurnAround = PReq->d.KbdInfo.chTurnAround; /* * update mask: * * 1. update mask of new bits SHIFT_REPORT & 2B_TURNAROUND * 2. if new mask includes new ECHO then update mask * 3. if new mask includes new INPUT then update mask */ Mask = KEYBOARD_NEW_MASK; if (KbdMask & KEYBOARD_ECHO) { Mask |= KEYBOARD_ECHO; } if (KbdMask & KEYBOARD_INPUT) { Mask |= KEYBOARD_INPUT; } pKbdSetup->fsMask = (pKbdSetup->fsMask & ~Mask) | (KbdMask & Mask); KbdNewSetup(&LastSetup); return (0L); } DWORD GetOs2KbdKey( IN BOOL PeekFlag, IN USHORT WaitFlag, OUT PKBDKEYINFO KeyInfo, IN PVOID pMsg, OUT PULONG pReply) /*++ Routine Description: This routine get kbd char for KbdCharIn and KbdPeek Arguments: PeekFlag - TRUE if peek (0 - CharIn, 1 - Peek) WaitFlag - Wait if no input (IO_WAIT or IO_NOWAIT) KeyInfo - Where to return the key input record pMsg - Pointer to the LPC message pReply - Pointer to flag if return reply on LPC Return Value: Note: If no event and IO_WAIT: save pMsg, put 0 into *pReply and the reply is postponed. --*/ { DWORD Rc; KEYEVENTINFO In; RtlZeroMemory(KeyInfo, sizeof(KBDKEYINFO)); KeyInfo->fsState = 1; if ( KbdQueue->Setup.fsMask & KEYBOARD_ASCII_MODE ) { KbdAsciiMode = 1; } else { KbdAsciiMode = 0; if ((KbdQueue->Setup.fsMask & KEYBOARD_BINARY_SHIFT) == KEYBOARD_BINARY_SHIFT) { WaitFlag |= ENABLE_SHIFT_KEY; } } WaitFlag |= ENABLE_NON_ASCII_KEY; KbdState = CharMode; KbdWaitFlag = (ULONG)WaitFlag; KbdPeekFlag = PeekFlag; for(;;) { if (KbdQueue->LastKeyFlag) { In = KbdQueue->LastKey; KbdQueue->LastKeyFlag = FALSE; } else { In.wRepeatCount = 0x7FFF; Rc = GetKeyboardInput( KbdWaitFlag, &In, pMsg, pReply); if ( !Rc ) /* no char & (NO_WAIT or postponed reply) */ return(Rc); } if (( HandleKeyboardInput( &In )) == NO_ERROR ) { *KeyInfo = In.KeyInfo[0].KeyInfo; return(0L); } } } DWORD GetOs2KbdString( IN USHORT WaitFlag, //IN OUT KBDRW *Length, IN OUT PKBDREQUEST PReq, IN PVOID pMsg, OUT PULONG pReply) { DWORD Rc; USHORT EditFlag = 0; STRINGINBUF String = PReq->d.String; KbdAsciiMode = (BOOL)(( KbdQueue->Setup.fsMask & KEYBOARD_ASCII_MODE ) ? 1 : 0); if ( String.cchIn && ( String.cchIn <= String.cb ) && ( KbdLastBuff[String.cchIn] == '\r' )) { EditFlag = 1; } String.cchIn = String.cb; Rc = GetOs2KbdStringRead( WaitFlag, EditFlag, 0, (ULONG)String.cb, &String.cchIn, pMsg, pReply); if ( pReply ) { PReq->Length = (ULONG)KbdLength; String.cchIn = KbdLength; if ( String.cchIn != String.cb ) PReq->Length++ ; // ASCII mode - copy the CR } return(Rc); } DWORD GetOs2KbdRead(IN PULONG Length, IN PVOID pMsg, OUT PULONG pReply) { DWORD Rc, i; KbdAsciiMode = (BOOL)(( KbdQueue->Setup.fsMask & KEYBOARD_ASCII_MODE ) ? 1 : 0); /* * ignore previously-typed-but-not-returned character in binary mode */ if ( !KbdAsciiMode || !KbdBuffNextLen) { Rc = GetOs2KbdStringRead( IO_WAIT, TRUE, 1, KbdBuffSize - 2, (PUSHORT)Length, pMsg, pReply); return(Rc); } /* * * Copy from kbd buffer * */ if (*Length > (ULONG)KbdBuffNextLen) *Length = KbdBuffNextLen; for (i = 0 ; i < *Length ; i++ ) { if ((KBD_BUFFER_ADDRESS[i] = KbdLastBuff[i + KbdBuffNextPtr]) == '\n') { *Length = i + 1; break; } } KbdBuffNextLen -= *((PUSHORT)Length); KbdBuffNextPtr += (USHORT)*Length; return(0L); } DWORD GetOs2KbdStringRead(IN USHORT WaitFlag, IN USHORT EditFlag, IN USHORT ReadMode, IN ULONG MaxLength, IN OUT PUSHORT Length, IN PVOID pMsg, OUT PULONG pReply) /*++ Routine Description: This routine get kbd string for KbdStringIn and Read("KBD$" or non-redirected STD-IN). Arguments: WaitFlag - Wait if no input (IO_WAIT or IO_NOWAIT) EditFlag - TRUE if edit last line(0/1 according to cchIn - StringIn, 1 - Read) ReadMode - Called by StringIn (0) or Read(1) MaxLength - Maximun input length (String.cb for StringIn, KbdBuffSize for Read) Length - On enter: the requested length, on exit: the returned string length (String.cchIn for StringIn, Length field in LPC for Read) pMsg - Pointer to the LPC message pReply - Pointer to flag if return reply on LPC Return Value: Note: If no event and IO_WAIT: save pMsg, put 0 into *pReply and the reply is postponed. --*/ { KEYEVENTINFO In; DWORD Rc; KbdLastBuffPtr = KbdInputLength = KbdFxWaitForChar = KbdDelIndex = 0; KbdIndexInLine = 0; KbdInsertOn = KbdEchoString = KbdLineWasEdited = FALSE; //KbdSecondTurnAround = KbdEndFlag = FALSE; KbdLength = *Length; if ( KbdAsciiMode ) { /* * ASCII mode */ KbdWaitFlag = (ULONG)(WaitFlag | ENABLE_LN_EDITOR_KEY); /* * * Get Start Cursor-Position * */ // force SesGrp->WinCoord and CurType params to get updated Ow2VioReadCurPos(); Ow2VioReadCurType(); if (SesGrp->KeysOnFlag) { KbdWaitFlag |= ENABLE_KEYS_ON_KEY; KbdCueSetCurTypeToQuater(); } KbdMaxLength = MaxLength - 1; /* leave space for the TurnAround char at the end */ KbdEndLength = 1; KbdReadMode = ReadMode; KbdEchoFlag = (BOOL)(( KbdQueue->Setup.fsMask & KEYBOARD_ECHO_ON ) ? 1 : 0); KbdTurnAroundChar = KbdQueue->Setup.chTurnAround; KbdTurnAroundCharTwo = KbdSetupTurnAroundCharTwo; //if (KbdQueue->Setup.chTurnAround & 0x80) if(KbdTurnAroundCharTwo) { KbdMaxLength--; /* need another space for 2-byte-TurnAround */ KbdEndLength++; } KbdEditFlag = EditFlag; LineInputBuff[KbdInputLength].X_Pos = KbdStartOfLine = KbdFirstColumn = GET_CURRENT_COORD.X; KbdState = AsciiMode; } else { KbdWaitFlag = (ULONG)(WaitFlag | ENABLE_NON_ASCII_KEY); KbdState = BinaryMode; } for(;;) { /* * * Restore saved Input Key if any * */ if (KbdQueue->LastKeyFlag) { In = KbdQueue->LastKey; KbdQueue->LastKeyFlag = FALSE; } else { /* * * Get Input Key if any * */ In.wRepeatCount = 0x7FFF; Rc = GetKeyboardInput( KbdWaitFlag, &In, pMsg, pReply); if ( !Rc ) /* no char & NO_WAIT */ return(Rc); } if (( HandleKeyboardInput( &In )) == NO_ERROR ) { *Length = KbdLength; return(0L); } } } DWORD HandleKeyboardInput(IN PKEYEVENTINFO pKbd) { DWORD NumChar = 0; UCHAR Char, Scan, *puchLastString; USHORT i, usIndex, StringLengthToEcho, NumBeep = 0; SHORT X_Pos, Offset; Scan = pKbd->KeyInfo[0].KeyInfo.chScan; Char = pKbd->KeyInfo[0].KeyInfo.chChar; #if DBG IF_OD2_DEBUG(KBD) { KdPrint(("HandleKeyboardInput: %s - Char %x, Scan %x, Status %x, State %x, Flag %x\n", (KbdState == CharMode) ? "CharMode" : (KbdState == AsciiMode) ? "AsciiMode" : "BinaryMode", Char, Scan, pKbd->KeyInfo[0].KeyInfo.fbStatus, pKbd->KeyInfo[0].KeyInfo.fsState, pKbd->KeyInfo[0].KeyboardFlag)); } #endif switch (KbdState) { case CharMode: if ( KbdPeekFlag || (pKbd->wRepeatCount > 1)) { KbdQueue->LastKey = *pKbd; KbdQueue->LastKeyFlag = TRUE; if (!KbdPeekFlag) { KbdQueue->LastKey.wRepeatCount--; } } return (NO_ERROR); break; case AsciiMode: KbdQueue->LastKey = *pKbd; // prepare it in case we read only one copy of the char KbdQueue->LastKey.wRepeatCount--; /* * * Handle CR (TurnAround Char) * * 1. put in buffer (if there is a room), beep otherwise * 2. echo if echo_on * 3. (READ only) add LF to CR (if there is a place) * */ if ( !KbdFxWaitForChar && KbdKeyIsTurnAround(Char, Scan) ) { if ( pKbd->wRepeatCount > 1 ) { KbdQueue->LastKeyFlag = TRUE; } if (( KbdReadMode == 1 ) && KbdInputLength && ( LineInputBuff[0].Char == 0x1A )) // ^Z { NumChar = KbdInputLength = 0; } else { NumChar = KbdInputLength; /* * Add the TurnAround char at the end of the buffer */ LineInputBuff[KbdInputLength++].Char = Char; if (KbdTurnAroundCharTwo) { if ( KbdReadMode == 1 ) { LineInputBuff[KbdInputLength - 1].Char = '\r'; Scan = '\n'; } LineInputBuff[KbdInputLength++].Char = Scan; } else if (( KbdReadMode == 1 ) && ( Char == '\r' ) && ( KbdInputLength <= (USHORT)KbdMaxLength )) { LineInputBuff[KbdInputLength++].Char = '\n'; } } /* * Echo the TurnAround char to console */ if (KbdEchoFlag && !KbdTurnAroundCharTwo) { KbdEchoNL(1); } /* * * Save string length and data in buffer for editing keys * */ for ( i = 0 ; i < KbdInputLength ; i++ ) { KbdLastBuff[i] = LineInputBuff[i].Char; } if (KbdReadMode == 0) { KbdInputLength = (USHORT)NumChar; } LastStringLength = (USHORT)NumChar; // not include the TurnAround char /* * * Copy to application buffer * */ if ( KbdLength > KbdInputLength ) KbdLength = KbdInputLength; RtlMoveMemory(KbdAddress, KbdLastBuff, KbdLength); if ( KbdReadMode == 0 ) KBD_BUFFER_ADDRESS[KbdLength] = Char; // add the CR at the end /* * * Keep info for Read in case we don't return all the string * */ KbdBuffNextPtr = KbdLength; KbdBuffNextLen = KbdInputLength - KbdLength; /* * * Copy string to CUE buffer if active * */ if ( SesGrp->KeysOnFlag ) { if( KbdLineWasEdited && NumChar ) { KbdCurrentLine = KbdNextLinePointer; for ( i = 0, usIndex = KbdNextLinePointer ; i < NumChar ; i++, usIndex++ ) { KbdCueBuffer[usIndex] = KbdLastBuff[i]; } KbdNextLinePointer = usIndex + 1; while (KbdCueBuffer[usIndex]) { // zero the end of the last string we copy the new // one on (fill with NULL till start of next line) KbdCueBuffer[usIndex++] = 0; } } KbdCueUpRowIsCurrent = TRUE; } return(0L); } /* * * Check for Speciel Keys (PFx, enhanced ...) * */ if (( Char == 0 ) || ( Char == 0xE0 )) { if (SesGrp->KeysOnFlag) { if ( Scan == OS2_SCAN_RIGHT_6 ) // Right { if (( NumChar = KbdInputLength - KbdIndexInLine ) > pKbd->wRepeatCount ) { NumChar = pKbd->wRepeatCount; } KbdCueMoveToRight( KbdIndexInLine, (USHORT)NumChar, FALSE ); } else if ( Scan == OS2_SCAN_LEFT_4 ) // Left { NumChar = ( KbdIndexInLine < pKbd->wRepeatCount ) ? KbdIndexInLine : pKbd->wRepeatCount; KbdCueMoveToLeft( KbdIndexInLine, (USHORT)NumChar ); } else if ( Scan == OS2_SCAN_UP_8 ) // Up { /* * Find previous command in the command queue */ if (KbdCueBuffer[KbdCurrentLine]) // if anything at the CUE buffer { if (KbdCueUpRowIsCurrent) { pKbd->wRepeatCount--; KbdCueUpRowIsCurrent = FALSE; } usIndex = KbdCurrentLine; for ( i = 0 ; i < pKbd->wRepeatCount ; i++ ) { usIndex--; while (!KbdCueBuffer[--usIndex]); // skip all null while (KbdCueBuffer[--usIndex]); // go to start of command usIndex++; } KbdCurrentLine = usIndex; } else { usIndex = KbdCurrentLine; } KbdCueEraseAndDisplayLine(usIndex); } else if ( Scan == OS2_SCAN_DOWN_2 ) // Down { /* * Find next command in the command queue */ if (KbdCueBuffer[KbdCurrentLine]) // if anything at the CUE buffer { usIndex = KbdCurrentLine; KbdCueUpRowIsCurrent = FALSE; for ( i = 0 ; i < pKbd->wRepeatCount ; i++ ) { while (KbdCueBuffer[++usIndex]); while (!KbdCueBuffer[++usIndex]); } KbdCurrentLine = usIndex; } else { usIndex = KbdCurrentLine; } KbdCueEraseAndDisplayLine(usIndex); } else if ( Scan == OS2_SCAN_HOME_7 ) // Home { KbdCueMoveToLeft( KbdIndexInLine, KbdIndexInLine ); } else if ( Scan == OS2_SCAN_END_1 ) // End { KbdCueMoveToRight( KbdIndexInLine, (USHORT)(KbdInputLength - KbdIndexInLine), FALSE ); } else if ( Scan == OS2_SCAN_CTRL_LEFT_4 ) // ^Left { USHORT PrevIndex = KbdIndexInLine; for ( i = 0; (i < pKbd->wRepeatCount) && PrevIndex ; i++ ) { /* for each char: * go one char left * skip all non-alphanumeric chars * akip all alphanumeric chars * while points to alpha, which is not the original */ usIndex = PrevIndex - 1; while (usIndex && !ALPHANUM_CHAR(usIndex)) { usIndex--; } while (usIndex && ALPHANUM_CHAR(usIndex)) { usIndex--; } if (usIndex || !ALPHANUM_CHAR(usIndex)) { usIndex++; } if (!ALPHANUM_CHAR(usIndex) || (PrevIndex == usIndex)) { break; } PrevIndex = usIndex; } if (NumChar = KbdIndexInLine - PrevIndex) { KbdCueMoveToLeft( KbdIndexInLine, (USHORT)NumChar ); } } else if ( Scan == OS2_SCAN_CTRL_RIGHT_6 ) // ^Right { USHORT PrevIndex = KbdIndexInLine; for ( i = 0; (i < pKbd->wRepeatCount) && (PrevIndex < KbdInputLength); i++ ) { /* for each char: * go one char right * akip all alphanumeric chars * skip all non-alphanumeric chars * while points to alpha, which is not the original */ usIndex = PrevIndex; while ((usIndex < KbdInputLength) && ALPHANUM_CHAR(usIndex)) { usIndex++; } while ((usIndex < KbdInputLength) && !ALPHANUM_CHAR(usIndex)) { usIndex++; } if ((usIndex >= KbdInputLength) || !ALPHANUM_CHAR(usIndex)) { break; } PrevIndex = usIndex; } if (NumChar = PrevIndex - KbdIndexInLine) { KbdCueMoveToRight( KbdIndexInLine, (USHORT)NumChar, FALSE ); } } else if ( Scan == OS2_SCAN_CTRL_END_1 ) // ^End { KbdLineWasEdited = TRUE; KbdEchoBSAndFillSpaces(0, LineInputBuff[KbdInputLength].X_Pos - LineInputBuff[KbdIndexInLine].X_Pos); KbdInputLength = KbdIndexInLine; } else if ( Scan == OS2_SCAN_DEL ) // Del { KbdLineWasEdited = TRUE; if (( NumChar = KbdInputLength - KbdIndexInLine ) > pKbd->wRepeatCount ) { NumChar = pKbd->wRepeatCount; } KbdCueDeleteCharAndShift( KbdIndexInLine, (USHORT)NumChar ); } else if ( Scan == OS2_SCAN_CTRL_HOME_7 ) // ^Home { if (NumChar = KbdIndexInLine) { KbdLineWasEdited = TRUE; KbdCueMoveToLeft( KbdIndexInLine, (USHORT)NumChar ); KbdCueDeleteCharAndShift( KbdIndexInLine, (USHORT)NumChar ); } } else if ( Scan == OS2_SCAN_INSERT_0 ) // Ins { if ( pKbd->wRepeatCount % 2 ) { if( KbdInsertOn = ~KbdInsertOn ) { KbdCueSetCurTypeToHalf(); } else { KbdCueSetCurTypeToQuater(); } } } break; } else { if ( KbdFxWaitForChar ) { KbdFxWaitForChar = 0; if (--pKbd->wRepeatCount) { KbdQueue->LastKey.wRepeatCount--; KbdQueue->LastKeyFlag = TRUE; } else { break; } } if ( Scan == 0x40 ) { Char = 0x1A; // F6 => ^Z } else if ( Scan == 0x41 ) { Char = 0x00; // F7 => ^@ } else if (KbdEditFlag) { if (( Scan == 0x3B ) || // F1 ( Scan == OS2_SCAN_RIGHT_6 )) // Right { KbdInsertOn = FALSE; if ((USHORT)(KbdDelIndex + KbdLastBuffPtr) < LastStringLength) { Char = KbdLastBuff[KbdDelIndex + KbdLastBuffPtr]; // => previous char } else break; } else if ( Scan == 0x3C ) // F2 { KbdInsertOn = FALSE; if (pKbd->wRepeatCount % 2) { KbdFxWaitForChar = 1; } break; } else if ( Scan == 0x3D ) // F3 { KbdInsertOn = FALSE; if ((USHORT)(KbdDelIndex + KbdLastBuffPtr) < LastStringLength) { StringLengthToEcho = LastStringLength - KbdDelIndex - KbdLastBuffPtr; KbdEchoString = TRUE; } else break; } else if ( Scan == 0x3E ) // F4 { KbdInsertOn = FALSE; if (pKbd->wRepeatCount % 2) { KbdFxWaitForChar = 2; } break; } else if ( Scan == OS2_SCAN_DEL ) // Del { KbdDelIndex += pKbd->wRepeatCount; if(KbdDelIndex > LastStringLength) { KbdDelIndex = LastStringLength; } break; } else if ( Scan == OS2_SCAN_INSERT_0 ) // Ins { if (pKbd->wRepeatCount % 2) { KbdInsertOn = ~KbdInsertOn; } break; } else if ( Scan == OS2_SCAN_LEFT_4 ) // Left { Char = '\b'; // => BS KbdInsertOn = FALSE; } else break; } else break; } } /* * * Search for char in KbdLastBuff (for F2 & F4) * */ if (KbdFxWaitForChar) { if (pKbd->wRepeatCount > 1) { KbdQueue->LastKeyFlag = TRUE; } for ( i = KbdDelIndex + KbdLastBuffPtr ; (i < LastStringLength) && (KbdLastBuff[i] != Char) ; i++ ); if ((i == (USHORT)(KbdDelIndex + KbdLastBuffPtr)) || (KbdLastBuff[i] != Char)) { KbdFxWaitForChar = 0; break; } StringLengthToEcho = i - (KbdDelIndex + KbdLastBuffPtr); if (KbdFxWaitForChar == 1) // F2 { KbdFxWaitForChar = 0; KbdEchoString = TRUE; } else // F4 { KbdDelIndex += i; KbdFxWaitForChar = 0; break; } } /* * * Echo string from KbdLastBuff (for F2 & F3) * * StringLengthToEcho - is the string length */ if (KbdEchoString) { X_Pos = GET_CURRENT_COORD.X; NumChar = 0; for ( i = KbdDelIndex + KbdLastBuffPtr, puchLastString = &KbdLastBuff[i] ; StringLengthToEcho && (KbdInputLength < (USHORT)KbdMaxLength) ; StringLengthToEcho-- ) { Char = KbdLastBuff[i++]; NumChar++ ; LineInputBuff[KbdInputLength++].Char = Char; if (Char == '\t') // TAB { X_Pos += 8 - (X_Pos % 8); } else if (Char < ' ') { X_Pos += 2; } else { X_Pos++; } if (X_Pos >= SesGrp->ScreenColNum) { X_Pos -= SesGrp->ScreenColNum; KbdStartOfLine = 0; } LineInputBuff[KbdInputLength].X_Pos = X_Pos; } if (KbdEchoFlag && NumChar) { KbdEchoAString(puchLastString, NumChar); } KbdLastBuffPtr += (USHORT)NumChar; if (StringLengthToEcho) { KbdEchoBeep(i); } KbdEchoString = FALSE; break; } /* * * Handle BS * */ if (( Char == '\b' ) || ( Char == 0x7F )) { if (SesGrp->KeysOnFlag) { if ( NumChar = KbdIndexInLine ) { if ( NumChar > pKbd->wRepeatCount ) { NumChar = pKbd->wRepeatCount; } KbdCueMoveToLeft( KbdIndexInLine, (USHORT)NumChar ); KbdCueDeleteCharAndShift( KbdIndexInLine, (USHORT)NumChar ); KbdLineWasEdited = TRUE; } break; } else { KbdInsertOn = FALSE; for ( i = 0 ; (i < pKbd->wRepeatCount) && KbdInputLength && (LineInputBuff[KbdInputLength].X_Pos != KbdStartOfLine) ; i++ ) { if (KbdLastBuffPtr) { KbdLastBuffPtr--; } else if (KbdDelIndex) { KbdDelIndex--; } KbdInputLength--; } NumChar = GET_CURRENT_COORD.X - LineInputBuff[KbdInputLength].X_Pos; if(KbdEchoFlag && NumChar) { KbdEchoBSAndFillSpaces(NumChar, NumChar); } break; } } if (!SesGrp->KeysOnFlag) { /* * * Handle LF * */ if (Char == '\n') { if (KbdEchoFlag) { KbdEchoNL(pKbd->wRepeatCount); } LineInputBuff[KbdInputLength].X_Pos = 0; KbdStartOfLine = 0; break; } /* * * Handle ^W * */ if (Char == 0x17) { USHORT PrevIndex = KbdIndexInLine; KbdInsertOn = FALSE; for ( i = 0; (i < pKbd->wRepeatCount) && ( PrevIndex > KbdStartOfLine ) ; i++ ) { /* for each char: * go one char left * skip all non-alphanumeric chars * akip all alphanumeric chars * while points to alpha, which is not the original */ usIndex = PrevIndex - 1; while (( usIndex > KbdStartOfLine ) && !ALPHANUM_CHAR(usIndex)) { usIndex--; } while (( usIndex > KbdStartOfLine ) && ALPHANUM_CHAR(usIndex)) { usIndex--; } if (( usIndex > KbdStartOfLine ) || !ALPHANUM_CHAR(usIndex)) { usIndex++; } if (!ALPHANUM_CHAR(usIndex) || (PrevIndex == usIndex)) { break; } PrevIndex = usIndex; } NumChar = LineInputBuff[KbdIndexInLine].X_Pos - LineInputBuff[PrevIndex].X_Pos ; if(KbdEchoFlag && NumChar) { KbdEchoBSAndFillSpaces(NumChar, NumChar); } KbdIndexInLine = KbdInputLength = PrevIndex; //KbdLastBuffPtr = 0; break; } } /* * * Handle ESC * */ if (Char == 0x1B) { // ^[ => Write '\' & Clear Buff KbdInsertOn = FALSE; KbdLastBuffPtr = KbdDelIndex = 0; if (SesGrp->KeysOnFlag) { if (KbdCueBuffer[KbdCurrentLine]) { usIndex = KbdCurrentLine - 1; } else { usIndex = KbdCurrentLine; } KbdCueEraseAndDisplayLine(usIndex); // don't display anything } else if (KbdEchoFlag) { KbdEchoESC(pKbd->wRepeatCount, KbdFirstColumn); } KbdStartOfLine = LineInputBuff[0].X_Pos = KbdFirstColumn; KbdInputLength = 0; break; } /* * * Handle ^F * */ if (Char == 0x6) { break; } /* * * Handle char : * * 1. put in buffer (if there is a room), beep otherwise * 2. save in buffer cursor position of next char * 3. echo if echo_on * */ NumChar = 0; if (SesGrp->KeysOnFlag) { KbdCueHandleChar(Char, pKbd->wRepeatCount); } else { X_Pos = GET_CURRENT_COORD.X; if (Char < ' ') { if (Char == '\t') // TAB { Offset = 8; X_Pos &= ~7; } else { Offset = 2; } } else { Offset = 1; } for ( i = 0 ; (i < pKbd->wRepeatCount) && (KbdInputLength < (USHORT)KbdMaxLength) ; i++ ) { if (!KbdInsertOn) { KbdLastBuffPtr++; } LineInputBuff[KbdInputLength++].Char = Char; X_Pos += Offset; if (X_Pos >= SesGrp->ScreenColNum) { X_Pos -= SesGrp->ScreenColNum; KbdStartOfLine = 0; } LineInputBuff[KbdInputLength].X_Pos = X_Pos; } if (KbdEchoFlag && i) { KbdEchoChar(Char, i); } if (i < pKbd->wRepeatCount) { KbdEchoBeep(pKbd->wRepeatCount - i); } } break; case BinaryMode: /* * * Binary mode * */ /* * * Handle char : * * put in buffer (if a place exist) * if enhanced - put also scan code * */ for ( i = 0 ; (i < pKbd->wRepeatCount) && (KbdInputLength < KbdLength); i++ ) { KBD_BUFFER_ADDRESS[KbdInputLength++] = Char; if ((Char == 0x0) && (KbdInputLength < KbdLength)) { KBD_BUFFER_ADDRESS[KbdInputLength++] = Scan; } } if ( KbdInputLength < KbdLength ) { break; } else if ( i < pKbd->wRepeatCount ) { KbdQueue->LastKey = *pKbd; // prepare it in case we read only one copy of the char KbdQueue->LastKey.wRepeatCount -= i; KbdQueue->LastKeyFlag = TRUE; } /* * * Copy to application buffer * */ if ( KbdLength > KbdInputLength ) KbdLength = KbdInputLength; /* * * Keep info for Read in case we don't return all the string * */ KbdBuffNextPtr = KbdLength; KbdBuffNextLen = KbdInputLength - KbdLength; /* * * No editing keys in binary mode * */ LastStringLength = 0; return(0L); default: break; } #if DBG IF_OD2_DEBUG( KBD ) { if ( KbdState == AsciiMode ) { USHORT CurrentIdx; CONSOLE_SCREEN_BUFFER_INFO ConsoleScreenBufferInfo; CurrentIdx = (SesGrp->KeysOnFlag) ? KbdIndexInLine : KbdInputLength; if (!GetConsoleScreenBufferInfo( hConOut, &ConsoleScreenBufferInfo )) { ConsoleScreenBufferInfo.dwCursorPosition.X = ConsoleScreenBufferInfo.dwCursorPosition.Y = 255; KdPrint(("OS2SES(Ow2VioReadCurPos): Rc %lu\n", GetLastError())); ASSERT( FALSE ); // should not happend } KdPrint(("HandleKeyboardInput: Len %u, CUE-Idx %u, Cur-Offset %u, Prev-Offset %u, Col %u, Pos %u:%u\n", KbdInputLength, KbdIndexInLine, LineInputBuff[CurrentIdx].X_Pos, (CurrentIdx) ? LineInputBuff[CurrentIdx - 1].X_Pos : 255, SesGrp->WinCoord.X, ConsoleScreenBufferInfo.dwCursorPosition.Y, ConsoleScreenBufferInfo.dwCursorPosition.X )); if (KbdEchoFlag) { ASSERT( ConsoleScreenBufferInfo.dwCursorPosition.X == SesGrp->WinCoord.X ); ASSERT( ConsoleScreenBufferInfo.dwCursorPosition.Y == SesGrp->WinCoord.Y ); ASSERT( (LineInputBuff[CurrentIdx].X_Pos % SesGrp->ScreenColNum) == SesGrp->WinCoord.X ); } } } #endif return(1L); } DWORD KbdHandlePackage(IN PKEY_EVENT_QUEUE NextKbdMon, IN PKBD_MON_PACKAGE KbdPackage) { KEYEVENTINFO In; if ( KbdCheckPackage( KbdPackage )) { return (0L); // ignore key } #ifdef DBCS // MSKK Jul.23.1992 KazuM In.wRepeatCount = NextKbdMon->In->wRepeatCount; #else In.wRepeatCount = 1; #endif In.KeyInfo[0] = *KbdPackage; if ( HandleKeyboardInput( &In )) { return (0L); // not time to send reply yet } NextKbdMon->MonHdr.WaitForEvent = FALSE; #if DBG IF_OD2_DEBUG( KBD ) { KdPrint(("KbdHandlePackage: %s respond\n", (KbdRequestSaveArea.Request == KBDCharIn) ? "KbdCharIn" : (KbdRequestSaveArea.Request == KBDStringIn) ? "KbdStringIn" : "KbdRead")); } #endif if ( KbdRequestSaveArea.Request == KBDCharIn ) { KbdRequestSaveArea.d.KeyInfo = In.KeyInfo[0].KeyInfo; SendKbdReply((PVOID)NextKbdMon->MonHdr.MemoryStartAddress, (PVOID)&KbdRequestSaveArea, KbdAddress, 0); } else { KbdRequestSaveArea.Length = (ULONG)KbdLength; if ( KbdRequestSaveArea.Request == KBDStringIn ) { KbdRequestSaveArea.d.String.cchIn = KbdLength; if ( KbdRequestSaveArea.d.String.cchIn != KbdRequestSaveArea.d.String.cb ) KbdRequestSaveArea.Length++ ; // ASCII mode - copy the CR } SendKbdReply ((PVOID)NextKbdMon->MonHdr.MemoryStartAddress, (PVOID)&KbdRequestSaveArea, KbdAddress, 0); } return (1L); } DWORD KbdCheckPackage(IN PKBD_MON_PACKAGE KbdPackage) { BOOL IgnoreKey = FALSE; UCHAR Scan, Char; Char = KbdPackage->KeyInfo.chChar; Scan = KbdPackage->KeyInfo.chScan; if (( Char == 0 ) && ( Scan == 0 )) { if(!( ENABLE_SHIFT_KEY & KbdWaitFlag )) { /* * Ignore shift keys if { in ASCII mode or shift report off } */ #if DBG IF_OD2_DEBUG(KBD) { KdPrint((" - ignore since shift report disable\n")); } #endif IgnoreKey = TRUE; // ignore shift report } else if(!( KbdPackage->KeyInfo.fbStatus & 1)) { /* * Ignore non-shift keys */ #if DBG IF_OD2_DEBUG(KBD) { KdPrint((" - ignore since non-shift key\n")); } #endif IgnoreKey = TRUE; } } else if ( KbdPackage->KeyboardFlag & KBD_KEY_BREAK ) { /* * Ignore Break if non-shift */ #if DBG IF_OD2_DEBUG( KBD ) { KdPrint(("KbdCheckPackage: ignore key release\n")); } #endif IgnoreKey = TRUE; // ignore KEY_UP } else if (( KbdWaitFlag & ENABLE_LN_EDITOR_KEY ) && KbdKeyIsTurnAround(Char, Scan) ) { // don't ignore the turn around char in ASCII mode } else if ( !( KbdWaitFlag & ENABLE_NON_ASCII_KEY ) && (( Char == 0 ) || ( Char == 0xE0 ))) { IgnoreKey = TRUE; // ignore NON_ASCII if ( KbdWaitFlag & ENABLE_KEYS_ON_KEY ) { if (( Scan == OS2_SCAN_HOME_7 ) || // Home ( Scan == OS2_SCAN_CTRL_HOME_7 ) || // ^Home ( Scan == OS2_SCAN_END_1 ) || // End ( Scan == OS2_SCAN_CTRL_END_1 ) || // ^End ( Scan == OS2_SCAN_LEFT_4 ) || // Left ( Scan == OS2_SCAN_CTRL_LEFT_4 ) || // ^Left ( Scan == OS2_SCAN_RIGHT_6 ) || // Right ( Scan == OS2_SCAN_CTRL_RIGHT_6 ) || // ^Right ( Scan == OS2_SCAN_UP_8 ) || // Up ( Scan == OS2_SCAN_DOWN_2 ) || // Down ( Scan == OS2_SCAN_DEL ) || // Del ( Scan == OS2_SCAN_INSERT_0 )) // Ins { IgnoreKey = FALSE; // don't ignore CUE keys } } else if ( KbdWaitFlag & ENABLE_LN_EDITOR_KEY ) { if (( Scan == 0x3B ) || // F1 ( Scan == 0x3C ) || // F2 ( Scan == 0x3D ) || // F3 ( Scan == 0x3E ) || // F4 ( Scan == 0x40 ) || // F6 ( Scan == 0x41 ) || // F7 ( Scan == OS2_SCAN_LEFT_4 ) || // Left ( Scan == OS2_SCAN_RIGHT_6 ) || // Right ( Scan == OS2_SCAN_DEL ) || // Del ( Scan == OS2_SCAN_INSERT_0 )) // Ins { IgnoreKey = FALSE; // don't ignore editing keys } } if (IgnoreKey) { #if DBG IF_OD2_DEBUG( KBD ) { KdPrint(("KbdCheckPackage: ignore non-ASCII key\n")); } #endif } } else if ( KbdAsciiMode ) { /* * * Ignore speciel CTRL-Keys in ASCII mode * */ if (( Char == 0x03 ) || // ^C ( Char == 0x10 ) || // ^P // ^Q: in non-US kbd(AZARTY) ^Q is passed // and ^A not (mjarus 7/5/93) (( Scan == 0x10 ) && ((KbdPackage->KeyInfo.fsState & (OS2_CONTROL | OS2_ALT)) == OS2_CONTROL)) || ( Char == 0x13 )) // ^S { #if DBG IF_OD2_DEBUG(KBD) { KdPrint((" - ignore Char %x in ASCII\n", Char)); } #endif IgnoreKey = TRUE; // ignore NON_ASCII } } return ( (DWORD)IgnoreKey ); } VOID KbdNewSetup( IN PKBDINFO LastSetup ) { PKBDINFO NewSetup = &KbdQueue->Setup; USHORT Mask; // if (*LastSetup == *NewSetup) // return; /* BUGBUG=> handle new setup */ SesGrp->ModeFlag = (USHORT)((NewSetup->fsMask & KEYBOARD_BINARY_MODE ) ? 1 : 0); Mask = NewSetup->fsMask & (KEYBOARD_BINARY_MODE | KEYBOARD_SHIFT_REPORT); Ow2KbdXlateVars.XInputMode = (Mask) ? ((Mask & KEYBOARD_SHIFT_REPORT) ? (BINARY_MODE | SHIFT_REPORT_MODE) : BINARY_MODE) : 0; if ((NewSetup->fsMask & KEYBOARD_ASCII_MODE ) && (LastSetup->fsMask & KEYBOARD_BINARY_MODE )) { LastStringLength = 0; KbdBuffNextPtr = 0; KbdBuffNextLen = 0; } KbdAsciiMode = (BOOL)(( NewSetup->fsMask & KEYBOARD_ASCII_MODE ) ? 1 : 0); if (NewSetup->fsMask & KEYBOARD_2B_TURNAROUND) { KbdSetupTurnAroundCharTwo = (BOOLEAN)TRUE; } else { KbdSetupTurnAroundCharTwo = (BOOLEAN)FALSE; } return; } VOID KbdCueEraseAndDisplayLine( IN ULONG NewLineIndex ) /*++ Routine Description: This routine erase the current input line and display new one. Arguments: NewLineIndex - pointer in CUE buffer for new line (or to NULL if nothing to diaply). Return Value: Note: ASCII CUE string mode. Used by UP-ARROW, DOWN-ARROW and ESC. 1. Erase the active command line being displayed and 2. Display the new command in the command queue. Uses: - KbdInputLength - active command line length. - KbdIndexInLine - current index in command line. - LineInputBuff[0, KbdIndexInLine, KbdInputLength].X_Pos - KbdCueBuffer[NewLineIndex..] Updates: - KbdInputLength - new line length. - KbdIndexInLine - 0. - LineInputBuff[0..KbdInputLength].Char and .X_Pos - console display - LVB - SesGrp->WinCoord - by other routines. Calls: - KbdEchoBSAndFillSpaces - KbdCueUpdateBufferOffset - KbdCueMoveToRight - KbdCueMoveToLeft --*/ { /* * Erase the active command line being displayed. */ if ( KbdInputLength ) { KbdEchoBSAndFillSpaces( LineInputBuff[KbdIndexInLine].X_Pos - LineInputBuff[0].X_Pos, LineInputBuff[KbdInputLength].X_Pos - LineInputBuff[0].X_Pos ); KbdIndexInLine = 0; KbdInputLength = 0; } /* * Display the new command in the command queue */ for ( KbdInputLength = 0 ; LineInputBuff[KbdInputLength].Char = KbdCueBuffer[NewLineIndex + KbdInputLength] ; KbdInputLength++ ); if (KbdInputLength) { KbdCueUpdateBufferOffset( 0, KbdInputLength, LineInputBuff[0].X_Pos ); KbdCueMoveToRight( 0, KbdInputLength, TRUE ); KbdCueMoveToLeft( KbdInputLength, KbdInputLength ); } } VOID KbdCueMoveToRight( IN ULONG StartIndex, IN ULONG StringLength, IN ULONG UpdateLVB ) /*++ Routine Description: This routine moves the console cursor position to the right while sending the active command line to the console. Arguments: StartIndex - index in LineInputBuff[] (the active command line) to start moving right from. StringLength - number of character to move right. UpdateLVB - flag if to set LVB also (for new info) Return Value: Note: ASCII CUE string mode. Used by RIGHT-ARROW, END, ^RIGHT-ARROW, KbdCueEraseAndDisplayLine, KbdCueDeleteCharAndShift and KbdCueHandleChar. 1. Send to console 2. Update Coord 3. Update LVB 4. Update position Uses: - LineInputBuff[0..KbdInputLength].Char and .X_Pos Updates: - KbdInputLength - NO. - KbdIndexInLine - add StringLength. - LineInputBuff[0..KbdInputLength].Char and .X_Pos - NO - console display - LVB (if UpdateLVB) - SesGrp->WinCoord - add StringLength. Calls: - Or2WinWriteConsoleA - Ow2VioUpdateCurPos - VioLVBScrollBuff - VioLVBCopyStr --*/ { UCHAR Char; ULONG NumChar, NumBytes, NumWritten, NumLines = 0; COORD OldCoord, Coord; OldCoord = Coord = GET_CURRENT_COORD; /* * Copy to temp buffer */ for ( NumBytes = 0, NumChar = 0 ; NumChar < StringLength ; NumChar++ ) { if ((Char = LineInputBuff[StartIndex + NumChar].Char) < ' ') { KBD_BUFFER_ADDRESS[NumBytes++] = '^'; KBD_BUFFER_ADDRESS[NumBytes++] = (UCHAR)(Char + '@'); } else { KBD_BUFFER_ADDRESS[NumBytes++] = Char; } } if (!NumBytes) { return ; } if ( KbdEchoFlag ) { /* * Send to console */ if(!Or2WinWriteConsoleA( #if DBG KbdCueMoveToRightStr, #endif hConOut, (LPSTR)KBD_BUFFER_ADDRESS, NumBytes, &NumWritten, NULL )) { #if DBG ASSERT1("OS2SES(KbdCueMoveToRight): failed on WriteConsoleA", FALSE); #endif } #if DBG if ( NumBytes != NumWritten ) { KdPrint(("OS2SES(KbdCueMoveToRight): partial data WriteConsoleA (%u from %u)\n", NumWritten, NumBytes)); ASSERT( FALSE ); } #endif /* * Update Coord */ Coord.X += (SHORT)NumWritten; while ( Coord.X >= SesGrp->ScreenColNum ) { Coord.Y++; Coord.X -= SesGrp->ScreenColNum; } if ( Coord.Y >= SesGrp->ScreenRowNum ) { NumLines = Coord.Y - SesGrp->ScreenRowNum + 1; Coord.Y = SesGrp->ScreenRowNum - 1; } Ow2VioUpdateCurPos(Coord); /* * Update LVB */ if ( UpdateLVB ) { if ( NumLines && ( SesGrp->ScreenSize < 512 )) { ULONG NumChar1 = SesGrp->ScreenRowNum - OldCoord.X; UCHAR *Ptr = &KBD_BUFFER_ADDRESS[0]; while ( NumWritten ) { VioLVBCopyStr( Ptr, OldCoord, NumChar1 ); VioLVBFillAtt( SesGrp->AnsiCellAttr, OldCoord, NumChar1 ); OldCoord.X = 0; if ( ++OldCoord.Y >= SesGrp->ScreenRowNum ) { OldCoord.Y--; VioLVBScrollBuff(1); NumLines--; } NumWritten -= NumChar1; if (( NumChar1 = NumWritten ) > (ULONG)SesGrp->ScreenColNum ) { NumChar1 = SesGrp->ScreenColNum; } } ASSERT( NumLines == 0 ); } else { if ( NumLines ) { OldCoord.Y -= (SHORT)NumLines; VioLVBScrollBuff(NumLines); } VioLVBCopyStr( KBD_BUFFER_ADDRESS, OldCoord, NumWritten ); VioLVBFillAtt( SesGrp->AnsiCellAttr, OldCoord, NumWritten ); } } } /* * Update position index */ KbdIndexInLine += (USHORT)StringLength; } VOID KbdCueMoveToLeft( IN ULONG StartIndex, IN ULONG MoveLength ) /*++ Routine Description: This routine moves the console cursor position to the left using '\b'. Arguments: StartIndex - index in LineInputBuff[] (the active command line) to start moving left from. MoveLength - number of character to move left. Return Value: Note: ASCII CUE string mode. Used by LEFT-ARROW, HOME, ^LEFT-ARROW, ^HOME, BS, KbdCueEraseAndDisplayLine, KbdCueDeleteCharAndShift and KbdCueHandleChar. 1. Send to console 2. Update position Uses: - LineInputBuff[StartIndex - MoveLength,StartIndex].X_Pos - LineInputBuff[StartIndex - MoveLength..StartIndex].Char Updates: - KbdInputLength - NO. - KbdIndexInLine - sub MoveLength. - LineInputBuff[0..KbdInputLength].Char and .X_Pos - NO - console display - NO - LVB - NO - SesGrp->WinCoord - by other routines. Calls: - KbdEchoBSAndFillSpaces --*/ { ULONG NumBytes; /* * Calculate byte count */ NumBytes = LineInputBuff[StartIndex].X_Pos - LineInputBuff[StartIndex - MoveLength].X_Pos; if (!NumBytes) { return ; } if ( KbdEchoFlag ) { if ( SesGrp->ScreenSize < 512 ) { ULONG Row1, Row2; Row1 = LineInputBuff[StartIndex - MoveLength].X_Pos / SesGrp->ScreenColNum; Row2 = LineInputBuff[KbdInputLength].X_Pos / SesGrp->ScreenColNum; if (( Row2 - Row1 + 1 ) > (ULONG)SesGrp->ScreenRowNum ) { NumBytes += LineInputBuff[StartIndex - MoveLength].X_Pos % SesGrp->ScreenColNum; NumBytes -= (Row2 - Row1 + 1 - SesGrp->ScreenRowNum) * SesGrp->ScreenColNum; } } /* * Send to console and update coord */ KbdEchoBSAndFillSpaces(NumBytes, 0); } /* * Update position index */ KbdIndexInLine -= (USHORT)MoveLength; } VOID KbdCueUpdateBufferOffset( IN ULONG StartIndex, IN ULONG StringLength, IN ULONG StartOffset ) /*++ Routine Description: This routine updates the offset in buffer for the active command line. This is done from StartIndex for StringLength + 1 (to update the offset of the next char according to the last char in string). The StartIndex gets X_Pos of StartOffset and the following are updated according the char type (char under 0x20 holds two columns for ^X). Arguments: StartIndex - index in LineInputBuff[] (the active command line) to start updaing the X_Pos field from. StringLength - number of character to update X_Pos for. StartOffset - X_Pos for the first character. Return Value: Note: ASCII CUE string mode. Used by KbdCueEraseAndDisplayLine, KbdCueDeleteCharAndShift and KbdCueHandleChar. 1. Updates the X_Pos field in LineInputBuff[]. Uses: - KbdInputLength - active command line length. - KbdIndexInLine - current index in command line. - LineInputBuff[0, KbdIndexInLine, KbdInputLength].X_Pos - KbdCueBuffer[NewLineIndex..] --*/ { ULONG NumChar, Index, Offset; /* * Update the offset in buffer. This is done for StringLength + 1 * to update the offset of the next char according to the last char * in string. */ for ( Index = StartIndex, Offset = StartOffset, NumChar = 0 ; NumChar <= StringLength ; NumChar++ ) { LineInputBuff[Index].X_Pos = (USHORT)Offset++; if ( LineInputBuff[Index++].Char < ' ' ) { Offset++; } } } VOID KbdCueDeleteCharAndShift( IN ULONG StartIndex, IN ULONG NumChar ) /*++ Routine Description: This routine delete character and shift the remaining command line input to the left. Arguments: StartIndex - index in LineInputBuff[] (the active command line) to start deleting from. NumChar - number of character to delete. Return Value: Note: ASCII CUE string mode. Used by DEL, ^HOME and BS. 1 Shift buffer info (Char field) 2 Update X_Pos (Offset) field in the shifted area 3 Send the shifted string to console and LVB 4 Clear remaining line 5 Return to the cursor position Uses: - LineInputBuff[].X_Pos and Char Updates: - KbdInputLength - sub NumChar. - KbdIndexInLine - NO - LineInputBuff[0..KbdInputLength].Char and .X_Pos - console display - LVB - SesGrp->WinCoord - by other routines. Calls: - KbdCueUpdateBufferOffset - KbdCueMoveToRight - KbdEchoBSAndFillSpaces - KbdCueMoveToLeft --*/ { if (NumChar) { ULONG Offset = LineInputBuff[StartIndex].X_Pos; ULONG Delta = LineInputBuff[StartIndex + NumChar].X_Pos - Offset; ULONG NumShift = KbdInputLength - StartIndex - NumChar; if ( NumShift ) { /* * Shift buffer info (Char field) */ RtlMoveMemory( &LineInputBuff[StartIndex].Char, &LineInputBuff[StartIndex + NumChar].Char, NumShift * sizeof(LINE_EDIT_KBD) ); /* * Update X_Pos (Offset) field in the shifted area */ KbdCueUpdateBufferOffset( StartIndex, NumShift, Offset ); /* * Send the shifted string to console and LVB */ KbdCueMoveToRight( StartIndex, NumShift, TRUE ); } /* * Clear remaining line */ KbdEchoBSAndFillSpaces(0, Delta); /* * Return to the cursor position */ KbdCueMoveToLeft( StartIndex + NumShift, NumShift ); KbdInputLength -= (USHORT)NumChar; } } VOID KbdCueHandleChar( IN UCHAR Char, IN ULONG Count ) /*++ Routine Description: This routine handle new char at CUE mode. Arguments: Char - char to handle. NumChar - number of character. Return Value: Note: ASCII CUE string mode. Used by CHAR. For INSERT: 1 Shift buffer info (Char field) 2 Fill new char 3 Update X_Pos (Offset) field 4 Send the new+old string to console and LVB 5 Return to the cursor position 6 Beep if no place Else: 1 Shift buffer info (Char field) 2 Fill new char 3 Update X_Pos (Offset) field 4 Send the shifted string to console and LVB 5 Clear remaining line 6 Return to the cursor position 7 Beep if no place Uses: - LineInputBuff[].X_Pos and Char - KbdInsertOn - KbdIndexInLine - KbdMaxLength - KbdInputLength Updates: - KbdInputLength - KbdIndexInLine - LineInputBuff[0..KbdInputLength].Char and .X_Pos - console display - LVB - SesGrp->WinCoord - by other routines. Calls: - KbdCueUpdateBufferOffset - KbdCueMoveToRight - KbdCueMoveToLeft - KbdEchoBSAndFillSpaces - KbdEchoBeep - RtlMoveMemory --*/ { ULONG NumChar, NumBeep = 0, NumShift, UpdateRight, i; ULONG LastOffset = LineInputBuff[KbdInputLength].X_Pos; if ( KbdInsertOn ) { if (( NumChar = KbdMaxLength - KbdInputLength ) > Count ) { NumChar = Count; } else { NumBeep = Count - NumChar; } /* * Shift buffer info (Char field) to free space for new char */ NumShift = KbdInputLength - KbdIndexInLine; RtlMoveMemory( &LineInputBuff[KbdIndexInLine + NumChar].Char, &LineInputBuff[KbdIndexInLine].Char, NumShift * sizeof(LINE_EDIT_KBD) ); /* * Fill new char */ for ( i = 0 ; i < NumChar ; i++ ) { LineInputBuff[KbdIndexInLine + i].Char = Char; } /* * Update X_Pos (Offset) field in the shifted and new areas */ KbdCueUpdateBufferOffset( KbdIndexInLine, NumChar + NumShift, LineInputBuff[KbdIndexInLine].X_Pos ); /* * Send the shifted string to console and LVB */ KbdCueMoveToRight( KbdIndexInLine, NumChar + NumShift, TRUE ); /* * Return to the cursor position */ KbdCueMoveToLeft( KbdIndexInLine, NumShift ); KbdInputLength += (USHORT)NumChar; } else { if (( NumChar = KbdMaxLength - KbdIndexInLine ) > Count ) { NumChar = Count; } else { NumBeep = Count - NumChar; } UpdateRight = max(NumChar, (ULONG)(KbdInputLength - KbdIndexInLine)); /* * Fill new char */ for ( i = 0 ; i < NumChar ; i++ ) { LineInputBuff[KbdIndexInLine + i].Char = Char; } /* * Update X_Pos (Offset) field in the old and new areas */ KbdCueUpdateBufferOffset( KbdIndexInLine, UpdateRight, LineInputBuff[KbdIndexInLine].X_Pos ); /* * Send the shifted string to console and LVB */ KbdCueMoveToRight( KbdIndexInLine, UpdateRight, TRUE ); if ( LastOffset > (ULONG)LineInputBuff[KbdIndexInLine].X_Pos ) { /* * Fill spaces at the EOL if needed */ KbdEchoBSAndFillSpaces( 0, LastOffset - LineInputBuff[KbdIndexInLine].X_Pos ); } if ( UpdateRight != NumChar ) { /* * Return to the cursor position */ KbdCueMoveToLeft( KbdIndexInLine, UpdateRight - NumChar ); } if ( KbdIndexInLine > KbdInputLength ) { KbdInputLength = KbdIndexInLine; } } if ( NumBeep != Count ) { KbdLineWasEdited = TRUE; } if ( NumBeep ) { KbdEchoBeep(NumBeep); } } VOID KbdCueSetCurTypeToHalf() { VIOCURSORINFO CurType; //Ow2VioGetCurType((PVOID)&CurType); //CurType = SesGrp->CursorInfo; //CurType.cEnd = SesGrp->CellVSize; CurType.cEnd = SesGrp->CursorInfo.cEnd; CurType.yStart = (CurType.cEnd + 1 ) / 2; CurType.cx = 1; CurType.attr = 0; Ow2VioSetCurType((PVOID)&CurType); } VOID KbdCueSetCurTypeToQuater() { VIOCURSORINFO CurType; //Ow2VioGetCurType((PVOID)&CurType); //CurType = SesGrp->CursorInfo; //CurType.cEnd = SesGrp->CellVSize; CurType.cEnd = SesGrp->CursorInfo.cEnd; CurType.yStart = (CurType.cEnd + 1 ) * 3 / 4; CurType.cx = 1; CurType.attr = 0; Ow2VioSetCurType((PVOID)&CurType); } DWORD KbdEchoCharToConsole( IN UCHAR Char, IN ULONG Count ) /*++ Routine Description: This routine write to console times. Arguments: Char - character to write. Count - number of times to write char Return Value: Note: ASCII CUE/EDIT string mode. Used by KbdEchoNL, KbdEchoBSAndFillSpaces, KbdEchoBeep and KbdEchoChar. Calls: - Or2WinWriteConsoleA --*/ { ULONG NumChar, NumWritten, MaxCount = Count; NumChar = (MaxCount > KBD_BUFFER_SIZE) ? KBD_BUFFER_SIZE : MaxCount; memset(KBD_BUFFER_ADDRESS, Char, NumChar); while (MaxCount) { if(!Or2WinWriteConsoleA( #if DBG KbdEchoCharToConsoleStr, #endif hConOut, (LPSTR)KBD_BUFFER_ADDRESS, NumChar, &NumWritten, NULL)) { #if DBG ASSERT1("OS2SES(KbdEchoCharToConsole): failed on WriteConsoleA", FALSE); #endif } #if DBG if ( NumChar != NumWritten ) { KdPrint(("OS2SES(KbdEchoCharToConsole): partial data WriteConsoleA %u from %u\n", NumWritten, NumChar)); ASSERT( FALSE ); } #endif MaxCount -= NumChar; NumChar = (MaxCount > KBD_BUFFER_SIZE) ? KBD_BUFFER_SIZE : MaxCount; } return(NO_ERROR); } DWORD KbdEchoNL( IN ULONG Count ) /*++ Routine Description: This routine write NL to console times and update LVB. Arguments: Count - number of times to write char Return Value: Note: ASCII CUE/EDIT string mode. Used by LF (EDIT only) and CR. Updates: - SesGrp->WinCoord - LVB Calls: - KbdEchoCharToConsole - VioLVBScrollBuff --*/ { ULONG NumLines = 0; COORD Coord = GET_CURRENT_COORD; Coord.X = 0; Coord.Y += (SHORT)Count; if ( Coord.Y >= SesGrp->ScreenRowNum ) { NumLines = Coord.Y - SesGrp->ScreenRowNum + 1; Coord.Y = SesGrp->ScreenRowNum - 1; } KbdEchoCharToConsole('\n', Count); Ow2VioUpdateCurPos(Coord); if (NumLines) { VioLVBScrollBuff(NumLines); } return(NO_ERROR); } DWORD KbdEchoESC( IN ULONG Count, IN ULONG HorzMove ) /*++ Routine Description: This routine write to console times with number of spaces on the next line. It also update LVB. Arguments: Count - number of times to write char HorzMove - number of spaces on the start of the new line. Return Value: Note: ASCII EDIT string mode. Used by ESC. Updates: - SesGrp->WinCoord - LVB Calls: - Or2WinWriteConsoleA - VioLVBScrollBuff --*/ { ULONG NumChar, NumWritten, MaxCount = Count, NumLines = 0, Length = HorzMove + 1; COORD OldCoord, Coord; OldCoord = Coord = GET_CURRENT_COORD; KBD_BUFFER_ADDRESS[0] = '\\'; KBD_BUFFER_ADDRESS[1] = '\n'; memset(&KBD_BUFFER_ADDRESS[2], ' ', HorzMove); KBD_BUFFER_ADDRESS[HorzMove + 2] = '\\'; NumChar = HorzMove + 2; Coord.Y += (SHORT)Count; Coord.X = (SHORT)HorzMove; if ( Coord.Y >= SesGrp->ScreenRowNum ) { NumLines = Coord.Y - SesGrp->ScreenRowNum + 1; Coord.Y = SesGrp->ScreenRowNum - 1; } while ( MaxCount ) { if(!Or2WinWriteConsoleA( #if DBG KbdEchoESCStr, #endif hConOut, (LPSTR)KBD_BUFFER_ADDRESS, NumChar, &NumWritten, NULL)) { #if DBG ASSERT1("OS2SES(KbdEchoESC): failed on WriteConsoleA", FALSE); #endif //return (1); } #if DBG if ( NumChar != NumWritten ) { KdPrint(("OS2SES(KbdEchoESC): partial data WriteConsoleA %u from %u\n", NumWritten, NumChar)); ASSERT( FALSE ); } #endif MaxCount--; } Ow2VioUpdateCurPos(Coord); VioLVBFillChar( #ifdef DBCS // MSKK Oct.14.1993 V-AkihiS "\\", #else '\\', #endif OldCoord, 1 ); VioLVBFillAtt( SesGrp->AnsiCellAttr, OldCoord, 1 ); OldCoord.X = 0; for ( NumChar = 0 ; NumChar < Count ; NumChar++ ) { if ( ++OldCoord.Y >= SesGrp->ScreenRowNum ) { OldCoord.Y--; VioLVBScrollBuff(1); NumLines--; } if ( NumChar == ( Count - 1 )) { Length--; // don't put the slash at the last line } VioLVBCopyStr( &KBD_BUFFER_ADDRESS[2], OldCoord, Length ); VioLVBFillAtt( SesGrp->AnsiCellAttr, OldCoord, Length ); } ASSERT( NumLines == 0 ); return(NO_ERROR); } DWORD KbdEchoBSAndFillSpaces( IN ULONG BSCount, IN ULONG SpaceCount ) /*++ Routine Description: This routine write BS ('\b') to console times and fill times spaces in console and LVB. Arguments: BSCount - number of times to write \b char to console SpaceCount - number of times to fill space char to console and LVB Return Value: Note: ASCII EDIT/CUE string mode. Used by ^END, BS (EDIT only), LF (EDIT only), KbdCueEraseAndDisplayLine, KbdCueMoveToLeft, KbdCueDeleteCharAndShift and KbdCueHandleChar. Updates: - SesGrp->WinCoord (for BSCount only) - LVB (for SpaceCount only) Calls: - KbdEchoCharToConsole - Or2WinFillConsoleOutputCharacterA - VioLVBFillChar --*/ { ULONG NumFilled; COORD OldCoord, Coord; if ( !KbdEchoFlag ) { return (0L); } if (((long) BSCount < 0) || ((long) SpaceCount < 0)) { #if DBG DbgPrint("KbdEchoBSAndFillSpaces: BSCount %d or SpaceCount %d are negative\n", (long)BSCount, (long)SpaceCount); #endif return ERROR_INVALID_PARAMETER; } OldCoord = Coord = GET_CURRENT_COORD; Coord.X -= (SHORT)BSCount; while ( Coord.X < 0 ) { if ( Coord.Y ) { Coord.Y--; Coord.X += SesGrp->ScreenColNum; } else { if ( SpaceCount ) { if ( SpaceCount > (ULONG)abs(Coord.X) ) { SpaceCount += (ULONG)Coord.X; } else { SpaceCount = 0; } } BSCount += (ULONG)Coord.X; // sub the negative value Coord.X = 0; } } KbdEchoCharToConsole('\b', BSCount); Ow2VioUpdateCurPos(Coord); if ( SpaceCount ) { if (!Or2WinFillConsoleOutputCharacterA( #if DBG KbdEchoBSAndFillSpacesStr, #endif hConOut, ' ', SpaceCount, Coord, &NumFilled)) { #if DBG ASSERT1("OS2SES(KbdEchoBSAndFillSpaces): failed on FillConsoleOutputCharacterA\n", FALSE); #endif } #if DBG if ( NumFilled != SpaceCount ) { KdPrint(("OS2SES(KbdEchoBSAndFillSpaces): partial data %u from %u\n", NumFilled, SpaceCount)); ASSERT( FALSE ); } #endif VioLVBFillChar( #ifdef DBCS // MSKK Oct.14.1993 V-AkihiS " ", #else ' ', #endif Coord, SpaceCount ); VioLVBFillAtt( SesGrp->AnsiCellAttr, Coord, SpaceCount ); } return(NO_ERROR); } DWORD KbdEchoBeep( IN ULONG Count ) /*++ Routine Description: This routine send BEPP ('\07') to console times. Arguments: Count - number of times to write \g char to console Return Value: Note: ASCII EDIT/CUE string mode. Used when no place in the active command line by KbdEchoString, Char and KbdCueHandleChar. Calls: - KbdEchoCharToConsole --*/ { KbdEchoCharToConsole('\07', Count); return(NO_ERROR); } DWORD KbdEchoChar( IN UCHAR Char, IN ULONG Count ) /*++ Routine Description: This routine echo to console times and update LVB. Arguments: Char - char to send to console Count - number of times to send char to console Return Value: Note: ASCII EDIT string mode. Updates: - SesGrp->WinCoord - LVB Calls: - KbdEchoCharToConsole - VioLVBScrollBuff --*/ { COORD OldCoord, Coord; BOOL SendByLine = FALSE; UCHAR FillChar; ULONG Offset; OldCoord = Coord = GET_CURRENT_COORD; if (( Char >= ' ' ) || ( Char == '\t' )) { KbdEchoCharToConsole(Char, Count); if ( Char == '\t' ) { Offset = 8 * Count - (Coord.X & 7); FillChar = ' '; } else { FillChar = Char; Offset = Count; } if ((ULONG)( Offset + 2 * SesGrp->ScreenColNum ) > SesGrp->ScreenSize ) { SendByLine = TRUE; } else { Coord.X += (SHORT)Offset; while ( Coord.X >= SesGrp->ScreenColNum ) { Coord.Y++; Coord.X -= SesGrp->ScreenColNum; } if ( Coord.Y >= SesGrp->ScreenRowNum ) { VioLVBScrollBuff(Coord.Y - SesGrp->ScreenRowNum + 1); OldCoord.Y -= Coord.Y - SesGrp->ScreenRowNum + 1; Coord.Y = SesGrp->ScreenRowNum - 1; } Ow2VioUpdateCurPos(Coord); VioLVBFillChar( #ifdef DBCS // MSKK Oct.14.1993 V-AkihiS &FillChar, #else FillChar, #endif OldCoord, Offset ); VioLVBFillAtt( SesGrp->AnsiCellAttr, OldCoord, Offset ); } } if ( SendByLine || (( Char < ' ' ) && ( Char != '\t' ))) { ULONG NumChar, NumWritten, MaxCount, Pattern; if ( SendByLine ) { Pattern = (ULONG)((FillChar << 24) | (FillChar << 16) | (FillChar << 8) | (FillChar)); MaxCount = 0; } else { MaxCount = Offset = 2 * Count; FillChar = (UCHAR)(Char + '@'); Pattern = (ULONG)((FillChar << 24) | ('^' << 16) | (FillChar << 8) | ('^')); } NumChar = ( Offset > KBD_BUFFER_SIZE ) ? KBD_BUFFER_SIZE : Offset; RtlFillMemoryUlong( KBD_BUFFER_ADDRESS, (NumChar + 3) & ~3, Pattern ); while ( MaxCount ) { if(!Or2WinWriteConsoleA( #if DBG KbdEchoCharStr, #endif hConOut, (LPSTR)KBD_BUFFER_ADDRESS, NumChar, &NumWritten, NULL)) { #if DBG ASSERT1("OS2SES(KbdEchoChar): failed on WriteConsoleA", FALSE); #endif //return (1); } #if DBG if ( NumChar != NumWritten ) { KdPrint(("OS2SES(KbdEchoChar): partial data WriteConsoleA %u from %u\n", NumWritten, NumChar)); ASSERT( FALSE ); } #endif MaxCount -= NumChar; NumChar = ( MaxCount > KBD_BUFFER_SIZE ) ? KBD_BUFFER_SIZE : MaxCount; } if (( NumChar = SesGrp->ScreenColNum - Coord.X ) > Offset ) { NumChar = Offset; } while ( Offset ) { VioLVBCopyStr( &KBD_BUFFER_ADDRESS[0], Coord, NumChar ); VioLVBFillAtt( SesGrp->AnsiCellAttr, Coord, NumChar ); Coord.X += (SHORT)NumChar; if ( Coord.X >= SesGrp->ScreenColNum ) { Coord.X -= SesGrp->ScreenColNum; if ( ++Coord.Y >= SesGrp->ScreenRowNum ) { VioLVBScrollBuff(1); Coord.Y--; } } Offset -= NumChar; if (( NumChar = SesGrp->ScreenColNum - Coord.X ) > Offset ) { NumChar = Offset; } } Ow2VioUpdateCurPos(Coord); } return(NO_ERROR); } DWORD KbdEchoAString( IN PUCHAR String, IN ULONG Length ) /*++ Routine Description: This routine echo , which size is to console and update LVB. Arguments: String - char string to send to console Length - string length Return Value: Note: ASCII EDIT string mode. Updates: - SesGrp->WinCoord - LVB Calls: - Or2WinWriteConsoleA --*/ { ULONG NumWritten, NumChar, NumBytes, Num; COORD OldCoord, Coord; UCHAR Char; OldCoord = Coord = GET_CURRENT_COORD; for ( NumChar = 0, NumBytes = 0 ; NumChar < Length ; NumChar++ ) { Char = String[NumChar]; if ( Char >= ' ' ) { KBD_BUFFER_ADDRESS[NumBytes++] = Char; } else if ( Char = '\t' ) { Num = 8 - ((Coord.X + NumBytes) & 7); memset(&KBD_BUFFER_ADDRESS[NumBytes], ' ', Num); NumBytes += Num; } else { KBD_BUFFER_ADDRESS[NumBytes++] = '^'; KBD_BUFFER_ADDRESS[NumBytes++] = (UCHAR)(Char + '@'); } if (((ULONG)( Coord.X + NumBytes ) >= (ULONG)SesGrp->ScreenColNum ) || ( NumChar == ( Length - 1 ))) { if(!Or2WinWriteConsoleA( #if DBG KbdEchoAStringStr, #endif hConOut, (LPSTR)KBD_BUFFER_ADDRESS, NumBytes, &NumWritten, NULL)) { #if DBG ASSERT1("OS2SES(KbdEchoAString): failed on WriteConsoleA", FALSE); #endif } #if DBG if ( NumBytes != NumWritten ) { KdPrint(("OS2SES(KbdEchoAString): partial data WriteConsoleA %u from %u\n", NumWritten, NumBytes)); ASSERT( FALSE ); } #endif OldCoord = Coord; Coord.X += (SHORT)NumBytes; if ( Coord.X >= SesGrp->ScreenColNum ) { Coord.Y++; Coord.X -= SesGrp->ScreenColNum; if ( Coord.Y >= SesGrp->ScreenRowNum ) { Coord.Y = SesGrp->ScreenRowNum - 1; OldCoord.Y--; } } Ow2VioUpdateCurPos(Coord); VioLVBCopyStr( &KBD_BUFFER_ADDRESS[0], OldCoord, NumBytes ); VioLVBFillAtt( SesGrp->AnsiCellAttr, OldCoord, NumBytes ); NumBytes = 0; } } return(NO_ERROR); } BOOL KbdKeyIsTurnAround( IN UCHAR Char, IN UCHAR Scan ) { if ( KbdTurnAroundCharTwo ) { if ( Scan == (UCHAR)KbdTurnAroundChar ) { if ((( KbdReadMode == 0 ) && (( Char == 0 ) || ( Char == 0xE0 ))) || (( KbdReadMode == 1 ) && ( Char == HIBYTE(KbdTurnAroundChar) ))) { return(TRUE); } } } else { if ( Char == (UCHAR)KbdTurnAroundChar ) { return(TRUE); } } return(FALSE); }