[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 /* Basic size for one line... */
63 size = selWidth;
64 /* ... and for the other lines, add newline characters if needed. */
65 if (selHeight > 0)
66 {
67 /*
68 * If we are not in inline-text copy mode, each selected line must
69 * finish with \r\n . Otherwise, the lines will be just concatenated.
70 */
71 size += (selWidth + (!InlineCopyMode ? 2 : 0)) * (selHeight - 1);
72 }
73 size += 1; /* Null-termination */
74 size *= sizeof(WCHAR);
75
76 /* Allocate some memory area to be given to the clipboard, so it will not be freed here */
77 hData = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size);
78 if (hData == NULL) return;
79
80 data = GlobalLock(hData);
81 if (data == NULL)
82 {
83 GlobalFree(hData);
84 return;
85 }
86
87 DPRINT("Copying %dx%d selection\n", selWidth, selHeight);
88 dstPos = data;
89
90 for (yPos = 0; yPos < selHeight; yPos++)
91 {
92 ptr = ConioCoordToPointer(Buffer,
93 Console->Selection.srSelection.Left,
94 yPos + Console->Selection.srSelection.Top);
95 /* Copy only the characters, leave attributes alone */
96 for (xPos = 0; xPos < selWidth; xPos++)
97 {
98 /*
99 * Sometimes, applications can put NULL chars into the screen-buffer
100 * (this behaviour is allowed). Detect this and replace by a space.
101 * FIXME - HACK: Improve the way we're doing that (i.e., put spaces
102 * instead of NULLs (or even, nothing) only if it exists a non-null
103 * char *after* those NULLs, before the end-of-line of the selection.
104 * Do the same concerning spaces -- i.e. trailing spaces --).
105 */
106 dstPos[xPos] = (ptr[xPos].Char.UnicodeChar ? ptr[xPos].Char.UnicodeChar : L' ');
107 }
108 dstPos += selWidth;
109
110 /* Add newline characters if we are not in inline-text copy mode */
111 if (!InlineCopyMode)
112 {
113 if (yPos != (selHeight - 1))
114 {
115 wcscat(data, L"\r\n");
116 dstPos += 2;
117 }
118 }
119 }
120
121 DPRINT("Setting data <%S> to clipboard\n", data);
122 GlobalUnlock(hData);
123
124 EmptyClipboard();
125 SetClipboardData(CF_UNICODETEXT, hData);
126 }
127
128 VOID
129 GuiPasteToTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
130 PGUI_CONSOLE_DATA GuiData)
131 {
132 /*
133 * This function supposes that the system clipboard was opened.
134 */
135
136 PCONSOLE Console = Buffer->Header.Console;
137
138 HANDLE hData;
139 LPWSTR str;
140 WCHAR CurChar = 0;
141
142 SHORT VkKey; // MAKEWORD(low = vkey_code, high = shift_state);
143 INPUT_RECORD er;
144
145 hData = GetClipboardData(CF_UNICODETEXT);
146 if (hData == NULL) return;
147
148 str = GlobalLock(hData);
149 if (str == NULL) return;
150
151 DPRINT("Got data <%S> from clipboard\n", str);
152
153 er.EventType = KEY_EVENT;
154 er.Event.KeyEvent.wRepeatCount = 1;
155 while (*str)
156 {
157 /* \r or \n characters. Go to the line only if we get "\r\n" sequence. */
158 if (CurChar == L'\r' && *str == L'\n')
159 {
160 str++;
161 continue;
162 }
163 CurChar = *str++;
164
165 /* Get the key code (+ shift state) corresponding to the character */
166 VkKey = VkKeyScanW(CurChar);
167 if (VkKey == 0xFFFF)
168 {
169 DPRINT1("VkKeyScanW failed - Should simulate the key...\n");
170 continue;
171 }
172
173 /* Pressing some control keys */
174
175 /* Pressing the character key, with the control keys maintained pressed */
176 er.Event.KeyEvent.bKeyDown = TRUE;
177 er.Event.KeyEvent.wVirtualKeyCode = LOBYTE(VkKey);
178 er.Event.KeyEvent.wVirtualScanCode = MapVirtualKeyW(LOBYTE(VkKey), MAPVK_VK_TO_CHAR);
179 er.Event.KeyEvent.uChar.UnicodeChar = CurChar;
180 er.Event.KeyEvent.dwControlKeyState = 0;
181 if (HIBYTE(VkKey) & 1)
182 er.Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
183 if (HIBYTE(VkKey) & 2)
184 er.Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED; // RIGHT_CTRL_PRESSED;
185 if (HIBYTE(VkKey) & 4)
186 er.Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED; // RIGHT_ALT_PRESSED;
187
188 ConioProcessInputEvent(Console, &er);
189
190 /* Up all the character and control keys */
191 er.Event.KeyEvent.bKeyDown = FALSE;
192 ConioProcessInputEvent(Console, &er);
193 }
194
195 GlobalUnlock(hData);
196 }
197
198 VOID
199 GuiPaintTextModeBuffer(PTEXTMODE_SCREEN_BUFFER Buffer,
200 PGUI_CONSOLE_DATA GuiData,
201 PRECT rcView,
202 PRECT rcFramebuffer)
203 {
204 PCONSOLE Console = Buffer->Header.Console;
205 // ASSERT(Console == GuiData->Console);
206
207 ULONG TopLine, BottomLine, LeftChar, RightChar;
208 ULONG Line, Char, Start;
209 PCHAR_INFO From;
210 PWCHAR To;
211 WORD LastAttribute, Attribute;
212 ULONG CursorX, CursorY, CursorHeight;
213 HBRUSH CursorBrush, OldBrush;
214 HFONT OldFont;
215
216 if (Buffer->Buffer == NULL) return;
217
218 rcFramebuffer->left = Buffer->ViewOrigin.X * GuiData->CharWidth + rcView->left;
219 rcFramebuffer->top = Buffer->ViewOrigin.Y * GuiData->CharHeight + rcView->top;
220 rcFramebuffer->right = Buffer->ViewOrigin.X * GuiData->CharWidth + rcView->right;
221 rcFramebuffer->bottom = Buffer->ViewOrigin.Y * GuiData->CharHeight + rcView->bottom;
222
223 LeftChar = rcFramebuffer->left / GuiData->CharWidth;
224 TopLine = rcFramebuffer->top / GuiData->CharHeight;
225 RightChar = rcFramebuffer->right / GuiData->CharWidth;
226 BottomLine = rcFramebuffer->bottom / GuiData->CharHeight;
227
228 if (RightChar >= Buffer->ScreenBufferSize.X) RightChar = Buffer->ScreenBufferSize.X - 1;
229 if (BottomLine >= Buffer->ScreenBufferSize.Y) BottomLine = Buffer->ScreenBufferSize.Y - 1;
230
231 LastAttribute = ConioCoordToPointer(Buffer, LeftChar, TopLine)->Attributes;
232
233 SetTextColor(GuiData->hMemDC, RGBFromAttrib2(Console, TextAttribFromAttrib(LastAttribute)));
234 SetBkColor(GuiData->hMemDC, RGBFromAttrib2(Console, BkgdAttribFromAttrib(LastAttribute)));
235
236 OldFont = SelectObject(GuiData->hMemDC, GuiData->Font);
237
238 for (Line = TopLine; Line <= BottomLine; Line++)
239 {
240 WCHAR LineBuffer[80]; // Buffer containing a part or all the line to be displayed
241 From = ConioCoordToPointer(Buffer, LeftChar, Line); // Get the first code of the line
242 Start = LeftChar;
243 To = LineBuffer;
244
245 for (Char = LeftChar; Char <= RightChar; Char++)
246 {
247 /*
248 * We flush the buffer if the new attribute is different
249 * from the current one, or if the buffer is full.
250 */
251 if (From->Attributes != LastAttribute || (Char - Start == sizeof(LineBuffer) / sizeof(WCHAR)))
252 {
253 TextOutW(GuiData->hMemDC,
254 Start * GuiData->CharWidth,
255 Line * GuiData->CharHeight,
256 LineBuffer,
257 Char - Start);
258 Start = Char;
259 To = LineBuffer;
260 Attribute = From->Attributes;
261 if (Attribute != LastAttribute)
262 {
263 SetTextColor(GuiData->hMemDC, RGBFromAttrib2(Console, TextAttribFromAttrib(Attribute)));
264 SetBkColor(GuiData->hMemDC, RGBFromAttrib2(Console, BkgdAttribFromAttrib(Attribute)));
265 LastAttribute = Attribute;
266 }
267 }
268
269 *(To++) = (From++)->Char.UnicodeChar;
270 }
271
272 TextOutW(GuiData->hMemDC,
273 Start * GuiData->CharWidth,
274 Line * GuiData->CharHeight,
275 LineBuffer,
276 RightChar - Start + 1);
277 }
278
279 /*
280 * Draw the caret
281 */
282 if (Buffer->CursorInfo.bVisible &&
283 Buffer->CursorBlinkOn &&
284 !Buffer->ForceCursorOff)
285 {
286 CursorX = Buffer->CursorPosition.X;
287 CursorY = Buffer->CursorPosition.Y;
288 if (LeftChar <= CursorX && CursorX <= RightChar &&
289 TopLine <= CursorY && CursorY <= BottomLine)
290 {
291 CursorHeight = ConioEffectiveCursorSize(Console, GuiData->CharHeight);
292
293 Attribute = ConioCoordToPointer(Buffer, Buffer->CursorPosition.X, Buffer->CursorPosition.Y)->Attributes;
294 if (Attribute == DEFAULT_SCREEN_ATTRIB) Attribute = Buffer->ScreenDefaultAttrib;
295
296 CursorBrush = CreateSolidBrush(RGBFromAttrib2(Console, TextAttribFromAttrib(Attribute)));
297 OldBrush = SelectObject(GuiData->hMemDC, CursorBrush);
298
299 PatBlt(GuiData->hMemDC,
300 CursorX * GuiData->CharWidth,
301 CursorY * GuiData->CharHeight + (GuiData->CharHeight - CursorHeight),
302 GuiData->CharWidth,
303 CursorHeight,
304 PATCOPY);
305 SelectObject(GuiData->hMemDC, OldBrush);
306 DeleteObject(CursorBrush);
307 }
308 }
309
310 SelectObject(GuiData->hMemDC, OldFont);
311 }
312
313 /* EOF */