2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Console Server DLL
4 * FILE: win32ss/user/winsrv/consrv/frontends/gui/text.c
5 * PURPOSE: GUI Terminal Front-End - Support for text-mode screen-buffers
6 * PROGRAMMERS: Gé van Geldorp
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
12 /* INCLUDES *******************************************************************/
21 /* GLOBALS ********************************************************************/
23 #define IS_WHITESPACE(c) ((c) == L'\0' || (c) == L' ' || (c) == L'\t')
25 /* FUNCTIONS ******************************************************************/
27 COLORREF
PaletteRGBFromAttrib(PCONSOLE Console
, WORD Attribute
)
29 HPALETTE hPalette
= Console
->ActiveBuffer
->PaletteHandle
;
32 if (hPalette
== NULL
) return RGBFromAttrib(Console
, Attribute
);
34 GetPaletteEntries(hPalette
, Attribute
, 1, &pe
);
35 return PALETTERGB(pe
.peRed
, pe
.peGreen
, pe
.peBlue
);
39 CopyBlock(PTEXTMODE_SCREEN_BUFFER Buffer
,
40 PSMALL_RECT Selection
)
43 * Pressing the Shift key while copying text, allows us to copy
44 * text without newline characters (inline-text copy mode).
46 BOOL InlineCopyMode
= !!(GetKeyState(VK_SHIFT
) & 0x8000);
51 ULONG selWidth
, selHeight
;
55 DPRINT("CopyBlock(%u, %u, %u, %u)\n",
56 Selection
->Left
, Selection
->Top
, Selection
->Right
, Selection
->Bottom
);
58 /* Prevent against empty blocks */
59 if (Selection
== NULL
) return;
60 if (Selection
->Left
> Selection
->Right
|| Selection
->Top
> Selection
->Bottom
)
63 selWidth
= Selection
->Right
- Selection
->Left
+ 1;
64 selHeight
= Selection
->Bottom
- Selection
->Top
+ 1;
66 /* Basic size for one line... */
68 /* ... and for the other lines, add newline characters if needed. */
72 * If we are not in inline-text copy mode, each selected line must
73 * finish with \r\n . Otherwise, the lines will be just concatenated.
75 size
+= (selWidth
+ (!InlineCopyMode
? 2 : 0)) * (selHeight
- 1);
79 DPRINT1("This case must never happen, because selHeight is at least == 1\n");
82 size
+= 1; /* Null-termination */
83 size
*= sizeof(WCHAR
);
85 /* Allocate some memory area to be given to the clipboard, so it will not be freed here */
86 hData
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_ZEROINIT
, size
);
87 if (hData
== NULL
) return;
89 data
= GlobalLock(hData
);
96 DPRINT("Copying %dx%d selection\n", selWidth
, selHeight
);
99 for (yPos
= 0; yPos
< selHeight
; yPos
++)
101 ULONG length
= selWidth
;
103 ptr
= ConioCoordToPointer(Buffer
,
105 Selection
->Top
+ yPos
);
107 /* Trim whitespace from the right */
110 if (IS_WHITESPACE(ptr
[length
-1].Char
.UnicodeChar
))
116 /* Copy only the characters, leave attributes alone */
117 for (xPos
= 0; xPos
< length
; xPos
++)
120 * Sometimes, applications can put NULL chars into the screen-buffer
121 * (this behaviour is allowed). Detect this and replace by a space.
123 *dstPos
++ = (ptr
[xPos
].Char
.UnicodeChar
? ptr
[xPos
].Char
.UnicodeChar
: L
' ');
126 /* Add newline characters if we are not in inline-text copy mode */
129 if (yPos
!= (selHeight
- 1))
131 wcscat(dstPos
, L
"\r\n");
137 DPRINT("Setting data <%S> to clipboard\n", data
);
141 SetClipboardData(CF_UNICODETEXT
, hData
);
145 CopyLines(PTEXTMODE_SCREEN_BUFFER Buffer
,
152 ULONG NumChars
, size
;
153 ULONG xPos
, yPos
, xBeg
, xEnd
;
155 DPRINT("CopyLines((%u, %u) ; (%u, %u))\n",
156 Begin
->X
, Begin
->Y
, End
->X
, End
->Y
);
158 /* Prevent against empty blocks... */
159 if (Begin
== NULL
|| End
== NULL
) return;
160 /* ... or malformed blocks */
161 if (Begin
->Y
> End
->Y
|| (Begin
->Y
== End
->Y
&& Begin
->X
> End
->X
)) return;
163 /* Compute the number of characters to copy */
164 if (End
->Y
== Begin
->Y
) // top == bottom
166 NumChars
= End
->X
- Begin
->X
+ 1;
168 else // if (End->Y > Begin->Y)
170 NumChars
= (Buffer
->ScreenBufferSize
.X
- 1) - (Begin
->X
) + 1;
172 if (Begin
->Y
+ 1 <= End
->Y
- 1)
174 NumChars
+= ( (Buffer
->ScreenBufferSize
.X
- 1) + 1 ) *
175 ( (End
->Y
- 1) - (Begin
->Y
+ 1) + 1);
178 NumChars
+= End
->X
+ 1;
181 size
= (NumChars
+ 1) * sizeof(WCHAR
); /* Null-terminated */
183 /* Allocate some memory area to be given to the clipboard, so it will not be freed here */
184 hData
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_ZEROINIT
, size
);
185 if (hData
== NULL
) return;
187 data
= GlobalLock(hData
);
194 DPRINT("Copying %d characters\n", NumChars
);
198 * We need to walk per-lines, and not just looping in the big screen-buffer
199 * array, because of the way things are stored inside it. The downside is
200 * that it makes the code more complicated.
202 for (yPos
= Begin
->Y
; (yPos
<= End
->Y
) && (NumChars
> 0); yPos
++)
204 xBeg
= (yPos
== Begin
->Y
? Begin
->X
: 0);
205 xEnd
= (yPos
== End
->Y
? End
->X
: Buffer
->ScreenBufferSize
.X
- 1);
207 ptr
= ConioCoordToPointer(Buffer
, xBeg
, yPos
);
209 /* Copy only the characters, leave attributes alone */
210 for (xPos
= xBeg
; (xPos
<= xEnd
) && (NumChars
-- > 0); xPos
++)
213 * Sometimes, applications can put NULL chars into the screen-buffer
214 * (this behaviour is allowed). Detect this and replace by a space.
216 *dstPos
++ = (ptr
[xPos
].Char
.UnicodeChar
? ptr
[xPos
].Char
.UnicodeChar
: L
' ');
220 DPRINT("Setting data <%S> to clipboard\n", data
);
224 SetClipboardData(CF_UNICODETEXT
, hData
);
229 GetSelectionBeginEnd(PCOORD Begin
, PCOORD End
,
230 PCOORD SelectionAnchor
,
231 PSMALL_RECT SmallRect
);
234 GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
235 PGUI_CONSOLE_DATA GuiData
)
238 * This function supposes that the system clipboard was opened.
241 BOOL LineSelection
= GuiData
->LineSelection
;
243 DPRINT("Selection is (%d|%d) to (%d|%d) in %s mode\n",
244 GuiData
->Selection
.srSelection
.Left
,
245 GuiData
->Selection
.srSelection
.Top
,
246 GuiData
->Selection
.srSelection
.Right
,
247 GuiData
->Selection
.srSelection
.Bottom
,
248 (LineSelection
? "line" : "block"));
252 CopyBlock(Buffer
, &GuiData
->Selection
.srSelection
);
258 GetSelectionBeginEnd(&Begin
, &End
,
259 &GuiData
->Selection
.dwSelectionAnchor
,
260 &GuiData
->Selection
.srSelection
);
262 CopyLines(Buffer
, &Begin
, &End
);
267 GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
268 PGUI_CONSOLE_DATA GuiData
)
271 * This function supposes that the system clipboard was opened.
274 PCONSOLE Console
= Buffer
->Header
.Console
;
280 USHORT VkKey
; // MAKEWORD(low = vkey_code, high = shift_state);
283 hData
= GetClipboardData(CF_UNICODETEXT
);
284 if (hData
== NULL
) return;
286 str
= GlobalLock(hData
);
287 if (str
== NULL
) return;
289 DPRINT("Got data <%S> from clipboard\n", str
);
291 er
.EventType
= KEY_EVENT
;
292 er
.Event
.KeyEvent
.wRepeatCount
= 1;
295 /* \r or \n characters. Go to the line only if we get "\r\n" sequence. */
296 if (CurChar
== L
'\r' && *str
== L
'\n')
303 /* Get the key code (+ shift state) corresponding to the character */
304 VkKey
= VkKeyScanW(CurChar
);
307 DPRINT1("VkKeyScanW failed - Should simulate the key...\n");
311 /* Pressing some control keys */
313 /* Pressing the character key, with the control keys maintained pressed */
314 er
.Event
.KeyEvent
.bKeyDown
= TRUE
;
315 er
.Event
.KeyEvent
.wVirtualKeyCode
= LOBYTE(VkKey
);
316 er
.Event
.KeyEvent
.wVirtualScanCode
= MapVirtualKeyW(LOBYTE(VkKey
), MAPVK_VK_TO_CHAR
);
317 er
.Event
.KeyEvent
.uChar
.UnicodeChar
= CurChar
;
318 er
.Event
.KeyEvent
.dwControlKeyState
= 0;
319 if (HIBYTE(VkKey
) & 1)
320 er
.Event
.KeyEvent
.dwControlKeyState
|= SHIFT_PRESSED
;
321 if (HIBYTE(VkKey
) & 2)
322 er
.Event
.KeyEvent
.dwControlKeyState
|= LEFT_CTRL_PRESSED
; // RIGHT_CTRL_PRESSED;
323 if (HIBYTE(VkKey
) & 4)
324 er
.Event
.KeyEvent
.dwControlKeyState
|= LEFT_ALT_PRESSED
; // RIGHT_ALT_PRESSED;
326 ConioProcessInputEvent(Console
, &er
);
328 /* Up all the character and control keys */
329 er
.Event
.KeyEvent
.bKeyDown
= FALSE
;
330 ConioProcessInputEvent(Console
, &er
);
337 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer
,
338 PGUI_CONSOLE_DATA GuiData
,
342 PCONSOLE Console
= Buffer
->Header
.Console
;
343 // ASSERT(Console == GuiData->Console);
345 ULONG TopLine
, BottomLine
, LeftChar
, RightChar
;
346 ULONG Line
, Char
, Start
;
349 WORD LastAttribute
, Attribute
;
350 ULONG CursorX
, CursorY
, CursorHeight
;
351 HBRUSH CursorBrush
, OldBrush
;
354 if (Buffer
->Buffer
== NULL
) return;
356 if (!ConDrvValidateConsoleUnsafe(Console
, CONSOLE_RUNNING
, TRUE
)) return;
358 rcFramebuffer
->left
= Buffer
->ViewOrigin
.X
* GuiData
->CharWidth
+ rcView
->left
;
359 rcFramebuffer
->top
= Buffer
->ViewOrigin
.Y
* GuiData
->CharHeight
+ rcView
->top
;
360 rcFramebuffer
->right
= Buffer
->ViewOrigin
.X
* GuiData
->CharWidth
+ rcView
->right
;
361 rcFramebuffer
->bottom
= Buffer
->ViewOrigin
.Y
* GuiData
->CharHeight
+ rcView
->bottom
;
363 LeftChar
= rcFramebuffer
->left
/ GuiData
->CharWidth
;
364 TopLine
= rcFramebuffer
->top
/ GuiData
->CharHeight
;
365 RightChar
= rcFramebuffer
->right
/ GuiData
->CharWidth
;
366 BottomLine
= rcFramebuffer
->bottom
/ GuiData
->CharHeight
;
368 if (RightChar
>= Buffer
->ScreenBufferSize
.X
) RightChar
= Buffer
->ScreenBufferSize
.X
- 1;
369 if (BottomLine
>= Buffer
->ScreenBufferSize
.Y
) BottomLine
= Buffer
->ScreenBufferSize
.Y
- 1;
371 LastAttribute
= ConioCoordToPointer(Buffer
, LeftChar
, TopLine
)->Attributes
;
373 SetTextColor(GuiData
->hMemDC
, PaletteRGBFromAttrib(Console
, TextAttribFromAttrib(LastAttribute
)));
374 SetBkColor(GuiData
->hMemDC
, PaletteRGBFromAttrib(Console
, BkgdAttribFromAttrib(LastAttribute
)));
376 OldFont
= SelectObject(GuiData
->hMemDC
, GuiData
->Font
);
378 for (Line
= TopLine
; Line
<= BottomLine
; Line
++)
380 WCHAR LineBuffer
[80]; // Buffer containing a part or all the line to be displayed
381 From
= ConioCoordToPointer(Buffer
, LeftChar
, Line
); // Get the first code of the line
385 for (Char
= LeftChar
; Char
<= RightChar
; Char
++)
388 * We flush the buffer if the new attribute is different
389 * from the current one, or if the buffer is full.
391 if (From
->Attributes
!= LastAttribute
|| (Char
- Start
== sizeof(LineBuffer
) / sizeof(WCHAR
)))
393 TextOutW(GuiData
->hMemDC
,
394 Start
* GuiData
->CharWidth
,
395 Line
* GuiData
->CharHeight
,
400 Attribute
= From
->Attributes
;
401 if (Attribute
!= LastAttribute
)
403 SetTextColor(GuiData
->hMemDC
, PaletteRGBFromAttrib(Console
, TextAttribFromAttrib(Attribute
)));
404 SetBkColor(GuiData
->hMemDC
, PaletteRGBFromAttrib(Console
, BkgdAttribFromAttrib(Attribute
)));
405 LastAttribute
= Attribute
;
409 *(To
++) = (From
++)->Char
.UnicodeChar
;
412 TextOutW(GuiData
->hMemDC
,
413 Start
* GuiData
->CharWidth
,
414 Line
* GuiData
->CharHeight
,
416 RightChar
- Start
+ 1);
422 if (Buffer
->CursorInfo
.bVisible
&&
423 Buffer
->CursorBlinkOn
&&
424 !Buffer
->ForceCursorOff
)
426 CursorX
= Buffer
->CursorPosition
.X
;
427 CursorY
= Buffer
->CursorPosition
.Y
;
428 if (LeftChar
<= CursorX
&& CursorX
<= RightChar
&&
429 TopLine
<= CursorY
&& CursorY
<= BottomLine
)
431 CursorHeight
= ConioEffectiveCursorSize(Console
, GuiData
->CharHeight
);
433 Attribute
= ConioCoordToPointer(Buffer
, Buffer
->CursorPosition
.X
, Buffer
->CursorPosition
.Y
)->Attributes
;
434 if (Attribute
== DEFAULT_SCREEN_ATTRIB
) Attribute
= Buffer
->ScreenDefaultAttrib
;
436 CursorBrush
= CreateSolidBrush(PaletteRGBFromAttrib(Console
, TextAttribFromAttrib(Attribute
)));
437 OldBrush
= SelectObject(GuiData
->hMemDC
, CursorBrush
);
439 PatBlt(GuiData
->hMemDC
,
440 CursorX
* GuiData
->CharWidth
,
441 CursorY
* GuiData
->CharHeight
+ (GuiData
->CharHeight
- CursorHeight
),
445 SelectObject(GuiData
->hMemDC
, OldBrush
);
446 DeleteObject(CursorBrush
);
450 SelectObject(GuiData
->hMemDC
, OldFont
);
452 LeaveCriticalSection(&Console
->Lock
);