Index: trunk/src/kernel32/console/MonitorApi.h
===================================================================
--- trunk/src/kernel32/console/MonitorApi.h	(revision 5024)
+++ trunk/src/kernel32/console/MonitorApi.h	(revision 5024)
@@ -0,0 +1,51 @@
+#if !defined (OS2_MONITOR_API)
+#define OS2_MONITOR_API
+
+#pragma pack(1)
+
+struct MonRecord {
+    USHORT MonFlagWord;
+    BYTE   XlatedChar;
+    BYTE   XlatedScan;
+    BYTE   DBCS_Status;
+    BYTE   DBCS_Shift;
+    USHORT Shift_State;
+    ULONG  Milliseconds;
+    USHORT KbdDDFlagWord;
+    USHORT extra;
+};
+
+#define MONSIZE (118)
+typedef struct _MONIN {    /* mnin */
+    USHORT cb;
+    BYTE   abReserved[18];
+    BYTE   abBuffer[MONSIZE];
+} MONIN;
+
+typedef struct _MONOUT {    /* mnout */
+    USHORT cb;
+    BYTE   abReserved[18];
+    BYTE   abBuffer[MONSIZE];
+} MONOUT;
+#pragma pack(4)
+
+
+typedef SHANDLE HMONITOR;       /* hmon */
+typedef HMONITOR FAR *PHMONITOR;
+
+#define DosMonOpen              DOSMONOPEN
+#define DosMonClose             DOSMONCLOSE
+#define DosMonRead              DOSMONREAD
+#define DosMonWrite             DOSMONWRITE
+#define DosMonReg               DOSMONREG
+
+APIRET16 APIENTRY16  DosMonOpen(PSZ pszDevName, PHMONITOR phmon);
+APIRET16 APIENTRY16  DosMonClose(HMONITOR hmon);
+APIRET16 APIENTRY16  DosMonReg(HMONITOR hmon, PBYTE pbInBuf, PBYTE pbOutBuf,
+                          USHORT fPosition, USHORT usIndex);
+APIRET16 APIENTRY16  DosMonRead(PBYTE pbInBuf, USHORT fWait, PBYTE pbDataBuf,
+                           PUSHORT pcbData);
+APIRET16 APIENTRY16  DosMonWrite(PBYTE pbOutBuf, PBYTE pbDataBuf, USHORT cbData);
+
+
+#endif
Index: trunk/src/kernel32/console/makefile
===================================================================
--- trunk/src/kernel32/console/makefile	(revision 5024)
+++ trunk/src/kernel32/console/makefile	(revision 5024)
@@ -0,0 +1,44 @@
+COMPILER=icc
+CFLAGS= -Gm+
+DEBUG= -Ti+
+OPTIM=
+
+OBJS = vio32Dll.cpp vio32Utils.obj vio32SharedData.obj vio32Client.obj vio32StdFilters.obj
+
+%.obj : %.cpp
+	$(COMPILER) -c $(CFLAGS) $(DEBUG) $(OPTIM)  $*.cpp -o $*.obj
+
+
+all: $(OBJS) vio32.dll vio32.lib vio32VioServ.exe vio32test.exe vio32test2.exe vio32test3.exe test.exe
+	echo done
+
+vio32VioServ.exe: vio32VioServ.obj vio32.lib vio32.h
+	$(COMPILER) $(CFLAGS) $(DEBUG) $(OPTIM) vio32VioServ.obj vio32.lib -Fe vio32VioServ.exe
+
+vio32test.exe: vio32test.obj vio32.lib  vio32.h
+	$(COMPILER) $(CFLAGS) $(DEBUG) $(OPTIM) vio32test.obj vio32.lib -Fe vio32test.exe
+
+vio32test2.exe: vio32test2.obj vio32.lib  vio32.h
+	$(COMPILER) $(CFLAGS) $(DEBUG) $(OPTIM) vio32test2.obj vio32.lib -Fe vio32test2.exe
+
+vio32test3.exe: vio32test3.obj vio32.lib  vio32.h
+	$(COMPILER) $(CFLAGS) $(DEBUG) $(OPTIM) vio32test3.obj vio32.lib -Fe vio32test3.exe
+
+vio32.dll: $(OBJS) vio32.def vio32.h moncalls.lib MonitorApi.h vio32private.h
+	$(COMPILER)  $(CFLAGS)  $(DEBUG) $(OPTIM) -Ge- $(OBJS) DosQuerySysState.lib moncalls.lib vio32.def -Fe vio32.dll
+
+#/B"/NOE"
+
+vio32.lib: vio32.def
+	implib vio32.lib vio32.def
+
+test.exe: test.obj vio32.lib  vio32.h vio32Utils.h
+	$(COMPILER) $(CFLAGS) $(DEBUG) $(OPTIM) test.obj vio32.lib -Fe test.exe
+
+
+$(OBJS):    vio32Client.h       \
+        vio32Private.h      \
+        vio32Utils.h        \
+        vio32SharedData.h   \
+        vio32.h         \
+        vio32Errors.h
Index: trunk/src/kernel32/console/moncalls.def
===================================================================
--- trunk/src/kernel32/console/moncalls.def	(revision 5024)
+++ trunk/src/kernel32/console/moncalls.def	(revision 5024)
@@ -0,0 +1,10 @@
+;
+; wrap.def (created by emximp)
+;
+LIBRARY MONCALLS
+EXPORTS
+  DOSMONWRITE                      @1
+  DOSMONREAD                       @2
+  DOSMONCLOSE                      @3
+  DOSMONOPEN                       @4
+  DOSMONREG                        @5
Index: trunk/src/kernel32/console/test.cpp
===================================================================
--- trunk/src/kernel32/console/test.cpp	(revision 5024)
+++ trunk/src/kernel32/console/test.cpp	(revision 5024)
@@ -0,0 +1,32 @@
+#define INCL_WIN
+#define INCL_DOS
+#define INCL_VIO
+#define INCL_SUB
+#define INCL_DOSERRORS
+#define INCL_WINSWITCHLIST
+#include <os2.h>
+
+#include <stdio.h>
+#include "vio32Utils.h"
+
+void main(){
+    HWND hwndClient  = VIOWindowClient();
+    HWND hwndFrame   = VIOWindowFrame();
+    HWND hwndParent  = WinQueryWindow(hwndFrame,QW_PARENT);
+    HWND hwndParent2 = WinQueryWindow(hwndParent,QW_PARENT);
+
+    printf("client = %x, frame = %x, parent = %x, parent2 = %x\n",hwndClient,hwndFrame,hwndParent,hwndParent2);
+
+    // now get the message Queue
+    HMQ queue1 = WinQueryWindowULong(hwndClient, QWL_HMQ);
+    // now get the message Queue
+    HMQ queue2 = WinQueryWindowULong(hwndFrame, QWL_HMQ);
+    // now get the message Queue
+    HMQ queue3 = WinQueryWindowULong(hwndParent, QWL_HMQ);
+    // now get the message Queue
+    HMQ queue4 = WinQueryWindowULong(hwndParent2, QWL_HMQ);
+
+    printf("Q client = %x, frame = %x, parent = %x, parent2 = %x\n",queue1,queue2,queue3,queue4);
+
+    while(1) DosSleep(1000);
+}
Index: trunk/src/kernel32/console/test2.cpp
===================================================================
--- trunk/src/kernel32/console/test2.cpp	(revision 5024)
+++ trunk/src/kernel32/console/test2.cpp	(revision 5024)
@@ -0,0 +1,63 @@
+#define INCL_DOS
+#define INCL_PM
+#define INCL_WIN
+#define INCL_VIO
+#define INCL_SUB
+#define INCL_DOSERRORS
+#define INCL_DOSDEVICES
+#include <os2.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <MonitorApi.h>
+
+#pragma pack(1)
+#define MOUSE_MONSIZE (1024 - 20)
+typedef struct _MOUSE_MONIN {    /* mnin */
+    USHORT cb;
+    BYTE   abReserved[18];
+    BYTE   abBuffer[MOUSE_MONSIZE];
+} MOUSE_MONIN;
+
+typedef struct _MOUSE_MONOUT {    /* mnout */
+    USHORT cb;
+    BYTE   abReserved[18];
+    BYTE   abBuffer[MOUSE_MONSIZE];
+} MOUSE_MONOUT;
+#pragma pack(4)
+
+void main(){
+
+    HMONITOR mon;
+    APIRET rc = DosMonOpen("MOUSE$",&mon);
+printf("rc = %i\n",rc);
+    if (rc != 0){
+        DosMonClose(mon);
+        return;
+    }
+
+    MOUSE_MONIN monin;
+    monin.cb = sizeof(monin);
+    MOUSE_MONOUT monout;
+    monout.cb = sizeof(monout);
+    rc = DosMonReg(mon,(BYTE *)&monin,(BYTE *)&monout,0,-1);
+printf("rc = %i\n",rc);
+    if (rc != 0) {
+        DosMonClose(mon);
+        return;
+    }
+
+    DosSetPriority(PRTYS_THREAD,PRTYC_FOREGROUNDSERVER,10,0);
+
+    while(1){
+        ULONG buffer[8];
+        USHORT bufSize = sizeof(buffer);
+        rc = DosMonRead((PBYTE)&monin,DCWW_WAIT,(PBYTE)&buffer,&bufSize);
+printf("rc = %i bs =%i\n",rc,bufSize);
+        if (rc != 0) break;
+        printf(">>%08x %08x %08x %08x %08x %08x %08x %08x\n",buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7]);
+        rc = DosMonWrite((PBYTE)&monout,(PBYTE)&buffer,bufSize);
+
+        if (rc != 0) break;
+    }
+    DosMonClose(mon);
+}
Index: trunk/src/kernel32/console/vio32.def
===================================================================
--- trunk/src/kernel32/console/vio32.def	(revision 5024)
+++ trunk/src/kernel32/console/vio32.def	(revision 5024)
@@ -0,0 +1,26 @@
+LIBRARY VIO32 INITINSTANCE
+DATA MULTIPLE NONSHARED
+
+EXPORTS
+  InputHook         @1
+  SendMsgHook       @2
+  vio32Open         @10
+  vio32Close        @11
+  kbd32GetKey       @12
+  kbd32SetMode      @13
+  kbd32GetMode      @14
+  kbd32AddFilter    @15
+  kbd32RemoveFilter @16
+  vio32GetEvent     @17
+  kbd32GetKeyStatus @18
+  vio32GetMouse     @19
+  vio32WriteEvent   @20
+  vio32GetEventQSize @21
+  vio32PeekEvent    @22
+  vio32FlushEventQ  @23
+  InstallHook       @31
+  DeInstallHook     @32
+  VIOWindowClient   @33
+  VIOWindowFrame    @34
+
+ 
Index: trunk/src/kernel32/console/vio32.h
===================================================================
--- trunk/src/kernel32/console/vio32.h	(revision 5024)
+++ trunk/src/kernel32/console/vio32.h	(revision 5024)
@@ -0,0 +1,260 @@
+#if !defined (_KBD32_)
+#define _KBD32_
+
+#define INCL_DOS
+#define INCL_PM
+#define INCL_WIN
+#define INCL_VIO
+#define INCL_SUB
+#define INCL_DOSERRORS
+#include <os2.h>
+#include "MonitorApi.h"
+
+#pragma pack (1)
+/** */
+typedef struct _KBD32KEYINFO {
+    BOOL   keyUp;
+    ULONG  status;
+    USHORT repeat;
+    USHORT scancode;
+    USHORT chr;
+    USHORT vKey;
+} KBD32KEYINFO;
+
+/** */
+typedef struct _VIO32MOUINFO {
+    USHORT x;
+    USHORT y;
+    ULONG  buttonStatus;
+    ULONG  status;
+    ULONG  eventType;
+} VIO32MOUINFO;
+
+/** */
+typedef struct _pmMsg{
+    /** */
+    MPARAM mp1;
+    /** */
+    MPARAM mp2;
+} pmMsgType;
+
+// any of the possible messages
+typedef union _VIO32EVENTINFO {
+    /** generic mp1 mp2 message */
+    pmMsgType       pmMsg;
+    /** */
+    KBDKEYINFO      vioKbd;
+    /** */
+    MOUEVENTINFO    vioMou;
+    /** */
+    MonRecord       monKbd;
+    /** hook intercepted data */
+    CHRMSG          wmchar;
+    /** */
+//    MSEMSG          wmmouse;
+    /** */
+    KBD32KEYINFO    vio32Kbd;
+    /** */
+    VIO32MOUINFO    vio32Mou;
+} VIO32EVENTINFO;
+
+// the kbd + mouse status (as scan codes)
+typedef struct _VIO32STATUSINFO {
+    // 256 bits (scan codes) + 32 bit special scans: mouse...
+    ULONG status[9];
+} VIO32STATUSINFO;
+
+/** to create hook-like plugins for vio32 */
+typedef struct _vio32Filter {
+    VOID *next;
+    /** associated information: MUST be unique for each filter! NOT NULL!! */
+    VOID *filterData;
+    /** filtering function */
+    BOOL (*filter)(ULONG *eventType,VIO32EVENTINFO *event,VOID *filterData);
+} vio32Filter;
+
+#pragma pack(4)
+
+// macro to check if a key is pressed on a VIO32STATUSINFO : BOOL
+#define KBD32_CHECKKEY(scanState,scanCode) ((scanState.status[scanCode >> 5] & (1 << (scanCode & 0x1F))) != 0)
+
+// macro to mark a key as pressed on a VIO32STATUSINFO : VOID
+#define KBD32_SETKEY(scanState,scanCode) (scanState.status[scanCode >> 5] |= (1 << (scanCode & 0x1F)))
+
+// macro to mark a key as dePressed on a VIO32STATUSINFO : VOID
+#define KBD32_UNSETKEY(scanState,scanCode) (scanState.status[scanCode >> 5] &= (~(1 << (scanCode & 0x1F))))
+
+// macro to toggle a key status : VOID
+#define KBD32_TOGGLEKEY(scanState,scanCode) (scanState.status[scanCode >> 5] ^= (1 << (scanCode & 0x1F)))
+
+// macro to cleanup a scanState structure
+#define KBD32_RESETKEYS(scanState) {    \
+    scanState.status[0] = 0;            \
+    scanState.status[1] = 0;            \
+    scanState.status[2] = 0;            \
+    scanState.status[3] = 0;            \
+    scanState.status[4] = 0;            \
+    scanState.status[5] = 0;            \
+    scanState.status[6] = 0;            \
+    scanState.status[7] = 0;            \
+    scanState.status[8] = 0;            \
+}
+
+
+// the scan assigned to mouse button 1
+#define KBD32_MB1_SCAN          0x101
+
+// the scan assigned to mouse button 2
+#define KBD32_MB2_SCAN          0x102
+
+// the scan assigned to mouse button 3
+#define KBD32_MB3_SCAN          0x103
+
+// the scan assigned to mouse button 4
+#define KBD32_MB4_SCAN          0x104
+
+// the scan assigned to mouse button 5
+#define KBD32_MB5_SCAN          0x105
+
+// the scan assigned to the caps lock status
+#define KBD32_CAPSLOCK_SCAN     0x106
+
+// the scan assigned to the scroll lock status
+#define KBD32_SCROLLLOCK_SCAN   0x107
+
+// the scan assigned to the num lock status
+#define KBD32_NUMLOCK_SCAN      0x108
+
+// the scan assigned to the insert status
+#define KBD32_INSERT_SCAN       0x109
+
+//
+#define KBD32_SHIFTL_SCAN       0x02A
+
+//
+#define KBD32_SHIFTR_SCAN       0x036
+
+// the normal scan code produced by the api, as a status it is the left ALT
+#define KBD32_ALTL_SCAN         0x038
+
+// only valid as status: right ALT
+#define KBD32_ALTR_SCAN         0x10A
+
+// the normal scan code produced by the api, as a status it is the left ALT
+#define KBD32_CTRLL_SCAN        0x01D
+
+// only valid as status: right ALT
+#define KBD32_CTRLR_SCAN        0x10B
+
+// only valid as status: Mouse button 1
+#define VIO32_MB1_SCAN          0x10C
+
+// only valid as status: Mouse button 2
+#define VIO32_MB2_SCAN          0x10D
+
+// only valid as status: Mouse button 3
+#define VIO32_MB3_SCAN          0x10E
+
+// only valid as status: Mouse button 4
+#define VIO32_MB4_SCAN          0x10F
+
+// only valid as status: Mouse button 5
+#define VIO32_MB5_SCAN          0x110
+
+// a message coming from the KbdCharIn call
+#define VIO_CHAR WM_USER
+
+// a message coming from the monitor routine
+#define MON_CHAR WM_USER+1
+
+// a char message translated to the KBD32KEYINFO
+#define KBD32_CHAR WM_USER+2
+
+// a message coming from the mouse calls
+#define VIO_MOU WM_USER+3
+
+// the translated mouse messages
+#define VIO32_MOU WM_USER+4
+
+// CTRL-BREAK is disallowed to break the program
+#define KBD32MODE_DISABLEBREAK 0x1
+
+// enable mouse click events
+#define KBD32MODE_ENABLEMOUSE  0x2
+
+// enable mouse move events
+#define KBD32MODE_ENABLEMMOVE  0x4
+
+// compatible with win32
+#define KBD32_SHIFT              0x00000010
+#define KBD32_CTRL_L             0x00000008
+#define KBD32_CTRL_R             0x00000004
+#define KBD32_ALT_L              0x00000002
+#define KBD32_ALT_R              0x00000001
+#define KBD32_NUMLOCK            0x00000020
+#define KBD32_CAPSLOCK           0x00000080
+#define KBD32_SCROLLLOCK         0x00000040
+#define KBD32_ENHANCED_KEY       0x00000100
+
+// compatible with win32: mouse button status
+#define VIO32_MB1                0x0001
+#define VIO32_MB2                0x0002
+#define VIO32_MB3                0x0004
+#define VIO32_MB4                0x0008
+#define VIO32_MB5                0x0010
+// compatible with win32: mouse event types
+#define VIO32_MOUSEMOVE          0x0001
+#define VIO32_DOUBLECLICK        0x0002
+
+// Filter where modes
+// first of the preprocessing filters
+#define VIO32_PRE_FIRST         0x000000000
+// last of the preprocessing filters
+#define VIO32_PRE_LAST          0x00000FFFF
+// first of the postprocessing filters (activated on read)
+#define VIO32_POST_FIRST        0x000010000
+// last of the postprocessing filters  (activated on read)
+#define VIO32_POST_LAST         0x00001FFFF
+
+
+
+/** for client use */
+extern "C" {
+    /** */
+    APIRET EXPENTRY vio32Open();
+    /** */
+    APIRET EXPENTRY vio32Close();
+    /** */
+    APIRET EXPENTRY kbd32GetKey(KBD32KEYINFO *key,ULONG msecTimeout);
+    /** */
+    APIRET EXPENTRY vio32GetMouse(VIO32MOUINFO *mou,ULONG msecTimeout);
+    /** */
+    APIRET EXPENTRY vio32GetEvent(VIO32EVENTINFO *event,ULONG *eventType,ULONG msecTimeout);
+    /** */
+    APIRET EXPENTRY vio32GetEventQSize(ULONG *size,ULONG msecTimeout);
+    /** */
+    APIRET EXPENTRY vio32WriteEvent(VIO32EVENTINFO *event, ULONG *eventType);
+    /** inconsistency problems with the output filters To be Solved*/
+    APIRET EXPENTRY vio32PeekEvent(VIO32EVENTINFO *event,ULONG *eventType,ULONG position);
+    /** inconsistency problems with the output filters To be Solved*/
+    APIRET EXPENTRY vio32FlushEventQ();
+    /** */
+    APIRET EXPENTRY kbd32SetMode(ULONG mode);
+    /** */
+    APIRET EXPENTRY kbd32GetMode(ULONG *mode);
+    /** where is the position on the LIST returns the actual position 0x10000 ored indicates the output list */
+    APIRET EXPENTRY kbd32AddFilter(vio32Filter *filter,ULONG *where);
+    /** the filter is identified by its data field */
+    APIRET EXPENTRY kbd32RemoveFilter(VOID *filterData);
+    /** */
+    APIRET EXPENTRY kbd32GetKeyStatus(VIO32STATUSINFO *status);
+
+}
+
+
+
+
+
+
+
+#endif
Index: trunk/src/kernel32/console/vio32Client.cpp
===================================================================
--- trunk/src/kernel32/console/vio32Client.cpp	(revision 5024)
+++ trunk/src/kernel32/console/vio32Client.cpp	(revision 5024)
@@ -0,0 +1,1135 @@
+#define INCL_WIN
+#define INCL_DOS
+#define INCL_VIO
+#define INCL_SUB
+#define INCL_DOSERRORS
+#define INCL_WINSWITCHLIST
+#include <os2.h>
+#include "DosQuerySysState2.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "vio32Client.h"
+#include "vio32Private.h"
+#include "vio32Utils.h"
+#include "vio32SharedData.h"
+#include "vio32Errors.h"
+
+extern "C" {
+void __cdecl _ctordtorInit();
+}
+
+kbd32Client kbd32ClientInstance;
+
+#define USE_EXCEPT 0
+
+#if (USE_EXCEPT==1)
+//*****************************************************************************
+//
+//      Event handler to act on ctrl-c ctrl-break or any other kill message
+//
+//*****************************************************************************
+
+EXCEPTIONREGISTRATIONRECORD RegRec;
+
+ULONG _System MyTermHandler(  PEXCEPTIONREPORTRECORD       p1,
+                              PEXCEPTIONREGISTRATIONRECORD p2,
+                              PCONTEXTRECORD               p3,
+                              PVOID                        pv ){
+    switch( p1->ExceptionNum) {
+        case XCPT_PROCESS_TERMINATE:
+        case XCPT_ASYNC_PROCESS_TERMINATE: {
+            kbd32Close();
+        }
+        default:;
+    }
+
+   return XCPT_CONTINUE_SEARCH;          /* Exception not resolved... */
+}
+
+#else
+static void APIENTRY vio32Cleanup(ULONG ulReason)
+{
+   DosBeep(200,100);
+   vio32Close();
+   DosExitList(EXLST_EXIT, vio32Cleanup);
+}
+
+#endif
+//*****************************************************************************
+//
+//      Threads
+//
+//*****************************************************************************
+
+VOID _Optlink kbdThread(PVOID pParameters){
+    kbd32ClientInstance.kbdThread();
+}
+
+VOID _Optlink mouThread(PVOID pParameters){
+    kbd32ClientInstance.mouThread();
+}
+
+VOID _Optlink kbdMonitorThread(void * pParameters){
+    kbd32ClientInstance.kbdMonitorThread();
+}
+
+VOID _Optlink dataProcessingThread(void * pParameters){
+    kbd32ClientInstance.dataProcessingThread();
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::kbd32Client()
+//
+//*****************************************************************************
+
+kbd32Client::kbd32Client(){
+    SharedData              = NULL;
+    patched                 = FALSE;
+    mux                     = (HMTX)0;
+    accessSemaphore         = (HMTX)0;
+    primaryQ                = (HQUEUE)0;
+    secondaryQ              = (HQUEUE)0;
+    primaryQSem             = (HEV)0;
+    secondaryQSem           = (HEV)0;
+    mon                     = (HMONITOR)0;
+    mou                     = (HMOU)0;
+    kbdThreadId             = (TID)0;
+    mouThreadId             = (TID)0;
+    kbdMonitorThreadId      = (TID)0;
+    dataProcessingThreadId  = (TID)0;
+    threadsMustContinue     = TRUE;
+    applicationType         = 0;
+    applicationPid          = 0;
+    hwndFrame               = 0;
+    hwndClient              = 0;
+    pos                     = &events[0];
+    inputFilters            = NULL;
+    outputFilters           = NULL;
+
+    DosCreateMutexSem(NULL,&mux,0,0);
+
+}
+
+
+//*****************************************************************************
+//
+//      kbd32Client::~kbd32Client()
+//
+//*****************************************************************************
+
+kbd32Client::~kbd32Client(){
+    Close();
+    if (mux != 0) DosCloseMutexSem(mux);
+
+    // deallocate input filters
+    while(inputFilters != NULL){
+        vio32Filter *f = inputFilters;
+        inputFilters = (vio32Filter *)inputFilters->next;
+        free(f);
+    }
+
+    // deallocate output filters
+    while(outputFilters != NULL){
+        vio32Filter *f = outputFilters;
+        outputFilters = (vio32Filter *)outputFilters->next;
+        free(f);
+    }
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::init()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::init(){
+    // get application pid and type
+    PPIB pib;
+    PTIB tib;
+    APIRET ret;
+
+    KBDINFO kInfo;
+    KbdGetStatus(&kInfo,0);
+    kInfo.fsMask |=  (KEYBOARD_BINARY_MODE | KEYBOARD_ASCII_MODE);
+    kInfo.fsMask -=  ( KEYBOARD_ASCII_MODE);
+    KbdSetStatus(&kInfo,0);
+
+    // GET APPLICATION TYPE AND MORPH THREAD
+    ret = DosGetInfoBlocks(&tib, &pib);
+    if (ret != 0) return VIO32_GETAPPINFO | ret;
+    applicationType = pib->pib_ultype;
+    applicationPid  = pib->pib_ulpid;
+
+    // check valid application type
+    if ((applicationType != 2) && (applicationType != 3) && (applicationType != 0)) return VIO32_WRONGAPPTYPE;
+
+    // allow PM calls
+    if (pib->pib_ultype == 2) pib->pib_ultype = 3;
+
+    // get window information
+    if ((applicationType == 2) || (applicationType == 3)){
+        hwndClient = VIOWindowClient();
+        hwndFrame  = VIOWindowFrame();
+    }
+
+#if (USE_EXCEPT==1)
+    // SETUP EXCEPTION HANDLER STRUCTURES
+    RegRec.prev_structure = NULL;
+    RegRec.ExceptionHandler = (ERR)MyTermHandler;
+#endif
+
+    // PREPARE PRIMARY QUEUE
+    char qName[64];
+    sprintf(qName,PRIMARY_QUEUE_NAME,applicationPid);
+    ret = DosCreateQueue(&primaryQ,0,qName);
+    if (ret != 0) return VIO32_CREATEQUEUE | ret;
+
+    // PREPARE SECONDARY QUEUE
+    sprintf(qName,SECONDARY_QUEUE_NAME,applicationPid);
+    ret = DosCreateQueue(&secondaryQ,0,qName);
+    if (ret != 0) return VIO32_CREATEQUEUE | ret;
+
+    // PRIMARY EVENTS SEM CREATION: to wait for data
+    ret = DosCreateEventSem(NULL,&primaryQSem,DC_SEM_SHARED,0);
+    if (ret != 0) return VIO32_CREATEHEV | ret;
+
+    // SECONDARY EVENTS SEM CREATION: to wait for data
+    ret = DosCreateEventSem(NULL,&secondaryQSem,DC_SEM_SHARED,0);
+    if (ret != 0) return VIO32_CREATEHEV | ret;
+
+    // MUTEX SEM CREATION: protect shared mem
+    char *  mxName = MUTEX_NAME;
+    accessSemaphore = 0;
+    ret = DosCreateMutexSem((PSZ)mxName,&accessSemaphore,DC_SEM_SHARED,1);
+    if ((ret != 0) && (ret != ERROR_DUPLICATE_NAME)) return VIO32_CREATESHMUX | ret;
+
+    // if it already existed let's get hold of it
+    if (ret == ERROR_DUPLICATE_NAME){
+        accessSemaphore = 0;
+        ret = DosOpenMutexSem((PSZ)mxName,&accessSemaphore);
+        if (ret != 0) return VIO32_OPENSHMUX | ret;
+
+        ret = DosRequestMutexSem(accessSemaphore,SEM_INDEFINITE_WAIT);
+        if (ret != 0) return VIO32_REQUESTSHMUX | ret;
+    }
+
+    // SHARED MEMORY: comunicate from PM
+    // at this stage we have the semaphore and it is locked
+    // now do the same with the shared memory
+    PPVOID  pmem = (void **)&SharedData;
+    char *  shName = SHMEM_NAME;
+    BOOL    creator = FALSE;
+    ret = DosAllocSharedMem(pmem,(PSZ)shName,(sizeof(kbd32SharedData)+4096)&0xFFFFF000,PAG_COMMIT | PAG_WRITE | PAG_READ );
+    if ((ret != 0) && (ret != ERROR_ALREADY_EXISTS)){
+        SharedUnlock();
+        return VIO32_ALLOCSHMEM | ret;
+    }
+
+    // if it is already there then lets' simply attach to it
+    if (ret == ERROR_ALREADY_EXISTS){
+        ret = DosGetNamedSharedMem(pmem,(PSZ)shName,PAG_READ | PAG_WRITE);
+        if (ret != 0){
+            SharedUnlock();
+            return VIO32_GETSHMEM | ret;
+        }
+    } else creator = TRUE;
+
+    // FUNNY FAILURE
+    if (SharedData == NULL){
+        SharedUnlock();
+        return VIO32_SHMEMNOTALLOCATED;
+    }
+
+    // now I have to initialize the memory: I get here only if I created it
+    if (creator) SharedData->Init();
+
+    SharedUnlock();
+
+    // start KBD thread
+    if (kbdThreadId == 0) kbdThreadId = _beginthread(::kbdThread,NULL,32768,NULL);
+
+    // start KBD thread
+    if (dataProcessingThreadId == 0) dataProcessingThreadId = _beginthread(::dataProcessingThread,NULL,32768,NULL);
+
+    // now do application type specifics
+    if (applicationType == 0){
+
+        // PREPARE MONITOR
+        ret = DosMonOpen("KBD$",&mon);
+        if (ret != 0)  return VIO32_MONOPEN | ret;
+
+        monin.cb = sizeof(monin);
+        monout.cb = sizeof(monout);
+        ret = DosMonReg(mon,(BYTE *)&monin,(BYTE *)&monout,0,-1);
+        if (ret != 0) return VIO32_MONREG | ret;
+
+        // now start mon thread
+        if (kbdMonitorThreadId == 0) kbdMonitorThreadId = _beginthread(::kbdMonitorThread,NULL,32768,NULL);
+    }
+
+    // reset keyboard status
+    KBD32_RESETKEYS(keyStatus);
+
+    // add default filters
+    ULONG where = VIO32_PRE_FIRST;
+    AddFilter(&kbdMapper,where);
+
+    // prepare mouse support
+    // Get mouse handle
+    ret = MouOpen(NULL, &mou);
+    if (ret != 0)  return VIO32_MOUOPEN | ret;
+
+    // Enable mouse
+    ret = MouDrawPtr(mou);
+    if (ret != 0)  return VIO32_MOUDRAWPTR | ret;
+
+    // Enable all events fails on WSEB ??
+//    USHORT mask = 0x7F;
+//    ret = MouSetEventMask(&mask,mou);
+//    if (ret != 0)  return VIO32_MOUSETEVENTMASK | ret;
+
+    // now start mon thread
+    if (mouThreadId == 0) mouThreadId = _beginthread(::mouThread,NULL,32768,NULL);
+
+    // success
+    return 0;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::finish()
+//
+//*****************************************************************************
+
+VOID kbd32Client::finish(){
+    threadsMustContinue = FALSE;
+    if (primaryQSem != 0)       DosCloseEventSem(primaryQSem);
+    if (secondaryQSem != 0)     DosCloseEventSem(secondaryQSem);
+    if (primaryQ != 0)          DosCloseQueue(primaryQ);
+    if (secondaryQ != 0)        DosCloseQueue(secondaryQ);
+    if (accessSemaphore != 0)   DosCloseMutexSem(accessSemaphore);
+    if (mon != 0)               DosMonClose(mon);
+    if (SharedData != NULL)     DosFreeMem(SharedData);
+    if (mou != 0)               MouClose(mou);
+#if (USE_EXCEPT==1)
+    DosUnsetExceptionHandler(&RegRec);
+#endif
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::Open()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::Open(){
+    if (patched) return VIO32_ALREADYOPENED;
+
+    // serialize
+    LocalLock();
+
+    APIRET ret;
+
+#if (USE_EXCEPT==1)
+    // ACTIVATE EXCEPTION HANDLER
+    ret = DosSetExceptionHandler(&RegRec);
+    if (ret != 0){
+        LocalUnlock();
+        return ret  | VIO32_SETEXCHANDLER;
+    }
+#else
+    APIRET rc = DosExitList(0x00008000|EXLST_ADD, vio32Cleanup);
+
+#endif
+
+    // INITIALIZE THE SYSTEM
+    ret = init();
+    if (ret != 0){
+        finish();
+        LocalUnlock();
+        return ret;
+    }
+
+    // INSTALL APPLICATION
+    ULONG nesting;
+    DosEnterMustComplete(&nesting);
+    SharedLock();
+    ret = SharedData->InstallApplication(applicationPid,((applicationType == 2) || (applicationType == 3)));
+    SharedUnlock();
+    DosExitMustComplete(&nesting);
+
+    if (ret != 0){
+        finish();
+        LocalUnlock();
+        return ret;
+    }
+
+    patched = TRUE;
+
+    LocalUnlock();
+    return 0;
+}
+
+
+//*****************************************************************************
+//
+//      kbd32Client::Close()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::Close(){
+    if (patched    == FALSE) return VIO32_NOTOPENED;
+    if (SharedData == NULL)  return VIO32_SHMEMNOTALLOCATED;
+
+    // remove settings on memory
+    ULONG nesting;
+    DosEnterMustComplete(&nesting);
+    LocalLock();
+    SharedLock();
+    SharedData->UninstallApplication(applicationPid);
+    SharedUnlock();
+    LocalLock();
+    DosExitMustComplete(&nesting);
+
+    finish();
+    patched = FALSE;
+
+    return 0;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::AddFilter()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::AddFilter(vio32Filter *filter,ULONG &where){
+    if (filter == NULL) return VIO32_INVALIDPARAM;
+
+    LocalLock();
+
+    // MAKE A COPY
+    vio32Filter *f = (vio32Filter *)malloc(sizeof(vio32Filter));
+    *f = *filter;
+    f->next = NULL;
+
+    vio32Filter **list = &inputFilters;
+    // select list
+    if (where & VIO32_POST_FIRST){
+        list = &outputFilters;
+    }
+
+    // now look only at the position
+    ULONG pos = where & 0x0000FFFF;
+
+    if (((*list) == NULL)||(pos==0)) {
+        pos = 0;
+        f->next = (*list);
+        (*list) = f;
+    } else {
+        ULONG index = 1;
+        vio32Filter *q = (*list);
+        while((pos > index)&&(q->next != NULL)){
+            index++;
+            q=(vio32Filter *)q->next;
+        }
+        f->next = q->next;
+        q->next = f;
+        pos = index;
+    }
+
+    where &= 0xFFFF0000;
+    where += pos;
+
+    LocalUnlock();
+    return 0;
+}
+
+APIRET kbd32Client::_removeFilter(VOID *filterData,vio32Filter *&list){
+    BOOL found = FALSE;
+
+    if (list != NULL){
+        vio32Filter *pf = list;
+        if (list->filterData == filterData){
+            list = (vio32Filter *)list->next;
+            free(pf);
+            found = TRUE;
+        } else {
+            while ((pf->next != NULL)&&(((vio32Filter *)pf->next)->filterData != filterData)) pf = (vio32Filter *)pf->next;
+            if (pf->next != NULL){
+                vio32Filter *pf2 = (vio32Filter *)pf->next;
+                pf->next = pf2->next;
+                free(pf2);
+                found = TRUE;
+            }
+        }
+    }
+
+    if (!found) return VIO32_NOTFOUND;
+    return 0;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::RemoveFilter()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::RemoveFilter(VOID *filterData){
+    if (filterData == NULL) return VIO32_INVALIDPARAM;
+
+    LocalLock();
+
+    APIRET found = _removeFilter(filterData,inputFilters);
+    if (found == VIO32_NOTFOUND)
+    found = _removeFilter(filterData,outputFilters);
+
+    LocalUnlock();
+
+    return found;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::GetEvent()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::GetEvent(VIO32EVENTINFO *event,ULONG *eventType,ULONG msecTimeout){
+
+    if (event == NULL)      return VIO32_INVALIDPARAM;
+    if (eventType == NULL)  return VIO32_INVALIDPARAM;
+
+    BOOL            dataUsed = TRUE;
+    REQUESTDATA     request;
+    ULONG           dataSize;
+    VIO32EVENTINFO *data;
+    BYTE            priority;
+    while(dataUsed == TRUE){
+        // exclusive access
+        LocalLock();
+
+        APIRET rc = DosReadQueue(secondaryQ,&request,&dataSize,(PPVOID)&data,0,DCWW_NOWAIT, &priority,secondaryQSem);
+
+        if ((rc != 0)&&(rc != ERROR_QUE_EMPTY)){
+            LocalUnlock();
+            return rc | VIO32_READQUEUE;
+        }
+
+        if (rc == ERROR_QUE_EMPTY){
+            LocalUnlock();
+            rc= DosWaitEventSem(secondaryQSem,msecTimeout);
+            if (rc == ERROR_TIMEOUT) return rc;
+            if (rc != 0) return rc | VIO32_WAITHEV;
+
+            LocalLock();
+            rc = DosReadQueue(secondaryQ,&request,&dataSize,(PPVOID)&data,0,DCWW_NOWAIT, &priority,secondaryQSem);
+            if (rc != 0){
+                LocalUnlock();
+                return rc | VIO32_READQUEUE;
+            }
+        }
+
+        // PROCESS THE DATA here!
+        vio32Filter *f = outputFilters;
+        dataUsed = FALSE;
+        while ((f != NULL)&&(!dataUsed)){
+//FISA
+//printf("output processing using %s\n",f->filterData);
+            dataUsed = f->filter(&request.ulData,data,f->filterData);
+            f = (vio32Filter *)f->next;
+        }
+
+        // if we are about to exit copy data
+        if (!dataUsed){
+            *eventType = request.ulData;
+            *event = *data;
+        }
+
+        LocalUnlock();
+    }
+
+    return 0;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::PeekEvent()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::PeekEvent(VIO32EVENTINFO *event,ULONG *eventType,ULONG position){
+
+    if (event == NULL)      return VIO32_INVALIDPARAM;
+    if (eventType == NULL)  return VIO32_INVALIDPARAM;
+
+    REQUESTDATA     request;
+    ULONG           dataSize;
+    VIO32EVENTINFO *data;
+    BYTE            priority;
+    // exclusive access
+    LocalLock();
+
+    ULONG pos = 0;
+    // start from the top
+    APIRET rc = DosPeekQueue(secondaryQ,&request,&dataSize,(PPVOID)&data,&pos,DCWW_NOWAIT, &priority,0);
+
+    // move on if necessary
+    while((rc==0)&&(pos != position)){
+        pos = 1;
+        rc = DosPeekQueue(secondaryQ,&request,&dataSize,(PPVOID)&data,&pos,DCWW_NOWAIT, &priority,0);
+    }
+
+    if (rc != 0){
+        LocalUnlock();
+        return rc | VIO32_READQUEUE;
+    }
+
+    *eventType = request.ulData;
+    *event = *data;
+    LocalUnlock();
+
+    return 0;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::FlushEventQ()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::FlushEventQ(){
+
+    REQUESTDATA     request;
+    ULONG           dataSize;
+    VIO32EVENTINFO *data;
+    BYTE            priority;
+    // exclusive access
+    LocalLock();
+
+    ULONG pos = 0;
+    // start from the top
+    APIRET rc = DosReadQueue(secondaryQ,&request,&dataSize,(PPVOID)&data,0,DCWW_NOWAIT, &priority,0);
+    // move on if necessary
+    while(rc==0) rc = DosReadQueue(secondaryQ,&request,&dataSize,(PPVOID)&data,0,DCWW_NOWAIT, &priority,0);
+
+    LocalUnlock();
+
+    return 0;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::GetEventQSize()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::GetEventQSize(ULONG *size,ULONG msecTimeout){
+
+    if (size == NULL)      return VIO32_INVALIDPARAM;
+
+    // exclusive access
+    LocalLock();
+
+    APIRET rc = DosQueryQueue(secondaryQ,size);
+
+    LocalUnlock();
+
+    return rc;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::GetKeyStroke()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::GetKeyStroke(KBD32KEYINFO *key,ULONG msecTimeout){
+
+    if (key == NULL) return VIO32_INVALIDPARAM;
+
+    VIO32EVENTINFO event;
+    ULONG eventType;
+    APIRET ret;
+
+    // flush all events until a key event is reached
+    while(1){
+        ret = GetEvent(&event,&eventType,0);
+        // no more events in Q, wait for next event
+        if (ret == ERROR_TIMEOUT) {
+            ret = GetEvent(&event,&eventType,msecTimeout);
+            if (ret != 0 ) return ret;
+            // not a key event, must abort otw I will loop forever
+            if (eventType != KBD32_CHAR) return VIO32_WRONGEVENTTYPE;
+            // success!
+            *key = event.vio32Kbd;
+            return 0;
+        }
+        // some error, not a timeout
+        if (ret != 0 ) return ret;
+        if (eventType == KBD32_CHAR){
+            *key = event.vio32Kbd;
+            return 0;
+        }
+    }
+
+    // will never each this code
+    return 0;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::GetMouse()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::GetMouse(VIO32MOUINFO *mou,ULONG msecTimeout){
+
+    if (mou == NULL) return VIO32_INVALIDPARAM;
+
+    VIO32EVENTINFO event;
+    ULONG eventType;
+    APIRET ret;
+
+    // flush all events until a key event is reached
+    while(1){
+        ret = GetEvent(&event,&eventType,0);
+        // no more events in Q, wait for next event
+        if (ret == ERROR_TIMEOUT) {
+            ret = GetEvent(&event,&eventType,msecTimeout);
+            if (ret != 0 ) return ret;
+            // not a key event, must abort otw I will loop forever
+            if (eventType != VIO32_MOU) return VIO32_WRONGEVENTTYPE;
+            // success!
+            *mou = event.vio32Mou;
+            return 0;
+        }
+        // some error, not a timeout
+        if (ret != 0 ) return ret;
+        if (eventType == VIO32_MOU){
+            *mou = event.vio32Mou;
+            return 0;
+        }
+    }
+
+    // will never each this code
+    return 0;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::WriteEvent()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::WriteEvent(VIO32EVENTINFO *event, ULONG *eventType){
+
+    if (event == NULL)      return VIO32_INVALIDPARAM;
+    if (eventType == NULL)  return VIO32_INVALIDPARAM;
+
+    ULONG nesting;
+    DosEnterMustComplete(&nesting);
+    SharedLock();
+
+    HWND hwndClient;
+    HWND hwndFrame;
+    int index;
+    APIRET ret = 0;
+    if (SharedData->searchByPid(applicationPid,hwndClient,hwndFrame,index)){
+
+        // now check how many entries are busy
+        ULONG entries = 0;
+        ret = DosQueryQueue(primaryQ, &entries);
+
+        // if too many are used bleep
+        if ((ret == 0) && (entries >= MAX_PRIMARY_Q_LEN)){
+            ret = VIO32_QUEUEFULL;
+            DosBeep(1000,20);
+        }
+        // if all is good send data
+        if (ret == 0){
+            // allocate a Q object.
+            VIO32EVENTINFO *ev = SharedData->getBuffer(index);
+            *ev = *event;
+            // send the data
+            ret = DosWriteQueue(primaryQ,*eventType,sizeof(VIO32EVENTINFO),ev,0);
+            if (ret != 0) ret |= VIO32_WRITEQUEUE;
+        }
+        // now mark the buffer as used
+        if (ret == 0){
+            SharedData->advanceBuffer(index);
+        }
+    } else ret = VIO32_UNREGISTERED;
+
+    SharedUnlock();
+    DosExitMustComplete(&nesting);
+
+    return ret;
+};
+
+//*****************************************************************************
+//
+//      kbd32Client::kbdThread()
+//
+//*****************************************************************************
+
+APIRET kbd32Client::GetKeyStatus(VIO32STATUSINFO *status){
+    if (status == NULL) return VIO32_INVALIDPARAM;
+    APIRET ret = 0;
+    VIO32EVENTINFO event;
+    ULONG eventType;
+    while(ret == 0) ret = GetEvent(&event,&eventType,0);
+    if (ret == ERROR_TIMEOUT) ret = 0;
+    LocalLock();
+    *status = keyStatus;
+    LocalUnlock();
+    return ret;
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::kbdThread()
+//
+//*****************************************************************************
+
+VOID kbd32Client::kbdThread(){
+    DosSetPriority(PRTYS_THREAD,PRTYC_FOREGROUNDSERVER,10,0);
+
+    // finish together with the kbd monitor
+    while(threadsMustContinue){
+        KBDKEYINFO charData;
+        APIRET ret = KbdCharIn(&charData,0,0);
+        if (!threadsMustContinue) break;
+        if (ret != 0) return;
+        if (ret == 0){
+            ULONG nesting;
+            DosEnterMustComplete(&nesting);
+            SharedLock();
+
+            HWND hwndClient;
+            HWND hwndFrame;
+            int index;
+            if (SharedData->searchByPid(applicationPid,hwndClient,hwndFrame,index)){
+
+                // now check how many entries are busy
+                ULONG entries = 0;
+                ret = DosQueryQueue(primaryQ, &entries);
+
+                // if too many are used bleep
+                if ((ret == 0) && (entries >= MAX_PRIMARY_Q_LEN)){
+                    ret = 1;
+                    DosBeep(1000,20);
+                }
+                // if all is good send data
+                if (ret == 0){
+                    // allocate a Q object.
+                    VIO32EVENTINFO *key = SharedData->getBuffer(index);
+                    key->vioKbd = charData;
+                    // send the data
+                    ret = DosWriteQueue(primaryQ,VIO_CHAR,sizeof(VIO32EVENTINFO),key,0);
+                }
+                // now mark the buffer as used
+                if (ret == 0){
+                    SharedData->advanceBuffer(index);
+                }
+            }
+
+            SharedUnlock();
+            DosExitMustComplete(&nesting);
+        }
+    }
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::mouThread()
+//
+//*****************************************************************************
+
+VOID kbd32Client::mouThread(){
+    DosSetPriority(PRTYS_THREAD,PRTYC_FOREGROUNDSERVER,10,0);
+
+    MOUEVENTINFO newMouEvent;
+    MOUEVENTINFO outStandingMouEvent;
+    BOOL hasOutStanding = FALSE;
+    USHORT wait = 1;
+    USHORT noWait = 0;
+    // finish together with the kbd monitor
+    while(threadsMustContinue){
+        APIRET ret = 0;
+        // check if there is a pending mouse event
+        if (hasOutStanding == FALSE){
+            // if not read a new and wait if it is not available
+            ret = MouReadEventQue(&newMouEvent,&wait,mou);
+            if (!threadsMustContinue) break;
+        } else {
+            // if an event was waiting use it as a new event
+            newMouEvent = outStandingMouEvent;
+        }
+        hasOutStanding = FALSE;
+        // now collapse all movements into a single event
+        if (ret == 0){
+            // stop on error or if a different event was encountered and stored
+            while((ret == 0) && (hasOutStanding == FALSE)){
+                // empty the Q
+                ret = MouReadEventQue(&outStandingMouEvent,&noWait,mou);
+                // an empty event does not produce error, so I generate one myself
+                if (outStandingMouEvent.time == 0) ret = 1;
+                if (ret == 0){
+//printf("@%i %i %i %i\n",newMouEvent.time,newMouEvent.fs,newMouEvent.col,newMouEvent.row);
+//printf("@%i %i %i %i\n",outStandingMouEvent.time,outStandingMouEvent.fs,outStandingMouEvent.col,outStandingMouEvent.row);
+                    // bug fix for VIO window and spurius mouse move messages
+                    if (((outStandingMouEvent.fs & 0x1)!= 0) &&
+                        (newMouEvent.col == outStandingMouEvent.col) &&
+                        (newMouEvent.row == outStandingMouEvent.row)) outStandingMouEvent.fs -= 0x1;
+//printf("@%i %i %i %i\n",outStandingMouEvent.time,outStandingMouEvent.fs,outStandingMouEvent.col,outStandingMouEvent.row);
+
+                    // if the status is different remember the event for later
+                    if (outStandingMouEvent.fs != newMouEvent.fs) hasOutStanding = TRUE;
+                    // just keep the last event
+                    else newMouEvent = outStandingMouEvent;
+                }
+            }
+            ret = 0;
+        }
+
+
+        // now Q the new event
+        if (ret == 0){
+            ULONG nesting;
+            DosEnterMustComplete(&nesting);
+            SharedLock();
+
+            HWND hwndClient;
+            HWND hwndFrame;
+            int index;
+            if (SharedData->searchByPid(applicationPid,hwndClient,hwndFrame,index)){
+
+                // get mode of operation of given app
+                ULONG mode = SharedData->getMode(index);
+
+//printf("@%i %i %i %i\n",newMouEvent.time,newMouEvent.fs,newMouEvent.col,newMouEvent.row);
+                // see whether to filter out messages
+                static ULONG lastMouseStatus = 0;
+                if ((mode & KBD32MODE_ENABLEMOUSE)==0) ret = 1;
+                ULONG newMouseStatus = (newMouEvent.fs & 0x54) | ((newMouEvent.fs & 0x2A)<<1);
+                if ((mode & KBD32MODE_ENABLEMMOVE)==0){
+                    newMouEvent.fs = newMouseStatus;
+                    if (newMouEvent.fs == lastMouseStatus) ret = 1;
+                }
+                lastMouseStatus = newMouseStatus;
+
+                // now check how many entries are busy
+                ULONG entries = 0;
+                if (ret == 0)
+                    ret = DosQueryQueue(primaryQ, &entries);
+
+                // if too many are used bleep
+                if ((ret == 0) && (entries >= MAX_PRIMARY_Q_LEN)){
+                    ret = 1;
+                    DosBeep(1000,20);
+                }
+
+                // if all is good send data
+                if (ret == 0){
+                    // allocate a Q object.
+                    VIO32EVENTINFO *key = SharedData->getBuffer(index);
+                    key->vioMou = newMouEvent;
+                    // send the data
+                    ret = DosWriteQueue(primaryQ,VIO_MOU,sizeof(VIO32EVENTINFO),key,0);
+                }
+                // now mark the buffer as used
+                if (ret == 0){
+                    SharedData->advanceBuffer(index);
+                }
+            }
+
+            SharedUnlock();
+            DosExitMustComplete(&nesting);
+        }
+    }
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::kbdMonitorThread()
+//
+//*****************************************************************************
+
+
+void kbd32Client::kbdMonitorThread(){
+    DosSetPriority(PRTYS_THREAD,PRTYC_FOREGROUNDSERVER,10,0);
+    //
+    while(threadsMustContinue){
+        MonRecord monData;
+        USHORT bufSize = sizeof(monData);
+        APIRET ret = DosMonRead((PBYTE)&monin,DCWW_WAIT,(PBYTE)&monData,&bufSize);
+        if (!threadsMustContinue) break;
+
+        BOOL dataUsed = (ret != 0);
+        if (ret == 0){
+            ULONG nesting;
+            DosEnterMustComplete(&nesting);
+            SharedLock();
+
+            HWND hwndClient;
+            HWND hwndFrame;
+            int index;
+            if (SharedData->searchByPid(applicationPid,hwndClient,hwndFrame,index)){
+
+                // get mode of operation of given app
+                ULONG mode = SharedData->getMode(index);
+
+                // bypass certain keys
+                ULONG specialKeys = monData.KbdDDFlagWord & 0x003F;
+                if (specialKeys != 0){
+                    ret = 1;
+                    // pass all the CTRL/SHIFT/ALT/N-LOCK... events
+                    if (specialKeys == 0x7) ret = 0;
+                    if ((mode & KBD32MODE_DISABLEBREAK) && (specialKeys == 0x11)) ret = 0;
+                }
+
+                // now check how many entries are busy
+                ULONG entries = 0;
+                if (ret == 0){
+                    ret = DosQueryQueue(primaryQ, &entries);
+                }
+
+                // if too many are used bleep
+                if ((ret == 0) && (entries >= MAX_PRIMARY_Q_LEN)){
+                    ret = 1;
+                    DosBeep(1000,20);
+                }
+
+                // if all is good send data
+                if (ret == 0){
+                    // allocate a Q object.
+                    VIO32EVENTINFO *key = SharedData->getBuffer(index);
+                    key->monKbd = monData;
+                    // send the data
+                    ret = DosWriteQueue(primaryQ,MON_CHAR,sizeof(VIO32EVENTINFO),key,0);
+                }
+                // now mark the buffer as used
+                if (ret == 0){
+                    SharedData->advanceBuffer(index);
+                    dataUsed = TRUE;
+                }
+            }
+            SharedUnlock();
+            DosExitMustComplete(&nesting);
+        }
+        if (dataUsed == FALSE){
+/*
+            if ((monData.KbdDDFlagWord & 0x7) == 0x7){
+                monData.KbdDDFlagWord &= 0xFFF8;
+                monData.Shift_State |= 0x2000; // means special char remapped -64
+            }
+            if (monData.KbdDDFlagWord & 0x0040){
+                monData.KbdDDFlagWord &= 0xFFBF;
+                monData.Shift_State |= 0x1000; // use  KBDSTF_SCROLLLOCK to say KEY-UP
+            }
+            CHAR scanCode = monData.MonFlagWord >> 8;
+            monData.XlatedScan =  scanCode;
+printf(">>%c %i 0x%x 0x%x 0x%x\n",monData.XlatedChar,monData.XlatedScan,
+                        monData.MonFlagWord,monData.Shift_State,monData.KbdDDFlagWord);
+*/
+            DosMonWrite((PBYTE)&monout,(PBYTE)&monData,14);
+        }
+    }
+}
+
+//*****************************************************************************
+//
+//      kbd32Client::dataProcessingThread()
+//
+//*****************************************************************************
+
+
+VOID kbd32Client::dataProcessingThread(){
+    DosSetPriority(PRTYS_THREAD,PRTYC_FOREGROUNDSERVER,10,0);
+
+    // the message read
+    VIO32EVENTINFO queuedData;
+
+    //
+    while(threadsMustContinue){
+        // exclusive access to primary Q
+        SharedLock();
+
+        // READ DATA OFF the primary Q
+        REQUESTDATA request;
+        ULONG dataSize;
+        VIO32EVENTINFO *data;
+        BYTE priority;
+        APIRET rc = DosReadQueue(primaryQ,&request,&dataSize,(PPVOID)&data,0,DCWW_NOWAIT, &priority,primaryQSem);
+        if (!threadsMustContinue) break;
+        if (rc == ERROR_QUE_EMPTY){
+            SharedUnlock();
+            rc= DosWaitEventSem(primaryQSem,-1);
+            SharedLock();
+
+            if (rc == 0)
+                rc = DosReadQueue(primaryQ,&request,&dataSize,(PPVOID)&data,0,DCWW_NOWAIT, &priority,primaryQSem);
+        }
+
+        // copy data before releasing the semaphore
+        if (rc == 0) queuedData = *data;
+
+        // relinquish primary Q
+        SharedUnlock();
+
+
+        // exclusive access to secondary Q
+        LocalLock();
+
+        // now check how many entries are busy
+        ULONG entries = 0;
+        if (rc == 0) rc = DosQueryQueue(secondaryQ, &entries);
+
+        // if too many are used bleep
+        if ((rc == 0) && (entries >= MAX_SECONDARY_Q_LEN)){
+            rc = 1;
+            DosBeep(2000,20);
+        }
+
+        // now allocate a space in the secondary Q
+        VIO32EVENTINFO *key;
+        if (rc == 0){
+            // allocate a Q object.
+            key = getBuffer();
+            //
+            if (key == NULL) rc = 1;
+        }
+
+        // PROCESS THE DATA here!
+        vio32Filter *f = inputFilters;
+        BOOL dataUsed = FALSE;
+        if (rc==0)
+            while ((f != NULL)&&(!dataUsed)){
+//FISA
+//printf("INPUT processing with %s\n",f->filterData);
+                dataUsed = f->filter(&request.ulData,&queuedData,f->filterData);
+                f = (vio32Filter *)f->next;
+            }
+
+        // if all is right and the data was not consumed send it forward
+        if ((rc == 0) && (!dataUsed)){
+            // copy content
+            *key = queuedData;
+            // send the data
+            rc = DosWriteQueue(secondaryQ,request.ulData,sizeof(VIO32EVENTINFO),key,0);
+
+            // now mark the buffer as used
+            if (rc == 0) advanceBuffer();
+        }
+
+        // free secondary system
+        LocalUnlock();
+
+        if ((rc != 0) && (rc != ERROR_TIMEOUT)) return;
+    }
+}
+
+
Index: trunk/src/kernel32/console/vio32Client.h
===================================================================
--- trunk/src/kernel32/console/vio32Client.h	(revision 5024)
+++ trunk/src/kernel32/console/vio32Client.h	(revision 5024)
@@ -0,0 +1,161 @@
+#if !defined (KBD32_CLIENT_H)
+#define KBD32_CLIENT_H
+
+#define INCL_WIN
+#define INCL_DOS
+#define INCL_VIO
+#define INCL_SUB
+#define INCL_DOSERRORS
+#define INCL_WINSWITCHLIST
+#include <os2.h>
+#include "DosQuerySysState2.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "vio32SharedData.h"
+#include "vio32Errors.h"
+
+//#define VIO32_PREFILTER   0x00000
+//#define VIO32_POSTFILTER  0x10000
+
+//
+class kbd32Client{
+    //      semaphore to allow muliple threads to use the structures of VIO32
+    HMTX                mux;
+    //      semaphore used to access shared memory
+    HMTX                accessSemaphore;
+    ///     the shared memory address.
+    kbd32SharedData    *SharedData;
+    ///     when the kbd32 is active = TRUE
+    BOOL                patched;
+    ///     the message queue used to collect all the messages
+    HQUEUE              primaryQ;
+    ///     the message queue where the processed messages are written to
+    HQUEUE              secondaryQ;
+    ///     a semaphore used to wait on the primary Q
+    HEV                 primaryQSem;
+    ///     a semaphore used to wait on the secondary Q
+    HEV                 secondaryQSem;
+    ///     the id of the thread listening to VIO kbd api
+    TID                 kbdThreadId;
+    ///     the id of the thread listening to a monitor
+    TID                 kbdMonitorThreadId;
+    ///     the id of the thread listening to the mou events
+    TID                 mouThreadId;
+    ///     the id of the thread elaborating data
+    TID                 dataProcessingThreadId;
+    ///     a flag to get the threads to exit.
+    BOOL                threadsMustContinue;
+    ///     the monitor handles
+    HMONITOR            mon;
+    ///     the monitor handles
+    MONIN               monin;
+    ///     the monitor handles
+    MONOUT              monout;
+    ///
+    HMOU                mou;
+    ///
+    ULONG               applicationType;
+    ///
+    ULONG               applicationPid;
+    ///
+    HWND                hwndFrame;
+    ///
+    HWND                hwndClient;
+    //
+    VIO32EVENTINFO      events[MAX_SECONDARY_Q_LEN];
+    //
+    VIO32EVENTINFO     *pos;
+    //      filters acting on the data stream as soon as it gets to the main Q
+    vio32Filter        *inputFilters;
+    //      filters acting on the data read
+    vio32Filter        *outputFilters;
+    //      the status of the keyboard + mouse buttons
+    VIO32STATUSINFO    keyStatus;
+    ///
+    APIRET             _removeFilter(VOID *filterData,vio32Filter *&list);
+public:
+
+    ///
+    VOID                kbdThread();
+    ///
+    VOID                mouThread();
+    ///
+    VOID                kbdMonitorThread();
+    ///
+    VOID                dataProcessingThread();
+    ///     do all the general initialization needed for Open
+    APIRET              init();
+    ///     clean - up all the initialization done by init();
+    VOID                finish();
+    ///     gets a buffer
+    VIO32EVENTINFO       *getBuffer(){
+        if (pos >= (&events[MAX_PRIMARY_Q_LEN])) pos = &events[0];
+        return pos;
+    }
+    ///     automatically updates the pointer
+    void                advanceBuffer() { pos++; }
+
+    ///
+    VIO32STATUSINFO    &KeyStatus()     { return keyStatus; }
+
+public:
+    ///
+    void                SharedLock()    { DosRequestMutexSem(accessSemaphore,SEM_INDEFINITE_WAIT); }
+    ///
+    void                SharedUnlock()  { DosReleaseMutexSem(accessSemaphore); }
+    ///
+    void                LocalLock()     { DosRequestMutexSem(mux,SEM_INDEFINITE_WAIT); }
+    ///
+    void                LocalUnlock()   { DosReleaseMutexSem(mux); }
+    /// this initialization simply connects to the shared memory or creates it
+                        kbd32Client();
+    ///
+                       ~kbd32Client();
+    ///
+    APIRET              Open();
+    ///
+    APIRET              Close();
+    ///
+    APIRET              GetKeyStroke(KBD32KEYINFO *key,ULONG msecTimeout);
+    ///
+    APIRET              GetMouse(VIO32MOUINFO *mou,ULONG msecTimeout);
+    ///
+    APIRET              GetEvent(VIO32EVENTINFO *event,ULONG *eventType,ULONG msecTimeout);
+    ///
+    APIRET              PeekEvent(VIO32EVENTINFO *event,ULONG *eventType,ULONG position);
+    ///
+    APIRET              FlushEventQ();
+    ///
+    APIRET              GetEventQSize(ULONG *size,ULONG msecTimeout);
+    ///
+    APIRET              WriteEvent(VIO32EVENTINFO *event, ULONG *eventType);
+    ///     copies the kbd status to the user provided variable status. Will flush all the events..
+    APIRET              GetKeyStatus(VIO32STATUSINFO *status);
+    ///
+    APIRET              SetMode(ULONG mode){
+        if (patched==FALSE)         return VIO32_NOTOPENED;
+        if (SharedData == NULL)     return VIO32_SHMEMNOTALLOCATED;
+        return SharedData->SetMode(mode,applicationPid);
+    }
+    ///
+    APIRET              GetMode(ULONG *mode){
+        if (patched==FALSE)         return VIO32_NOTOPENED;
+        if (SharedData == NULL)     return VIO32_SHMEMNOTALLOCATED;
+        if (mode==NULL)             return VIO32_INVALIDPARAM;
+        return SharedData->GetMode(*mode,applicationPid);
+    }
+    /// filter content is copied into a new allocated structure
+    APIRET              AddFilter(vio32Filter *filter,ULONG &where);
+    ///
+    APIRET              RemoveFilter(VOID *filterData);
+
+};
+
+extern  kbd32Client kbd32ClientInstance;
+
+// the filter that deals with KBD messages and MOU messages and FOCUS messages in order to produce the correct KBD32 messages and MOU32 messages
+extern vio32Filter kbdMapper;
+#define KBD32_REMAPPER_NAME "KbdMapper"
+
+#endif
Index: trunk/src/kernel32/console/vio32Dll.cpp
===================================================================
--- trunk/src/kernel32/console/vio32Dll.cpp	(revision 5024)
+++ trunk/src/kernel32/console/vio32Dll.cpp	(revision 5024)
@@ -0,0 +1,378 @@
+#define INCL_WIN
+#define INCL_DOS
+#define INCL_VIO
+#define INCL_SUB
+#define INCL_DOSERRORS
+#define INCL_WINSWITCHLIST
+#include <os2.h>
+#include "DosQuerySysState2.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "vio32Private.h"
+#include "vio32Utils.h"
+#include "vio32SharedData.h"
+#include "vio32Client.h"
+
+
+APIRET EXPENTRY vio32Open(){
+    return kbd32ClientInstance.Open();
+}
+
+APIRET EXPENTRY vio32Close(){
+    return kbd32ClientInstance.Close();
+}
+
+APIRET EXPENTRY kbd32GetKey(KBD32KEYINFO *key,ULONG msecTimeout){
+    return kbd32ClientInstance.GetKeyStroke(key,msecTimeout);
+}
+
+APIRET EXPENTRY vio32GetMouse(VIO32MOUINFO *mou,ULONG msecTimeout){
+    return kbd32ClientInstance.GetMouse(mou,msecTimeout);
+}
+
+APIRET EXPENTRY vio32GetEvent(VIO32EVENTINFO *event,ULONG *eventType,ULONG msecTimeout){
+    return kbd32ClientInstance.GetEvent(event,eventType,msecTimeout);
+}
+
+APIRET EXPENTRY vio32PeekEvent(VIO32EVENTINFO *event,ULONG *eventType,ULONG position){
+    return kbd32ClientInstance.PeekEvent(event,eventType,position);
+}
+
+APIRET EXPENTRY vio32FlushEventQ(){
+    return kbd32ClientInstance.FlushEventQ();
+}
+
+APIRET EXPENTRY vio32GetEventQSize(ULONG *size,ULONG msecTimeout){
+    return kbd32ClientInstance.GetEventQSize(size,msecTimeout);
+}
+
+APIRET EXPENTRY vio32WriteEvent(VIO32EVENTINFO *event, ULONG *eventType){
+    return kbd32ClientInstance.WriteEvent(event,eventType);
+}
+
+APIRET EXPENTRY kbd32GetKeyStatus(VIO32STATUSINFO *status){
+    return kbd32ClientInstance.GetKeyStatus(status);
+}
+
+APIRET EXPENTRY kbd32SetMode(ULONG mode){
+    return kbd32ClientInstance.SetMode(mode);
+}
+
+APIRET EXPENTRY kbd32GetMode(ULONG *mode){
+    return kbd32ClientInstance.GetMode(mode);
+}
+
+APIRET kbd32AddFilter(vio32Filter *filter,ULONG *where){
+    ULONG defaultPos=VIO32_PRE_FIRST;
+    if (where == NULL) where = &defaultPos;
+    return kbd32ClientInstance.AddFilter(filter,*where);
+}
+
+APIRET kbd32RemoveFilter(VOID *filterData){
+    return kbd32ClientInstance.RemoveFilter(filterData);
+}
+
+// hook stuff
+HMODULE module  = 0;
+PFN     pfn1     = NULL;
+PFN     pfn2     = NULL;
+
+BOOL EXPENTRY InstallHook(){
+    // already done!
+    if (module != 0) return FALSE;
+
+    // already done!
+    if (pfn1 != NULL) return FALSE;
+
+    // already done!
+    if (pfn2 != NULL) return FALSE;
+
+    // now morph into PM on this thread in acse it didn't happen before
+    PPIB pib;
+    PTIB tib;
+    DosGetInfoBlocks(&tib, &pib);
+    if (pib->pib_ultype == 2) pib->pib_ultype = 3;
+
+    // this code can be run only from a VIO app
+    if (pib->pib_ultype != 3) return FALSE;
+
+    // get anchor block
+    HAB hab = WinInitialize(0);
+
+    // now get the message Queue
+    HMQ queue = WinQueryWindowULong(VIOWindowClient(), QWL_HMQ);
+
+    // now get my own module handle
+    char buffer[256];
+    APIRET rc = DosLoadModule(buffer,256,"vio32.dll",&module);
+    if (rc != 0){
+        printf("DosLoadModule rc is %i\n", rc);
+        return FALSE;
+    }
+
+    // get function pointer
+    rc = DosQueryProcAddr(module,1,NULL,&pfn1);
+    if (rc != 0){
+        printf("DosQueryProcAddr(2) rc is %i\n", rc);
+        return FALSE;
+    }
+
+    BOOL ret = WinSetHook(hab,queue,HK_INPUT,pfn1,module);
+    if (!ret){
+        printf("WinSetHook(1) failed\n");
+        return FALSE;
+    }
+
+    // get function pointer
+    rc = DosQueryProcAddr(module,2,NULL,&pfn2);
+    if (rc != 0){
+        printf("DosQueryProcAddr(2) rc is %i\n", rc);
+        return FALSE;
+    }
+
+    ret = WinSetHook(hab,queue,HK_SENDMSG,pfn2,module);
+    if (!ret){
+        printf("WinSetHook(2) failed\n");
+        return FALSE;
+    }
+
+    return (rc == 0);
+}
+
+BOOL EXPENTRY DeInstallHook(){
+    // never installed
+    if (module == 0) return FALSE;
+
+    // never installed
+    if (pfn1 == NULL) return FALSE;
+
+    // never installed
+    if (pfn2 == NULL) return FALSE;
+
+    // now morph into PM on this thread in acse it didn't happen before
+    PPIB pib;
+    PTIB tib;
+    DosGetInfoBlocks(&tib, &pib);
+    if (pib->pib_ultype == 2) pib->pib_ultype = 3;
+
+    // this code can be run only from a VIO app
+    if (pib->pib_ultype != 3) return FALSE;
+
+    // get anchor block
+    HAB hab = WinInitialize(0);
+
+    // now get the message Queue
+    HMQ queue = WinQueryWindowULong(VIOWindowClient(), QWL_HMQ);
+
+    // finally remove hook
+    BOOL ret = WinReleaseHook(hab,queue,HK_INPUT,pfn1,module);
+
+    // remove hook 2
+    ret &= WinReleaseHook(hab,queue,HK_SENDMSG,pfn2,module);
+
+    // deallocate the DLL
+    DosFreeModule(module);
+    module = NULL;
+    pfn1   = NULL;
+    pfn2   = NULL;
+
+    return ret;
+}
+
+
+BOOL  EXPENTRY InputHook(HAB hab, PQMSG pQmsg, ULONG fs){
+
+    // take only mouse and kbd messages
+//    if ((pQmsg->msg < WM_MOUSEMOVE) || (pQmsg->msg > WM_CHAR)) return FALSE;
+    if (pQmsg->msg != WM_CHAR) return FALSE;
+
+    // now grab mutex sem
+    APIRET ret;
+    HMTX   hmtx = 0;
+    BOOL   locked = FALSE;
+    ret = DosOpenMutexSem((PSZ)MUTEX_NAME,&hmtx);
+    if (ret == 0){
+        ret = DosRequestMutexSem(hmtx,SEM_INDEFINITE_WAIT);
+        if (ret == 0) locked = TRUE;
+    }
+
+    // grab shared mem
+    kbd32SharedData *SharedData = NULL;
+    BOOL haveMem = FALSE;
+    if (ret == 0){
+        ret = DosGetNamedSharedMem((PPVOID)&SharedData,(PSZ)SHMEM_NAME,PAG_READ | PAG_WRITE);
+        // ok I have the pointer to the memory I am ok! let's release the memory
+        if (ret == 0) haveMem = TRUE;
+    }
+
+    // now send the key stroke
+    BOOL dataUsed = FALSE;
+    if (ret == 0){
+        // find if the application is registered
+        PID pid;
+        int index;
+        HWND hwndFrame;
+        if (SharedData->searchByHwndClient(pQmsg->hwnd,hwndFrame,pid,index)){
+            // get mode of operation of given app
+            ULONG mode = SharedData->getMode(index);
+
+            // treat specific WM_CHAR msg
+            if (pQmsg->msg == WM_CHAR){
+                // trasnform qmsg in the specific msg
+                CHRMSG *wmchar = (CHRMSG *)&pQmsg->mp1;
+                // on special modes abort
+                if (((mode & KBD32MODE_DISABLEBREAK)==0) && (wmchar->scancode == 110)) ret = 1;
+            }
+//            else // mouse move
+//            if (pQmsg->msg == WM_MOUSEMOVE){
+//                if ((mode & KBD32MODE_ENABLEMMOVE)==0) ret = 1;
+//            } else // mouse clicks
+//                if ((mode & KBD32MODE_ENABLEMOUSE)==0) ret = 1;
+
+
+            HQUEUE keyQ = 0;
+
+            // get the associated Q
+            if (ret == 0){
+                PID pid_;
+                char qName[64];
+                sprintf(qName,PRIMARY_QUEUE_NAME,pid);
+                ret = DosOpenQueue(&pid_,&keyQ,qName);
+            }
+
+            // now check how many entries are busy
+            ULONG entries = 0;
+            if (ret == 0) ret = DosQueryQueue(keyQ, &entries);
+
+            // if too many are used bleep
+            if ((ret == 0) && (entries >= MAX_PRIMARY_Q_LEN)){
+                ret = 1;
+                DosBeep(1000,20);
+            }
+            // if all is good send data
+            if (ret == 0){
+                // allocate a Q object.
+                VIO32EVENTINFO *key = SharedData->getBuffer(index);
+                // copy data
+                key->pmMsg.mp1 = pQmsg->mp1;
+                key->pmMsg.mp2 = pQmsg->mp2;
+                // send the data
+                ret = DosWriteQueue(keyQ,pQmsg->msg,sizeof(VIO32EVENTINFO),key,0);
+            }
+            // now mark the buffer as used
+            if (ret == 0){
+                SharedData->advanceBuffer(index);
+                dataUsed = TRUE;
+            }
+            // close Q
+            if (keyQ != 0) DosCloseQueue(keyQ);
+        }
+    }
+
+    // release memory
+    if (haveMem) DosFreeMem((PVOID)SharedData);
+    haveMem = FALSE;
+
+    // relase mutex sem
+    if (locked) DosReleaseMutexSem(hmtx);
+    locked = FALSE;
+
+    // let click do focus change
+    if ((pQmsg->msg >= 0x71) && (pQmsg->msg <= 0x79)) return FALSE;
+    return dataUsed;
+}
+
+VOID EXPENTRY SendMsgHook(HAB hab,PSMHSTRUCT psmh,BOOL fInterTask){
+    if (fInterTask) return ;
+
+    // filter messages
+    BOOL toBeProcessed = FALSE;
+    if (psmh->msg == WM_FOCUSCHANGE) toBeProcessed = TRUE;
+    if (psmh->msg == WM_SIZE)        toBeProcessed = TRUE;
+    if (psmh->msg == WM_MOVE)        toBeProcessed = TRUE;
+
+    if (!toBeProcessed) return;
+
+    // now grab mutex sem
+    APIRET ret;
+    HMTX   hmtx = 0;
+    BOOL   locked = FALSE;
+    ret = DosOpenMutexSem((PSZ)MUTEX_NAME,&hmtx);
+    if (ret == 0){
+        ret = DosRequestMutexSem(hmtx,SEM_INDEFINITE_WAIT);
+        if (ret == 0) locked = TRUE;
+    }
+
+    // grab shared mem
+    kbd32SharedData *SharedData = NULL;
+    BOOL haveMem = FALSE;
+    if (ret == 0){
+        ret = DosGetNamedSharedMem((PPVOID)&SharedData,(PSZ)SHMEM_NAME,PAG_READ | PAG_WRITE);
+        // ok I have the pointer to the memory I am ok! let's release the memory
+        if (ret == 0) haveMem = TRUE;
+    }
+
+    // now send the key stroke
+    BOOL dataUsed = FALSE;
+    if (ret == 0){
+        // find if the application is registered
+        PID pid;
+        int index;
+        HWND hwndClient;
+        if (SharedData->searchByHwndFrame(psmh->hwnd,hwndClient,pid,index)){
+
+            HQUEUE keyQ = 0;
+
+            // get the associated Q
+            if (ret == 0){
+                PID pid_;
+                char qName[64];
+                sprintf(qName,PRIMARY_QUEUE_NAME,pid);
+                ret = DosOpenQueue(&pid_,&keyQ,qName);
+            }
+
+            // now check how many entries are busy
+            ULONG entries = 0;
+            if (ret == 0) ret = DosQueryQueue(keyQ, &entries);
+
+            // if too many are used bleep
+            if ((ret == 0) && (entries >= MAX_PRIMARY_Q_LEN)){
+                ret = 1;
+                DosBeep(1000,20);
+            }
+            // if all is good send data
+            if (ret == 0){
+                // allocate a Q object.
+                VIO32EVENTINFO *key = SharedData->getBuffer(index);
+                // copy content
+                key->pmMsg.mp1 = psmh->mp1;
+                key->pmMsg.mp2 = psmh->mp2;
+                // send the data
+                ret = DosWriteQueue(keyQ,psmh->msg,sizeof(VIO32EVENTINFO),key,0);
+            }
+            // now mark the buffer as used
+            if (ret == 0){
+                SharedData->advanceBuffer(index);
+                dataUsed = TRUE;
+            }
+            // close Q
+            if (keyQ != 0) DosCloseQueue(keyQ);
+        }
+    }
+
+    // release memory
+    if (haveMem) DosFreeMem((PVOID)SharedData);
+    haveMem = FALSE;
+
+    // relase mutex sem
+    if (locked) DosReleaseMutexSem(hmtx);
+    locked = FALSE;
+
+
+    return ;
+}
+
+
+
+
Index: trunk/src/kernel32/console/vio32Errors.h
===================================================================
--- trunk/src/kernel32/console/vio32Errors.h	(revision 5024)
+++ trunk/src/kernel32/console/vio32Errors.h	(revision 5024)
@@ -0,0 +1,42 @@
+#if !defined (VIO32_ERRS)
+#define VIO32_ERRS
+
+
+// all the actual errors are added to the os2 error causing it
+
+#define VIO32_GETAPPINFO        0x10010000
+#define VIO32_CREATEQUEUE       0x10020000
+#define VIO32_CREATEHEV         0x10030000
+#define VIO32_CREATESHMUX       0x10040000
+#define VIO32_OPENSHMUX         0x10050000
+#define VIO32_REQUESTSHMUX      0x10060000
+#define VIO32_ALLOCSHMEM        0x10070000
+#define VIO32_GETSHMEM          0x10080000
+#define VIO32_MONOPEN           0x10090000
+#define VIO32_MONREG            0x100A0000
+#define VIO32_SETEXCHANDLER     0x100B0000
+#define VIO32_READQUEUE         0x100C0000
+#define VIO32_WAITHEV           0x100D0000
+#define VIO32_MOUOPEN           0x100E0000
+#define VIO32_MOUDRAWPTR        0x100F0000
+#define VIO32_MOUSETEVENTMASK   0x10100000
+#define VIO32_WRITEQUEUE        0x10110000
+
+// standalone errors
+#define VIO32_NOTOPENED         0x00010001
+#define VIO32_SHMEMNOTALLOCATED 0x00020001
+#define VIO32_INTERNALERROR     0x00030001
+#define VIO32_ALREADYOPENED     0x00040001
+#define VIO32_WRONGAPPTYPE      0x00050001
+#define VIO32_INVALIDPARAM      0x00060001
+#define VIO32_UNKNOWNEVENT      0x00070001
+#define VIO32_NOTWINDOWED       0x00080001
+#define VIO32_ALREADYINSTALLED  0x00090001
+#define VIO32_TOOMANYAPPS       0x000A0001
+#define VIO32_NOTINSTALLED      0x000B0001
+#define VIO32_NOTFOUND          0x000C0001
+#define VIO32_WRONGEVENTTYPE    0x000D0001
+#define VIO32_QUEUEFULL         0x000E0001
+#define VIO32_UNREGISTERED      0x000F0001
+
+#endif
Index: trunk/src/kernel32/console/vio32Private.h
===================================================================
--- trunk/src/kernel32/console/vio32Private.h	(revision 5024)
+++ trunk/src/kernel32/console/vio32Private.h	(revision 5024)
@@ -0,0 +1,37 @@
+#if !defined (_KBD32_PRIVATE)
+#define _KBD32_PRIVATE
+
+#define INCL_DOS
+#include <os2.h>
+#include "vio32.h"
+
+// the queue on which all the messages arrive
+#define PRIMARY_QUEUE_NAME  "\\QUEUES\\VIO32\\PRIMARY%x"
+// the queue on which all the messages arrive
+#define SECONDARY_QUEUE_NAME"\\QUEUES\\VIO32\\SECONDARY%x"
+// a sh mem containing global KBD32 info
+#define SHMEM_NAME          "\\SHAREMEM\\VIO32HOOKX"
+// a mux protecting the above mem
+#define MUTEX_NAME          "\\SEM32\\VIO32HOOKX"
+// max number of VIO32 apps
+#define MAX_VIO32 256
+// max number of messages on the primary mixing Q
+#define MAX_PRIMARY_Q_LEN 4
+// max number of messages on the secondary, data elaborated Q
+#define MAX_SECONDARY_Q_LEN 64
+
+// not for client use
+extern "C" {
+    //
+    BOOL EXPENTRY InstallHook();
+    //
+    BOOL EXPENTRY DeInstallHook();
+    //
+    BOOL EXPENTRY InputHook(HAB hab, PQMSG pQmsg, ULONG fs);
+    //
+    VOID EXPENTRY SendMsgHook(HAB hab,PSMHSTRUCT psmh,BOOL fInterTask);
+
+}
+
+
+#endif
Index: trunk/src/kernel32/console/vio32SharedData.cpp
===================================================================
--- trunk/src/kernel32/console/vio32SharedData.cpp	(revision 5024)
+++ trunk/src/kernel32/console/vio32SharedData.cpp	(revision 5024)
@@ -0,0 +1,129 @@
+#define INCL_WIN
+#define INCL_DOS
+#define INCL_VIO
+#define INCL_SUB
+#define INCL_DOSERRORS
+#include <os2.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "vio32private.h"
+#include "vio32SharedData.h"
+#include "vio32Errors.h"
+
+void kbd32SharedData::Init(){
+    nOfWindows = 0;
+    for (int i=0;i<MAX_VIO32;i++) {
+        clientWindows[i] = 0;
+        frameWindows[i] = 0;
+        processId[i] = 0;
+        mode[i] = 0;
+        pos[i] = &events[i * MAX_PRIMARY_Q_LEN];
+    }
+}
+
+
+BOOL kbd32SharedData::searchByHwndClient(HWND hwndClient,HWND &hwndFrame,PID &pid,int &ix){
+    ix = 0;
+    for (;(ix<nOfWindows) && (clientWindows[ix] != hwndClient);ix++);
+    if (ix < nOfWindows){
+        pid = processId[ix];
+        hwndFrame = frameWindows[ix];
+        return TRUE;
+    }
+    return FALSE;
+}
+
+BOOL kbd32SharedData::searchByHwndFrame(HWND hwndFrame,HWND &hwndClient,PID &pid,int &ix){
+    ix = 0;
+    for (;(ix<nOfWindows) && (frameWindows[ix] != hwndFrame);ix++);
+    if (ix < nOfWindows){
+        pid = processId[ix];
+        hwndClient = clientWindows[ix];
+        return TRUE;
+    }
+    return FALSE;
+}
+
+BOOL kbd32SharedData::searchByPid(PID pid,HWND &hwndClient,HWND &hwndFrame,int &ix){
+    ix = 0;
+    for (;(ix<nOfWindows) && (processId[ix] != pid);ix++);
+    if (ix < nOfWindows){
+        hwndClient = clientWindows[ix];
+        hwndFrame  = frameWindows[ix];
+        return TRUE;
+    }
+    return FALSE;
+}
+
+VIO32EVENTINFO *kbd32SharedData::getBuffer(int ix){
+    if (ix < nOfWindows){
+        VIO32EVENTINFO *maxPos = &events[(ix+1)*MAX_PRIMARY_Q_LEN];
+        if (pos[ix] >= maxPos) pos[ix] = &events[ix*MAX_PRIMARY_Q_LEN];
+        return pos[ix];
+    }
+    return NULL;
+}
+
+APIRET kbd32SharedData::SetMode(ULONG mode,ULONG pid){
+    for (int ix=0;(ix<nOfWindows) && (processId[ix] != pid);ix++);
+    if (ix >= nOfWindows) return VIO32_NOTINSTALLED;
+    this->mode[ix] = mode;
+    return 0;
+}
+
+APIRET kbd32SharedData::GetMode(ULONG &mode,ULONG pid){
+    for (int ix=0;(ix<nOfWindows) && (processId[ix] != pid);ix++);
+    if (ix >= nOfWindows) return VIO32_NOTINSTALLED;
+    mode = this->mode[ix];
+    return 0;
+}
+
+APIRET kbd32SharedData::InstallApplication(ULONG pid,BOOL windowed){
+    HWND hwndClient = -1;
+    HWND hwndFrame = -1;
+    if (windowed){
+        hwndClient = VIOWindowClient();
+        hwndFrame  = VIOWindowFrame();
+        if (hwndClient == 0) return VIO32_NOTWINDOWED;
+        if (hwndFrame == 0)  return VIO32_NOTWINDOWED;
+    }
+
+    APIRET ret = FALSE;
+    for (int ix=0;(ix<nOfWindows) && (clientWindows[ix] != hwndClient);ix++);
+    if (ix < nOfWindows) ret = VIO32_ALREADYINSTALLED;
+    else {
+        for (int ix=0;(ix<nOfWindows) && (clientWindows[ix] != 0);ix++);
+        if (ix < nOfWindows){
+            clientWindows[ix] = hwndClient;
+            frameWindows[ix]  = hwndFrame;
+            processId[ix] = pid;
+            mode[ix] = 0;
+            ret = 0;
+        } else
+        if (nOfWindows < MAX_VIO32){
+            clientWindows[nOfWindows] = hwndClient;
+            frameWindows[nOfWindows]  = hwndFrame;
+            processId[nOfWindows] = pid;
+            mode[nOfWindows] = 0;
+            nOfWindows++;
+            ret = 0;
+        } else ret = VIO32_TOOMANYAPPS;
+    }
+    return ret;
+}
+
+BOOL kbd32SharedData::UninstallApplication(ULONG pid){
+
+    APIRET ret;
+    for (int ix=0;(ix<nOfWindows) && (processId[ix] != pid);ix++);
+    if (ix < nOfWindows){
+        ret = 0;
+        clientWindows[ix] = 0;
+        frameWindows[ix]  = 0;
+        processId[ix] = 0;
+        if (ix == (nOfWindows-1)) nOfWindows--;
+    } else VIO32_NOTINSTALLED;
+    return ret;
+}
+
Index: trunk/src/kernel32/console/vio32SharedData.h
===================================================================
--- trunk/src/kernel32/console/vio32SharedData.h	(revision 5024)
+++ trunk/src/kernel32/console/vio32SharedData.h	(revision 5024)
@@ -0,0 +1,54 @@
+#if !defined (KBD32_SHARED_DATA_H)
+#define KBD32_SHARED_DATA_H
+
+#include "vio32Private.h"
+#include "vio32Utils.h"
+
+
+// this object represents the shared memory
+class kbd32SharedData {
+    // size of the partially used buffer
+    int             nOfWindows;
+    // the hwnd client
+    HWND            clientWindows[MAX_VIO32];
+    // the hwnd frame
+    HWND            frameWindows[MAX_VIO32];
+    // the task to be served
+    ULONG           processId[MAX_VIO32];
+    // the task to be served
+    ULONG           mode[MAX_VIO32];
+    //
+    VIO32EVENTINFO      events[MAX_VIO32*MAX_PRIMARY_Q_LEN];
+    //
+    VIO32EVENTINFO     *pos[MAX_VIO32];
+
+public:
+    ///
+    void Init();
+    /// installs a patch for the vio kbd stream for the current task
+    APIRET InstallApplication(ULONG pid,BOOL windowed=TRUE);
+    ///
+    APIRET UninstallApplication(ULONG pid);
+    ///
+    APIRET SetMode(ULONG mode,ULONG pid);
+    ///
+    APIRET GetMode(ULONG &mode,ULONG pid);
+    /// gets a buffer
+    VIO32EVENTINFO *getBuffer(int ix);
+    /// automatically updates the pointer
+    void advanceBuffer(int ix){ pos[ix]++; }
+    ///
+    BOOL searchByHwndClient(HWND hwndClient,HWND &hwndFrame,PID &pid,int &ix);
+    ///
+    BOOL searchByHwndFrame(HWND hwndFrame,HWND &hwndClient,PID &pid,int &ix);
+    ///
+    BOOL searchByPid(PID pid,HWND &hwndClient,HWND &hwndFrame,int &ix);
+    ///
+    ULONG getMode(int ix){ return mode[ix]; }
+};
+
+
+
+
+
+#endif
Index: trunk/src/kernel32/console/vio32StdFilters.cpp
===================================================================
--- trunk/src/kernel32/console/vio32StdFilters.cpp	(revision 5024)
+++ trunk/src/kernel32/console/vio32StdFilters.cpp	(revision 5024)
@@ -0,0 +1,473 @@
+#define INCL_DOS
+#define INCL_PM
+#define INCL_WIN
+#define INCL_VIO
+#define INCL_SUB
+#define INCL_BSE
+#define INCL_DOSERRORS
+#define INCL_DOSDEVICES
+#include <os2.h>
+#include <bsedev.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "vio32Client.h"
+#include "vio32Private.h"
+#include "vio32Utils.h"
+#include "vio32SharedData.h"
+#include "vio32Errors.h"
+
+
+// scan to vkey  it seems that vkey is a sole function of the kbd (NUMLOCK OFF)
+char vKeyMap1[256]= {
+    0,  27,  49,  50,  51,  52,  53,  54,  55,  56,  57,  48, 189, 187,   8,   9, //0
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 219, 221,  13,  17,   0,   0, //16
+    0,   0,   0,   0,   0,   0,   0, 186, 192, 223,  16, 222,   0,   0,   0,   0, //32
+    0,   0,   0, 188, 190, 191,  16, 106,  18,  32,  20, 112, 113, 114, 115, 116, //48
+  117, 118, 119, 120, 121, 144, 145,  36,  38,  33, 109,  37, 101,  39, 107,  35, //64
+   40,  34,  45,  46,   0,   0, 220, 122, 123,   0,   0,  91,  92,  93,   0,   0, //80
+    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,   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,   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,   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,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
+};
+
+// scan to vkey  it seems that vkey is a sole function of the kbd (NUMLOCK ON)
+char vKeyMap2[256]= {
+    0,  27,  49,  50,  51,  52,  53,  54,  55,  56,  57,  48, 189, 187,   8,   9, //0
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, 219, 221,  13,  17,   0,   0, //16
+    0,   0,   0,   0,   0,   0,   0, 186, 192, 223,  16, 222,   0,   0,   0,   0, //32
+    0,   0,   0, 188, 190, 191,  16, 106,  18,  32,  20, 112, 113, 114, 115, 116, //48
+  117, 118, 119, 120, 121, 144, 145, 103, 104, 105, 109, 100, 101, 102, 107,  97, //64
+   98,  99,  96, 110,   0,   0, 220, 122, 123,   0,   0,  91,  92,  93,   0,   0, //80
+    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,   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,   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,   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,   0,   0,   0,   0,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0
+};
+
+// maps PM msg scan to win32 scan
+char PMScanMapper[256]={
+    0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
+   10,  11,  12,  13,  14,  15,  16,  17,  18,  19,
+   20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
+   30,  31,  32,  33,  34,  35,  36,  37,  38,  39,
+   40,  41,  42,  43,  44,  45,  46,  47,  48,  49,
+   50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
+   60,  61,  62,  63,  64,  65,  66,  67,  68,  69,
+   70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
+   80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
+   28,  29,  53,   0,  56,  95,  71,  72,  73,  75,
+   77,  79, 102,  81,  82,  83, 106, 107, 108, 109,
+  110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
+  120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
+  130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
+  140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
+  150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+  160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
+  170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
+  180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
+  190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
+  200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
+  210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
+  220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
+  230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+  240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
+  250, 251, 252, 253, 254, 255
+};
+
+// finds extended keys amon pm scan codes
+char PMExtKeys[256]={
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //10
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //20
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //30
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //40
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //50
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   1, //60
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //70
+    0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //80
+    1,   1,   1,   0,   1,   0,   1,   1,   1,   1, //90
+    1,   1,   0,   1,   1,   1,   0,   0,   0,   0, //100
+    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,   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,   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,   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,   0,   0,   0,   0,
+    0,   0,   0,   0,   0,   0
+};
+
+// ALT-x combinations are not treated correctly: we would need to know scan->vkey translation !!
+CHAR calcVkey(KBD32KEYINFO &key){
+    int c = key.chr;
+    if ((c >= 1) && (c <=26))  return c + 64;
+    if ((c >=65) && (c <=90))  return c;
+    if ((c >=97) && (c <=122)) return c - 32;
+    int scan = key.scancode;
+    CHAR vk =0;
+    ULONG status = key.status;
+    if (status & 0x20)  vk = vKeyMap2[scan];
+    else                vk = vKeyMap1[scan];
+    if ((status & 0x100) && (scan == 53)) vk = 111;
+    return vk;
+}
+
+#define keyStatus kbd32ClientInstance.KeyStatus()
+
+
+VOID updateKeyStatus(char scanCode,BOOL enhancedKey,BOOL keyUp){
+    kbd32ClientInstance.LocalLock();
+
+    // MODIFY status normal bits
+    ULONG extScan = scanCode;
+    if (enhancedKey){
+        if (extScan == KBD32_ALTL_SCAN)  extScan = KBD32_ALTR_SCAN;
+        if (extScan == KBD32_CTRLL_SCAN) extScan = KBD32_CTRLR_SCAN;
+    }
+    if (keyUp)  KBD32_UNSETKEY(keyStatus,extScan);
+    else        KBD32_SETKEY(keyStatus,extScan);
+
+    // MODIFY status toggling bit CAPS/LOCK/NUM/INS
+    if (keyUp)  {
+        ULONG specialScan = 0;
+        switch (extScan){
+            case 58: specialScan = KBD32_CAPSLOCK_SCAN;     break;
+            case 69: specialScan = KBD32_NUMLOCK_SCAN;      break;
+            case 70: specialScan = KBD32_SCROLLLOCK_SCAN;   break;
+            case 82: specialScan = KBD32_INSERT_SCAN;       break;
+        }
+        if (specialScan!=0) KBD32_TOGGLEKEY(keyStatus,specialScan);
+    }
+    kbd32ClientInstance.LocalUnlock();
+}
+
+// without the knowledge of up/down but with the shift status info from kbd VIO call
+VOID updateKeyStatusNoKeys(ULONG shiftStatus){
+    kbd32ClientInstance.LocalLock();
+    if (shiftStatus & 0x0040) KBD32_SETKEY(keyStatus,KBD32_CAPSLOCK_SCAN);   else KBD32_UNSETKEY(keyStatus,KBD32_CAPSLOCK_SCAN);
+    if (shiftStatus & 0x0020) KBD32_SETKEY(keyStatus,KBD32_NUMLOCK_SCAN);    else KBD32_UNSETKEY(keyStatus,KBD32_NUMLOCK_SCAN);
+    if (shiftStatus & 0x0010) KBD32_SETKEY(keyStatus,KBD32_SCROLLLOCK_SCAN); else KBD32_UNSETKEY(keyStatus,KBD32_SCROLLLOCK_SCAN);
+    if (shiftStatus & 0x0002) KBD32_SETKEY(keyStatus,KBD32_SHIFTL_SCAN);     else KBD32_UNSETKEY(keyStatus,KBD32_SHIFTL_SCAN);
+    if (shiftStatus & 0x0001) KBD32_SETKEY(keyStatus,KBD32_SHIFTR_SCAN);     else KBD32_UNSETKEY(keyStatus,KBD32_SHIFTR_SCAN);
+    if (shiftStatus & 0x0200) KBD32_SETKEY(keyStatus,KBD32_ALTL_SCAN);       else KBD32_UNSETKEY(keyStatus,KBD32_ALTL_SCAN);
+    if (shiftStatus & 0x0800) KBD32_SETKEY(keyStatus,KBD32_ALTR_SCAN);       else KBD32_UNSETKEY(keyStatus,KBD32_ALTR_SCAN);
+    if (shiftStatus & 0x0100) KBD32_SETKEY(keyStatus,KBD32_CTRLL_SCAN);      else KBD32_UNSETKEY(keyStatus,KBD32_CTRLL_SCAN);
+    if (shiftStatus & 0x0400) KBD32_SETKEY(keyStatus,KBD32_CTRLR_SCAN);      else KBD32_UNSETKEY(keyStatus,KBD32_CTRLR_SCAN);
+    kbd32ClientInstance.LocalUnlock();
+}
+
+// use the knowledge of the status to set special keys but also update geberic key
+VOID updateKeyStatus2(char scanCode,ULONG shiftStatus,BOOL keyUp){
+    kbd32ClientInstance.LocalLock();
+    // MODIFY status normal bits
+    if (keyUp)  KBD32_UNSETKEY(keyStatus,scanCode);
+    else        KBD32_SETKEY(keyStatus,scanCode);
+
+    if (shiftStatus & 0x0040) KBD32_SETKEY(keyStatus,KBD32_CAPSLOCK_SCAN);   else KBD32_UNSETKEY(keyStatus,KBD32_CAPSLOCK_SCAN);
+    if (shiftStatus & 0x0020) KBD32_SETKEY(keyStatus,KBD32_NUMLOCK_SCAN);    else KBD32_UNSETKEY(keyStatus,KBD32_NUMLOCK_SCAN);
+    if (shiftStatus & 0x0010) KBD32_SETKEY(keyStatus,KBD32_SCROLLLOCK_SCAN); else KBD32_UNSETKEY(keyStatus,KBD32_SCROLLLOCK_SCAN);
+    if (shiftStatus & 0x0002) KBD32_SETKEY(keyStatus,KBD32_SHIFTL_SCAN);     else KBD32_UNSETKEY(keyStatus,KBD32_SHIFTL_SCAN);
+    if (shiftStatus & 0x0001) KBD32_SETKEY(keyStatus,KBD32_SHIFTR_SCAN);     else KBD32_UNSETKEY(keyStatus,KBD32_SHIFTR_SCAN);
+    if (shiftStatus & 0x0200) KBD32_SETKEY(keyStatus,KBD32_ALTL_SCAN);       else KBD32_UNSETKEY(keyStatus,KBD32_ALTL_SCAN);
+    if (shiftStatus & 0x0800) KBD32_SETKEY(keyStatus,KBD32_ALTR_SCAN);       else KBD32_UNSETKEY(keyStatus,KBD32_ALTR_SCAN);
+    if (shiftStatus & 0x0100) KBD32_SETKEY(keyStatus,KBD32_CTRLL_SCAN);      else KBD32_UNSETKEY(keyStatus,KBD32_CTRLL_SCAN);
+    if (shiftStatus & 0x0400) KBD32_SETKEY(keyStatus,KBD32_CTRLR_SCAN);      else KBD32_UNSETKEY(keyStatus,KBD32_CTRLR_SCAN);
+    kbd32ClientInstance.LocalUnlock();
+}
+
+//
+BOOL kbdMapperF(ULONG *eventType,VIO32EVENTINFO *event,VOID *filterData){
+    VIO32EVENTINFO ev = *event;
+    switch (*eventType){
+        case WM_CHAR: {
+//CHRMSG *data = &ev.wmchar;
+//printf(">>fs=0x%x repeat=%i scan=%i char=%i,%i vkey=%i\n",data->fs,data->cRepeat,data->scancode,data->chr,data->chr & 0xFF,data->vkey );
+            // STANDARD COPY
+            event->vio32Kbd.chr      = ev.wmchar.chr & 0xFF;
+            event->vio32Kbd.scancode = PMScanMapper[ev.wmchar.scancode];
+            event->vio32Kbd.repeat   = ev.wmchar.cRepeat;
+            event->vio32Kbd.keyUp    = ((ev.wmchar.fs & KC_KEYUP) != 0);
+
+            // CHANGE event type
+            *eventType = (ULONG)KBD32_CHAR;
+
+            // work out extended keys
+            BOOL enhancedKey = (PMExtKeys[ev.wmchar.scancode] == 1);
+
+            // update the key status bits
+            updateKeyStatus(event->vio32Kbd.scancode,enhancedKey,event->vio32Kbd.keyUp);
+
+            // CALCULATE SHIFT status from global key-status
+            event->vio32Kbd.status   = 0;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_CAPSLOCK_SCAN))      event->vio32Kbd.status |= KBD32_CAPSLOCK;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_NUMLOCK_SCAN))       event->vio32Kbd.status |= KBD32_NUMLOCK;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_SCROLLLOCK_SCAN))    event->vio32Kbd.status |= KBD32_SCROLLLOCK;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_SHIFTL_SCAN))        event->vio32Kbd.status |= KBD32_SHIFT;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_SHIFTR_SCAN))        event->vio32Kbd.status |= KBD32_SHIFT;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_ALTL_SCAN))          event->vio32Kbd.status |= KBD32_ALT_L;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_ALTR_SCAN))          event->vio32Kbd.status |= KBD32_ALT_R;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_CTRLL_SCAN))         event->vio32Kbd.status |= KBD32_CTRL_L;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_CTRLR_SCAN))         event->vio32Kbd.status |= KBD32_CTRL_R;
+            if (enhancedKey ){
+                event->vio32Kbd.chr = 0;
+                event->vio32Kbd.status |= KBD32_ENHANCED_KEY;
+            }
+
+            // compute vKey
+            event->vio32Kbd.vKey     = calcVkey(event->vio32Kbd);
+
+            // on special intermediate keys. Discard them
+            if (event->vio32Kbd.scancode == 0)  return TRUE;
+
+        } break;
+        case VIO_CHAR:{
+//KBDKEYINFO *k = &ev.vioKbd;
+//printf(">>chr=%i scan=%i fbst=0x%x nlss=0x%x fsst=0x%x %i \n",k->chChar,k->chScan,k->fbStatus,k->bNlsShift,k->fsState,k->time);
+
+            // STANDARD COPY
+            event->vio32Kbd.chr      = ev.vioKbd.chChar & 0xFF;
+            event->vio32Kbd.scancode = ev.vioKbd.chScan;
+            event->vio32Kbd.repeat   = 1;
+            event->vio32Kbd.keyUp    = FALSE;
+            event->vio32Kbd.status   = 0;
+
+            // CHANGE event type
+            *eventType = (ULONG)KBD32_CHAR;
+
+            // PATCH-UP SOME SCAN CODE
+            if (event->vio32Kbd.scancode == 133) event->vio32Kbd.scancode = 87;
+            if (event->vio32Kbd.scancode == 134) event->vio32Kbd.scancode = 88;
+            if (event->vio32Kbd.scancode == 224) event->vio32Kbd.scancode = 28;
+
+            // work out extended keys
+            BOOL enhancedKey = (event->vio32Kbd.chr == 224);
+
+            // update the key status bits
+            updateKeyStatusNoKeys(ev.vioKbd.fsState);
+
+            // SHIFT STATUS TRANSLATION
+            if (ev.vioKbd.fsState & 0x0040) event->vio32Kbd.status |= KBD32_CAPSLOCK;
+            if (ev.vioKbd.fsState & 0x0020) event->vio32Kbd.status |= KBD32_NUMLOCK;
+            if (ev.vioKbd.fsState & 0x0010) event->vio32Kbd.status |= KBD32_SCROLLLOCK;
+            if (ev.vioKbd.fsState & 0x0002) event->vio32Kbd.status |= KBD32_SHIFT;
+            if (ev.vioKbd.fsState & 0x0001) event->vio32Kbd.status |= KBD32_SHIFT;
+            if (ev.vioKbd.fsState & 0x0100) event->vio32Kbd.status |= KBD32_CTRL_L;
+            if (ev.vioKbd.fsState & 0x0400) event->vio32Kbd.status |= KBD32_CTRL_R;
+            if (ev.vioKbd.fsState & 0x0200) event->vio32Kbd.status |= KBD32_ALT_L;
+            if (ev.vioKbd.fsState & 0x0800) event->vio32Kbd.status |= KBD32_ALT_R;
+            if (enhancedKey ){
+                event->vio32Kbd.chr = 0;
+                event->vio32Kbd.status |= KBD32_ENHANCED_KEY;
+            }
+
+            // compute vKey
+            event->vio32Kbd.vKey     = calcVkey(event->vio32Kbd);
+
+        }break;
+        case MON_CHAR:{
+
+//MonRecord *m = &ev.monKbd;
+//printf(">>flag=0x%x chr=%i scan=%i dbst=0x%x dbs=0x%x ss=0x%x %i 0x%x\n",m->MonFlagWord,m->XlatedChar,m->XlatedScan,m->DBCS_Status,m->DBCS_Shift,m->Shift_State,m->Milliseconds,m->KbdDDFlagWord);
+
+            // STANDARD COPY
+            event->vio32Kbd.chr      = ev.monKbd.XlatedChar;
+            event->vio32Kbd.scancode = ev.monKbd.XlatedScan;
+            event->vio32Kbd.repeat   = 1;
+            event->vio32Kbd.keyUp    = ((ev.monKbd.KbdDDFlagWord & 0x40) != 0);
+            event->vio32Kbd.status   = 0;
+
+            // CHANGE event type
+            *eventType = (ULONG)KBD32_CHAR;
+
+            // PATCH-UP SOME SCAN CODE
+            if (event->vio32Kbd.scancode == 133) event->vio32Kbd.scancode = 87;
+            if (event->vio32Kbd.scancode == 134) event->vio32Kbd.scancode = 88;
+            if (event->vio32Kbd.scancode == 224) event->vio32Kbd.scancode = 28;
+
+            // work out extended keys
+            BOOL enhancedKey = ((ev.monKbd.KbdDDFlagWord & 0x80) != 0);
+
+            // SHIFT STATUS TRANSLATION
+            if (ev.monKbd.Shift_State & 0x0040) event->vio32Kbd.status |= KBD32_CAPSLOCK;
+            if (ev.monKbd.Shift_State & 0x0020) event->vio32Kbd.status |= KBD32_NUMLOCK;
+            if (ev.monKbd.Shift_State & 0x0010) event->vio32Kbd.status |= KBD32_SCROLLLOCK;
+            if (ev.monKbd.Shift_State & 0x0002) event->vio32Kbd.status |= KBD32_SHIFT;
+            if (ev.monKbd.Shift_State & 0x0001) event->vio32Kbd.status |= KBD32_SHIFT;
+            if (ev.monKbd.Shift_State & 0x0100) event->vio32Kbd.status |= KBD32_CTRL_L;
+            if (ev.monKbd.Shift_State & 0x0200) event->vio32Kbd.status |= KBD32_ALT_L;
+            if (ev.monKbd.Shift_State & 0x0800) event->vio32Kbd.status |= KBD32_ALT_R;
+            if (ev.monKbd.Shift_State & 0x0400) event->vio32Kbd.status |= KBD32_CTRL_R;
+            if (enhancedKey ){
+                event->vio32Kbd.chr = 0;
+                event->vio32Kbd.status |= KBD32_ENHANCED_KEY;
+            }
+
+            // TREAT char 224 -> 0
+            if (event->vio32Kbd.chr == 224)     event->vio32Kbd.chr = 0;
+
+            // DETECT SHIFT STATUS CHANGES EVENTS
+            if ((ev.monKbd.KbdDDFlagWord & 0x3F)==7){
+
+                // CALCULATE SHIFT status from global key-status
+                ULONG lastShiftStatus = 0;
+                if (KBD32_CHECKKEY(keyStatus,58))                       lastShiftStatus |= 0x4000;
+                if (KBD32_CHECKKEY(keyStatus,69))                       lastShiftStatus |= 0x2000;
+                if (KBD32_CHECKKEY(keyStatus,70))                       lastShiftStatus |= 0x1000;
+                if (KBD32_CHECKKEY(keyStatus,KBD32_SHIFTL_SCAN))        lastShiftStatus |= 0x0002;
+                if (KBD32_CHECKKEY(keyStatus,KBD32_SHIFTR_SCAN))        lastShiftStatus |= 0x0001;
+                if (KBD32_CHECKKEY(keyStatus,KBD32_ALTL_SCAN))          lastShiftStatus |= 0x0200;
+                if (KBD32_CHECKKEY(keyStatus,KBD32_ALTR_SCAN))          lastShiftStatus |= 0x0800;
+                if (KBD32_CHECKKEY(keyStatus,KBD32_CTRLL_SCAN))         lastShiftStatus |= 0x0100;
+                if (KBD32_CHECKKEY(keyStatus,KBD32_CTRLR_SCAN))         lastShiftStatus |= 0x0400;
+
+//printf("old:%08x - %08x:new\n", lastShiftStatus,ev.monKbd.Shift_State);
+
+                ULONG changes = lastShiftStatus ^ ev.monKbd.Shift_State;
+                if (changes & 0x1)      event->vio32Kbd.scancode = 54;
+                else
+                if (changes & 0x2)      event->vio32Kbd.scancode = 42;
+                else
+                if (changes & 0x4000)   event->vio32Kbd.scancode = 58;
+                else
+                if (changes & 0x100)    event->vio32Kbd.scancode = 29;
+                else
+                if (changes & 0x200)    event->vio32Kbd.scancode = 56;
+                else
+                if (changes & 0x800)    event->vio32Kbd.scancode = 56;
+                else
+                if (changes & 0x400)    event->vio32Kbd.scancode = 29;
+                else
+                if (changes & 0x1000)   event->vio32Kbd.scancode = 70;
+                else
+                if (changes & 0x2000)   event->vio32Kbd.scancode = 69;
+            }
+
+            // update the key status bits
+            updateKeyStatus2(event->vio32Kbd.scancode,ev.monKbd.Shift_State,event->vio32Kbd.keyUp);
+
+            // compute vKey
+            event->vio32Kbd.vKey     = calcVkey(event->vio32Kbd);
+
+            // on special intermediate keys. Discard them
+            if (event->vio32Kbd.scancode == 0){
+                return TRUE;
+            }
+        }break;
+        case VIO_MOU:{
+            static ULONG lastClickTime = 0;
+            static ULONG lastClickBits = 0;
+
+            // STANDARD COPY
+            event->vio32Mou.x               = ev.vioMou.row;
+            event->vio32Mou.y               = ev.vioMou.col;
+            event->vio32Mou.buttonStatus    = 0;
+            event->vio32Mou.status          = 0;
+            event->vio32Mou.eventType       = 0;
+
+            // CHANGE event type
+            *eventType = (ULONG)VIO32_MOU;
+
+            // check for movement in the bit set
+            BOOL hasMoved    = FALSE;
+            if (ev.vioMou.fs & 0x2B) hasMoved = TRUE;
+
+            // check the new status
+            if (ev.vioMou.fs & 0x06) event->vio32Mou.buttonStatus |= VIO32_MB1;
+            if (ev.vioMou.fs & 0x18) event->vio32Mou.buttonStatus |= VIO32_MB2;
+            if (ev.vioMou.fs & 0x60) event->vio32Mou.buttonStatus |= VIO32_MB3;
+
+            // work out the old status
+            ULONG lastButtonStatus = 0;
+            if (KBD32_CHECKKEY(keyStatus,VIO32_MB1_SCAN))   lastButtonStatus |= VIO32_MB1;
+            if (KBD32_CHECKKEY(keyStatus,VIO32_MB2_SCAN))   lastButtonStatus |= VIO32_MB2;
+            if (KBD32_CHECKKEY(keyStatus,VIO32_MB3_SCAN))   lastButtonStatus |= VIO32_MB3;
+
+            // work out the clicking bits : only going up
+            ULONG pressed;
+            pressed = ~lastButtonStatus & event->vio32Mou.buttonStatus;
+
+            // a new pressed bit? the same as before? not too far in time?
+            BOOL doubleClick = FALSE;
+            if (pressed != 0){
+                if (pressed == lastClickBits){
+                    if ((ev.vioMou.time - lastClickTime) < 500) {
+                        doubleClick = TRUE;
+                        pressed = 0;
+                    }
+                }
+                lastClickBits = pressed;
+                lastClickTime = ev.vioMou.time;
+            }
+
+            // work out right event
+            if (doubleClick) event->vio32Mou.eventType = VIO32_DOUBLECLICK;
+            else
+            if (hasMoved)    event->vio32Mou.eventType = VIO32_MOUSEMOVE;
+
+            // fill in key status
+            if (KBD32_CHECKKEY(keyStatus,KBD32_CAPSLOCK_SCAN))      event->vio32Mou.status |= KBD32_CAPSLOCK;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_NUMLOCK_SCAN))       event->vio32Mou.status |= KBD32_NUMLOCK;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_SCROLLLOCK_SCAN))    event->vio32Mou.status |= KBD32_SCROLLLOCK;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_SHIFTL_SCAN))        event->vio32Mou.status |= KBD32_SHIFT;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_SHIFTR_SCAN))        event->vio32Mou.status |= KBD32_SHIFT;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_ALTL_SCAN))          event->vio32Mou.status |= KBD32_ALT_L;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_ALTR_SCAN))          event->vio32Mou.status |= KBD32_ALT_R;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_CTRLL_SCAN))         event->vio32Mou.status |= KBD32_CTRL_L;
+            if (KBD32_CHECKKEY(keyStatus,KBD32_CTRLR_SCAN))         event->vio32Mou.status |= KBD32_CTRL_R;
+
+            // save new mouse status
+            if (ev.vioMou.fs & 0x06) KBD32_SETKEY(keyStatus,VIO32_MB1_SCAN); else KBD32_UNSETKEY(keyStatus,VIO32_MB1_SCAN);
+            if (ev.vioMou.fs & 0x18) KBD32_SETKEY(keyStatus,VIO32_MB2_SCAN); else KBD32_UNSETKEY(keyStatus,VIO32_MB2_SCAN);
+            if (ev.vioMou.fs & 0x60) KBD32_SETKEY(keyStatus,VIO32_MB3_SCAN); else KBD32_UNSETKEY(keyStatus,VIO32_MB3_SCAN);
+
+//printf("x=%i y=%i bs=%x ks=%x ev=%x\n",event->vio32Mou.x,event->vio32Mou.y,event->vio32Mou.buttonStatus,event->vio32Mou.status,event->vio32Mou.eventType);
+
+        } break;
+        case WM_FOCUSCHANGE:{
+
+            HFILE   DevHandle  = NULLHANDLE;   /* Handle for device */
+            ULONG   action;
+            APIRET  rc = DosOpen("KBD$",&DevHandle, &action, 0, 0, FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, NULL);
+
+            SHIFTSTATE shiftState;
+            if (rc == 0){
+                ULONG parmLen = 0;
+                ULONG dataLen = 0;
+                rc = DosDevIOCtl(DevHandle,IOCTL_KEYBOARD,KBD_GETSHIFTSTATE,0,0,&parmLen,&shiftState,sizeof(SHIFTSTATE),&dataLen);
+            }
+
+            // update the key status bits
+            updateKeyStatusNoKeys(shiftState.fsState);
+
+            DosClose(DevHandle);
+
+        } break;
+        default:
+        break;
+    }
+    return FALSE;
+}
+
+vio32Filter kbdMapper={NULL,(VOID *)KBD32_REMAPPER_NAME,kbdMapperF};
+
Index: trunk/src/kernel32/console/vio32Utils.cpp
===================================================================
--- trunk/src/kernel32/console/vio32Utils.cpp	(revision 5024)
+++ trunk/src/kernel32/console/vio32Utils.cpp	(revision 5024)
@@ -0,0 +1,107 @@
+#define INCL_WIN
+#define INCL_DOS
+#define INCL_VIO
+#define INCL_SUB
+#define INCL_DOSERRORS
+#define INCL_WINSWITCHLIST
+#include <os2.h>
+#include "DosQuerySysState2.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "vio32Utils.h"
+
+//
+ULONG getParentPID(ULONG pid){
+    union {
+        struct {
+            int extra[11];
+            qsPrec_s process;
+        } formatted;
+        char raw[256];
+        int intRaw[64];
+    } data;
+    APIRET rc = DosQuerySysState(QS_PROCESS, 0,pid, 0, &data, sizeof(data));
+    if (rc != 0) return 0;
+    return data.formatted.process.ppid;
+}
+
+// returns the window id of the client window of the VIO that is hosting the current program
+HWND VIOWindowClient(){
+    PPIB pib;
+    PTIB tib;
+    DosGetInfoBlocks(&tib, &pib);
+
+    // now search for the window frame of this VIO window
+    USHORT num = WinQuerySwitchList(0L, NULL, 0);
+    if(!num) return 0;
+
+    SWBLOCK *pSwb = (SWBLOCK *)malloc(sizeof(HSWITCH) + sizeof(SWENTRY) * num );
+    num = WinQuerySwitchList(0L, pSwb, sizeof(HSWITCH) + sizeof(SWENTRY) * num );
+    BOOL found = FALSE;
+    ULONG pid = pib->pib_ulpid;
+    ULONG level = 0;
+    HWND hwndFrame;
+    while (!found){
+//printf ("searching pid %i\n",pid);
+        for(USHORT i=0; i<num; i++){
+            if (pSwb->aswentry[i].swctl.idProcess == pid){
+//printf("LEVEL %i %04x %08x %s\n", level,pSwb->aswentry[i].swctl.idProcess,pSwb->aswentry[i].swctl.hwnd,pSwb->aswentry[i].swctl.szSwtitle);
+                found = TRUE;
+                hwndFrame = pSwb->aswentry[i].swctl.hwnd;
+            }
+        }
+        level++;
+        if (!found ) pid = getParentPID(pid);
+        if (pid == 1) break;
+        if (pid == 0) break;
+    }
+    free(pSwb);
+
+    if (!found) return 0;
+
+    // now get the client window id
+    HWND hwndClient = WinWindowFromID(hwndFrame, FID_CLIENT);
+//printf ("window frame %x client %x\n",hwndFrame,hwndClient);
+
+    return hwndClient;
+}
+
+
+// returns the window id of the client window of the VIO that is hosting the current program
+HWND VIOWindowFrame(){
+    PPIB pib;
+    PTIB tib;
+    DosGetInfoBlocks(&tib, &pib);
+
+    // now search for the window frame of this VIO window
+    USHORT num = WinQuerySwitchList(0L, NULL, 0);
+    if(!num) return 0;
+
+    SWBLOCK *pSwb = (SWBLOCK *)malloc(sizeof(HSWITCH) + sizeof(SWENTRY) * num );
+    num = WinQuerySwitchList(0L, pSwb, sizeof(HSWITCH) + sizeof(SWENTRY) * num );
+    BOOL found = FALSE;
+    ULONG pid = pib->pib_ulpid;
+    ULONG level = 0;
+    HWND hwndFrame;
+    while (!found){
+//printf ("searching pid %i\n",pid);
+        for(USHORT i=0; i<num; i++){
+            if (pSwb->aswentry[i].swctl.idProcess == pid){
+//printf("LEVEL %i %04x %08x %s\n", level,pSwb->aswentry[i].swctl.idProcess,pSwb->aswentry[i].swctl.hwnd,pSwb->aswentry[i].swctl.szSwtitle);
+                found = TRUE;
+                hwndFrame = pSwb->aswentry[i].swctl.hwnd;
+            }
+        }
+        level++;
+        if (!found ) pid = getParentPID(pid);
+        if (pid == 1) break;
+        if (pid == 0) break;
+    }
+    free(pSwb);
+
+    if (!found) return 0;
+
+    return hwndFrame;
+}
+
Index: trunk/src/kernel32/console/vio32Utils.h
===================================================================
--- trunk/src/kernel32/console/vio32Utils.h	(revision 5024)
+++ trunk/src/kernel32/console/vio32Utils.h	(revision 5024)
@@ -0,0 +1,17 @@
+#if !defined (KBD32_UTILS_H)
+#define KBD32_UTILS_H
+
+#include <os2.h>
+
+extern "C" {
+/// returns the parent pid of a given pid
+ULONG getParentPID(ULONG pid);
+
+/// returns the window associated with the current Vio wondow
+HWND VIOWindowClient();
+
+///
+HWND VIOWindowFrame();
+
+}
+#endif
Index: trunk/src/kernel32/console/vio32VioServ.cpp
===================================================================
--- trunk/src/kernel32/console/vio32VioServ.cpp	(revision 5024)
+++ trunk/src/kernel32/console/vio32VioServ.cpp	(revision 5024)
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define INCL_DOS
+#define INCL_PM
+#define INCL_WIN
+#define INCL_VIO
+#define INCL_SUB
+#define INCL_DOSERRORS
+#include <os2.h>
+#include "vio32.h"
+
+extern "C" {
+    //
+    BOOL EXPENTRY InstallHook();
+    //
+    BOOL EXPENTRY DeInstallHook();
+}
+
+
+ULONG _System MyTermHandler(  PEXCEPTIONREPORTRECORD       p1,
+                              PEXCEPTIONREGISTRATIONRECORD p2,
+                              PCONTEXTRECORD               p3,
+                              PVOID                        pv ){
+    switch( p1->ExceptionNum) {
+        case XCPT_PROCESS_TERMINATE:
+        case XCPT_ASYNC_PROCESS_TERMINATE: {
+printf("termination handler called \n");
+            DeInstallHook();
+        }
+        default:;
+    }
+
+   return XCPT_CONTINUE_SEARCH;          /* Exception not resolved... */
+}
+
+
+void main(int argc, char **argv){
+
+    EXCEPTIONREGISTRATIONRECORD RegRec;
+    RegRec.prev_structure = NULL;
+    RegRec.ExceptionHandler = (ERR)MyTermHandler;
+
+
+    DosSetExceptionHandler(&RegRec);
+    InstallHook();
+
+    DosSleep(-1);
+
+    DeInstallHook();
+    DosUnsetExceptionHandler(&RegRec);
+
+}
Index: trunk/src/kernel32/console/vio32test.cpp
===================================================================
--- trunk/src/kernel32/console/vio32test.cpp	(revision 5024)
+++ trunk/src/kernel32/console/vio32test.cpp	(revision 5024)
@@ -0,0 +1,91 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define  INCL_DOS
+#define  INCL_WIN
+#define  INCL_BASE
+#include <os2.h>
+#include "vio32.h"
+
+
+BOOL filter1F(ULONG *eventType,VIO32EVENTINFO *event,VOID *filterData){
+    switch (*eventType){
+        case WM_CHAR:
+            printf("1WM_CHAR\n");
+        break;
+        case VIO_CHAR:
+            printf("1VIO_CHAR\n");
+        break;
+        case MON_CHAR:
+            printf("1MON_CHAR\n");
+        break;
+        case WM_MOVE:{
+            printf("1WM_MOVE\n");
+        } break;
+        default:
+        break;
+    }
+    return FALSE;
+}
+
+BOOL filter2F(ULONG *eventType,VIO32EVENTINFO *event,VOID *filterData){
+    switch (*eventType){
+        case WM_CHAR:
+            printf("2WM_CHAR\n");
+        break;
+        case VIO_CHAR:
+            printf("2VIO_CHAR\n");
+        break;
+        case MON_CHAR:
+            printf("2MON_CHAR\n");
+        break;
+        case WM_MOVE:{
+            printf("2WM_MOVE\n");
+        } break;
+        case KBD32_CHAR:
+            printf("2KBD32_CHAR\n");
+        break;
+        case VIO32_MOU:
+            printf("2VIO32_MOU\n");
+        break;
+        default:
+        break;
+    }
+    return FALSE;
+}
+
+vio32Filter filter1={NULL,(VOID *)"filter1",filter1F};
+vio32Filter filter2={NULL,(VOID *)"filter2",filter2F};
+
+
+void main(int argc, char **argv){
+
+    vio32Open();
+
+    kbd32SetMode(0);
+
+    ULONG where = VIO32_PRE_FIRST;
+    kbd32AddFilter(&filter1,&where);
+    where = VIO32_POST_FIRST;
+    kbd32AddFilter(&filter2,&where);
+
+    USHORT  fs;
+    UCHAR   cRepeat;
+    UCHAR   scancode;
+    USHORT  chr;
+    USHORT  vkey;
+    while(1){
+        KBD32KEYINFO key;
+//    DosSleep(1000);
+        BOOL ret = kbd32GetKey(&key,2000);
+        if (ret==0){
+            char cc = key.chr;
+            if (cc == 0) cc = ' ';
+            printf("ascii=(%c,%i) scan=%i status=%x vkey=%i up=%i\n",cc,key.chr & 255,key.scancode,key.status,key.vKey,key.keyUp);
+        } else printf("NO\n");
+    }
+
+    vio32Close();
+
+
+}
Index: trunk/src/kernel32/console/vio32test2.cpp
===================================================================
--- trunk/src/kernel32/console/vio32test2.cpp	(revision 5024)
+++ trunk/src/kernel32/console/vio32test2.cpp	(revision 5024)
@@ -0,0 +1,36 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define  INCL_DOS
+#define  INCL_WIN
+#define  INCL_BASE
+#include <os2.h>
+#include "vio32.h"
+
+
+void main(int argc, char **argv){
+
+
+    vio32Open();
+    kbd32SetMode(KBD32MODE_ENABLEMOUSE);
+
+    printf("\n");
+    VIO32STATUSINFO status;
+    KBD32KEYINFO key;
+    while(1){
+        BOOL ret = kbd32GetKey(&key,2000);
+        if (ret==0){
+            kbd32GetKeyStatus(&status);
+//            for(int i=0;i<79;i++)
+//                if( KBD32_CHECKKEY(status,i)) printf("1");
+//                else                          printf("0");
+            printf("%08x%08x%08x%08x",status.status[0],status.status[1],status.status[2],status.status[3]);
+            printf("%08x%08x%08x%08x%08x\n",status.status[4],status.status[5],status.status[6],status.status[7],status.status[8]);
+
+        } else DosSleep(100);
+    }
+
+    vio32Close();
+
+
+}
Index: trunk/src/kernel32/console/vio32test3.cpp
===================================================================
--- trunk/src/kernel32/console/vio32test3.cpp	(revision 5024)
+++ trunk/src/kernel32/console/vio32test3.cpp	(revision 5024)
@@ -0,0 +1,31 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define  INCL_DOS
+#define  INCL_WIN
+#define  INCL_BASE
+#include <os2.h>
+#include "vio32.h"
+
+
+void main(int argc, char **argv){
+
+
+    vio32Open();
+    kbd32SetMode(KBD32MODE_DISABLEBREAK | KBD32MODE_ENABLEMOUSE | KBD32MODE_ENABLEMMOVE);
+
+
+    printf("\n");
+    VIO32EVENTINFO event;
+    ULONG eventType;
+    while(1){
+        BOOL ret = vio32GetEvent(&event,&eventType,-1);
+        if (ret==0){
+            printf("%x\n",eventType);
+        } else DosSleep(100);
+    }
+
+    vio32Close();
+
+
+}
