xref: /btstack/platform/windows/btstack_stdin_windows.c (revision 7ea7688a8f341f3783e40a238546a118134c6d1b)
1*7ea7688aSMatthias Ringwald /*
2*7ea7688aSMatthias Ringwald  * Copyright (C) 2014 BlueKitchen GmbH
3*7ea7688aSMatthias Ringwald  *
4*7ea7688aSMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5*7ea7688aSMatthias Ringwald  * modification, are permitted provided that the following conditions
6*7ea7688aSMatthias Ringwald  * are met:
7*7ea7688aSMatthias Ringwald  *
8*7ea7688aSMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9*7ea7688aSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10*7ea7688aSMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11*7ea7688aSMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12*7ea7688aSMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13*7ea7688aSMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14*7ea7688aSMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15*7ea7688aSMatthias Ringwald  *    from this software without specific prior written permission.
16*7ea7688aSMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17*7ea7688aSMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18*7ea7688aSMatthias Ringwald  *    monetary gain.
19*7ea7688aSMatthias Ringwald  *
20*7ea7688aSMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21*7ea7688aSMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22*7ea7688aSMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23*7ea7688aSMatthias Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24*7ea7688aSMatthias Ringwald  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25*7ea7688aSMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26*7ea7688aSMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27*7ea7688aSMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28*7ea7688aSMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29*7ea7688aSMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30*7ea7688aSMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31*7ea7688aSMatthias Ringwald  * SUCH DAMAGE.
32*7ea7688aSMatthias Ringwald  *
33*7ea7688aSMatthias Ringwald  * Please inquire about commercial licensing options at
34*7ea7688aSMatthias Ringwald  * [email protected]
35*7ea7688aSMatthias Ringwald  *
36*7ea7688aSMatthias Ringwald  */
37*7ea7688aSMatthias Ringwald 
38*7ea7688aSMatthias Ringwald #define __BTSTACK_FILE__ "btstack_stdin_windows.c"
39*7ea7688aSMatthias Ringwald 
40*7ea7688aSMatthias Ringwald #include <errno.h>
41*7ea7688aSMatthias Ringwald #include <stdio.h>
42*7ea7688aSMatthias Ringwald #include <unistd.h>
43*7ea7688aSMatthias Ringwald 
44*7ea7688aSMatthias Ringwald #include "btstack_run_loop.h"
45*7ea7688aSMatthias Ringwald #include <stdlib.h>
46*7ea7688aSMatthias Ringwald 
47*7ea7688aSMatthias Ringwald #include "btstack_stdin.h"
48*7ea7688aSMatthias Ringwald 
49*7ea7688aSMatthias Ringwald // From MSDN:
50*7ea7688aSMatthias Ringwald // __WIN32 Defined as 1 when the compilation target is 32-bit ARM, 64-bit ARM, x86, or x64.
51*7ea7688aSMatthias Ringwald //         Otherwise, undefined.
52*7ea7688aSMatthias Ringwald 
53*7ea7688aSMatthias Ringwald #include <Windows.h>
54*7ea7688aSMatthias Ringwald #include <conio.h>  //provides non standard getch() function
55*7ea7688aSMatthias Ringwald #include <signal.h>
56*7ea7688aSMatthias Ringwald 
57*7ea7688aSMatthias Ringwald static btstack_data_source_t stdin_source;
58*7ea7688aSMatthias Ringwald static int activated = 0;
59*7ea7688aSMatthias Ringwald 
60*7ea7688aSMatthias Ringwald static HANDLE stdin_reader_thread_handle;
61*7ea7688aSMatthias Ringwald static char   key_read_buffer;
62*7ea7688aSMatthias Ringwald static HANDLE key_processed_handle;
63*7ea7688aSMatthias Ringwald 
64*7ea7688aSMatthias Ringwald static WINAPI DWORD stdin_reader_thread_process(void * p){
65*7ea7688aSMatthias Ringwald     while (1){
66*7ea7688aSMatthias Ringwald         key_read_buffer = getch();
67*7ea7688aSMatthias Ringwald         SignalObjectAndWait(stdin_source.handle , key_processed_handle, INFINITE, FALSE);
68*7ea7688aSMatthias Ringwald     }
69*7ea7688aSMatthias Ringwald     return 0;
70*7ea7688aSMatthias Ringwald }
71*7ea7688aSMatthias Ringwald 
72*7ea7688aSMatthias Ringwald void btstack_stdin_setup(void (*stdin_process)(btstack_data_source_t *_ds, btstack_data_source_callback_type_t callback_type)){
73*7ea7688aSMatthias Ringwald 
74*7ea7688aSMatthias Ringwald     if (activated) return;
75*7ea7688aSMatthias Ringwald 
76*7ea7688aSMatthias Ringwald     // asynchronous io on stdin via OVERLAPPED seems to be problematic.
77*7ea7688aSMatthias Ringwald 
78*7ea7688aSMatthias Ringwald     // Use separate thread and event objects instead
79*7ea7688aSMatthias Ringwald     stdin_source.handle  = CreateEvent(NULL, FALSE, FALSE, NULL);
80*7ea7688aSMatthias Ringwald     key_processed_handle = CreateEvent(NULL, FALSE, FALSE, NULL);
81*7ea7688aSMatthias Ringwald     // default attributes, default stack size, proc, args, start immediately, don't care for thread id
82*7ea7688aSMatthias Ringwald     stdin_reader_thread_handle = CreateThread(NULL, 0, &stdin_reader_thread_process, NULL, 0, NULL);
83*7ea7688aSMatthias Ringwald 
84*7ea7688aSMatthias Ringwald     btstack_run_loop_enable_data_source_callbacks(&stdin_source, DATA_SOURCE_CALLBACK_READ);
85*7ea7688aSMatthias Ringwald     btstack_run_loop_set_data_source_handler(&stdin_source, stdin_process);
86*7ea7688aSMatthias Ringwald     btstack_run_loop_add_data_source(&stdin_source);
87*7ea7688aSMatthias Ringwald 
88*7ea7688aSMatthias Ringwald     activated = 1;
89*7ea7688aSMatthias Ringwald }
90*7ea7688aSMatthias Ringwald 
91*7ea7688aSMatthias Ringwald void btstack_stdin_reset(void){
92*7ea7688aSMatthias Ringwald     if (!activated) return;
93*7ea7688aSMatthias Ringwald     activated = 0;
94*7ea7688aSMatthias Ringwald 
95*7ea7688aSMatthias Ringwald     btstack_run_loop_remove_data_source(&stdin_source);
96*7ea7688aSMatthias Ringwald 
97*7ea7688aSMatthias Ringwald     // shutdown thread
98*7ea7688aSMatthias Ringwald     TerminateThread(stdin_reader_thread_handle, 0);
99*7ea7688aSMatthias Ringwald     WaitForSingleObject(stdin_reader_thread_handle, INFINITE);
100*7ea7688aSMatthias Ringwald     CloseHandle(stdin_reader_thread_handle);
101*7ea7688aSMatthias Ringwald 
102*7ea7688aSMatthias Ringwald     // free events
103*7ea7688aSMatthias Ringwald     CloseHandle(stdin_source.handle);
104*7ea7688aSMatthias Ringwald     CloseHandle(key_processed_handle);
105*7ea7688aSMatthias Ringwald }
106*7ea7688aSMatthias Ringwald 
107*7ea7688aSMatthias Ringwald // read single byte after data source callback was triggered
108*7ea7688aSMatthias Ringwald char btstack_stdin_read(void){
109*7ea7688aSMatthias Ringwald 
110*7ea7688aSMatthias Ringwald     // raise SIGINT for CTRL-c on main thread
111*7ea7688aSMatthias Ringwald     if (key_read_buffer == 0x03){
112*7ea7688aSMatthias Ringwald         raise(SIGINT);
113*7ea7688aSMatthias Ringwald         return 0;
114*7ea7688aSMatthias Ringwald     }
115*7ea7688aSMatthias Ringwald 
116*7ea7688aSMatthias Ringwald     char data = key_read_buffer;
117*7ea7688aSMatthias Ringwald     SetEvent(key_processed_handle);
118*7ea7688aSMatthias Ringwald 
119*7ea7688aSMatthias Ringwald     return data;
120*7ea7688aSMatthias Ringwald }
121*7ea7688aSMatthias Ringwald 
122