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