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     // || (KeyState[VK_LSHIFT] & 0x80) || (KeyState[VK_RSHIFT] & 0x80)
38         ssOut |= SHIFT_PRESSED;
39 
40     if (KeyState[VK_LCONTROL] & 0x80)
41         ssOut |= LEFT_CTRL_PRESSED;
42     if (KeyState[VK_RCONTROL] & 0x80)
43         ssOut |= RIGHT_CTRL_PRESSED;
44     // if (KeyState[VK_CONTROL] & 0x80) { ... }
45 
46     if (KeyState[VK_LMENU] & 0x80)
47         ssOut |= LEFT_ALT_PRESSED;
48     if (KeyState[VK_RMENU] & 0x80)
49         ssOut |= RIGHT_ALT_PRESSED;
50     // if (KeyState[VK_MENU] & 0x80) { ... }
51 
52     /* See WM_CHAR MSDN documentation for instance */
53     if (lParam & 0x01000000)
54         ssOut |= ENHANCED_KEY;
55 
56     return ssOut;
57 }
58 
59 VOID NTAPI
60 ConioProcessKey(PCONSRV_CONSOLE Console, MSG* msg)
61 {
62     static BYTE KeyState[256] = { 0 };
63     /* MSDN mentions that you should use the last virtual key code received
64      * when putting a virtual key identity to a WM_CHAR message since multiple
65      * or translated keys may be involved. */
66     static UINT LastVirtualKey = 0;
67     DWORD ShiftState;
68     WCHAR UnicodeChar;
69     UINT VirtualKeyCode;
70     UINT VirtualScanCode;
71     BOOL Down = FALSE;
72     BOOLEAN Fake;          // Synthesized, not a real event
73     BOOLEAN NotChar;       // Message should not be used to return a character
74 
75     INPUT_RECORD er;
76 
77     if (Console == NULL)
78     {
79         DPRINT1("No Active Console!\n");
80         return;
81     }
82 
83     VirtualScanCode = HIWORD(msg->lParam) & 0xFF;
84     Down = msg->message == WM_KEYDOWN || msg->message == WM_CHAR ||
85            msg->message == WM_SYSKEYDOWN || msg->message == WM_SYSCHAR;
86 
87     GetKeyboardState(KeyState);
88     ShiftState = ConioGetShiftState(KeyState, msg->lParam);
89 
90     if (msg->message == WM_CHAR || msg->message == WM_SYSCHAR)
91     {
92         VirtualKeyCode = LastVirtualKey;
93         UnicodeChar = msg->wParam;
94     }
95     else
96     {
97         WCHAR Chars[2];
98         INT RetChars = 0;
99 
100         VirtualKeyCode = msg->wParam;
101         RetChars = ToUnicodeEx(VirtualKeyCode,
102                                VirtualScanCode,
103                                KeyState,
104                                Chars,
105                                2,
106                                0,
107                                NULL);
108         UnicodeChar = (RetChars == 1 ? Chars[0] : 0);
109     }
110 
111     Fake = UnicodeChar &&
112             (msg->message != WM_CHAR && msg->message != WM_SYSCHAR &&
113              msg->message != WM_KEYUP && msg->message != WM_SYSKEYUP);
114     NotChar = (msg->message != WM_CHAR && msg->message != WM_SYSCHAR);
115     if (NotChar) LastVirtualKey = msg->wParam;
116 
117     DPRINT("CONSRV: %s %s %s %s %02x %02x '%lc' %04x\n",
118            Down ? "down" : "up  ",
119            (msg->message == WM_CHAR || msg->message == WM_SYSCHAR) ?
120            "char" : "key ",
121            Fake ? "fake" : "real",
122            NotChar ? "notc" : "char",
123            VirtualScanCode,
124            VirtualKeyCode,
125            (UnicodeChar >= L' ') ? UnicodeChar : L'.',
126            ShiftState);
127 
128     if (Fake) return;
129 
130 //
131 // FIXME: Scrolling via keyboard shortcuts must be done differently,
132 // without touching the internal VirtualY variable.
133 //
134 #if 0
135     if ( (ShiftState & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED)) != 0 &&
136          (VirtualKeyCode == VK_UP || VirtualKeyCode == VK_DOWN) )
137     {
138         if (!Down) return;
139 
140         /* Scroll up or down */
141         if (VirtualKeyCode == VK_UP)
142         {
143             /* Only scroll up if there is room to scroll up into */
144             if (Console->ActiveBuffer->CursorPosition.Y != Console->ActiveBuffer->ScreenBufferSize.Y - 1)
145             {
146                 Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY +
147                                                    Console->ActiveBuffer->ScreenBufferSize.Y - 1) %
148                                                    Console->ActiveBuffer->ScreenBufferSize.Y;
149                 Console->ActiveBuffer->CursorPosition.Y++;
150             }
151         }
152         else
153         {
154             /* Only scroll down if there is room to scroll down into */
155             if (Console->ActiveBuffer->CursorPosition.Y != 0)
156             {
157                 Console->ActiveBuffer->VirtualY = (Console->ActiveBuffer->VirtualY + 1) %
158                                                    Console->ActiveBuffer->ScreenBufferSize.Y;
159                 Console->ActiveBuffer->CursorPosition.Y--;
160             }
161         }
162 
163         ConioDrawConsole(Console);
164         return;
165     }
166 #endif
167 
168     /* Send the key press to the console driver */
169 
170     er.EventType                        = KEY_EVENT;
171     er.Event.KeyEvent.bKeyDown          = Down;
172     er.Event.KeyEvent.wRepeatCount      = 1;
173     er.Event.KeyEvent.wVirtualKeyCode   = VirtualKeyCode;
174     er.Event.KeyEvent.wVirtualScanCode  = VirtualScanCode;
175     er.Event.KeyEvent.uChar.UnicodeChar = UnicodeChar;
176     er.Event.KeyEvent.dwControlKeyState = ShiftState;
177 
178     ConioProcessInputEvent(Console, &er);
179 }
180 
181 DWORD
182 ConioEffectiveCursorSize(PCONSRV_CONSOLE Console, DWORD Scale)
183 {
184     DWORD Size = (Console->ActiveBuffer->CursorInfo.dwSize * Scale + 99) / 100;
185     /* If line input in progress, perhaps adjust for insert toggle */
186     if (Console->LineBuffer && !Console->LineComplete && (Console->InsertMode ? !Console->LineInsertToggle : Console->LineInsertToggle))
187         return (Size * 2 <= Scale) ? (Size * 2) : (Size / 2);
188     return Size;
189 }
190 
191 /* EOF */
192