1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Console Server DLL
4  * FILE:            win32ss/user/winsrv/consrv/frontends/input.c
5  * PURPOSE:         Common Front-Ends Input functions
6  * PROGRAMMERS:     Jeffrey Morlan
7  *                  Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8  */
9 
10 /* INCLUDES *******************************************************************/
11 
12 #include "consrv.h"
13 #include "include/term.h"
14 #include "coninput.h"
15 
16 #define NDEBUG
17 #include <debug.h>
18 
19 
20 /* PRIVATE FUNCTIONS **********************************************************/
21 
22 static DWORD
23 ConioGetShiftState(PBYTE KeyState, LPARAM lParam)
24 {
25     DWORD ssOut = 0;
26 
27     if (KeyState[VK_CAPITAL] & 0x01)
28         ssOut |= CAPSLOCK_ON;
29 
30     if (KeyState[VK_NUMLOCK] & 0x01)
31         ssOut |= NUMLOCK_ON;
32 
33     if (KeyState[VK_SCROLL] & 0x01)
34         ssOut |= SCROLLLOCK_ON;
35 
36     if (KeyState[VK_SHIFT] & 0x80)
37         ssOut |= SHIFT_PRESSED;
38 
39     if (KeyState[VK_LCONTROL] & 0x80)
40         ssOut |= LEFT_CTRL_PRESSED;
41     if (KeyState[VK_RCONTROL] & 0x80)
42         ssOut |= RIGHT_CTRL_PRESSED;
43 
44     if (KeyState[VK_LMENU] & 0x80)
45         ssOut |= LEFT_ALT_PRESSED;
46     if (KeyState[VK_RMENU] & 0x80)
47         ssOut |= RIGHT_ALT_PRESSED;
48 
49     /* See WM_CHAR MSDN documentation for instance */
50     if (lParam & 0x01000000)
51         ssOut |= ENHANCED_KEY;
52 
53     return ssOut;
54 }
55 
56 VOID NTAPI
57 ConioProcessKey(PCONSRV_CONSOLE Console, MSG* msg)
58 {
59     static BYTE KeyState[256] = { 0 };
60     /* MSDN mentions that you should use the last virtual key code received
61      * when putting a virtual key identity to a WM_CHAR message since multiple
62      * or translated keys may be involved. */
63     static UINT LastVirtualKey = 0;
64     DWORD ShiftState;
65     WCHAR UnicodeChar;
66     UINT VirtualKeyCode;
67     UINT VirtualScanCode;
68     BOOL Down = FALSE;
69     BOOLEAN Fake;          // Synthesized, not a real event
70     BOOLEAN NotChar;       // Message should not be used to return a character
71 
72     INPUT_RECORD er;
73 
74     if (Console == NULL)
75     {
76         DPRINT1("No Active Console!\n");
77         return;
78     }
79 
80     VirtualScanCode = HIWORD(msg->lParam) & 0xFF;
81     Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR ||
82            msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR;
83 
84     GetKeyboardState(KeyState);
85     ShiftState = ConioGetShiftState(KeyState, msg->lParam);
86 
87     if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
88     {
89         VirtualKeyCode = LastVirtualKey;
90         UnicodeChar = msg->wParam;
91     }
92     else
93     {
94         WCHAR Chars[2];
95         INT RetChars = 0;
96 
97         VirtualKeyCode = msg->wParam;
98         RetChars = ToUnicodeEx(VirtualKeyCode,
99                                VirtualScanCode,
100                                KeyState,
101                                Chars,
102                                2,
103                                0,
104                                NULL);
105         UnicodeChar = (RetChars == 1 ? Chars[0] : 0);
106     }
107 
108     Fake = UnicodeChar &&
109             (msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
110              msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
111     NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
112     if (NotChar) LastVirtualKey = msg->wParam;
113 
114     DPRINT("CONSRV: %s %s %s %s %02x %02x '%lc' %04x\n",
115            Down ? "down" : "up  ",
116            (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
117            "char" : "key ",
118            Fake ? "fake" : "real",
119            NotChar ? "notc" : "char",
120            VirtualScanCode,
121            VirtualKeyCode,
122            (UnicodeChar >= L' ') ? UnicodeChar : L'.',
123            ShiftState);
124 
125     if (Fake) return;
126 
127     /* Process Ctrl-C and Ctrl-Break */
128     if ( Console->InputBuffer.Mode & ENABLE_PROCESSED_INPUT &&
129          Down && (VirtualKeyCode == VK_PAUSE || VirtualKeyCode == 'C') &&
130          (ShiftState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) || KeyState[VK_CONTROL] & 0x80) )
131     {
132         DPRINT1("Console_Api Ctrl-C\n");
133         ConSrvConsoleProcessCtrlEvent(Console, 0, CTRL_C_EVENT);
134 
135         if (Console->LineBuffer && !Console->LineComplete)
136         {
137             /* Line input is in progress; end it */
138             Console->LinePos = Console->LineSize = 0;
139             Console->LineComplete = TRUE;
140         }
141         return;
142     }
143 
144     if ( (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) != 0 &&
145          (VirtualKeyCode == VK_UP || VirtualKeyCode == VK_DOWN) )
146     {
147         if (!Down) return;
148 
149         /* Scroll up or down */
150         if (VirtualKeyCode == VK_UP)
151         {
152             /* Only scroll up if there is room to scroll up into */
153             if (Console->ActiveBuffer->CursorPosition.Y != Console->ActiveBuffer->ScreenBufferSize.Y - 1)
154             {
155                 Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY +
156                                                    Console->ActiveBuffer->ScreenBufferSize.Y - 1) %
157                                                    Console->ActiveBuffer->ScreenBufferSize.Y;
158                 Console->ActiveBuffer->CursorPosition.Y++;
159             }
160         }
161         else
162         {
163             /* Only scroll down if there is room to scroll down into */
164             if (Console->ActiveBuffer->CursorPosition.Y != 0)
165             {
166                 Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) %
167                                                    Console->ActiveBuffer->ScreenBufferSize.Y;
168                 Console->ActiveBuffer->CursorPosition.Y--;
169             }
170         }
171 
172         ConioDrawConsole(Console);
173         return;
174     }
175 
176     /* Send the key press to the console driver */
177 
178     er.EventType                        = KEY_EVENT;
179     er.Event.KeyEvent.bKeyDown          = Down;
180     er.Event.KeyEvent.wRepeatCount      = 1;
181     er.Event.KeyEvent.wVirtualKeyCode   = VirtualKeyCode;
182     er.Event.KeyEvent.wVirtualScanCode  = VirtualScanCode;
183     er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
184     er.Event.KeyEvent.dwControlKeyState = ShiftState;
185 
186     ConioProcessInputEvent(Console, &er);
187 }
188 
189 DWORD
190 ConioEffectiveCursorSize(PCONSRV_CONSOLE Console, DWORD Scale)
191 {
192     DWORD Size = (Console->ActiveBuffer->CursorInfo.dwSize * Scale + 99) / 100;
193     /* If line input in progress, perhaps adjust for insert toggle */
194     if (Console->LineBuffer && !Console->LineComplete && (Console->InsertMode ? !Console->LineInsertToggle : Console->LineInsertToggle))
195         return (Size * 2 <= Scale) ? (Size * 2) : (Size / 2);
196     return Size;
197 }
198 
199 /* EOF */
200