FreeBASIC  0.91.0
io_multikey.c
Go to the documentation of this file.
1 /* multikey function for DOS console mode apps */
2 
3 #include "../fb.h"
4 #include "fb_private_console.h"
5 #include <pc.h>
6 #include <go32.h>
7 #include <dpmi.h>
8 #include <sys/farptr.h>
9 
10 void (*__fb_dos_multikey_hook)(int scancode, int flags) = NULL;
11 
12 static void end_fb_ConsoleMultikey(void);
13 
14 static int inited = FALSE;
15 static volatile char key[128];
16 static volatile int got_extended_key = FALSE;
17 
18 static __inline__
19 int fb_hWriteControlCommand( unsigned char uchValue )
20 {
21  unsigned char uchStatus;
22  size_t count = 65535;
23  do {
24  uchStatus = inportb(0x64); /* read keyboard status */
25  } while( ((uchStatus & 0x02)!=0) && --count );
26  outportb( 0x64, uchValue );
27  return (uchStatus & 0x02)==0;
28 }
29 
30 static int fb_MultikeyHandler(unsigned irq_number)
31 {
32 #if 1
33  __dpmi_regs regs;
34 #endif
35  unsigned char scancode_raw;
36 
37  fb_hWriteControlCommand( 0xAD ); /* Lock keyboard */
38 
39  /* read the raw scancode from the keyboard */
40  scancode_raw = inportb(0x60); /* read scancode */
41 
42 #if 0
43  printf(":%02x", scancode_raw);
44 #endif
45 
46 #if 1
47  /* Translate scancode */
48  regs.h.ah = 0x4F;
49  regs.h.al = scancode_raw;
50  __dpmi_int(0x15, &regs);
51  if( regs.x.flags & 1 )
52 #endif
53  {
54 #if 0
55  size_t code = regs.h.al;
56 #else
57  size_t code = scancode_raw;
58 #endif
59  if( code==0xE0 )
60  {
62  }
63  else
64  {
65  int release_code = (code & 0x80)!=0;
66  code &= 0x7F;
67  if( got_extended_key ) {
68  switch( code ) {
69  case 0x2A:
70  code = 0;
71  break;
72  }
73  }
74  if( code != 0 )
75  {
76  int prev;
77  int kbflags;
78 
79  prev = key[code];
80 
81  /* make sure there is at least one free entry in the keyboard buffer */
82  {
83  unsigned int beg, end, fre, nxt;
84  unsigned short old_sel;
85 
86  old_sel = _fargetsel();
87  _farsetsel(_dos_ds);
88 
89  beg = _farnspeekw( (0x40 << 4) | 0x80 );
90  end = _farnspeekw( (0x40 << 4) | 0x82 );
91  fre = _farnspeekw( (0x40 << 4) | 0x1C );
92  nxt = _farnspeekw( (0x40 << 4) | 0x1A );
93 
94  if( (fre == nxt - 2) || ((nxt == beg) && (fre == end - 2)) )
95  {
96  nxt += 2;
97  if( nxt == end )
98  {
99  nxt = beg;
100  }
101  _farnspokew( (0x40 << 4) | 0x1A, nxt);
102  }
103 
104  kbflags = _farnspeekb( (0x40 << 4) | 0x17 );
105 
106  _farsetsel(old_sel);
107  }
108 
109  /* Remeber scancode status */
110  __fb_con.forceInpBufferChanged = key[code] = !release_code;
111  if( __fb_dos_multikey_hook != 0 )
112  {
113  int flags = 0;
114 
115  if( !release_code )
116  {
117  flags |= KB_PRESS;
118  if( prev )
119  flags |= KB_REPEAT;
120  }
121 
122  if( key[SC_CONTROL] )
123  flags |= KB_CTRL;
124 
125  if( key[SC_LSHIFT] || key[SC_RSHIFT] )
126  flags |= KB_SHIFT;
127 
128  if( key[SC_ALT] )
129  flags |= KB_ALT;
130 
131  if( kbflags & (1 << 6) )
132  flags |= KB_CAPSLOCK;
133 
134  if( kbflags & (1 << 5) )
135  flags |= KB_NUMLOCK;
136 
137  if( got_extended_key )
138  {
140  flags |= KB_EXTENDED;
141  }
142 
143  __fb_dos_multikey_hook(code, flags);
144  }
145  }
146  }
147  }
148 
149  fb_hWriteControlCommand( 0xAE ); /* Unlock keyboard */
150 
151  return FALSE;
152 }
154 
155 static void fb_ConsoleMultikeyExit(void)
156 {
157  fb_isr_reset( 1 );
160  unlock_array(key);
164 }
165 
167 {
168  if (inited)
169  return;
170 
171  inited = TRUE;
172  memset((void*)key, FALSE, sizeof(key));
173 
174  /* We have to lock the memory BEFORE we redirect the ISR! */
175  lock_array(key);
181  fb_isr_set( 1,
183  0,
184  16384 );
185 
186  atexit( fb_ConsoleMultikeyExit );
187 }
188 
189 int fb_ConsoleMultikey( int scancode )
190 {
191  if( scancode >= sizeof( key ) )
192  return FB_FALSE;
193 
195 
196  return (key[scancode]? FB_TRUE: FB_FALSE);
197 }