#include #include #include #include "wterm.h" //**************************************************************************** // FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int) // PURPOSE: initialization function, processes message loop //**************************************************************************** int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow) HANDLE hInstance; // Current instance HANDLE hPrevInstance; // Previous instance LPSTR lpCmdLine; // Command line parameters int nCmdShow; // Show-window type: open or icon { MSG msg; WNDCLASS Win_Class; HWND hWnd; // Main window handle BOOL Message_available; unsigned int Num_Bytes; static short xscreen, yscreen; if (!hPrevInstance) { // Set up window class structure with parameters that describe the // main Wterm window. Win_Class.style = CS_HREDRAW | CS_VREDRAW; // Class style(s). Win_Class.cbClsExtra = 0; // No per-class extra data Win_Class.cbWndExtra = 0; // No per-window extra data Win_Class.hInstance = hInstance; // Application that owns the class Win_Class.hIcon = LoadIcon(NULL, IDI_APPLICATION); Win_Class.hCursor = LoadCursor(NULL, IDC_ARROW); Win_Class.hbrBackground = GetStockObject(WHITE_BRUSH); Win_Class.lpfnWndProc = MainWndProc; // Function to receive messages Win_Class.lpszMenuName = "Wterm_Menu"; // Name of menu in .RC file Win_Class.lpszClassName = "WtermWClass"; // Class name // Register the window class RegisterClass(&Win_Class); xscreen = GetSystemMetrics (SM_CXSCREEN); yscreen = GetSystemMetrics (SM_CYSCREEN); // Create a main window for this application instance hWnd = CreateWindow( "WtermWClass", // See RegisterClass() call "DOS/RMX Sample Application", // Text for window title bar WS_OVERLAPPEDWINDOW, // Window style CW_USEDEFAULT, // initial x pos CW_USEDEFAULT, // initial y pos xscreen / 2, // length x yscreen / 2, // length y NULL, // Overlapped windows have no parent NULL, // Use the window class menu hInstance, // This instance owns this window NULL // Pointer not needed ); // If CreateWindow call failled - just say NO if (!hWnd) return (FALSE); } else { MessageBeep(2); return (FALSE); } hInst = hInstance; // save token for this instance // set icon for Wterm SetClassWord(hWnd, GCW_HICON, LoadIcon( hInstance, MAKEINTRESOURCE(WTERMICON) )); // Make the window visible and update client area ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); // Sends WM_PAINT message // initialize global variables xCaret = 0; yCaret = 0; response = 0; Connected = FALSE; Num_Bytes = 0; cxBuffer = MAX_COLUMN ; cyBuffer = MAX_ROW; if((pBuffer = malloc (cxBuffer * cyBuffer)) == NULL) { MessageBox(hWnd, "Cannot allocate enought memory" " for Wterm.", "iRMX Terminal", MB_ICONEXCLAMATION | MB_OK); return (FALSE); } else for (y=0; y < cyBuffer; y++) for (x=0; x < cxBuffer; x++) BUFFER(x, y) = ' '; // Initialize input/output buffer @ iRMX comm. area // Note: We are using 32 bytes of DOS memory at the end // of the BIOS communication area, starting at 4E0H if( in_buf->count > 29 ) in_buf->count = 0; out_buf->flag_byte = 0; out_buf->data_byte = 0; // Process windows messages // Loop until a WM_QUIT message is received // If there is a message available, process it. // Otherwise check the RMX output buffer and handle // any available characters. while(TRUE) { Message_available = PeekMessage(&msg, NULL, 0, 0, PM_REMOVE); if(Message_available) { if(msg.message == WM_QUIT) break; TranslateMessage((LPMSG)&msg); DispatchMessage((LPMSG)&msg); } else { if( (Connected) && (in_buf->count > 0) && (!Stop_output)) { // copy data from iRMX to local buffer for(Num_Bytes=0; Num_Bytes < in_buf->count; Num_Bytes++) MsgBuff[Num_Bytes] = in_buf->data_byte[Num_Bytes]; in_buf->count = 0; // tell RMX we read the data // then display text Process_Text_Buffer(hWnd, Num_Bytes, (LPSTR)MsgBuff); } } } // end forever loop return (msg.wParam); // Returns the value from PostQuitMessage } //************************************************************************** // FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG) // PURPOSE: Processes messages //************************************************************************** long FAR PASCAL MainWndProc(hWnd, message, wParam, lParam) HWND hWnd; unsigned message; WORD wParam; LONG lParam; { HDC hdc; TEXTMETRIC tm; LPPOINT ptMinMaxInfo; FARPROC lpProcAbout; // pointer to the "About" function switch (message) { case WM_SIZE: xClientView = LOWORD (lParam); yClientView = HIWORD (lParam); break; case WM_CREATE: hdc = GetDC(hWnd); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); GetTextMetrics(hdc, &tm); cxChar= tm.tmAveCharWidth; cyChar= tm.tmHeight; ReleaseDC(hWnd, hdc); break; case WM_GETMINMAXINFO: // constrain the sizing of the window to 80 by 25 characters. ptMinMaxInfo = (LPPOINT) lParam; ptMinMaxInfo[1].x = (GetSystemMetrics (SM_CXSCREEN)+2); ptMinMaxInfo[1].y = (GetSystemMetrics (SM_CYSCREEN)- 51); ptMinMaxInfo[3].x = (GetSystemMetrics (SM_CXSCREEN) / 4); ptMinMaxInfo[3].y = (GetSystemMetrics (SM_CYSCREEN)- 51); ptMinMaxInfo[4].x = (GetSystemMetrics (SM_CXSCREEN)+2); ptMinMaxInfo[4].y = (GetSystemMetrics (SM_CYSCREEN)- 51); break; case WM_SETFOCUS: CreateCaret (hWnd, NULL, (cxChar/2), cyChar); SetCaretPos (xCaret * cxChar, yCaret * cyChar); ShowCaret(hWnd); break; case WM_KILLFOCUS: HideCaret (hWnd); DestroyCaret(); break; case WM_KEYDOWN: switch (wParam) { case VK_HOME: out_buf->data_byte = 0x1D; Signal_iRMX(hWnd); break; case VK_LEFT: out_buf->data_byte = 0x1F; Signal_iRMX(hWnd); break; case VK_RIGHT: out_buf->data_byte = 0x19; Signal_iRMX(hWnd); break; case VK_UP: out_buf->data_byte = 0x1E; Signal_iRMX(hWnd); break; case VK_DOWN: out_buf->data_byte = 0x1C; Signal_iRMX(hWnd); break; case VK_DELETE: out_buf->data_byte = 0x7F; Signal_iRMX(hWnd); break; case VK_PRIOR: // page up out_buf->data_byte = 0x1E; // up Signal_iRMX(hWnd); out_buf->data_byte = 0x1D; // home Signal_iRMX(hWnd); break; case VK_NEXT: // page down out_buf->data_byte = 0x1C; // down Signal_iRMX(hWnd); out_buf->data_byte = 0x1D; // home Signal_iRMX(hWnd); break; } break; case WM_CHAR: // if connected and iRMX buffer is empty, // then copy this keyboard characters to iRMX input buffer if ( (!(out_buf->flag_byte)) && (Connected) ) { KB_Char = (char) wParam; switch (KB_Char) { case '\x11': // Cntrl-Q Stop_output = FALSE; out_buf->data_byte = KB_Char; break; case '\x13': // Cntrl-S Stop_output = TRUE; out_buf->data_byte = KB_Char; break; case '\x1B': // Escape out_buf->data_byte = 0x1B; break; case '\b': out_buf->data_byte = 0x7F; break; case '\t': case '\n': // linefeed work ok case '\r': // cariage return default: out_buf->data_byte = KB_Char; break; } Signal_iRMX(hWnd); } break; case WM_PAINT: Paint_Window(hWnd); break; case WM_COMMAND: // message: command from application menu switch(wParam) { case IDM_ABOUT: lpProcAbout = MakeProcInstance(About, hInst); DialogBox(hInst, // this instance "AboutBox", // resource to use hWnd, // parent handle lpProcAbout); // About() instance address FreeProcInstance(lpProcAbout); break; case WTERM_EXIT: if(Connected) { Connected = FALSE; MessageBox(hWnd, "Wterm disconnected!", "iRMX Terminal", MB_ICONEXCLAMATION | MB_OK); } PostMessage(hWnd,WM_CLOSE, 0, 0L); break; case WTERM_CONNECT: // not yet implemented - just say OK if(!Connected) { if(Make_Connection(hWnd)) { Connected = TRUE; MessageBox(hWnd, "Connection successful", "", MB_OK); } break; } else MessageBox(hWnd, "Connection established", "", MB_OK); break; case WTERM_SHUTDOWN: // not yet implemented - just say OK { // not fully implemented, // for now, just inform the user that we have // remove the connection. Connected = FALSE; MessageBox(hWnd, "Wterm disconnected!", "iRMX Terminal", MB_ICONEXCLAMATION | MB_OK); } break; default: // Lets Windows process it return (DefWindowProc(hWnd, message, wParam, lParam)); } break; case WM_DESTROY: // message: window being destroyed PostQuitMessage(0); break; default: // Pass unused message back to Windows return (DefWindowProc(hWnd, message, wParam, lParam)); } // end switch message return (NULL); } //************************************************************************** // Function: Process_Text_Buffer // //************************************************************************** void Process_Text_Buffer(HWND hWnd, WORD Num_Chars, LPSTR lParam) { HDC hdc; unsigned i, temp; hdc = GetDC(hWnd); SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); // scan the text, handle any special characters, and display the rest. for(i=0; i < Num_Chars; i++) { temp = (char) lParam[i]; // save for routine index case HideCaret (hWnd); switch (Routine_index) { case 0 : // routine$index = 0 - ordinary character { switch(lParam[i]) { case 0 : /* CASE 0 - */ break; case 1 : /* CASE 1 - erase rest of screen */ for (y=(cyBuffer-yCaret-1); y < cyBuffer; y++) for (x=(cxBuffer-xCaret); x < cxBuffer; x++) BUFFER(x, y) = ' '; break; case 2 : /* CASE 2 - erase line */ y = yCaret; for (x=0; x < cxBuffer; x++) BUFFER(x, y) = ' '; break; case 3 : /* CASE 3 - erase rest of line */ y = yCaret; for (x = xCaret; x < cxBuffer; x++) BUFFER(x, y) = ' '; break; case 4 : /* CASE 4 - cursor absolute */ Routine_index = 1; break; case 5 : /* CASE 5 - line delete */ Scroll_Window_Up(yCaret, 0, hWnd); break; case 6 : /* CASE 6 - line insert */ Scroll_Window_Down(yCaret, 0, hWnd); break; case 7 : /* CASE 7 - bell */ MessageBeep(2); break; case 8 : /* CASE 8 - backspace */ if(xCaret > 0) --xCaret; break; case 9 : /* CASE 9 - tab */ break; case 10 : /* CASE 0A - linefeed */ if (yCaret >= cyBuffer-1) Scroll_Window_Up(0, 0, hWnd); else ++yCaret; break; case 11 : /* CASE 0B - set color */ Routine_index = 3; break; case 12 : /* CASE 0C - erase screen */ for (y=0; y < cyBuffer; y++) for (x=0; x < cxBuffer; x++) BUFFER(x, y) = ' '; xCaret = 0; yCaret = 0; break; case 13 : /* CASE 0D - CR */ xCaret = 0; // move to beginning of the line break; case 14 : /* CASE 0E - literal */ break; case 15 : /* CASE 0F - set raw mode */ break; case 16 : /* CASE 10 - set cooked mode */ break; case 17 : /* CASE 11 - X-ON */ break; case 18 : /* CASE 12 */ break; case 19 : /* CASE 13 - X-OFF */ break; case 20 : /* CASE 14 */ break; case 21 : /* CASE 15 */ break; case 22 : /* CASE 16 */ break; case 23 : /* CASE 17 */ break; case 24 : /* CASE 18 */ break; case 25 : /* CASE 19 - cursor right */ if(xCaret >= cxBuffer-1) { if (yCaret < cyBuffer-1) { ++yCaret; xCaret = 0; } } else ++xCaret; break; case 26 : /* CASE 1A */ break; case 27 : /* CASE 1B */ break; case 28 : /* CASE 1C - cursor down */ if (yCaret != cyBuffer-1) ++yCaret; break; case 29 : /* CASE 1D - cursor home */ xCaret = 0; yCaret = 0; break; case 30 : /* CASE 1E - cursor up */ if(yCaret != 0) --yCaret; break; case 31 : /* CASE 1F - cursor left */ if(xCaret == 0) { if (yCaret > 0) { --yCaret; xCaret = cxBuffer-1; } } else --xCaret; break; default: // all displayable characters // Filter out all characters not supported by windows if((lParam[i] < 32) || ((lParam[i] > 126) && (lParam[i] < 145)) || ((lParam[i] > 146) && (lParam[i] < 160))) break; // add char to screen buffer BUFFER(xCaret, yCaret) = (char) lParam[i]; TextOut(hdc, xCaret * cxChar, yCaret * cyChar, &BUFFER(xCaret, yCaret), 1); if (++xCaret > cxBuffer-1) { xCaret = 0; if (yCaret >= cyBuffer-1) Scroll_Window_Up(0, 0, hWnd); else ++yCaret; } break; } /* CASE char */ } /* of case 0 => routine$index = 0 */ InvalidateRect(hWnd, NULL, FALSE); break; case 1 : // routine$index = 1 - second byte of absolute cursor position { Routine_index = 2; temp -= 0x20; if (temp < cyBuffer) yCaret = temp; else yCaret = 0; } break; case 2 : // routine$index = 2 - third byte of absolute cursor position { Routine_index = 0; temp -= 0x20; if (temp < cxBuffer) xCaret = temp; else xCaret = 0; } break; case 3 : // routine$index = 3 - second byte of set foreground color { Routine_index = 0; } break; default: break; } // end of (switch (Routine_index)) SetCaretPos( xCaret *cxChar, yCaret * cyChar); ShowCaret (hWnd); } // end for(i=0; i < Num_Chars; i++) ReleaseDC(hWnd, hdc); } //************************************************************************** // Function: Scroll window down // //************************************************************************** void Scroll_Window_Down(unsigned row, unsigned column, HWND hWnd) { static int x, y, z; unsigned char Temp; // scroll down one line starting at the line containing the caret for (z=(cyBuffer-1); z > row; z--) // namly { for (x=column; x < cxBuffer; x++) { y = z-1; Temp = BUFFER(x, y); y = z; BUFFER(x, y) = Temp; } } // blank the line containing the caret y = row; for (x=0; x < cxBuffer; x++) BUFFER(x, y) = ' '; // SendMessage(hWnd, WM_PAINT, NULL, 1L); InvalidateRect(hWnd, NULL, FALSE); Paint_Window(hWnd); } //************************************************************************** // Function: Scroll window up // //************************************************************************** void Scroll_Window_Up(unsigned row, unsigned column, HWND hWnd) { static int x, y, z; unsigned char Temp; // scroll up one line for (z=row; z < cyBuffer-1; z++) { for (x=column; x < cxBuffer; x++) { y = z+1; Temp = BUFFER(x, y); y = z; BUFFER(x, y) = Temp; } } // blank the last line y = cyBuffer-1; for (x=0; x < cxBuffer; x++) BUFFER(x, y) = ' '; // SendMessage(hWnd, WM_PAINT, NULL, 1L); InvalidateRect(hWnd, NULL, FALSE); Paint_Window(hWnd); } //************************************************************************** // Function: About(HWND, unsigned, WORD, LONG) // Processes the About message and display dialog box. //************************************************************************** BOOL FAR PASCAL About( hDlg, message, wParam, lParam ) HWND hDlg; unsigned message; WORD wParam; LONG lParam; { switch(message) // message: initialize dialog box { case WM_COMMAND: // message: received a command case WM_LBUTTONDOWN: EndDialog( hDlg, TRUE ); return TRUE; case WM_INITDIALOG: return TRUE; default: // Didn't process a message return FALSE; } } //************************************************************************** // Function: Signal_iRMX // //************************************************************************** void Signal_iRMX(HWND hWnd) { out_buf->flag_byte = TRUE; // Send a message to iRMX driver RQSendMessage(Kb_Mux, segment, response, &except); if (except != EOK) { MessageBox(hWnd, "SendMessage error!", "iRMX Terminal", MB_ICONEXCLAMATION | MB_OK); // Add your own error handler here } } //************************************************************************** // Function: Paint window // //************************************************************************** void Paint_Window(HWND hWnd) { PAINTSTRUCT ps; HDC hdc; RECT rClRect; unsigned int Display_mem_ptr; unsigned int ax; static short Max_Screen_lines; // screen lines when resized // for now, it is not needed hdc = BeginPaint(hWnd, &ps); Max_Screen_lines = yClientView/cyChar; Display_mem_ptr = cyBuffer-Max_Screen_lines; SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT)); ax = 0; // not needed when use use: for (y=0; y < cyBuffer; y++, ax++) for (y=Display_mem_ptr; y < cyBuffer; y++, ax++) { TextOut(hdc, 0, ax * cyChar, &BUFFER(0, y), cxBuffer); } EndPaint(hWnd, &ps); } //************************************************************************** // Function: Make Connection to iRMX driver // //************************************************************************** BOOL Make_Connection(HWND hWnd) { // Make some calls to the RT extension to find out if the RMX // keyboard mail box is present. // NOTE: // If the RT extension is not configured then // Windows (and DOS) will get confused!!! roottoken = RQGetTaskTokens(rootjob,&except); // Display debug messages - you can delete the following four lines // and supply your own error handler if (except == EOK) MessageBox(hWnd, "gettasktoken OK", "", MB_OK); else { MessageBox(hWnd, "gettasktoken error", "", MB_OK); return(FALSE); } vm86j = RQLookupObject(roottoken,&vm86[0],0,&except); // Display debug messages - you can delete the following four lines // and supply your own error handler if (except == EOK) MessageBox(hWnd, "lookupobject root OK", "", MB_OK); else { MessageBox(hWnd, "lookupobject root error", "", MB_OK); return(FALSE); } Kb_Mux = RQLookupObject(vm86j,&kb_mb[0],0,&except); segment = Kb_Mux; // Display debug messages - you can delete the following four lines // and supply your own error handler if (except == EOK) MessageBox(hWnd, "lookupobject vm86 OK", "", MB_OK); else { MessageBox(hWnd, "lookupobject vm86 error", "", MB_OK); return(FALSE); } return(TRUE); } //************************* End Of Source Code Module *********************