windows-nt/Source/XPSP1/NT/multimedia/media/test/sbtest/wpf.c
2020-09-26 16:20:57 +08:00

1632 lines
44 KiB
C

/*
* WPF.C
*
* WPF line output/input windows. Taken from the wpf.dll library,
* originally written by ToddLa.
*
* History:
* 10/02/86 Todd Laney Created
* 04/14/87 toddla Added new function CreateDebugWin
* 07/08/87 brianc added iMaxLines parm to CreateDebugWin[dow]
* 2/90 russellw moved into Wincom and cleaned up.
* 10/1/92 robinsp moved to NT
*
* NT conversion
* remove the tricks on dereferencing and passing a pointer to
* the stack in wvsprintf. This means we can't do the printf
* thing so have to use a macro, sprintf etc which means wpfprintf
* must be coded :
* wpfprintf(hwnd, lpszFormat, (args))
*
*/
#include <windows.h>
#include <mmsystem.h>
#include "wincom.h"
#include "sbtest.h"
#include <stdarg.h>
/*
* This code appears to make use of the fact that a local handle can be
* double de-referenced to get the actual pointer that the local handle
* refers to. This is a somewhat shady practice.. maybe eliminate it?
*
*/
/*--------------------------------------------------------------------------*\
| |
| g e n e r a l c o n s t a n t s |
| |
\*--------------------------------------------------------------------------*/
#define MAXBUFLEN 200 /* Maximum string length for wprintf */
/* Macros to manipulate the printf window array of lines. This array
* wraps around, thus the need for the modulo arithmetic
*/
#define FIRST(pTxt) ((pTxt)->iFirst)
#define TOP(pTxt) (((pTxt)->iFirst + (pTxt)->iTop) % (pTxt)->iMaxLines)
#define LAST(pTxt) (((pTxt)->iFirst + (pTxt)->iCount-1) % (pTxt)->iMaxLines)
#define INC(pTxt,x) ((x) = ++(x) % (pTxt)->iMaxLines)
#define DEC(pTxt,x) ((x) = --(x) % (pTxt)->iMaxLines)
#define HWinInfo(hwnd) ((HTXT)GetWindowLong((hwnd),0))
#define LockWinInfo(hwnd) ((PTXT)LocalLock((HANDLE)HWinInfo(hwnd)))
#define UnlockWinInfo(hwnd) ((PTXT)LocalUnlock((HANDLE)HWinInfo(hwnd)))
#define VK(vk) ((vk) | 0x0100)
/* The pad values used between the edge of the window and the text.
* x = 1/2 ave char width, y = 1 pixel
*/
#define OFFSETX (pTxt->Tdx/2)
#define OFFSETY 1
#define VARSIZE 1
#define BOUND(x,min,max) ((x) < (min) ? (min) : ((x) > (max) ? (max) : (x)))
#define SEEK_CUR 1
#define SEEK_END 2
#define SEEK_SET 0
/*--------------------------------------------------------------------------*\
| |
| g l o b a l v a r i a b l e s |
| |
\*--------------------------------------------------------------------------*/
#define QUESIZE 128
/*
* QUEUE STRUCTURE: Support queuing of input characters.
*
*/
typedef struct {
int iLen;
char ach[QUESIZE];
} QUE;
typedef QUE *PQUE; /* pointer to a char que */
typedef PQUE *HQUE; /* handle (**) to a char que */
/*
* WPF WINDOW INSTANCE DATA STRUCTURE
*
*/
typedef struct {
int iLen;
char **hText;
} LINE;
struct TEXT_STRUCT {
HWND hwnd; // Window displaying the text
WORD wID; // window ID code, for WM_COMMAND messages
BOOL fScrollSemaphore;
WORD wOutputLocation;
int iFile;
int iFirst; // First line in que
int iCount; // Number of lines in que
int iTop; // Line at top of window
int iLeft; // X offset of the window
int MaxLen; // length of longest string currently stored.
int iMaxLines; // max number of LINEs
int iRangeH;
int iRangeV;
HFONT hFont; // Font to draw with
int Tdx,Tdy; // Font Size
HQUE hQue;
int nTabs;
PINT pTabs;
LINE arLines[VARSIZE]; // array of iMaxLines LINEs
};
typedef struct TEXT_STRUCT *PTXT; /* pointer to a text struct */
typedef PTXT *HTXT; /* Handle (**) to a text struct */
static int iSem=0;
static BOOL gbRedraw=TRUE;
static HWND hwndLast = NULL;
/* External buffer for scratch space */
char bufTmp[MAXBUFLEN]; /* intermediate buffer */
static char szClass[] = "WPFWIN";
static BOOL fInit = FALSE;
/*--------------------------------------------------------------------------*\
| |
| f u n c t i o n d e f i n i t i o n s |
| |
\*--------------------------------------------------------------------------*/
LONG FAR PASCAL PrintfWndProc(HWND, unsigned, UINT, LONG);
void NEAR PASCAL WpfSetFont(HWND hWnd, HFONT hFont);
void NEAR PASCAL WpfClear(HWND hWnd);
void NEAR PASCAL WpfSetTabs(HWND hwnd, int nTabs, LPINT pTabs);
BOOL NEAR PASCAL WpfGetTabs(HWND hwnd, LPINT pTabs);
void NEAR PASCAL WpfPaint(HWND hwnd, HDC hdc);
void NEAR PASCAL WpfVScroll(HWND hWnd, PTXT pTxt, int n);
void NEAR PASCAL WpfHScroll(HWND hWnd, PTXT pTxt, int n);
int NEAR PASCAL LinesInWpfWindow(HWND hWnd);
int NEAR PASCAL CharsInWpfWindow(HWND hWnd);
void NEAR PASCAL WpfMaxLen(PTXT pTxt);
void NEAR PASCAL WpfSetScrollRange(HWND hWnd, BOOL bRedraw);
void NEAR PASCAL NewLine(PTXT pTxt);
int NEAR PASCAL ChangeLine(PTXT pTxt, int iLine, LPSTR lpch);
int NEAR PASCAL InsertString(PTXT pTxt, LPSTR lpstr);
BOOL NEAR PASCAL EnQueChar(HTXT hTxt, WORD vk);
void NEAR PASCAL UpdateCursorPos(PTXT pTxt);
WORD NEAR PASCAL SetOutput(HWND hwnd, UINT wParam, LONG lParam);
WORD NEAR PASCAL GetOutput(HWND hwnd);
BOOL NEAR PASCAL wpfWrtTTY(HWND hWnd, LPSTR sz);
// BOOL FAR PASCAL DbgDestroy(HWND hwnd);
void wpfWrtFile(int fh, LPSTR sz);
/*
* fSuccess = WpfInit(hInst)
*
* Register the WinPrintf window class.
*
*/
BOOL FAR PASCAL WpfInit(HANDLE hInstance);
#pragma alloc_text(init, WpfInit)
BOOL FAR PASCAL WpfInit(HANDLE hInstance)
{
WNDCLASS rClass;
if (!fInit) {
rClass.hCursor = LoadCursor(NULL,IDC_ARROW);
rClass.hIcon = (HICON)NULL;
rClass.lpszMenuName = (LPSTR)NULL;
rClass.lpszClassName = szClass;
rClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
rClass.hInstance = hInstance;
rClass.style = CS_GLOBALCLASS;
rClass.lpfnWndProc = PrintfWndProc;
rClass.cbWndExtra = sizeof (HTXT);
rClass.cbClsExtra = 0;
if (!RegisterClass(&rClass))
return FALSE;
fInit++;
}
return TRUE;
}
/*
* @doc EXTERNAL WINCOM WPFWINDOW
*
* @api HWND | wpfCreateWindow | This function creates a
* text output window. WPF windows allow <f printf> style output
* and line oriented input. WPF windows also remember a fixed number of
* lines of previous output for scrolling back.
*
* @parm HWND | hwndParent | Specifies the parent window.
*
* @parm HANDLE | hInst | Specifies the module instance handle of the
* DLL owner. If the parameter is NULL, the module instance handle of
* the WINCOM DLL is used.
*
* @parm LPSTR | lpszTitle | Points to the window title. This
* information is ignored when the style specified by <p dwStyle> does
* not create a title bar for the window.
*
* @parm DWORD | dwStyle | Specifies the window style flags. All
* standard window style flags are valid. The WPF window class also defines
* the following additional flags:
*
* @flag WPF_CHARINPUT | The WPF window allows the user to input
* characters and sends its parent <m WPF_NCHAR> and <m WPF_NTEXT> messages.
*
* @parm WORD | x | Specifies the x position of the window.
* @parm WORD | y | Specifies the y position of the window.
* @parm WORD | dx | Specifies the width of the window.
* @parm WORD | dy | Specifies the height of the window.
*
* @parm int | iMaxLines | Specifies the maximum number of lines that
* the WPF window remembers for scrolling purposes. If this
* parameter is zero, a default value of 100 is supplied.
*
* @parm WORD | wID | Specifies the window ID of the WPF window. This
* code is used in WM_COMMAND message to notify the owner of the WPF
* window when key events have occurred.
*
* @rdesc Returns the window handle of the new WPF window, or NULL if
* an error occurs. The returned window handle may be used with the
* normal Windows window-management APIs.
*
* @comm A WPF window behaves like a partial Windows control. The
* owner may change the parameters of a WPF window by sending control
* messages (including WM_SETFONT, WM_GETFONT, and the WPF messages
* documented with the WINCOM DLL). The WPF window notifies its owner
* of state changes by sending the owner WM_COMMAND messages with a
* control ID of <p wID>. WPF windows are not full controls, however,
* as they cannot be used in dialog boxes. WPF windows also do not
* respond to WM_GETTEXT and WM_SETTEXT messages.
*
*/
HWND FAR PASCAL wpfCreateWindow(HWND hwndParent, HANDLE hInst,LPSTR lpszTitle,
DWORD dwStyle, WORD x, WORD y,
WORD dx, WORD dy, int iMaxLines, WORD wID)
{
HWND hWnd;
if (!fInit)
if (!WpfInit(ghInst))
/* Return NULL if the class could not be registered */
return NULL;
if (iMaxLines == 0)
iMaxLines = 100;
if (hInst == NULL)
hInst = ghInst;
hWnd = CreateWindow((LPSTR)szClass,
(LPSTR)lpszTitle,
dwStyle,
x,y,
dx,dy,
(HWND) hwndParent,
(HMENU) NULL,
(HANDLE) hInst,
(LPSTR) MAKELONG(iMaxLines, wID)
);
return hWnd;
}
/*****************************************************
*
* UTILITY PROCEDURES
*
*****************************************************/
/*
* WpfSetFont(hwnd, hfont)
*
* Changes the font of a winprintf window to be the specified handle.
* Rebuilds the internal character size measurements, and causes the
* window to repaint.
*
* Is there a problem with scroll ranges changing here?
*
*/
void NEAR PASCAL WpfSetFont(HWND hWnd, HFONT hFont)
{
PTXT pTxt;
HDC hDC;
TEXTMETRIC tm;
pTxt = LockWinInfo(hWnd);
pTxt->hFont = hFont;
/* Find out the size of a Char in the font */
hDC = GetDC(hWnd);
SelectObject(hDC, hFont);
GetTextMetrics(hDC, (LPTEXTMETRIC) &tm);
pTxt->Tdy = tm.tmHeight;
pTxt->Tdx = tm.tmAveCharWidth;
ReleaseDC (hWnd, hDC);
InvalidateRect(hWnd, NULL, TRUE);
UnlockWinInfo(hWnd);
}
/*
* WpfClear(hwnd)
*
* Clears all text from the window. Frees all allocated memory. The
* current queue is not modified?
*
*/
void NEAR PASCAL WpfClear(HWND hWnd)
{
int i,iQue;
PTXT pTxt;
pTxt = LockWinInfo(hWnd);
iQue = FIRST(pTxt);
for (i=0; i < pTxt->iCount; i++, INC(pTxt,iQue))
if (pTxt->arLines[iQue].hText != NULL)
LocalFree((HANDLE) pTxt->arLines[iQue].hText);
pTxt->iFirst = 0; /* Set the que up to have 1 NULL line */
pTxt->iCount = 1;
pTxt->iTop = 0;
pTxt->iLeft = 0;
pTxt->MaxLen = 0;
pTxt->arLines[0].hText = NULL;
pTxt->arLines[0].iLen = 0;
UnlockWinInfo(hWnd);
InvalidateRect(hWnd,NULL,TRUE);
WpfSetScrollRange(hWnd,TRUE);
UpdateWindow(hWnd);
}
/*
* WpfSetTabs(hwnd, nTabs, pTabs)
*
* Sets up hwnd to use the tabs stops specified by pTabs. Copies these
* tabs into a local-alloc'ed buffer. Any pre-existing tab stops are
* deallocated.
*
*/
void NEAR PASCAL WpfSetTabs(HWND hwnd, int nTabs, LPINT pTabs)
{
PTXT pTxt;
int i;
pTxt = LockWinInfo(hwnd);
/* Discard old tabs, allocate space for new tab settings */
if (pTxt->pTabs)
LocalFree((HANDLE)pTxt->pTabs);
if (pTabs == NULL || nTabs == 0) {
pTxt->pTabs = NULL;
pTxt->nTabs = 0;
}
else {
pTxt->pTabs = (PINT)LocalAlloc(LPTR, nTabs * sizeof(int));
pTxt->nTabs = nTabs;
/* Copy caller's tab settings into the current tab table */
if (pTxt->pTabs) {
for (i=0; i < nTabs; i++)
pTxt->pTabs[i] = *pTabs++;
}
}
InvalidateRect(hwnd,NULL,TRUE);
UnlockWinInfo(hwnd);
}
/*
* fIsTabs = WpfGetTabs(hwnd, pTabs)
*
* Responds to a WPF_GETTABSTOPS message by filling in the supplied
* buffer with the current tab settings. Returns TRUE if there are tabs
* stops, or FALSE if there aren't any tab stops in use.
*
*/
BOOL NEAR PASCAL WpfGetTabs(HWND hwnd, LPINT pTabs)
{
PTXT pTxt;
int i;
pTxt = LockWinInfo(hwnd);
/* If there are no current tabs, return FALSE */
if (pTxt->nTabs == 0 || pTxt->pTabs == NULL) {
UnlockWinInfo(hwnd);
return FALSE;
}
/* Otherwise, copy my tabs into the caller's buffer. Assume
* that the caller's buffer is large enough.
*/
for (i=0; i < pTxt->nTabs; i++) {
*pTabs++ = pTxt->pTabs[i];
}
UnlockWinInfo(hwnd);
return TRUE;
}
/***********************************
*
* WINDOW PROCEDURE
*
***********************************/
/*--------------------------------------------------------------------------*\
| WpfPaint(hWnd, hDC ) |
| |
| Description: |
| The paint function. |
| |
| Arguments: |
| hWnd Window to paint to. |
| hDC handle to update region's display context |
| |
| Returns: |
| nothing |
| |
\*--------------------------------------------------------------------------*/
void NEAR PASCAL WpfPaint(HWND hwnd, HDC hdc)
{
PTXT pTxt;
int i;
int iQue;
int xco;
int yco;
int iLast;
RECT rc;
RECT rcClip;
HFONT hfontOld;
//LockData(0); /* need from spy DS not locked! */
pTxt = LockWinInfo(hwnd);
GetClientRect(hwnd, &rc);
rc.left += OFFSETX;
rc.top += OFFSETY;
IntersectClipRect(hdc, rc.left, rc.top, rc.right, rc.bottom);
SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
/* If a font (other than the system font) has been specified, use it */
if (pTxt->hFont)
hfontOld = SelectObject(hdc, pTxt->hFont);
/* Setup counters as appropriate. Get indexes of first and last
* lines visible within the window.
*/
iLast = LAST(pTxt);
iQue = TOP(pTxt);
/* The x and y initial points for the text line.
* xco is shifted left to account for any horizonal scrolling
* that may be going on
*/
xco = OFFSETX - pTxt->iLeft * pTxt->Tdx; // shifted for h-scrolling
yco = OFFSETY; // starting y pix value
/* RC is the bounding rect for the current line.
*
* Calc initial line bounding rect.. top = top of window (padded),
* bottom = top + height of one line.
*/
rc.left = xco;
rc.top = yco;
rc.bottom = yco + pTxt->Tdy;
/* Get the clipping rectangle */
GetClipBox(hdc, &rcClip);
/* Iter over all lines that are visible - if the bounding rect
* for the current line intersects the clip rect, draw the line.
*/
for (;;) {
if (rc.bottom >= rcClip.top) {
/* If we're using tabs, then tab out the text.
*/
char *pStr;
pStr = LocalLock(pTxt->arLines[iQue].hText);
if (pTxt->nTabs > 0) {
/* Erase the background */
ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rc, NULL, 0, NULL);
/* Using *pTxt->arLines[iQue].hText returns the local
* string that is refered to by local handle hText.
*/
TabbedTextOut(hdc, xco, yco,
(LPSTR)pStr,
pTxt->arLines[iQue].iLen,
pTxt->nTabs, pTxt->pTabs, xco);
}
else {
/* Otherwise, blow it out using ExtTextOut */
ExtTextOut(hdc, xco, yco, ETO_OPAQUE, &rc,
(LPSTR)pStr,
pTxt->arLines[iQue].iLen, NULL);
}
LocalUnlock(pTxt->arLines[iQue].hText);
}
/* Bail out when finished printing window contents */
if (iQue == iLast)
break;
INC(pTxt, iQue);
/* Advance the boundry rect & char positions down one line */
yco = rc.top = rc.bottom;
rc.bottom += pTxt->Tdy;
if (yco > rcClip.bottom)
break;
}
/* Restore the old font */
if (hfontOld)
SelectObject(hdc, hfontOld);
// UnlockData(0);
}
LONG FAR PASCAL PrintfWndProc(HWND hWnd, unsigned uiMessage,
UINT wParam, LONG lParam)
{
PAINTSTRUCT rPS;
PTXT pTxt;
HTXT hTxt;
int i;
int iQue;
DWORD rc = 0L;
hTxt = (HTXT)GetWindowLong(hWnd,0);
if (hTxt) pTxt = LocalLock(hTxt);
#define lpCreate ((LPCREATESTRUCT)lParam)
switch (uiMessage) {
case WM_CREATE:
i = LOWORD((DWORD)lpCreate->lpCreateParams);
/* Allocate and initialize the window instance structure
* The storage for the current lines is placed at the end
* end of the instance data structure. allocate room for it.
*/
hTxt = (HTXT) LocalAlloc(LHND, sizeof(struct TEXT_STRUCT) +
(i - VARSIZE) * sizeof(LINE));
if (!hTxt)
return -1L;
pTxt = (PTXT)LocalLock((HANDLE)hTxt);
pTxt->hwnd = hWnd;
pTxt->wID = HIWORD(lpCreate->lpCreateParams);
pTxt->iFile = -1;
pTxt->wOutputLocation = WPFOUT_WINDOW;
pTxt->iFirst = 0; // initially 1 null line
pTxt->iCount = 1;
pTxt->iTop = 0;
pTxt->iLeft = 0; // no initial hscroll offset
pTxt->MaxLen = 0;
pTxt->iMaxLines = i;
pTxt->nTabs = 0;
/* If user specified character input, allocate a buffer */
if (lpCreate->style & WPF_CHARINPUT)
pTxt->hQue = (HQUE) LocalAlloc(LHND | LMEM_ZEROINIT,
sizeof(QUE));
else
pTxt->hQue = NULL;
/* Null initial first line */
pTxt->arLines[0].hText = NULL;
pTxt->arLines[0].iLen = 0;
/* Store the structure pointer onto the window */
SetWindowLong(hWnd, 0, (LONG) hTxt);
/* Setup to use the system font by default */
WpfSetFont(hWnd, GetStockObject(SYSTEM_FONT));
LocalUnlock((HANDLE) hTxt);
return 0L;
case WM_DESTROY:
// DbgDestroy(hWnd);
/* Flush any files in use by the window */
SetOutput(hWnd, WPFOUT_DISABLED, 0L);
/* Blow away all lines held by the window */
iQue = FIRST(pTxt);
for (i=0; i < pTxt->iCount; i++, INC(pTxt,iQue))
if (pTxt->arLines[iQue].hText != NULL)
LocalFree((HANDLE) pTxt->arLines[iQue].hText);
/* And kill char input and tab stop storage */
if (pTxt->hQue)
LocalFree ((HANDLE) pTxt->hQue);
if (pTxt->pTabs)
LocalFree ((HANDLE) pTxt->pTabs);
LocalUnlock(hTxt);
LocalFree((HANDLE)hTxt);
hTxt = NULL;
break;
// case WPF_SETNLINES:
// return 0L;
case WPF_GETNLINES:
rc = pTxt->iMaxLines;
break;
case WM_GETFONT:
rc = pTxt->hFont;
break;
case WM_SETFONT:
WpfSetFont(hWnd, wParam);
break;
/* Tab stop stuff */
case WPF_SETTABSTOPS:
WpfSetTabs(hWnd, wParam, (LPINT) lParam);
break;
case WPF_GETNUMTABS:
rc = pTxt->pTabs ? pTxt->nTabs : 0;
break;
case WPF_GETTABSTOPS:
rc = (LONG) WpfGetTabs(hWnd, (LPINT) lParam);
break;
case WPF_SETOUTPUT:
rc = (LONG) SetOutput(hWnd, wParam, lParam);
break;
case WPF_GETOUTPUT:
rc = (LONG) GetOutput(hWnd);
break;
case WPF_CLEARWINDOW:
WpfClear(hWnd);
break;
case WM_SIZE:
/* It is possible to get WM_SIZEs as a result of
* dicking with scrollbars.. Avoid race conditions
*/
if (!pTxt->fScrollSemaphore) {
pTxt->fScrollSemaphore++;
WpfSetScrollRange(hWnd, TRUE);
UpdateCursorPos(pTxt);
pTxt->fScrollSemaphore--;
}
break;
case WM_VSCROLL:
switch (wParam) {
case SB_LINEDOWN:
WpfVScroll (hWnd,pTxt,1);
break;
case SB_LINEUP:
WpfVScroll (hWnd,pTxt,-1);
break;
case SB_PAGEUP:
WpfVScroll (hWnd,pTxt,-LinesInWpfWindow(hWnd));
break;
case SB_PAGEDOWN:
WpfVScroll (hWnd,pTxt,LinesInWpfWindow(hWnd));
break;
case SB_THUMBTRACK:
WpfVScroll (hWnd,pTxt,LOWORD(lParam)-pTxt->iTop);
break;
case SB_THUMBPOSITION:
WpfVScroll (hWnd,pTxt,LOWORD(lParam)-pTxt->iTop);
/* Fall through */
case SB_ENDSCROLL:
WpfSetScrollRange(hWnd,TRUE);
UpdateCursorPos(pTxt);
break;
}
break;
case WM_HSCROLL:
switch (wParam) {
case SB_LINEDOWN:
WpfHScroll (hWnd, pTxt, 1);
break;
case SB_LINEUP:
WpfHScroll (hWnd, pTxt, -1);
break;
case SB_PAGEUP:
WpfHScroll (hWnd, pTxt, -CharsInWpfWindow(hWnd));
break;
case SB_PAGEDOWN:
WpfHScroll (hWnd, pTxt, CharsInWpfWindow(hWnd));
break;
case SB_THUMBTRACK:
WpfHScroll (hWnd, pTxt, LOWORD(lParam) - pTxt->iLeft);
break;
case SB_THUMBPOSITION:
WpfHScroll (hWnd, pTxt, LOWORD(lParam) - pTxt->iLeft);
/* Fall through */
case SB_ENDSCROLL:
WpfSetScrollRange(hWnd,TRUE);
UpdateCursorPos(pTxt);
break;
}
break;
case WM_PAINT:
BeginPaint(hWnd,&rPS);
WpfPaint (hWnd,rPS.hdc);
EndPaint(hWnd,&rPS);
break;
/* Allow keyboard scrolling */
case WM_KEYDOWN:
switch (wParam) {
case VK_UP:
PostMessage (hWnd,WM_VSCROLL,SB_LINEUP,0L); break;
case VK_DOWN:
PostMessage (hWnd,WM_VSCROLL,SB_LINEDOWN,0L); break;
case VK_PRIOR:
PostMessage (hWnd,WM_VSCROLL,SB_PAGEUP,0L); break;
case VK_NEXT:
PostMessage (hWnd,WM_VSCROLL,SB_PAGEDOWN,0L); break;
case VK_HOME:
PostMessage (hWnd,WM_HSCROLL,SB_PAGEUP,0L); break;
case VK_END:
PostMessage (hWnd,WM_HSCROLL,SB_PAGEDOWN,0L); break;
case VK_LEFT:
PostMessage (hWnd,WM_HSCROLL,SB_LINEUP,0L); break;
case VK_RIGHT:
PostMessage (hWnd,WM_HSCROLL,SB_LINEDOWN,0L); break;
}
break;
/* Handle focus messages to hide and show the caret
* if the WPF window allows for character input.
*/
case WM_SETFOCUS:
if (pTxt->hQue) {
CreateCaret(hWnd,0,1,pTxt->Tdy);
UpdateCursorPos(pTxt);
ShowCaret(hWnd);
}
break;
case WM_KILLFOCUS:
if (pTxt->hQue)
DestroyCaret();
break;
case WM_CHAR:
EnQueChar(hTxt,wParam);
break;
case WM_KEYUP:
switch (wParam) {
case VK_F3:
EnQueChar(hTxt,VK(wParam));
break;
/* Send endscroll when the key goes up - allows for
* type-a-matic action.
*/
case VK_UP:
case VK_DOWN:
case VK_PRIOR:
case VK_NEXT:
PostMessage (hWnd,WM_VSCROLL,SB_ENDSCROLL,0L);
break;
case VK_HOME:
case VK_END:
case VK_LEFT:
case VK_RIGHT:
PostMessage (hWnd,WM_HSCROLL,SB_ENDSCROLL,0L);
break;
}
break;
default:
return DefWindowProc(hWnd,uiMessage,wParam,lParam);
}
if (hTxt) LocalUnlock(hTxt);
return rc;
}
/***********************************************
*
* SCROLLING STUFF
*
***********************************************/
/*
* WpfVScroll(hwnd, pTxt, n)
*
* Vertical scroll the window by n number of lines.
*
*/
void NEAR PASCAL WpfVScroll(HWND hWnd, PTXT pTxt, int n)
{
RECT rect;
int iRange;
/* GetScrollRange (hWnd,SB_VERT,&iMinPos,&iMaxPos); */
iRange = pTxt->iRangeV; // where did this come from?
GetClientRect(hWnd, &rect);
rect.left += OFFSETX; // adjust for pad boundry
rect.top += OFFSETY;
n = BOUND(pTxt->iTop + n, 0, iRange) - pTxt->iTop;
pTxt->iTop += n;
ScrollWindow(hWnd, 0, -n * pTxt->Tdy, &rect, &rect);
SetScrollPos(hWnd, SB_VERT, pTxt->iTop, gbRedraw);
UpdateWindow(hWnd);
}
/*
* WpfHScroll(hwnd, ptxt, n)
*
* Horizontally scrolls the window by n number of character widths.
*
*/
void NEAR PASCAL WpfHScroll(HWND hWnd, PTXT pTxt, int n)
{
RECT rect;
int iRange;
/* GetScrollRange (hWnd,SB_HORZ,&iMinPos,&iMaxPos); */
iRange = pTxt->iRangeH;
GetClientRect (hWnd,&rect);
rect.left += OFFSETX;
rect.top += OFFSETY;
n = BOUND(pTxt->iLeft + n, 0, iRange) - pTxt->iLeft;
pTxt->iLeft += n;
ScrollWindow(hWnd, -n * pTxt->Tdx, 0, &rect, &rect);
SetScrollPos(hWnd, SB_HORZ, pTxt->iLeft, gbRedraw);
UpdateWindow(hWnd);
}
/*
* nLines = LinesInWpfWindow(hwnd)
*
* Returns the height in lines of the window.
*
*/
int NEAR PASCAL LinesInWpfWindow(HWND hWnd)
{
RECT rRect;
PTXT pTxt;
int iLines;
pTxt = *(HTXT) GetWindowLong(hWnd, 0);
GetClientRect(hWnd, &rRect);
iLines = 0;
if (pTxt) {
iLines = (rRect.bottom - rRect.top - OFFSETY) / pTxt->Tdy;
iLines = min(iLines, pTxt->iMaxLines);
}
return iLines;
}
/*
* nChars = CharsInWpfWindow(hwnd)
*
* Returns the width in characters of the window.
*
*/
int NEAR PASCAL CharsInWpfWindow(HWND hWnd)
{
RECT rRect;
PTXT pTxt;
pTxt = *(HTXT)GetWindowLong (hWnd,0);
GetClientRect(hWnd,&rRect);
return pTxt ? (rRect.right - rRect.left - OFFSETX) / pTxt->Tdx : 0;
}
/*
* WpfMaxLen(pTxt)
*
* This function sets the pTxt->MaxLen field to be the length in
* characters of the longest string currently being stored by the WPF
* window.
*
*/
void NEAR PASCAL WpfMaxLen(PTXT pTxt)
{
int iQue;
int iLast;
int iLen;
SIZE size;
// DWORD dwLen;
// HDC hdc;
#if 0
hdc = GetDC(NULL);
if (pTxt->hFont)
SelectObject(hdc, pTxt->hFont);
#endif
iLast = LAST(pTxt);
iQue = TOP(pTxt);
pTxt->MaxLen = 0;
for (;;) {
iLen = pTxt->arLines[iQue].iLen;
#if 0
if (pTxt->nTabs)
dwLen = GetTabbedTextExtent(hdc, (LPSTR) *pTxt->arLines[iQue].hText,
iLen, pTxt->nTabs, (LPINT)pTxt->pTabs);
else
GetTextExtent(hdc, (LPSTR) *pTxt->arLines[iQue].hText,iLen,&size);
iLen = size.cx // pTxt->Tdx + 1;
#endif
if (iLen > pTxt->MaxLen)
pTxt->MaxLen = iLen;
if (iQue == iLast) break;
INC(pTxt,iQue);
}
// ReleaseDC(NULL,hdc);
}
/*
* WpfSetScrollRange(hwnd, bRedraw)
*
* This function sets the scrollbar ranges according to the current
* character/line contents of the window. Both the horizontal and
* vertical scrollbars are adjusted.
*
* This function then calls WpfVScroll/WpfHScroll to adjust the
* scrollbar position accordingly.
*
*/
void NEAR PASCAL WpfSetScrollRange(HWND hWnd, BOOL bRedraw)
{
PTXT pTxt;
int iRange;
if (pTxt = *(HTXT) GetWindowLong(hWnd, 0)) {
gbRedraw = bRedraw;
/* Update the scroll bars */
iRange = pTxt->iCount - LinesInWpfWindow(hWnd) + 1;
/* Adjust for blank last line? */
if (pTxt->arLines[LAST(pTxt)].iLen == 0);
iRange -= 1;
if (iRange < 0) iRange = 0;
/* Set the scrollbar range to that calculated */
pTxt->iRangeV = iRange;
SetScrollRange(hWnd, SB_VERT, 0, iRange, FALSE);
WpfVScroll(hWnd, pTxt, 0);
/* Setup the horizontal scrollbar range */
WpfMaxLen(pTxt);
iRange = pTxt->MaxLen - CharsInWpfWindow(hWnd) + 1;
if (iRange < 0) iRange = 0;
pTxt->iRangeH = iRange;
SetScrollRange(hWnd, SB_HORZ, 0, iRange, FALSE);
WpfHScroll(hWnd, pTxt, 0);
gbRedraw = TRUE;
}
}
/***********************************************************
*
* STUFF TO ADD NEW TEXT LINES
*
***********************************************************/
/*
* NewLine(pTxt)
*
* Adjusts a WPF window when adding a line to the circular array.
* iCount is the count of valid lines in the array. If we
* haven't yet filled up the array, the count is merely increased.
* Otherwise, if the array is full and we're about to wrap around, fixup
* the wrap-around.
*
*/
void NEAR PASCAL NewLine(PTXT pTxt)
{
int iLast = LAST(pTxt);
int iLine,cLine;
RECT rect;
if (pTxt->iCount == pTxt->iMaxLines) {
/* If the array is full, check for wrap-around */
LocalFree ((HANDLE)pTxt->arLines[pTxt->iFirst].hText);
pTxt->arLines[pTxt->iFirst].hText = NULL;
INC(pTxt, pTxt->iFirst);
if (pTxt->iTop > 0)
pTxt->iTop--;
else {
GetClientRect (pTxt->hwnd,&rect);
rect.left += OFFSETX;
rect.top += OFFSETY;
ScrollWindow (pTxt->hwnd, 0, -pTxt->Tdy, &rect, &rect);
}
}
else {
pTxt->iCount++;
}
iLast = LAST(pTxt);
pTxt->arLines[iLast].hText = NULL;
pTxt->arLines[iLast].iLen = 0;
}
/*
* fSuccess = ChangeLine(pTxt, iLine, lpsz)
*
* Changes line number <iLine> to be the string pointed to by lpsz.
* Frees any line currently occupying index <iLine>, and then alloc and
* stores text lpsz.
*
*/
int NEAR PASCAL ChangeLine(PTXT pTxt, int iLine, LPSTR lpch)
{
int iLen;
LPSTR pData;
if (pTxt->arLines[iLine].hText != NULL)
LocalFree((HANDLE)pTxt->arLines[iLine].hText);
iLen = lstrlen(lpch);
if ((pTxt->arLines[iLine].hText = (char**)LocalAlloc(LHND,iLen+1))== NULL)
return FALSE;
pTxt->arLines[iLine].iLen = iLen;
pData = LocalLock(pTxt->arLines[iLine].hText);
lstrcpy(pData, lpch);
LocalUnlock(pTxt->arLines[iLine].hText);
return TRUE;
}
/*
*/
int NEAR PASCAL InsertString(PTXT pTxt, LPSTR lpstr)
{
int iBuf;
int iLast = LAST(pTxt);
int cLine = 0;
char buf[MAXBUFLEN];
buf[0] = '\0';
/*
* copy the string already there
*/
{
PSTR pch;
HANDLE hText;
hText = pTxt->arLines[iLast].hText;
if (hText) {
pch = LocalLock(hText); // (LocalLock eqiv)
iBuf = lstrlen(pch);
lstrcpy(buf, pch); // why?
LocalUnlock(pTxt->arLines[iLast].hText);
} else {
iBuf = 0;
}
}
while (*lpstr != '\0') {
while (*lpstr != '\n' && *lpstr != '\0' && iBuf < MAXBUFLEN-2)
switch (*lpstr) {
case '\b':
/* Backspace, blow away one character */
iBuf--;
lpstr++;
break;
case '\r':
/* Carriage return, go back to beginning of line */
iBuf = 0;
lpstr++;
break;
default:
/* Otherwise, add this char to line */
buf[iBuf++] = *lpstr++;
break;
}
buf[iBuf++] = 0;
/* Presto chango add the line */
ChangeLine(pTxt, iLast, buf); /* buf must be a asciiz string */
if (*lpstr == '\n') { /* Now do the next string after the \n */
lpstr++;
iBuf = 0;
cLine++;
NewLine(pTxt);
INC(pTxt, iLast);
}
}
return cLine; /* the number of new lines added to list */
}
/**********************************************************
*
* CHARACTER INPUT STUFF
*
**********************************************************/
BOOL NEAR PASCAL EnQueChar(HTXT hTxt, WORD vk)
{
PTXT pTxt;
PQUE pQue;
int i;
HWND hwndP;
pTxt = (PTXT)LocalLock((HANDLE)hTxt);
if (!pTxt->hQue)
goto noque;
pQue = (PQUE)LocalLock((HANDLE)pTxt->hQue);
i = pQue->iLen;
switch (vk)
{
case '\b':
if (i > 0)
{
--i;
wpfOut(pTxt->hwnd, "\b");
}
break;
case VK(VK_F3):
wpfOut(pTxt->hwnd, pQue->ach + i);
i += lstrlen(pQue->ach + i);
break;
case '\r':
case '\n':
if (GetKeyState(VK_CONTROL) < 0)
{
wpfOut(pTxt->hwnd,"\\\n");
}
else
{
wpfOut(pTxt->hwnd, "\n");
pQue->ach[i] = '\0';
if (hwndP = GetParent(pTxt->hwnd))
SendMessage(hwndP, WPF_NTEXT, pTxt->wID,
(LONG)(LPSTR)pQue->ach);
i = 0;
}
break;
default:
if (i < QUESIZE)
{
pQue->ach[i] = (char)vk;
sprintf(ach, ("%c", vk));
wpfOut(pTxt->hwnd, ach);
if (hwndP = GetParent(pTxt->hwnd))
SendMessage(hwndP, WPF_NCHAR, pTxt->wID, (LONG) vk);
i++;
}
else
{
/* Input que is full, beep to notify */
MessageBeep(0);
}
break;
}
pQue->iLen = i;
LocalUnlock((HANDLE)pTxt->hQue);
noque:
LocalUnlock((HANDLE)hTxt);
return TRUE;
}
void NEAR PASCAL UpdateCursorPos(PTXT pTxt)
{
int iLine;
int y,x;
int iLen;
DWORD dw;
HDC hdc;
SIZE size;
char **h;
char *ptxt;
/* If I don't do char input, or don't have the focus, forget it */
if (!pTxt->hQue || GetFocus() != pTxt->hwnd)
return;
hdc = GetDC(NULL);
SelectObject(hdc, pTxt->hFont);
iLen = pTxt->arLines[LAST(pTxt)].iLen - pTxt->iLeft;
h = pTxt->arLines[LAST(pTxt)].hText;
// HACK HACK Need to account for tabs?
ptxt = LocalLock(h);
dw = GetTextExtentPoint(hdc, (LPSTR) ptxt + pTxt->iLeft, iLen, &size);
LocalUnlock(h);
iLine = pTxt->iCount - pTxt->iTop;
ReleaseDC(NULL,hdc);
y = OFFSETY + (iLine - 1) * pTxt->Tdy;
x = OFFSETX + size.cx;
SetCaretPos(x,y);
}
/*************************************************
*
* OUTPUT APIS
*
*************************************************/
/*
* fSuccess = SetOutput(hwnd, wCommand, lpszFile)
*
* Changes the output location of the window to be the location
* designated by wParam, one of the WPFOUT_ codes. If this specifies a
* file, lParam points to the filename.
*
* If the new output location cannot be opened/used, the previous output
* location is not altered and FALSE is returned. Otherwise, the
* previous output location is closed (for files) and TRUE is returned.
*
*/
WORD NEAR PASCAL SetOutput(HWND hwnd, UINT wParam, LONG lParam)
{
PTXT pTxt;
int i;
HANDLE h;
int fhOld = -1;
#define COM1_FH (3) // stdaux
/* Check for invalid command code */
if (!(wParam == WPFOUT_WINDOW || wParam == WPFOUT_COM1 ||
wParam == WPFOUT_NEWFILE || wParam == WPFOUT_APPENDFILE ||
wParam == WPFOUT_DISABLED)) {
return FALSE;
}
h = GetWindowLong(hwnd, 0);
pTxt = (PTXT)LocalLock(h);
/* Save the old file handle */
fhOld = pTxt->iFile;
/* If I'm using a file output type, setup the file handle */
switch (wParam) {
case WPFOUT_COM1:
pTxt->iFile = COM1_FH;
break;
case WPFOUT_APPENDFILE:
/* Open file to see if it is there, then seek to end */
i = _lopen((LPSTR) lParam, OF_READWRITE);
if (i == -1) {
/* File didn't exist, just create it */
i = _lcreat((LPSTR) lParam, 0);
if (i == -1) {
/* Couldn't open, just return FALSE */
LocalUnlock(h);
return FALSE;
}
}
else {
/* Seek to the end of existing file */
_llseek(i, 0L, 2);
}
pTxt->iFile = i;
break;
case WPFOUT_NEWFILE:
i = _lcreat((LPSTR) lParam, 0);
if (i == -1) {
LocalUnlock(h);
return FALSE;
}
pTxt->iFile = i;
break;
case WPFOUT_DISABLED:
case WPFOUT_WINDOW:
pTxt->iFile = -1;
break;
}
/* Clear any existing open file handle by closing it */
if (fhOld != -1 && fhOld != COM1_FH) {
/* Close the file */
_lclose(fhOld);
}
pTxt->wOutputLocation = wParam;
LocalUnlock(h);
return TRUE;
}
/*
* wOutput = GetOutput(hwnd)
*
* Returns the output location for window hwnd (one of the WPFOUT_ codes)
*
*/
WORD NEAR PASCAL GetOutput(HWND hwnd)
{
PTXT pTxt;
WORD w;
HANDLE h;
h = GetWindowLong(hwnd, 0);
pTxt = (PTXT) LocalLock(h);
w = pTxt->wOutputLocation;
LocalUnlock(h);
return w;
}
/*
* @doc EXTERNAL WINCOM WPFWINDOW
*
* @api int | wpfPrintf | This function prints a string to a WPF window
* (or redirected output device) using <f printf> style formatting
* codes. The output is placed at the end of the specified WPF window,
* which is scrolled as required. This function does not yield.
*
* @parm HWND | hwnd | Specifies the WPF window. Output to the window
* may be redirected to a file or COM1 by sending a WPF_SETOUTPUT window
* message to <p hwnd>. If output has been redirected, this parameter
* is still required as the current output location is stored in the WPF
* window instance data.
*
* @parm LPSTR | lpszFormat | Points to the output string format
* specification. This string uses the same formatting codes as the
* Windows <f wsprintf> function.
*
* @parm argument | [ arguments, ...] | Extra parameters
* as required by the
* formatting string. Note that these parameters are in the form
* required by <p wsprintf>, so that all string arguments must be far
* pointers (LPSTR) or be cast to be far pointers.
*
* @rdesc Returns the number of characters output. If output to
* the WPF window is disabled, zero is returned. The returned count of
* characters output does not include the translation of newline
* characters into carriage return newline sequences.
*
* @xref wpfVprintf
*
*/
//int FAR cdecl wpfPrintf(HWND hwnd, LPSTR lpszFormat, ...)
//{
// return wpfVprintf(hwnd, lpszFormat, (LPSTR)(&lpszFormat + 1));
//}
/* wpfWrtTTY(hWnd, sz)
*
* Print <sz> to wprintf window <hWnd>.
*
*/
BOOL NEAR PASCAL wpfWrtTTY(HWND hWnd, LPSTR sz)
{
RECT rect;
int iFree;
int iLine;
PTXT pTxt;
HTXT hTxt;
MSG rMsg;
POINT rPoint;
if (!hWnd) hWnd = hwndLast;
if (!hWnd || !IsWindow(hWnd))
return FALSE; /* fail if bad window handle */
hwndLast = hWnd;
hTxt = (HTXT)GetWindowLong (hWnd,0);
pTxt = (PTXT)LocalLock((HANDLE)hTxt);
iLine = pTxt->iCount - pTxt->iTop;
/*
* invalidate the last line to the bottom of window so
* new text will be painted.
*/
GetClientRect(hWnd,&rect);
rect.top += (iLine-1) * pTxt->Tdy;
InvalidateRect (hWnd,&rect,FALSE);
InsertString (pTxt, sz); /* Insert text in the que */
iLine = (pTxt->iCount - pTxt->iTop) - iLine;
if (iLine > 0) {
WpfSetScrollRange (hWnd,FALSE);
WpfVScroll (hWnd,pTxt,pTxt->iCount);/* scroll all the way to bottom */
}
#if 0
else {
WpfSetScrollRange (hWnd,TRUE);
}
#endif
UpdateCursorPos(pTxt);
LocalUnlock((HANDLE)hTxt);
UpdateWindow (hWnd);
return TRUE;
}
/*
* @doc EXTERNAL WINCOM WPFWINDOW
*
* @api int | wpfVprintf | This function prints a string to a WPF window
* (or redirected output device) using <f printf> style formatting
* codes. This function is the same as the <f wpfOut> function, except
* that arguments to the format string are placed in an array of WORDs
* or DWORDs.
*
* @parm HWND | hwnd | Specifies the WPF window. Output to the window
* may be redirected to a file or COM1 by sending a WPF_SETOUTPUT window
* message to <p hwnd>. If output has been redirected, this parameter
* is still required as the current output location is stored in the WPF
* window instance data.
*
* @parm LPSTR | lpszFormat | Points to the output string format
* specification. This string uses the same formatting codes as the
* Windows <f wsprintf> function.
*
* @parm LPSTR | pargs | Points to an array of words, each of which
* specifies an argument for the format string <p lspzFormat>. The
* number, type, and interpretation of the arguments depend on the
* corresponding format control sequences in <p lpszFormat>.
*
* @rdesc Returns the number of characters output. If output to the
* WPF window is disabled, zero is returned. The returned count of
* characters output does not include the translation of newline
* characters into carriage return newline sequences.
*
* @xref wpfPrintf
*
*/
//int FAR cdecl wpfVprintf(HWND hwnd, LPSTR lpszFormat, LPSTR pargs)
//{
// int i;
//
//
// i = wvsprintf(bufTmp, lpszFormat, pargs);
// wpfOut(hwnd, bufTmp);
//
// return i;
//}
/*
* @doc WINCOM EXTERNAL WPFWINDOW
*
* @api void | wpfOut | This function prints a string to a WPF window
* or redirected output device. No formatting is carried out upon the
* string, it is printed verbatim.
*
* @parm HWND | hwnd | Specifies the WPF window. Output to the window
* may be redirected to a file or COM1 by sending a WPF_SETOUTPUT window
* message to <p hwnd>. If output has been redirected, this parameter
* is still required as the current output location is stored in the WPF
* window instance data.
*
* @parm LPSTR | lpsz | Points to the string to be output.
*
* @rdesc None.
*
* @xref wpfPrintf
*
*/
void FAR PASCAL wpfOut(HWND hwnd, LPSTR lpsz)
{
PTXT pTxt;
HTXT hTxt;
if (!IsWindow(hwnd))
return;
hTxt = (HTXT) GetWindowLong(hwnd, 0);
pTxt = (PTXT) LocalLock((HANDLE) hTxt);
if (pTxt->wOutputLocation != WPFOUT_DISABLED) {
if (pTxt->wOutputLocation == WPFOUT_WINDOW) {
wpfWrtTTY(hwnd, lpsz);
}
else {
wpfWrtFile(pTxt->iFile, lpsz);
}
}
LocalUnlock((HANDLE) hTxt);
}
void wpfWrtFile(int fh, LPSTR sz)
{
LPSTR p, q;
char save;
if (fh == -1)
return;
/* output to <fh>, but must convert \n's to \n\r's;
* code below is designed to minimize calls to write()
*/
for (p = q = sz; *p != 0; p++) {
/* e.g. bufTmp="hello\nabc", q->'h', p->'\n' */
if (*p == '\n') {
/* hack: temporarily replace next char by \r */
/* won't work if string is READ-ONLY!!! */
save = *++p; /* remember it */
p[0] = '\n'; /* replace by \r */
p[-1]= '\r'; /* replace by \r */
_lwrite(fh, q, p - q + 1);
q = p; /* for next write() */
*p-- = save; /* un-hack */
*p = '\n';
}
}
if (p > q) /* any part of <bufTmp> left to write */
_lwrite(fh, q, p - q);
//
// flush the file, by closing a copy of the file
//
FlushFileBuffers(fh);
}