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