001/*
002 * Copyright (C) 2009-2017 the original author(s).
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fusesource.jansi.internal;
017
018import java.io.IOException;
019
020import org.fusesource.jansi.WindowsSupport;
021
022/**
023 * Interface to access Win32 base APIs.
024 *
025 * @author <a href="http://hiramchirino.com">Hiram Chirino</a>
026 * @author Guillaume Nodet
027 * @see JansiLoader
028 */
029@SuppressWarnings("unused")
030public class Kernel32 {
031
032    static {
033        if (JansiLoader.initialize()) {
034            init();
035        }
036    }
037
038    private static native void init();
039
040    public static short FOREGROUND_BLUE;
041    public static short FOREGROUND_GREEN;
042    public static short FOREGROUND_RED;
043    public static short FOREGROUND_INTENSITY;
044    public static short BACKGROUND_BLUE;
045    public static short BACKGROUND_GREEN;
046    public static short BACKGROUND_RED;
047    public static short BACKGROUND_INTENSITY;
048    public static short COMMON_LVB_LEADING_BYTE;
049    public static short COMMON_LVB_TRAILING_BYTE;
050    public static short COMMON_LVB_GRID_HORIZONTAL;
051    public static short COMMON_LVB_GRID_LVERTICAL;
052    public static short COMMON_LVB_GRID_RVERTICAL;
053    public static short COMMON_LVB_REVERSE_VIDEO;
054    public static short COMMON_LVB_UNDERSCORE;
055    public static int FORMAT_MESSAGE_FROM_SYSTEM;
056    public static int STD_INPUT_HANDLE;
057    public static int STD_OUTPUT_HANDLE;
058    public static int STD_ERROR_HANDLE;
059    public static int INVALID_HANDLE_VALUE;
060
061
062    public static native long malloc(long size);
063
064    public static native void free(long ptr);
065
066    /**
067     * http://msdn.microsoft.com/en-us/library/ms686311%28VS.85%29.aspx
068     */
069    static public class SMALL_RECT {
070        static {
071            JansiLoader.initialize();
072            init();
073        }
074
075        private static native void init();
076
077        public static int SIZEOF;
078
079        public short left;
080        public short top;
081        public short right;
082        public short bottom;
083
084        public short width() {
085            return (short) (right - left);
086        }
087
088        public short height() {
089            return (short) (bottom - top);
090        }
091
092        public SMALL_RECT copy() {
093            SMALL_RECT rc = new SMALL_RECT();
094            rc.left = left;
095            rc.top = top;
096            rc.right = right;
097            rc.bottom = bottom;
098            return rc;
099        }
100    }
101
102    /**
103     * see http://msdn.microsoft.com/en-us/library/ms686047%28VS.85%29.aspx
104     */
105    public static native int SetConsoleTextAttribute(
106            long consoleOutput,
107            short attributes);
108
109    public static class COORD {
110
111        static {
112            JansiLoader.initialize();
113            init();
114        }
115
116        private static native void init();
117
118        public static int SIZEOF;
119
120        public short x;
121        public short y;
122
123        public COORD copy() {
124            COORD rc = new COORD();
125            rc.x = x;
126            rc.y = y;
127            return rc;
128        }
129    }
130
131    /**
132     * http://msdn.microsoft.com/en-us/library/ms682093%28VS.85%29.aspx
133     */
134    public static class CONSOLE_SCREEN_BUFFER_INFO {
135
136        static {
137            JansiLoader.initialize();
138            init();
139        }
140
141        private static native void init();
142
143        public static int SIZEOF;
144
145        public COORD size = new COORD();
146        public COORD cursorPosition = new COORD();
147        public short attributes;
148        public SMALL_RECT window = new SMALL_RECT();
149        public COORD maximumWindowSize = new COORD();
150
151        public int windowWidth() {
152            return window.width() + 1;
153        }
154
155        public int windowHeight() {
156            return window.height() + 1;
157        }
158    }
159
160
161    // DWORD WINAPI WaitForSingleObject(
162    //  _In_ HANDLE hHandle,
163    //  _In_ DWORD  dwMilliseconds
164    // );
165    public static native int WaitForSingleObject(long hHandle, int dwMilliseconds);
166
167    /**
168     * see: http://msdn.microsoft.com/en-us/library/ms724211%28VS.85%29.aspx
169     */
170    public static native int CloseHandle(long handle);
171
172
173    /**
174     * see: http://msdn.microsoft.com/en-us/library/ms679360(VS.85).aspx
175     */
176    public static native int GetLastError();
177
178    public static native int FormatMessageW(
179            int flags,
180            long source,
181            int messageId,
182            int languageId,
183            byte[] buffer,
184            int size,
185            long[] args
186    );
187
188
189    /**
190     * See: http://msdn.microsoft.com/en-us/library/ms683171%28VS.85%29.aspx
191     */
192    public static native int GetConsoleScreenBufferInfo(
193            long consoleOutput,
194            CONSOLE_SCREEN_BUFFER_INFO consoleScreenBufferInfo);
195
196    /**
197     * see: http://msdn.microsoft.com/en-us/library/ms683231%28VS.85%29.aspx
198     */
199    public static native long GetStdHandle(int stdHandle);
200
201    /**
202     * http://msdn.microsoft.com/en-us/library/ms686025%28VS.85%29.aspx
203     */
204    public static native int SetConsoleCursorPosition(
205            long consoleOutput,
206            COORD cursorPosition);
207
208    /**
209     * see: http://msdn.microsoft.com/en-us/library/ms682663%28VS.85%29.aspx
210     */
211    public static native int FillConsoleOutputCharacterW(
212            long consoleOutput,
213            char character,
214            int length,
215            COORD writeCoord,
216            int[] numberOfCharsWritten);
217
218    /**
219     * see: https://msdn.microsoft.com/en-us/library/ms682662%28VS.85%29.aspx
220     */
221    public static native int FillConsoleOutputAttribute(
222            long consoleOutput,
223            short attribute,
224            int length,
225            COORD writeCoord,
226            int[] numberOfAttrsWritten);
227
228    /**
229     * see: http://msdn.microsoft.com/en-us/library/ms687401(v=VS.85).aspx
230     */
231    public static native int WriteConsoleW(
232            long consoleOutput,
233            char[] buffer,
234            int numberOfCharsToWrite,
235            int[] numberOfCharsWritten,
236            long reserved);
237
238    /**
239     * see: http://msdn.microsoft.com/en-us/library/ms683167%28VS.85%29.aspx
240     */
241    public static native int GetConsoleMode(
242            long handle,
243            int[] mode);
244
245    /**
246     * see: http://msdn.microsoft.com/en-us/library/ms686033%28VS.85%29.aspx
247     */
248    public static native int SetConsoleMode(
249            long handle,
250            int mode);
251
252    /**
253     * see: http://msdn.microsoft.com/en-us/library/078sfkak(VS.80).aspx
254     */
255    public static native int _getch();
256
257
258    /**
259     * see: http://msdn.microsoft.com/en-us/library/ms686050%28VS.85%29.aspx
260     *
261     * @return 0 if title was set successfully
262     */
263    public static native int SetConsoleTitle(
264            String title);
265
266
267    /**
268     * see: http://msdn.microsoft.com/en-us/library/ms683169(v=VS.85).aspx
269     *
270     * @return the current output code page
271     */
272    public static native int GetConsoleOutputCP();
273
274    /**
275     * see: http://msdn.microsoft.com/en-us/library/ms686036(v=VS.85).aspx
276     *
277     * @return non 0 if code page was set
278     */
279    public static native int SetConsoleOutputCP(int codePageID);
280
281    /**
282     * see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682013(v=vs.85).aspx
283     */
284    public static class CHAR_INFO {
285
286        static {
287            JansiLoader.initialize();
288            init();
289        }
290
291        private static native void init();
292
293        public static int SIZEOF;
294
295        public short attributes;
296        public char unicodeChar;
297    }
298
299    /**
300     * see: https://msdn.microsoft.com/en-us/library/windows/desktop/ms685107(v=vs.85).aspx
301     */
302    public static native int ScrollConsoleScreenBuffer(
303            long consoleOutput,
304            SMALL_RECT scrollRectangle,
305            SMALL_RECT clipRectangle,
306            COORD destinationOrigin,
307            CHAR_INFO fill);
308
309    /**
310     * see: http://msdn.microsoft.com/en-us/library/ms684166(v=VS.85).aspx
311     */
312    public static class KEY_EVENT_RECORD {
313
314        static {
315            JansiLoader.initialize();
316            init();
317        }
318
319        private static native void init();
320
321        public static int SIZEOF;
322        public static int CAPSLOCK_ON;
323        public static int NUMLOCK_ON;
324        public static int SCROLLLOCK_ON;
325        public static int ENHANCED_KEY;
326        public static int LEFT_ALT_PRESSED;
327        public static int LEFT_CTRL_PRESSED;
328        public static int RIGHT_ALT_PRESSED;
329        public static int RIGHT_CTRL_PRESSED;
330        public static int SHIFT_PRESSED;
331
332        public boolean keyDown;
333        public short repeatCount;
334        public short keyCode;
335        public short scanCode;
336        public char uchar;
337        public int controlKeyState;
338
339        public String toString() {
340            return "KEY_EVENT_RECORD{" +
341                    "keyDown=" + keyDown +
342                    ", repeatCount=" + repeatCount +
343                    ", keyCode=" + keyCode +
344                    ", scanCode=" + scanCode +
345                    ", uchar=" + uchar +
346                    ", controlKeyState=" + controlKeyState +
347                    '}';
348        }
349    }
350
351    /**
352     * see: http://msdn.microsoft.com/en-us/library/ms684239(v=VS.85).aspx
353     */
354    public static class MOUSE_EVENT_RECORD {
355
356        static {
357            JansiLoader.initialize();
358            init();
359        }
360
361        private static native void init();
362
363        public static int SIZEOF;
364        public static int FROM_LEFT_1ST_BUTTON_PRESSED;
365        public static int FROM_LEFT_2ND_BUTTON_PRESSED;
366        public static int FROM_LEFT_3RD_BUTTON_PRESSED;
367        public static int FROM_LEFT_4TH_BUTTON_PRESSED;
368        public static int RIGHTMOST_BUTTON_PRESSED;
369
370        public static int CAPSLOCK_ON;
371        public static int NUMLOCK_ON;
372        public static int SCROLLLOCK_ON;
373        public static int ENHANCED_KEY;
374        public static int LEFT_ALT_PRESSED;
375        public static int LEFT_CTRL_PRESSED;
376        public static int RIGHT_ALT_PRESSED;
377        public static int RIGHT_CTRL_PRESSED;
378        public static int SHIFT_PRESSED;
379
380        public static int DOUBLE_CLICK;
381        public static int MOUSE_HWHEELED;
382        public static int MOUSE_MOVED;
383        public static int MOUSE_WHEELED;
384
385        public COORD mousePosition = new COORD();
386        public int buttonState;
387        public int controlKeyState;
388        public int eventFlags;
389
390        public String toString() {
391            return "MOUSE_EVENT_RECORD{" +
392                    "mousePosition=" + mousePosition +
393                    ", buttonState=" + buttonState +
394                    ", controlKeyState=" + controlKeyState +
395                    ", eventFlags=" + eventFlags +
396                    '}';
397        }
398    }
399
400    /**
401     * see: http://msdn.microsoft.com/en-us/library/ms687093(v=VS.85).aspx
402     */
403    public static class WINDOW_BUFFER_SIZE_RECORD {
404
405        static {
406            JansiLoader.initialize();
407            init();
408        }
409
410        private static native void init();
411
412        public static int SIZEOF;
413
414        public COORD size = new COORD();
415
416        public String toString() {
417            return "WINDOW_BUFFER_SIZE_RECORD{size=" + size + '}';
418        }
419    }
420
421    /**
422     * see: http://msdn.microsoft.com/en-us/library/ms683149(v=VS.85).aspx
423     */
424    public static class FOCUS_EVENT_RECORD {
425        static {
426            JansiLoader.initialize();
427            init();
428        }
429
430        private static native void init();
431
432        public static int SIZEOF;
433        public boolean setFocus;
434    }
435
436    /**
437     * see: http://msdn.microsoft.com/en-us/library/ms684213(v=VS.85).aspx
438     */
439    public static class MENU_EVENT_RECORD {
440        static {
441            JansiLoader.initialize();
442            init();
443        }
444
445        private static native void init();
446
447        public static int SIZEOF;
448        public int commandId;
449    }
450
451    /**
452     * see: http://msdn.microsoft.com/en-us/library/ms683499(v=VS.85).aspx
453     */
454    public static class INPUT_RECORD {
455
456        static {
457            JansiLoader.initialize();
458            init();
459        }
460
461        private static native void init();
462
463        public static int SIZEOF;
464        public static short KEY_EVENT;
465        public static short MOUSE_EVENT;
466        public static short WINDOW_BUFFER_SIZE_EVENT;
467        public static short FOCUS_EVENT;
468        public static short MENU_EVENT;
469        public short eventType;
470        public KEY_EVENT_RECORD keyEvent = new KEY_EVENT_RECORD();
471        public MOUSE_EVENT_RECORD mouseEvent = new MOUSE_EVENT_RECORD();
472        public WINDOW_BUFFER_SIZE_RECORD windowBufferSizeEvent = new WINDOW_BUFFER_SIZE_RECORD();
473        public MENU_EVENT_RECORD menuEvent = new MENU_EVENT_RECORD();
474        public FOCUS_EVENT_RECORD focusEvent = new FOCUS_EVENT_RECORD();
475
476        public static native void memmove(
477                INPUT_RECORD dest,
478                long src,
479                long size);
480
481    }
482
483    /**
484     * see: http://msdn.microsoft.com/en-us/library/ms684961(v=VS.85).aspx
485     */
486    private static native int ReadConsoleInputW(
487            long handle,
488            long inputRecord,
489            int length,
490            int[] eventsCount);
491
492    /**
493     * see: http://msdn.microsoft.com/en-us/library/ms684344(v=VS.85).aspx
494     */
495    private static native int PeekConsoleInputW(
496            long handle,
497            long inputRecord,
498            int length,
499            int[] eventsCount);
500
501    /**
502     * see: http://msdn.microsoft.com/en-us/library/ms683207(v=VS.85).aspx
503     */
504    public static native int GetNumberOfConsoleInputEvents(
505            long handle,
506            int[] numberOfEvents);
507
508    /**
509     * see: http://msdn.microsoft.com/en-us/library/ms683147(v=VS.85).aspx
510     */
511    public static native int FlushConsoleInputBuffer(
512            long handle);
513
514    /**
515     * Return console input events.
516     */
517    public static INPUT_RECORD[] readConsoleInputHelper(
518            long handle, int count, boolean peek) throws IOException {
519        int[] length = new int[1];
520        int res;
521        long inputRecordPtr = 0;
522        try {
523            inputRecordPtr = malloc(INPUT_RECORD.SIZEOF * count);
524            if (inputRecordPtr == 0) {
525                throw new IOException("cannot allocate memory with JNI");
526            }
527            res = peek ?
528                    PeekConsoleInputW(handle, inputRecordPtr, count, length)
529                    : ReadConsoleInputW(handle, inputRecordPtr, count, length);
530            if (res == 0) {
531                throw new IOException("ReadConsoleInputW failed: " + WindowsSupport.getLastErrorMessage());
532            }
533            if (length[0] <= 0) {
534                return new INPUT_RECORD[0];
535            }
536            INPUT_RECORD[] records = new INPUT_RECORD[length[0]];
537            for (int i = 0; i < records.length; i++) {
538                records[i] = new INPUT_RECORD();
539                INPUT_RECORD.memmove(records[i], inputRecordPtr + i * INPUT_RECORD.SIZEOF, INPUT_RECORD.SIZEOF);
540            }
541            return records;
542        } finally {
543            if (inputRecordPtr != 0) {
544                free(inputRecordPtr);
545            }
546        }
547    }
548
549    /**
550     * Return console input key events (discard other events).
551     *
552     * @param count requested number of events
553     * @return array possibly of size smaller then count
554     */
555    public static INPUT_RECORD[] readConsoleKeyInput(long handle, int count, boolean peek)
556            throws IOException {
557        while (true) {
558            // read events until we have keyboard events, the queue could be full
559            // of mouse events.
560            INPUT_RECORD[] evts = readConsoleInputHelper(handle, count, peek);
561            int keyEvtCount = 0;
562            for (INPUT_RECORD evt : evts) {
563                if (evt.eventType == INPUT_RECORD.KEY_EVENT) keyEvtCount++;
564            }
565            if (keyEvtCount > 0) {
566                INPUT_RECORD[] res = new INPUT_RECORD[keyEvtCount];
567                int i = 0;
568                for (INPUT_RECORD evt : evts) {
569                    if (evt.eventType == INPUT_RECORD.KEY_EVENT) {
570                        res[i++] = evt;
571                    }
572                }
573                return res;
574            }
575        }
576    }
577
578
579}