[CONSRV]
[reactos.git] / reactos / win32ss / user / winsrv / consrv / frontends / gui / text.c
1 /*
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
7 * Johannes Anderwald
8 * Jeffrey Morlan
9 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
10 */
11
12 /* INCLUDES *******************************************************************/
13
14 #include <consrv.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* FUNCTIONS ******************************************************************/
20
21 COLORREF RGBFromAttrib2(PCONSOLE Console, WORD Attribute)
22 {
23 HPALETTE hPalette = Console->ActiveBuffer->PaletteHandle;
24 PALETTEENTRY pe;
25
26 if (hPalette == NULL) return RGBFromAttrib(Console, Attribute);
27
28 GetPaletteEntries(hPalette, Attribute, 1, &pe);
29 return PALETTERGB(pe.peRed, pe.peGreen, pe.peBlue);
30 }
31
32 VOID
33 GuiCopyFromTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
34 PGUI_CONSOLE_DATA GuiData)
35 {
36 /*
37 * This function supposes that the system clipboard was opened.
38 */
39
40 PCONSOLE Console = Buffer->Header.Console;
41
42 /*
43 * Pressing the Shift key while copying text, allows us to copy
44 * text without newline characters (inline-text copy mode).
45 */
46 BOOL InlineCopyMode = (GetKeyState(VK_SHIFT) & 0x8000);
47
48 HANDLE hData;
49 PCHAR_INFO ptr;
50 LPWSTR data, dstPos;
51 ULONG selWidth, selHeight;
52 ULONG xPos, yPos, size;
53
54 selWidth = Console->Selection.srSelection.Right - Console->Selection.srSelection.Left + 1;
55 selHeight = Console->Selection.srSelection.Bottom - Console->Selection.srSelection.Top + 1;
56 DPRINT("Selection is (%d|%d) to (%d|%d)\n",
57 Console->Selection.srSelection.Left,
58 Console->Selection.srSelection.Top,
59 Console->Selection.srSelection.Right,
60 Console->Selection.srSelection.Bottom);
61
62 #ifdef IS_WHITESPACE
63 #undef IS_WHITESPACE
64 #endif
65 #define IS_WHITESPACE(c) ((c) == L'\0' || (c) == L' ' || (c) == L'\t')
66
67 /* Basic size for one line... */
68 size = selWidth;
69 /* ... and for the other lines, add newline characters if needed. */
70 if (selHeight > 0)
71 {
72 /*
73 * If we are not in inline-text copy mode, each selected line must
74 * finish with \r\n . Otherwise, the lines will be just concatenated.
75 */
76 size += (selWidth + (!InlineCopyMode ? 2 : 0)) * (selHeight - 1);
77 }
78 size += 1; /* Null-termination */
79 size *= sizeof(WCHAR);
80
81 /* Allocate some memory area to be given to the clipboard, so it will not be freed here */
82 hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size);
83 if (hData == NULL) return;
84
85 data = GlobalLock(hData);
86 if (data == NULL)
87 {
88 GlobalFree(hData);
89 return;
90 }
91
92 DPRINT("Copying %dx%d selection\n", selWidth, selHeight);
93 dstPos = data;
94
95 for (yPos = 0; yPos < selHeight; yPos++)
96 {
97 ULONG length = selWidth;
98
99 ptr = ConioCoordToPointer(Buffer,
100 Console->Selection.srSelection.Left,
101 Console->Selection.srSelection.Top + yPos);
102
103 /* Trim whitespace from the right */
104 while (length > 0)
105 {
106 if (IS_WHITESPACE(ptr[length-1].Char.UnicodeChar))
107 --length;
108 else
109 break;
110 }
111
112 /* Copy only the characters, leave attributes alone */
113 for (xPos = 0; xPos < length; xPos++)
114 {
115 /*
116 * Sometimes, applications can put NULL chars into the screen-buffer
117 * (this behaviour is allowed). Detect this and replace by a space.
118 */
119 dstPos[xPos] = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' ');
120 }
121 dstPos += length;
122
123 /* Add newline characters if we are not in inline-text copy mode */
124 if (!InlineCopyMode)
125 {
126 if (yPos != (selHeight - 1))
127 {
128 wcscat(data, L"\r\n");
129 dstPos += 2;
130 }
131 }
132 }
133
134 DPRINT("Setting data <%S> to clipboard\n", data);
135 GlobalUnlock(hData);
136
137 EmptyClipboard();
138 SetClipboardData(CF_UNICODETEXT, hData);
139 }
140
141 VOID
142 GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
143 PGUI_CONSOLE_DATA GuiData)
144 {
145 /*
146 * This function supposes that the system clipboard was opened.
147 */
148
149 PCONSOLE Console = Buffer->Header.Console;
150
151 HANDLE hData;
152 LPWSTR str;
153 WCHAR CurChar = 0;
154
155 USHORT VkKey; // MAKEWORD(low = vkey_code, high = shift_state);
156 INPUT_RECORD er;
157
158 hData = GetClipboardData(CF_UNICODETEXT);
159 if (hData == NULL) return;
160
161 str = GlobalLock(hData);
162 if (str == NULL) return;
163
164 DPRINT("Got data <%S> from clipboard\n", str);
165
166 er.EventType = KEY_EVENT;
167 er.Event.KeyEvent.wRepeatCount = 1;
168 while (*str)
169 {
170 /* \r or \n characters. Go to the line only if we get "\r\n" sequence. */
171 if (CurChar == L'\r' && *str == L'\n')
172 {
173 str++;
174 continue;
175 }
176 CurChar = *str++;
177
178 /* Get the key code (+ shift state) corresponding to the character */
179 VkKey = VkKeyScanW(CurChar);
180 if (VkKey == 0xFFFF)
181 {
182 DPRINT1("VkKeyScanW failed - Should simulate the key...\n");
183 continue;
184 }
185
186 /* Pressing some control keys */
187
188 /* Pressing the character key, with the control keys maintained pressed */
189 er.Event.KeyEvent.bKeyDown = TRUE;
190 er.Event.KeyEvent.wVirtualKeyCode = LOBYTE(VkKey);
191 er.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(LOBYTE(VkKey), MAPVK_VK_TO_CHAR);
192 er.Event.KeyEvent.uChar.UnicodeChar = CurChar;
193 er.Event.KeyEvent.dwControlKeyState = 0;
194 if (HIBYTE(VkKey) & 1)
195 er.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
196 if (HIBYTE(VkKey) & 2)
197 er.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; // RIGHT_CTRL_PRESSED;
198 if (HIBYTE(VkKey) & 4)
199 er.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; // RIGHT_ALT_PRESSED;
200
201 ConioProcessInputEvent(Console, &er);
202
203 /* Up all the character and control keys */
204 er.Event.KeyEvent.bKeyDown = FALSE;
205 ConioProcessInputEvent(Console, &er);
206 }
207
208 GlobalUnlock(hData);
209 }
210
211 VOID
212 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
213 PGUI_CONSOLE_DATA GuiData,
214 PRECT rcView,
215 PRECT rcFramebuffer)
216 {
217 PCONSOLE Console = Buffer->Header.Console;
218 // ASSERT(Console == GuiData->Console);
219
220 ULONG TopLine, BottomLine, LeftChar, RightChar;
221 ULONG Line, Char, Start;
222 PCHAR_INFO From;
223 PWCHAR To;
224 WORD LastAttribute, Attribute;
225 ULONG CursorX, CursorY, CursorHeight;
226 HBRUSH CursorBrush, OldBrush;
227 HFONT OldFont;
228
229 if (Buffer->Buffer == NULL) return;
230
231 rcFramebuffer->left = Buffer->ViewOrigin.X * GuiData->CharWidth + rcView->left;
232 rcFramebuffer->top = Buffer->ViewOrigin.Y * GuiData->CharHeight + rcView->top;
233 rcFramebuffer->right = Buffer->ViewOrigin.X * GuiData->CharWidth + rcView->right;
234 rcFramebuffer->bottom = Buffer->ViewOrigin.Y * GuiData->CharHeight + rcView->bottom;
235
236 LeftChar = rcFramebuffer->left / GuiData->CharWidth;
237 TopLine = rcFramebuffer->top / GuiData->CharHeight;
238 RightChar = rcFramebuffer->right / GuiData->CharWidth;
239 BottomLine = rcFramebuffer->bottom / GuiData->CharHeight;
240
241 if (RightChar >= Buffer->ScreenBufferSize.X) RightChar = Buffer->ScreenBufferSize.X - 1;
242 if (BottomLine >= Buffer->ScreenBufferSize.Y) BottomLine = Buffer->ScreenBufferSize.Y - 1;
243
244 LastAttribute = ConioCoordToPointer(Buffer, LeftChar, TopLine)->Attributes;
245
246 SetTextColor(GuiData->hMemDC, RGBFromAttrib2(Console, TextAttribFromAttrib(LastAttribute)));
247 SetBkColor(GuiData->hMemDC, RGBFromAttrib2(Console, BkgdAttribFromAttrib(LastAttribute)));
248
249 OldFont = SelectObject(GuiData->hMemDC, GuiData->Font);
250
251 for (Line = TopLine; Line <= BottomLine; Line++)
252 {
253 WCHAR LineBuffer[80]; // Buffer containing a part or all the line to be displayed
254 From = ConioCoordToPointer(Buffer, LeftChar, Line); // Get the first code of the line
255 Start = LeftChar;
256 To = LineBuffer;
257
258 for (Char = LeftChar; Char <= RightChar; Char++)
259 {
260 /*
261 * We flush the buffer if the new attribute is different
262 * from the current one, or if the buffer is full.
263 */
264 if (From->Attributes != LastAttribute || (Char - Start == sizeof(LineBuffer) / sizeof(WCHAR)))
265 {
266 TextOutW(GuiData->hMemDC,
267 Start * GuiData->CharWidth,
268 Line * GuiData->CharHeight,
269 LineBuffer,
270 Char - Start);
271 Start = Char;
272 To = LineBuffer;
273 Attribute = From->Attributes;
274 if (Attribute != LastAttribute)
275 {
276 SetTextColor(GuiData->hMemDC, RGBFromAttrib2(Console, TextAttribFromAttrib(Attribute)));
277 SetBkColor(GuiData->hMemDC, RGBFromAttrib2(Console, BkgdAttribFromAttrib(Attribute)));
278 LastAttribute = Attribute;
279 }
280 }
281
282 *(To++) = (From++)->Char.UnicodeChar;
283 }
284
285 TextOutW(GuiData->hMemDC,
286 Start * GuiData->CharWidth,
287 Line * GuiData->CharHeight,
288 LineBuffer,
289 RightChar - Start + 1);
290 }
291
292 /*
293 * Draw the caret
294 */
295 if (Buffer->CursorInfo.bVisible &&
296 Buffer->CursorBlinkOn &&
297 !Buffer->ForceCursorOff)
298 {
299 CursorX = Buffer->CursorPosition.X;
300 CursorY = Buffer->CursorPosition.Y;
301 if (LeftChar <= CursorX && CursorX <= RightChar &&
302 TopLine <= CursorY && CursorY <= BottomLine)
303 {
304 CursorHeight = ConioEffectiveCursorSize(Console, GuiData->CharHeight);
305
306 Attribute = ConioCoordToPointer(Buffer, Buffer->CursorPosition.X, Buffer->CursorPosition.Y)->Attributes;
307 if (Attribute == DEFAULT_SCREEN_ATTRIB) Attribute = Buffer->ScreenDefaultAttrib;
308
309 CursorBrush = CreateSolidBrush(RGBFromAttrib2(Console, TextAttribFromAttrib(Attribute)));
310 OldBrush = SelectObject(GuiData->hMemDC, CursorBrush);
311
312 PatBlt(GuiData->hMemDC,
313 CursorX * GuiData->CharWidth,
314 CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
315 GuiData->CharWidth,
316 CursorHeight,
317 PATCOPY);
318 SelectObject(GuiData->hMemDC, OldBrush);
319 DeleteObject(CursorBrush);
320 }
321 }
322
323 SelectObject(GuiData->hMemDC, OldFont);
324 }
325
326 /* EOF */