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