Use sink in navigate_complete instead of ClientSite's IDispatch.
[wine] / programs / wineconsole / curses.c
1 /*
2  * a GUI application for displaying a console
3  *      (N)Curses back end
4  *
5  * Copyright 2002 Eric Pouech
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /* Known issues & FIXME:
23  * - not all key mapping functions have been written
24  * - allow dyn loading of curses library (extreme care should be taken for 
25  *   functions which can be implemented as macros)
26  * - finish buffer scrolling (mainly, need to decide of a nice way for 
27  *   requesting the UP/DOWN operations
28  * - Resizing (unix) terminal does not change (Win32) console size.
29  * - Initial console size comes from registry and not from terminal size.
30  */
31
32 #include "config.h"
33 #include "wine/port.h"
34
35 #include <stdio.h>
36 #include <stdarg.h>
37 #include <stdlib.h>
38 #ifdef HAVE_NCURSES_H
39 # include <ncurses.h>
40 #elif defined(HAVE_CURSES_H)
41 # include <curses.h>
42 #endif
43 #undef KEY_EVENT  /* avoid redefinition warning */
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 #include <windef.h>
48 #include <winbase.h>
49 #include <winnls.h>
50 #include "winecon_private.h"
51
52 #include "wine/library.h"
53 #include "wine/server.h"
54 #include "wine/debug.h"
55
56 WINE_DEFAULT_DEBUG_CHANNEL(curses);
57
58 #define PRIVATE(data)   ((struct inner_data_curse*)((data)->private))
59
60 #if defined(HAVE_CURSES_H) || defined(HAVE_NCURSES_H)
61
62 #ifdef HAVE_NCURSES_H
63 # define CURSES_NAME "ncurses"
64 #else
65 # define CURSES_NAME "curses"
66 #endif
67
68 struct inner_data_curse 
69 {
70     mmask_t             initial_mouse_mask;
71     HANDLE              hInput;
72     WINDOW*             pad;
73     chtype*             line;
74     int                 allow_scroll;
75 };
76
77
78 static void *nc_handle = NULL;
79
80 #define MAKE_FUNCPTR(f) static typeof(f) * p_##f;
81
82 MAKE_FUNCPTR(curs_set)
83 MAKE_FUNCPTR(delwin)
84 MAKE_FUNCPTR(endwin)
85 MAKE_FUNCPTR(getmouse)
86 MAKE_FUNCPTR(has_colors)
87 MAKE_FUNCPTR(init_pair)
88 #ifndef initscr
89 MAKE_FUNCPTR(initscr)
90 #endif
91 #ifndef intrflush
92 MAKE_FUNCPTR(intrflush)
93 #endif
94 MAKE_FUNCPTR(keypad)
95 MAKE_FUNCPTR(mouseinterval)
96 MAKE_FUNCPTR(mousemask)
97 MAKE_FUNCPTR(newpad)
98 #ifndef nodelay
99 MAKE_FUNCPTR(nodelay)
100 #endif
101 #ifndef noecho
102 MAKE_FUNCPTR(noecho)
103 #endif
104 MAKE_FUNCPTR(prefresh)
105 MAKE_FUNCPTR(raw)
106 MAKE_FUNCPTR(start_color)
107 MAKE_FUNCPTR(stdscr)
108 MAKE_FUNCPTR(waddchnstr)
109 MAKE_FUNCPTR(wmove)
110 MAKE_FUNCPTR(wgetch)
111
112 #undef MAKE_FUNCPTR
113
114 /**********************************************************************/
115
116 static BOOL WCCURSES_bind_libcurses(void)
117 {
118 #ifdef HAVE_NCURSES_H
119     static const char *ncname = SONAME_LIBNCURSES;
120 #else
121     static const char *ncname = SONAME_LIBCURSES;
122 #endif
123
124     nc_handle = wine_dlopen(ncname, RTLD_NOW, NULL, 0);
125     if(!nc_handle)
126     {
127         WINE_MESSAGE("Wine cannot find the " CURSES_NAME " library (%s).\n",
128                      ncname);
129         return FALSE;
130     }
131
132 #define LOAD_FUNCPTR(f)                                      \
133     if((p_##f = wine_dlsym(nc_handle, #f, NULL, 0)) == NULL) \
134     {                                                        \
135         WINE_WARN("Can't find symbol %s\n", #f);             \
136         goto sym_not_found;                                  \
137     }
138
139     LOAD_FUNCPTR(curs_set)
140     LOAD_FUNCPTR(delwin)
141     LOAD_FUNCPTR(endwin)
142     LOAD_FUNCPTR(getmouse)
143     LOAD_FUNCPTR(has_colors)
144     LOAD_FUNCPTR(init_pair)
145 #ifndef initscr
146     LOAD_FUNCPTR(initscr)
147 #endif
148 #ifndef intrflush
149     LOAD_FUNCPTR(intrflush)
150 #endif
151     LOAD_FUNCPTR(keypad)
152     LOAD_FUNCPTR(mouseinterval)
153     LOAD_FUNCPTR(mousemask)
154     LOAD_FUNCPTR(newpad)
155 #ifndef nodelay
156     LOAD_FUNCPTR(nodelay)
157 #endif
158 #ifndef noecho
159     LOAD_FUNCPTR(noecho)
160 #endif
161     LOAD_FUNCPTR(prefresh)
162     LOAD_FUNCPTR(raw)
163     LOAD_FUNCPTR(start_color)
164     LOAD_FUNCPTR(stdscr)
165     LOAD_FUNCPTR(waddchnstr)
166     LOAD_FUNCPTR(wmove)
167     LOAD_FUNCPTR(wgetch)
168
169 #undef LOAD_FUNCPTR
170
171     return TRUE;
172
173 sym_not_found:
174     WINE_MESSAGE(
175       "Wine cannot find certain functions that it needs inside the "
176        CURSES_NAME "\nlibrary.  To enable Wine to use " CURSES_NAME 
177       " please upgrade your " CURSES_NAME "\nlibraries\n");
178     wine_dlclose(nc_handle, NULL, 0);
179     nc_handle = NULL;
180     return FALSE;
181 }
182
183 #define curs_set p_curs_set
184 #define delwin p_delwin
185 #define endwin p_endwin
186 #define getmouse p_getmouse
187 #define has_colors p_has_colors
188 #define init_pair p_init_pair
189 #ifndef initscr
190 #define initscr p_initscr
191 #endif
192 #ifndef intrflush
193 #define intrflush p_intrflush
194 #endif
195 #define keypad p_keypad
196 #define mouseinterval p_mouseinterval
197 #define mousemask p_mousemask
198 #define newpad p_newpad
199 #ifndef nodelay
200 #define nodelay p_nodelay
201 #endif
202 #ifndef noecho
203 #define noecho p_noecho
204 #endif
205 #define prefresh p_prefresh
206 #define raw p_raw
207 #define start_color p_start_color
208 #define stdscr (*p_stdscr)
209 #define waddchnstr p_waddchnstr
210 #define wmove p_wmove
211 #define wgetch p_wgetch
212
213 /******************************************************************
214  *              WCCURSES_ResizeScreenBuffer
215  *
216  *
217  */
218 static void WCCURSES_ResizeScreenBuffer(struct inner_data* data)
219 {
220     /* reallocate a new pad. next event would redraw the whole pad */
221     if (PRIVATE(data)->pad) delwin(PRIVATE(data)->pad);
222     PRIVATE(data)->pad = newpad(data->curcfg.sb_height, data->curcfg.sb_width);
223     if (!PRIVATE(data)->pad)
224         WINE_FIXME("Cannot create pad\n");
225     if (PRIVATE(data)->line) 
226         PRIVATE(data)->line = HeapReAlloc(GetProcessHeap(), 0, PRIVATE(data)->line, 
227                                       sizeof(chtype) * data->curcfg.sb_width);
228     else 
229         PRIVATE(data)->line = HeapAlloc(GetProcessHeap(), 0, 
230                                       sizeof(chtype) * data->curcfg.sb_width);
231 }
232
233 /******************************************************************
234  *              WCCURSES_PosCursor
235  *
236  * Set a new position for the cursor (and refresh any modified part of our pad)
237  */
238 static void     WCCURSES_PosCursor(const struct inner_data* data)
239 {
240     int scr_width;
241     int scr_height;
242
243     if (data->curcfg.cursor_visible &&
244         data->cursor.Y >= data->curcfg.win_pos.Y &&
245         data->cursor.Y < data->curcfg.win_pos.Y + data->curcfg.win_height &&
246         data->cursor.X >= data->curcfg.win_pos.X &&
247         data->cursor.X < data->curcfg.win_pos.X + data->curcfg.win_width)
248     {
249         if (curs_set(2) == ERR) curs_set(1);
250         wmove(PRIVATE(data)->pad, data->cursor.Y, data->cursor.X);
251     }
252     else
253     {
254         curs_set(0);
255     }
256     getmaxyx(stdscr, scr_height, scr_width); 
257     prefresh(PRIVATE(data)->pad,
258              data->curcfg.win_pos.Y, data->curcfg.win_pos.X,
259              0, 0, 
260              min(scr_height, data->curcfg.win_height) - 1, 
261              min(scr_width, data->curcfg.win_width) - 1);
262 }
263
264 /******************************************************************
265  *              WCCURSES_ShapeCursor
266  *
267  * Sets a new shape for the cursor
268  */
269 static void     WCCURSES_ShapeCursor(struct inner_data* data, int size, int vis, BOOL force)
270 {
271     /* we can't do much about the size... */
272     data->curcfg.cursor_size = size;
273     data->curcfg.cursor_visible = vis ? TRUE : FALSE;
274     WCCURSES_PosCursor(data);
275 }
276
277 /******************************************************************
278  *              WCCURSES_ComputePositions
279  *
280  * Recomputes all the components (mainly scroll bars) positions
281  */
282 static void     WCCURSES_ComputePositions(struct inner_data* data)
283 {
284     int         x, y;
285
286     getmaxyx(stdscr, y, x);
287     if ((data->curcfg.win_height && y < data->curcfg.win_height) ||
288         (data->curcfg.win_width && x < data->curcfg.win_width))
289     {
290         SMALL_RECT  pos;
291
292         WINE_WARN("Window too large (%dx%d), adjusting to curses' size (%dx%d)\n",
293                   data->curcfg.win_width, data->curcfg.win_height, x, y);
294         pos.Left = pos.Top = 0;
295         pos.Right = x - 1; pos.Bottom = y - 1;
296         SetConsoleWindowInfo(data->hConOut, FALSE, &pos);
297         return; /* we'll get called again upon event for new window size */
298     }
299     if (PRIVATE(data)->pad) WCCURSES_PosCursor(data);
300 }
301
302 /******************************************************************
303  *              WCCURSES_SetTitle
304  *
305  * Sets the title to the wine console
306  */
307 static void     WCCURSES_SetTitle(const struct inner_data* data)
308 {
309     WCHAR   wbuf[256];
310
311     if (WINECON_GetConsoleTitle(data->hConIn, wbuf, sizeof(wbuf)/sizeof(WCHAR)))
312     {
313         char        buffer[256];
314         
315         WideCharToMultiByte(CP_ACP, 0, wbuf, -1, buffer, sizeof(buffer), 
316                             NULL, NULL);
317         fputs("\033]2;", stdout);
318         fputs(buffer, stdout);
319         fputc('\a', stdout);
320         fflush(stdout);
321     }
322 }
323
324 /******************************************************************
325  *              WCCURSES_Refresh
326  *
327  *
328  */
329 static void WCCURSES_Refresh(const struct inner_data* data, int tp, int bm)
330 {
331     unsigned int x;
332     int         y;
333     CHAR_INFO*  cell;
334     DWORD       attr;
335     char        ch;
336
337     for (y = tp; y <= bm; y++)
338     {
339         cell = &data->cells[y * data->curcfg.sb_width];
340         for (x = 0; x < data->curcfg.sb_width; x++)
341         {
342             WideCharToMultiByte(CP_ACP, 0, &cell[x].Char.UnicodeChar, 1, 
343                                 &ch, 1, NULL, NULL);
344             attr = ((BYTE)ch < 32 || (BYTE)ch > 127) ? 32 : (BYTE)ch;
345
346             if (cell[x].Attributes & FOREGROUND_RED)       attr |= COLOR_PAIR(COLOR_RED);
347             if (cell[x].Attributes & FOREGROUND_BLUE)      attr |= COLOR_PAIR(COLOR_BLUE);
348             if (cell[x].Attributes & FOREGROUND_GREEN)     attr |= COLOR_PAIR(COLOR_GREEN);
349             if (cell[x].Attributes & BACKGROUND_RED)       attr |= COLOR_PAIR(COLOR_RED << 3);
350             if (cell[x].Attributes & BACKGROUND_BLUE)      attr |= COLOR_PAIR(COLOR_BLUE << 3);
351             if (cell[x].Attributes & BACKGROUND_GREEN)     attr |= COLOR_PAIR(COLOR_GREEN << 3);
352
353             if (cell[x].Attributes & FOREGROUND_INTENSITY) attr |= A_BOLD;
354             PRIVATE(data)->line[x] = attr;
355         }
356         mvwaddchnstr(PRIVATE(data)->pad, y, 0, PRIVATE(data)->line, data->curcfg.sb_width);
357     }
358
359     WCCURSES_PosCursor(data);
360 }
361
362 /******************************************************************
363  *              WCCURSES_Scroll
364  *
365  *
366  */
367 static void WCCURSES_Scroll(struct inner_data* data, int pos, BOOL horz)
368 {
369     if (horz)
370     {
371         data->curcfg.win_pos.X = pos;
372     }
373     else
374     {
375         data->curcfg.win_pos.Y = pos;
376     }
377     WCCURSES_PosCursor(data);
378 }
379
380 /******************************************************************
381  *              WCCURSES_SetFont
382  *
383  *
384  */
385 static void WCCURSES_SetFont(struct inner_data* data, const WCHAR* font, 
386                             unsigned height, unsigned weight)
387 {
388     /* FIXME: really not much to do ? */
389 }
390
391 /******************************************************************
392  *              WCCURSES_ScrollV
393  *
394  *
395  */
396 static void WCCURSES_ScrollV(struct inner_data* data, int delta)
397 {
398     int pos = data->curcfg.win_pos.Y;
399
400     pos += delta;
401     if (pos < 0) pos = 0;
402     if (pos > data->curcfg.sb_height - data->curcfg.win_height)
403         pos = data->curcfg.sb_height - data->curcfg.win_height;
404     if (pos != data->curcfg.win_pos.Y)
405     {
406         data->curcfg.win_pos.Y = pos;
407         WCCURSES_PosCursor(data);
408         WINECON_NotifyWindowChange(data);
409     }
410 }
411
412 /* Ascii -> VK, generated by calling VkKeyScanA(i) */
413 static int vkkeyscan_table[256] = 
414 {
415      0,0,0,0,0,0,0,0,8,9,0,0,0,13,0,0,0,0,0,19,145,556,0,0,0,0,0,27,0,0,0,
416      0,32,305,478,307,308,309,311,222,313,304,312,443,188,189,190,191,48,
417      49,50,51,52,53,54,55,56,57,442,186,444,187,446,447,306,321,322,323,
418      324,325,326,327,328,329,330,331,332,333,334,335,336,337,338,339,340,
419      341,342,343,344,345,346,219,220,221,310,445,192,65,66,67,68,69,70,71,
420      72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,475,476,477,
421      448,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
422      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
423      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
424      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,400,0,0,0,0,0,0
425 };
426
427 static int mapvkey_0[256] = 
428 {
429      0,0,0,0,0,0,0,0,14,15,0,0,0,28,0,0,42,29,56,69,58,0,0,0,0,0,0,1,0,0,
430      0,0,57,73,81,79,71,75,72,77,80,0,0,0,55,82,83,0,11,2,3,4,5,6,7,8,9,
431      10,0,0,0,0,0,0,0,30,48,46,32,18,33,34,35,23,36,37,38,50,49,24,25,16,
432      19,31,20,22,47,17,45,21,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,78,0,74,
433      0,53,59,60,61,62,63,64,65,66,67,68,87,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
434      0,0,0,0,0,0,69,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
435      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,13,51,12,52,53,41,0,0,0,0,0,0,0,0,0,
436      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,43,27,40,76,96,0,0,0,0,0,0,0,0,
437      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
438 }; 
439
440 /******************************************************************
441  *              WCCURSES_InitComplexChar
442  *
443  *
444  */
445 static inline void WCCURSES_InitComplexChar(INPUT_RECORD* ir, BOOL down, WORD vk, WORD kc, DWORD cks)
446 {
447     ir->EventType                        = KEY_EVENT;
448     ir->Event.KeyEvent.bKeyDown          = down;
449     ir->Event.KeyEvent.wRepeatCount      = 1;
450     
451     ir->Event.KeyEvent.wVirtualScanCode  = vk;
452     ir->Event.KeyEvent.wVirtualKeyCode   = kc;
453     ir->Event.KeyEvent.dwControlKeyState = cks;
454     ir->Event.KeyEvent.uChar.UnicodeChar = 0;
455 }
456
457 /******************************************************************
458  *              WCCURSES_FillSimpleChar
459  *
460  *
461  */
462 static unsigned WCCURSES_FillSimpleChar(INPUT_RECORD* ir, unsigned real_inchar)
463 {
464     unsigned vk;
465     unsigned inchar;
466     unsigned numEvent = 0;
467     DWORD    cks = 0;
468
469     switch (real_inchar)
470     {
471     case   9: inchar = real_inchar;
472               real_inchar = 27; /* so that we don't think key is ctrl- something */     
473               break;
474     case  10: inchar = '\r'; 
475               real_inchar = 27; /* Fixme: so that we don't think key is ctrl- something */ 
476               break;
477     case 127: inchar = '\b'; 
478               break;
479     case  27:
480         /* we assume that ESC & and the second character are atomically
481          * generated otherwise, we'll have a race here. FIXME: This gives 1 sec. delay
482          * because curses looks for a second character.
483          */
484         if ((inchar = wgetch(stdscr)) != ERR)
485         {
486             /* we got a alt-something key... */
487             cks = LEFT_ALT_PRESSED;
488         }
489         else
490             inchar = 27;
491         break;
492     default:
493         inchar = real_inchar;
494         break;
495     }
496     if ((inchar & ~0xFF) != 0) WINE_FIXME("What a char (%u)\n", inchar);
497     vk = vkkeyscan_table[inchar];
498     if (vk & 0x0100)
499         WCCURSES_InitComplexChar(&ir[numEvent++], 1, 0x2a, 0x10, SHIFT_PRESSED);
500     if ((vk & 0x0200) || (unsigned char)real_inchar <= 26)
501         WCCURSES_InitComplexChar(&ir[numEvent++], 1, 0x1d, 0x11, LEFT_CTRL_PRESSED);
502     if (vk & 0x0400)
503         WCCURSES_InitComplexChar(&ir[numEvent++], 1, 0x38, 0x12, LEFT_ALT_PRESSED);
504
505     ir[numEvent].EventType                        = KEY_EVENT;
506     ir[numEvent].Event.KeyEvent.bKeyDown          = 1;
507     ir[numEvent].Event.KeyEvent.wRepeatCount      = 1;
508     ir[numEvent].Event.KeyEvent.dwControlKeyState = cks;
509     if (vk & 0x0100)
510         ir[numEvent].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
511     if ((vk & 0x0200) || (unsigned char)real_inchar <= 26)
512         ir[numEvent].Event.KeyEvent.dwControlKeyState |= LEFT_CTRL_PRESSED;
513     if (vk & 0x0400)
514         ir[numEvent].Event.KeyEvent.dwControlKeyState |= LEFT_ALT_PRESSED;
515     ir[numEvent].Event.KeyEvent.wVirtualKeyCode = vk;
516     ir[numEvent].Event.KeyEvent.wVirtualScanCode = mapvkey_0[vk & 0x00ff]; /* VirtualKeyCodes to ScanCode */
517     ir[numEvent].Event.KeyEvent.uChar.UnicodeChar = (unsigned char)inchar;
518
519     ir[numEvent + 1] = ir[numEvent];
520     ir[numEvent + 1].Event.KeyEvent.bKeyDown      = 0;
521
522     numEvent += 2;
523
524     if (vk & 0x0400)
525         WCCURSES_InitComplexChar(&ir[numEvent++], 0, 0x38, 0x12, LEFT_ALT_PRESSED);
526     if ((vk & 0x0200) || (unsigned char)real_inchar <= 26)
527         WCCURSES_InitComplexChar(&ir[numEvent++], 0, 0x1d, 0x11, 0);
528     if (vk & 0x0100)
529         WCCURSES_InitComplexChar(&ir[numEvent++], 0, 0x2a, 0x10, 0);
530
531     return numEvent;
532 }
533
534 /******************************************************************
535  *              WCCURSES_FillComplexChar
536  *
537  *
538  */
539 static unsigned WCCURSES_FillComplexChar(INPUT_RECORD* ir, WORD vk, WORD kc, DWORD cks)
540 {
541     WCCURSES_InitComplexChar(&ir[0], 1, vk, kc, ENHANCED_KEY | cks);
542     WCCURSES_InitComplexChar(&ir[1], 0, vk, kc, ENHANCED_KEY | cks);
543
544     return 2;
545 }
546
547 /******************************************************************
548  *              WCCURSES_FillMouse
549  *
550  *
551  */
552 static unsigned WCCURSES_FillMouse(INPUT_RECORD* ir)
553 {
554     static      unsigned        bstate /* = 0 */;
555     static      COORD           pos /* = {0, 0} */;
556
557     MEVENT      mevt;
558
559     if (getmouse(&mevt) == ERR)
560         return 0;
561
562     WINE_TRACE("[%u]: (%d, %d) %08lx\n", 
563                mevt.id, mevt.x, mevt.y, (unsigned long)mevt.bstate);
564
565     /* macros to ease mapping ncurse button numbering to windows's one */
566 #define BTN1_BIT        FROM_LEFT_1ST_BUTTON_PRESSED
567 #define BTN2_BIT        RIGHTMOST_BUTTON_PRESSED
568 #define BTN3_BIT        FROM_LEFT_2ND_BUTTON_PRESSED
569 #define BTN4_BIT        0 /* not done yet */
570
571     if (mevt.bstate & BUTTON1_PRESSED)   bstate |= BTN1_BIT;
572     if (mevt.bstate & BUTTON1_RELEASED)  bstate &= ~BTN1_BIT;
573     if (mevt.bstate & BUTTON2_PRESSED)   bstate |= BTN2_BIT;
574     if (mevt.bstate & BUTTON2_RELEASED)  bstate &= ~BTN2_BIT;
575     if (mevt.bstate & BUTTON3_PRESSED)   bstate |= BTN3_BIT;
576     if (mevt.bstate & BUTTON3_RELEASED)  bstate &= ~BTN3_BIT;
577
578     ir->EventType = MOUSE_EVENT;
579     ir->Event.MouseEvent.dwMousePosition.X = mevt.x;
580     ir->Event.MouseEvent.dwMousePosition.Y = mevt.y;
581
582     ir->Event.MouseEvent.dwButtonState = bstate;
583
584     /* partial conversion */
585     ir->Event.MouseEvent.dwControlKeyState = 0;
586     if (mevt.bstate & BUTTON_SHIFT)     ir->Event.MouseEvent.dwControlKeyState |= SHIFT_PRESSED;
587     /* choose to map to left ctrl... could use both ? */
588     if (mevt.bstate & BUTTON_CTRL)      ir->Event.MouseEvent.dwControlKeyState |= LEFT_CTRL_PRESSED;
589     /* choose to map to left alt... could use both ? */
590     if (mevt.bstate & BUTTON_ALT)       ir->Event.MouseEvent.dwControlKeyState |= LEFT_ALT_PRESSED;
591     /* FIXME: unsupported yet flags: CAPSLOCK_ON, ENHANCED_KEY (??), NUMLOCK_ON, SCROLLLOCK_ON 
592      * could be reported from the key events...
593      */
594
595     ir->Event.MouseEvent.dwEventFlags = 0;
596     /* FIXME: we no longer generate double click events */
597
598     if (!(mevt.bstate & (BUTTON1_PRESSED|BUTTON1_RELEASED|BUTTON2_PRESSED|BUTTON2_RELEASED|BUTTON3_PRESSED|BUTTON3_RELEASED)) &&
599         (mevt.x != pos.X || mevt.y != pos.Y))
600     {
601         ir->Event.MouseEvent.dwEventFlags |= MOUSE_MOVED;
602     }
603     pos.X = mevt.x; pos.Y = mevt.y;
604
605     return 1;
606 }
607
608 /******************************************************************
609  *              WCCURSES_FillCode
610  *
611  *
612  */
613 static unsigned WCCURSES_FillCode(struct inner_data* data, INPUT_RECORD* ir, int inchar)
614 {
615     unsigned numEvent = 0;
616     
617     switch (inchar)
618     {
619     case KEY_BREAK:
620         goto notFound;
621     case KEY_DOWN:
622         numEvent = WCCURSES_FillComplexChar(ir, 0x50, 0x28, 0);
623         break;
624     case KEY_UP:
625         numEvent = WCCURSES_FillComplexChar(ir, 0x48, 0x26, 0);
626         break;
627     case KEY_LEFT:
628         numEvent = WCCURSES_FillComplexChar(ir, 0x4b, 0x25, 0);
629         break;
630     case KEY_RIGHT:
631         numEvent = WCCURSES_FillComplexChar(ir, 0x4d, 0x27, 0);
632         break;
633     case KEY_HOME:
634         numEvent = WCCURSES_FillComplexChar(ir, 0x47, 0x24, 0);
635         break;
636     case KEY_BACKSPACE:
637         numEvent = WCCURSES_FillSimpleChar(ir, 127);
638         break;
639         
640     case KEY_F0: /* up to F63 */
641         goto notFound;
642                     
643     case KEY_F( 1):
644     case KEY_F( 2):
645     case KEY_F( 3):
646     case KEY_F( 4):
647     case KEY_F( 5):
648     case KEY_F( 6):
649     case KEY_F( 7):
650     case KEY_F( 8):
651     case KEY_F( 9):
652     case KEY_F(10):
653         numEvent = WCCURSES_FillComplexChar(ir, 0x3b + inchar - KEY_F(1),
654                                             0x70 + inchar - KEY_F(1), 0);
655         break;
656     case KEY_F(11):
657     case KEY_F(12):
658         if (PRIVATE(data)->allow_scroll)
659         {
660             WCCURSES_ScrollV(data, inchar == KEY_F(11) ? 8 : -8);
661         }
662         else
663         {
664             numEvent = WCCURSES_FillComplexChar(ir, 0xd9 + inchar - KEY_F(11),
665                                                 0x7a + inchar - KEY_F(11), 0);
666         }
667         break;
668                     
669     case KEY_DL:
670     case KEY_IL:
671         goto notFound;
672
673     case KEY_DC:
674         numEvent = WCCURSES_FillComplexChar(ir, 0x53, 0x2e, 0);
675         break;
676     case KEY_IC:
677         numEvent = WCCURSES_FillComplexChar(ir, 0x52, 0x2d, 0);
678         break;
679
680     case KEY_EIC:
681     case KEY_CLEAR:
682     case KEY_EOS:
683     case KEY_EOL:
684     case KEY_SF:
685     case KEY_SR:
686         goto notFound;
687                     
688     case KEY_NPAGE:
689         numEvent = WCCURSES_FillComplexChar(ir, 0x51, 0x22, 0);
690         break;
691     case KEY_PPAGE:
692         numEvent = WCCURSES_FillComplexChar(ir, 0x49, 0x21, 0);
693         break;
694         
695     case KEY_STAB:
696     case KEY_CTAB:
697     case KEY_CATAB:
698     case KEY_ENTER:
699     case KEY_SRESET:
700     case KEY_RESET:
701     case KEY_PRINT:
702     case KEY_LL:
703     case KEY_A1:
704     case KEY_A3:
705     case KEY_B2:
706     case KEY_C1:
707     case KEY_C3:
708         goto notFound;
709     case KEY_BTAB:      /* shift tab */
710         numEvent = WCCURSES_FillSimpleChar(ir, 0x9);
711         ir[0].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;
712         ir[1].Event.KeyEvent.dwControlKeyState |= SHIFT_PRESSED;        
713         if (numEvent != 2) WINE_ERR("FillsimpleChar has changed");
714         break;
715
716     case KEY_BEG:
717     case KEY_CANCEL:
718     case KEY_CLOSE:
719     case KEY_COMMAND:
720     case KEY_COPY:
721     case KEY_CREATE:
722         goto notFound;
723
724     case KEY_END:
725         numEvent = WCCURSES_FillComplexChar(ir, 0x4f, 0x23, 0);
726         break;
727         
728     case KEY_EXIT:
729     case KEY_FIND:
730     case KEY_HELP:
731     case KEY_MARK:
732     case KEY_MESSAGE:
733         goto notFound;
734                     
735     case KEY_MOUSE:
736         numEvent = WCCURSES_FillMouse(ir);
737         break;
738         
739     case KEY_MOVE:
740     case KEY_NEXT:
741     case KEY_OPEN:
742     case KEY_OPTIONS:
743     case KEY_PREVIOUS:
744     case KEY_REDO:
745     case KEY_REFERENCE:
746     case KEY_REFRESH:
747     case KEY_REPLACE:
748     case KEY_RESIZE:
749     case KEY_RESTART:
750     case KEY_RESUME:
751     case KEY_SAVE:
752     case KEY_SBEG:
753     case KEY_SCANCEL:
754     case KEY_SCOMMAND:
755     case KEY_SCOPY:
756     case KEY_SCREATE:
757         goto notFound;
758
759     case KEY_SDC:
760         numEvent = WCCURSES_FillComplexChar(ir, 0x53, 0x2e, SHIFT_PRESSED);
761         break;
762     case KEY_SDL:
763     case KEY_SELECT:
764         goto notFound;
765
766     case KEY_SEND:
767         numEvent = WCCURSES_FillComplexChar(ir, 0x4f, 0x23, SHIFT_PRESSED);
768         break;
769
770     case KEY_SEOL:
771     case KEY_SEXIT:
772     case KEY_SFIND:
773     case KEY_SHELP:
774         goto notFound;
775
776     case KEY_SHOME:
777         numEvent = WCCURSES_FillComplexChar(ir, 0x47, 0x24, SHIFT_PRESSED);
778         break;
779     case KEY_SIC:
780         numEvent = WCCURSES_FillComplexChar(ir, 0x52, 0x2d, SHIFT_PRESSED);
781         break;
782     case KEY_SLEFT:
783         numEvent = WCCURSES_FillComplexChar(ir, 0x4b, 0x25, SHIFT_PRESSED);
784         break;
785
786     case KEY_SMESSAGE:
787     case KEY_SMOVE:
788     case KEY_SNEXT:
789     case KEY_SOPTIONS:
790     case KEY_SPREVIOUS:
791     case KEY_SPRINT:
792     case KEY_SREDO:
793     case KEY_SREPLACE:
794         goto notFound;
795
796     case KEY_SRIGHT:
797         numEvent = WCCURSES_FillComplexChar(ir, 0x4d, 0x27, SHIFT_PRESSED);
798         break;
799
800     case KEY_SRSUME:
801     case KEY_SSAVE:
802     case KEY_SSUSPEND:
803     case KEY_SUNDO:
804     case KEY_SUSPEND:
805     case KEY_UNDO:
806     notFound:
807         WINE_FIXME("Not done yet (%o)\n", inchar);
808         break;
809     default:
810         WINE_ERR("Unknown val (%o)\n", inchar);
811         break;
812     }
813     return numEvent;
814 }
815
816 /******************************************************************
817  *              WCCURSES_GetEvents
818  *
819  *
820  */
821 static void WCCURSES_GetEvents(struct inner_data* data)
822 {
823     int                 inchar;
824     INPUT_RECORD        ir[8];
825     unsigned            numEvent;
826     DWORD               n;
827     
828     if ((inchar = wgetch(stdscr)) == ERR) {WINE_FIXME("Ooch. somebody beat us\n");return;}
829     
830     WINE_TRACE("Got o%o (0x%x)\n", inchar,inchar);
831     
832     if (inchar & KEY_CODE_YES)
833     {
834         numEvent = WCCURSES_FillCode(data, ir, inchar);
835     }
836     else
837     {
838         numEvent = WCCURSES_FillSimpleChar(ir, inchar);
839     }
840     if (numEvent)
841         WriteConsoleInput(data->hConIn, ir, numEvent, &n);
842 }
843
844 /******************************************************************
845  *              WCCURSES_DeleteBackend
846  *
847  *
848  */
849 static void WCCURSES_DeleteBackend(struct inner_data* data)
850 {
851     mmask_t     mm;
852
853     if (!PRIVATE(data)) return;
854
855     CloseHandle(PRIVATE(data)->hInput);
856
857     delwin(PRIVATE(data)->pad);
858     mousemask(PRIVATE(data)->initial_mouse_mask, &mm);
859     endwin();
860
861     HeapFree(GetProcessHeap(), 0, PRIVATE(data)->line);
862     HeapFree(GetProcessHeap(), 0, PRIVATE(data));
863     data->private = NULL;
864 }
865
866 /******************************************************************
867  *              WCCURSES_MainLoop
868  *
869  *
870  */
871 static int WCCURSES_MainLoop(struct inner_data* data)
872 {
873     HANDLE hin[2];
874
875     hin[0] = PRIVATE(data)->hInput;
876     hin[1] = data->hSynchro;
877
878     for (;;) 
879     {
880         unsigned ret = WaitForMultipleObjects(2, hin, FALSE, INFINITE);
881         switch (ret)
882         {
883         case WAIT_OBJECT_0:
884             WCCURSES_GetEvents(data);
885             break;
886         case WAIT_OBJECT_0+1:
887             if (!WINECON_GrabChanges(data)) return 0;
888             break;
889         default:
890             WINE_ERR("got pb\n");
891             /* err */
892             break;
893         }
894     }
895 }
896
897 /******************************************************************
898  *              WCCURSES_InitBackend
899  *
900  * Initialisation part II: creation of window.
901  *
902  */
903 enum init_return WCCURSES_InitBackend(struct inner_data* data)
904 {
905     if( !WCCURSES_bind_libcurses() )
906         return init_failed;
907
908     data->private = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct inner_data_curse));
909     if (!data->private) return init_failed;
910
911     data->fnMainLoop           = WCCURSES_MainLoop;
912     data->fnPosCursor          = WCCURSES_PosCursor;
913     data->fnShapeCursor        = WCCURSES_ShapeCursor;
914     data->fnComputePositions   = WCCURSES_ComputePositions;
915     data->fnRefresh            = WCCURSES_Refresh;
916     data->fnResizeScreenBuffer = WCCURSES_ResizeScreenBuffer;
917     data->fnSetTitle           = WCCURSES_SetTitle;
918     data->fnScroll             = WCCURSES_Scroll;
919     data->fnSetFont            = WCCURSES_SetFont;
920     data->fnDeleteBackend      = WCCURSES_DeleteBackend;
921
922     if (wine_server_fd_to_handle(0, GENERIC_READ|SYNCHRONIZE, FALSE, 
923                                  (obj_handle_t*)&PRIVATE(data)->hInput))
924     {
925         WINE_FIXME("Cannot open 0\n");
926         return init_failed;
927     }
928
929     /* FIXME: should find a good way to enable buffer scrolling
930      * For the time being, setting this to 1 will allow scrolling up/down 
931      * on buffer with F11/F12.
932      */
933     /* PRIVATE(data)->allow_scroll = 1; */
934
935     initscr();
936
937     /* creating the basic colors - FIXME intensity not handled yet */
938     if (has_colors())
939     {
940         int i, j;
941
942         start_color();
943         for (i = 0; i < 8; i++)
944             for (j = 0; j < 8; j++)
945                 init_pair(i | (j << 3), i, j);
946     }
947
948     raw();
949     noecho();
950     intrflush(stdscr, FALSE);
951     nodelay(stdscr, TRUE);
952     keypad(stdscr, TRUE);
953     if (data->curcfg.quick_edit)
954     {
955         mousemask(BUTTON1_PRESSED|BUTTON1_RELEASED|
956                   BUTTON2_PRESSED|BUTTON2_RELEASED|
957                   BUTTON3_PRESSED|BUTTON3_RELEASED|
958                   BUTTON_SHIFT|BUTTON_CTRL|BUTTON_ALT|REPORT_MOUSE_POSITION,
959                   &PRIVATE(data)->initial_mouse_mask);
960         /* no click event generation... we just need button up/down events
961          * it doesn't seem that mouseinterval(-1) behaves as documented... 
962          * 0 seems to be better value to disable click event generation
963          */
964         mouseinterval(0);
965     }
966     else
967     {
968         mousemask(0, &PRIVATE(data)->initial_mouse_mask);
969     }
970
971     return init_success;
972 }
973
974 #else
975 enum init_return WCCURSES_InitBackend(struct inner_data* data)
976 {
977     return init_not_supported;
978 }
979 #endif