📄 cursor.c
字号:
//
// Permedia3 Sample Display Driver
// cursor.c
//
// Copyright (c) 2000 Microsoft Corporation. All rights reserved.
//
// This module contains the code for managing the cursor. This is implemented
// using the hardware cursor on the Permedia 3.
#include "pch.h" // Precompiled header support.
#include "debug.h"
#include "struct.h"
#include "proto.h"
#include "register.h"
// Each time we set a cursor, we record the unique value from that cursor.
// This helps us not set the same cursor twice. Start with a sentinal value.
#define HIDDEN_CURSOR 0xFFFFFFFF
static ULONG l_CurrentCursor = HIDDEN_CURSOR;
// Internal prototypes. These functions are not exposed outside this module.
static void
SetCursorPalette(
BYTE Index,
BYTE Red,
BYTE Green,
BYTE Blue
);
static BYTE
MonoCursorInterleave(
BYTE AndBits,
BYTE XorBits,
BOOL HighNibble
);
ULONG
DrvSetPointerShape(
SURFOBJ * Surface,
SURFOBJ * AndXorMask,
SURFOBJ * Colors,
XLATEOBJ * ColorsXlate,
LONG XHot,
LONG YHot,
LONG X,
LONG Y,
RECTL * BoundaryRect,
FLONG Flags
)
{
// DrvSetPointerShape
// This function is called by GDI to set the cursor shape, hot spot,
// and position. We rely on GDI calling this at least once as part of
// it's boot-up sequence.
// Local variables.
// This is the function's return value. You can find the definition of the
// SPS_* macros in winddi.h.
ULONG FnRetVal = SPS_ERROR;
ULONG i;
ULONG j;
ULONG Register;
ULONG Height;
ULONG Width;
ULONG BytesInCursor;
LONG Stride;
BYTE * AndMask;
BYTE * XorMask;
BYTE PixelValues;
// Check parameters.
// Windows CE does not currently use the BoundaryRect or the Flags
// parameters.
Assert(BoundaryRect == NULL);
Assert(Flags == 0);
Enter(L"DrvSetPointerShape");
// !TODO! FIFO Space check?
// Move the cursor.
DrvMovePointer(Surface, X, Y, BoundaryRect);
if (AndXorMask == NULL ||
AndXorMask->iUniq != l_CurrentCursor) {
// Disable the cursor for update.
WriteMaskedRdReg(r_RDCursorMode,
b_RDCursorMode_CursorEnable,
0);
// Disable byte doubling and position readback. The DDI interface has no
// provision for cursor position readback, so it doesn't matter what mode
// we use.
WriteRdReg(r_RDCursorControl, 0);
// Set the new hot-spot.
WriteRdReg(r_RDCursorHotSpotX,
(BYTE)(XHot & b_RDCursorHotSpotX_X));
WriteRdReg(r_RDCursorHotSpotY,
(BYTE)(YHot & b_RDCursorHotSpotY_Y));
// Update the pointer itself.
if (AndXorMask) {
if (!Colors) {
// It's a monochrome cursor.
// Enable "Microsoft Windows" monochrome mode. Also make sure that we
// disable reverse pixel ordering while we're at it.
WriteMaskedRdReg(r_RDCursorMode,
b_RDCursorMode_Type |
b_RDCursorMode_ReversePixelOrder,
0);
// Setup our "palette." Black as color 1 and white as color 2.
SetCursorPalette(1, 0x00, 0x00, 0x00);
SetCursorPalette(2, 0xFF, 0xFF, 0xFF);
// Load the monochrome bitmap by getting the AND and the XOR bits
// from their respective locations, smashing them together, and
// dropping them in the palette cursor pattern bits.
// Check size first. Can only be 32x32 or 64x64.
Height = AndXorMask->sizlBitmap.cy;
Width = AndXorMask->sizlBitmap.cx;
Stride = AndXorMask->lDelta;
BytesInCursor = (Width / 8) * (Height / 2);
// Set our pointers. The XOR mask is first in the AndXorMask, and the
// AND mask is directly after it. (Note that we need to position these
// pointers correctly based on if the bitmap is top-up or bottom-down.)
if (Stride > 0) {
XorMask = (BYTE *)AndXorMask->pvScan0;
AndMask = ((BYTE *)AndXorMask->pvScan0) + BytesInCursor;
}
else {
XorMask = ((BYTE *)AndXorMask->pvScan0) - BytesInCursor;
AndMask = (BYTE *)AndXorMask->pvScan0;
}
// Note that because there are two masks, the height is double.
if ((Width == 32 && Height == 64)) {
// Use partition 0 -> We can then share "pixel plotting" code
// with 64x64.
WriteMaskedRdReg(r_RDCursorMode,
b_RDCursorMode_Format,
2);
}
else if ((Width == 64 && Height == 128)) {
WriteMaskedRdReg(r_RDCursorMode,
b_RDCursorMode_Format,
0);
}
else {
Error(L"Unsupported cursor size.\n");
}
// Iterate over scanlines in the cursor. For each scanline, iterate over
// the bytes in the scanline. Each byte needs to be interleaved. This
// resolves into 8 pixels. There are 4 pixels per register, so each inner
// loop results in two byte register writes.
for (i = 0, Register = r_RDCursorPattern;
i < (Height / 2);
i++, AndMask += Stride, XorMask += Stride) {
for (j = 0; j < (Width / 8); j++) {
PixelValues = MonoCursorInterleave(*(AndMask + j),
*(XorMask + j),
TRUE);
WriteRdReg(Register++, PixelValues);
PixelValues = MonoCursorInterleave(*(AndMask + j),
*(XorMask + j),
FALSE);
WriteRdReg(Register++, PixelValues);
}
}
// Re-enable the cursor.
WriteMaskedRdReg(r_RDCursorMode,
b_RDCursorMode_CursorEnable,
b_RDCursorMode_CursorEnable);
l_CurrentCursor = AndXorMask->iUniq;
FnRetVal = SPS_ACCEPT_NOEXCLUDE;
}
else {
Message(L"Color cursors are not yet implemented!\n");
FnRetVal = SPS_DECLINE;
}
}
else {
// No AndXorMask means that we should hide the cursor. We
// accomplish this by leaving the cursor disabled.
l_CurrentCursor = HIDDEN_CURSOR;
FnRetVal = SPS_ACCEPT_NOEXCLUDE;
}
}
else {
// Don't change the cursor to something it already is!
FnRetVal = SPS_ACCEPT_NOEXCLUDE;
}
Exit(L"DrvSetPointerShape");
return FnRetVal;
}
void
DrvMovePointer(
SURFOBJ * Surface,
LONG X,
LONG Y,
RECTL * BoundaryRect
)
{
// DrvMovePointer
// This function is called by GDI in order to position the cursor. Note
// that the Permedia3 does not complete a cursor position change until
// the RDCursorYHigh register is written to in order to avoid artifacts
// from half-formed positions.
// Check parameters.
// We can only position the pointer on the primary surface.
Assert(((PERM3_SURFACE *)Surface->dhsurf)->Ptr == GetPrimarySurface()->Ptr);
Assert(X >= 0 && X < (LONG)GetDisplayModeWidth(GetCurrentMode()));
Assert(Y >= 0 && Y < (LONG)GetDisplayModeHeight(GetCurrentMode()));
// Windows CE does not currently use the BoundaryRect.
Assert(BoundaryRect == NULL);
// !TODO! FIFO space check.
Enter(L"DrvMovePointer");
// Write the X position.
WriteRdReg(r_RDCursorXLow,
(BYTE)(X & b_RDCursorXLow_XLow));
WriteRdReg(r_RDCursorXHigh,
(BYTE)((X >> 8) & b_RDCursorXHigh_XHigh));
// Write the Y position.
WriteRdReg(r_RDCursorYLow,
(BYTE)(Y & b_RDCursorYLow_YLow));
WriteRdReg(r_RDCursorYHigh,
(BYTE)((Y >> 8) & b_RDCursorYHigh_YHigh));
Exit(L"DrvMovePointer");
}
void
SetCursorPalette(
BYTE Index,
BYTE Red,
BYTE Green,
BYTE Blue
)
{
// SetCursorPalette
// This function helps set the registers that define a particular color
// for a particular index for the cursor. The Permedia3 literature refers
// to that palette as color index 1 to 15. We will continue that
// nomenclature, but note that color index 1 is offset 0 from the beginning
// of the palette registers.
// Local constants.
// Location of the R, G, and B components in relation to a base index
// offset.
const ULONG RedOffset = 0;
const ULONG GreenOffset = 1;
const ULONG BlueOffset = 2;
// Local variables.
ULONG IndexBase;
// Check parameters.
// Red, Green, and Blue can be anything.
Assert(Index <= 15);
Enter(L"SetCursorPalette");
// !TODO! FIFO space check
// Compute the base address of the registers for this index. Note that the
// Permedia's cursor palette is "upside-down." That's why we need the extra
// subtraction.
IndexBase = r_RDCursorPalette + ((15 - Index) * 3);
// Write the colors.
WriteRdReg(IndexBase + RedOffset,
Red);
WriteRdReg(IndexBase + GreenOffset,
Green);
WriteRdReg(IndexBase + BlueOffset,
Blue);
Exit(L"SetCursorPalette");
}
BYTE
MonoCursorInterleave(
BYTE AndBits,
BYTE XorBits,
BOOL HighNibble
)
{
// MonoCursorInterleave
// This function interleaves 4 bits from the high and low bits values
// into a single byte. We determine which nibble to interleave from
// from the BOOL.
// Local variables.
BYTE FnRetVal;
// Check parameters.
// No checking necessary for AndBits, XorBits, and HighNibble.
Enter(L"MonoCursorInterleave");
// Check if we are reading from the high nibble.
if (HighNibble) {
FnRetVal = ((AndBits & 0x00000010) << 3) |
((XorBits & 0x00000010) << 2) |
((AndBits & 0x00000020) ) |
((XorBits & 0x00000020) >> 1) |
((AndBits & 0x00000040) >> 3) |
((XorBits & 0x00000040) >> 4) |
((AndBits & 0x00000080) >> 6) |
((XorBits & 0x00000080) >> 7);
}
else {
FnRetVal = ((AndBits & 0x00000001) << 7) |
((XorBits & 0x00000001) << 6) |
((AndBits & 0x00000002) << 4) |
((XorBits & 0x00000002) << 3) |
((AndBits & 0x00000004) << 1) |
((XorBits & 0x00000004) ) |
((AndBits & 0x00000008) >> 2) |
((XorBits & 0x00000008) >> 3);
}
Exit(L"MonoCursorInterleave");
return FnRetVal;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -