From: e-mail DOT address AT end DOT of DOT text (Mike Collins) Newsgroups: comp.os.msdos.djgpp Subject: One PC shadows another (part 2) Date: 22 Jul 1997 10:34:00 GMT Organization: Storage Technology Limited Lines: 391 Message-ID: <5r22ao$3bq@news.network.com> NNTP-Posting-Host: 129.80.172.76 Mime-Version: 1.0 To: djgpp AT delorie DOT com DJ-Gateway: from newsgroup comp.os.msdos.djgpp Precedence: bulk /* Part-1 of this article contains the description of functions and the kb.h file. This part contains the kb.c file, which also contains a simple demonstration in main(). Read part-1 first. Hope it helps someone. Mike Collins. */ //==============FILE : KB.C====================// #include #include #include #include #include #include #include #include "kb.h" /* declare functions */ void Int09(void); void Int0C(void); void Int23(void); void rs232_send(char ch); void kb_putch(char ch); void ResetInt(void); void SetupInt(void); char hex(char ch); _go32_dpmi_seginfo KbInt09, KbOldInt09, KbInt0C, KbOldInt0C, KbInt23, KbOldInt23; char ScanCode[256]; int CommsMode = STANDALONE; int diffs; #define TEST // remove this line to use these routines with your program #ifdef TEST #define FUNC1 '\x3b' /* second character generated by F1 key */ #define FUNC10 '\x44' /* second character generated by F10 key */ main() { int i=0; char ch = '\0', str[80]; clrscr(); SetupInt(); cprintf("Enter some characters on the MASTER or STANDALONE PC\n\r"); cprintf("They will be displayed on it and on the SLAVE PC.\n\n\r"); cprintf("To set this PC to STANDALONE, press ALT-CTL-1 (It defaults to this)\n\r"); cprintf("To set this PC to MASTER, press ALT-CTL-M\n\r"); cprintf("To set this PC to SLAVE, press ALT-CTL-S\n\n\r"); while(1) { ch = kb_getch(); if(ch == '\r') exit(0); else if(ch == '\0') { ch = kb_getch(); if(ch >= FUNC1 && ch <= FUNC10) cprintf("",ch-0x3a); // Second char of FUNC1 = 0x3b // Only the function keys are detected here, but all two-character sets // are sent through the serial link (cursor, delete, etc.) } else cprintf("%c", ch); } } #endif char save21; /* Interrupt 9 keyboard service (occurs when a key is pressed) */ void Int09(void) { int c; c = inportb(0x60); // Get keyboard scan code from keyboard port if (c < 0x80) ScanCode[c] = 1; else ScanCode[c & 0x7F] = 0; if(ScanCode[0x1d] && ScanCode[0x38]) { disable(); { if(ScanCode[MASTER]) CommsMode = MASTER; else if(ScanCode[SLAVE]) CommsMode = SLAVE; else if(ScanCode[STANDALONE]) CommsMode = STANDALONE; } enable(); } } /* Interrupt 0C RS232 service (occurs when a character is received) */ void Int0C(void) { /* get a character from COM1 and put it into the keyboard buffer */ char in_ch, gpc; disable(); // Test for error conditions - see file "UART" for signal definitions // ScreenSetCursor(24, 60); // if(((gpc = inportb(0x3fa)) & 0x06) != 0x04) printf("3fa = %02x", gpc); // if(((gpc = inportb(0x3fd)) & 0x9f) != 0x01) printf("3fd = %02x", gpc); // if(((gpc = inportb(0x3fe)) & 0x0f) != 0x00) printf("3fe = %02x", gpc); in_ch = (char)inportb(0x3f8); outportb(0x20, 0x20); if((CommsMode == MASTER) && (in_ch & 0x80)) diffs = in_ch & 0x7f; else if(CommsMode == SLAVE) kb_putch(in_ch); //### lock kb_putch + all its variables enable(); } void Int23(void) { exit(0); /* perform normal exit so interrupt vectors can be reset */ } void rs232_send(char ch) { while(!(inportb(0x3fd) & 0x20)); // wait for Tx buffer empty outportb(0x3f8, ch); } void kb_putch(char ch) // put character/scancode into key buffer { int chr_pt, scn_pt; static int special = 0; // A 'special' character is the first of a two-character set - used for // function keys, arrows, etc. unsigned int head, tail, base = 0x400; head = _farpeekw(_dos_ds, 0x41a); tail = _farpeekw(_dos_ds, 0x41c); chr_pt = tail+base; scn_pt = chr_pt+1; if(ch == '\0') { special = 1; return; } if(special) { special = 0; _farpokeb(_dos_ds, chr_pt, 0); _farpokeb(_dos_ds, scn_pt, ch); } else { _farpokeb(_dos_ds, chr_pt, ch); _farpokeb(_dos_ds, scn_pt, 0); } tail += 2; if(tail > 0x3c) tail = 0x1e; _farpokew(_dos_ds, 0x41c, tail); // SLAVE sends diffs to master if(CommsMode == SLAVE) { diffs = tail - head; if(diffs<0) diffs += 34; rs232_send((char)diffs | 0x80); } } /* Reset interrupt 9 & C vector */ void ResetInt(void) { _go32_dpmi_set_protected_mode_interrupt_vector(9, &KbOldInt09); _go32_dpmi_set_protected_mode_interrupt_vector(0x23, &KbOldInt23); _go32_dpmi_set_protected_mode_interrupt_vector(0x0C, &KbOldInt0C); _go32_dpmi_free_iret_wrapper(&KbInt0C); _go32_dpmi_free_iret_wrapper(&KbInt23); outp(0x20, 0x00); // clean up UART - these values read from a clean system outp(0x21, save21); outp(0x3f9, 0x00); outp(0x3fa, 0x00); outp(0x3fb, 0x03); outp(0x3fc, 0x00); } /* Interrupt 23 Ctrl Break service (gets control for Ctrl Break or Ctrl C) */ void SetupInt(void) { static char first_time = '\xff'; union REGS regs; // Check to see if this is first time called if(first_time) { first_time = 0; diffs = 0; _go32_dpmi_lock_code(Int09, (unsigned long)(ResetInt - Int09)); _go32_dpmi_lock_data(ScanCode, sizeof(ScanCode)); _go32_dpmi_lock_data(&CommsMode, sizeof(CommsMode)); _go32_dpmi_lock_data(&diffs, sizeof(diffs)); /* Interrupt 9 keyboard service (occurs when a key is pressed) */ _go32_dpmi_get_protected_mode_interrupt_vector(0x09, &KbOldInt09); KbInt09.pm_offset = (int)Int09; KbInt09.pm_selector = _go32_my_cs(); _go32_dpmi_get_protected_mode_interrupt_vector(0x0C, &KbOldInt0C); KbInt0C.pm_offset = (int)Int0C; KbInt0C.pm_selector = _go32_my_cs(); _go32_dpmi_allocate_iret_wrapper(&KbInt0C); /* perform normal exit if program interrupted by Ctrl C or Ctrl Break */ _go32_dpmi_get_protected_mode_interrupt_vector(0x23, &KbOldInt23); KbInt23.pm_offset = (int)Int23; KbInt23.pm_selector = _go32_my_cs(); _go32_dpmi_allocate_iret_wrapper(&KbInt23); _go32_dpmi_set_protected_mode_interrupt_vector(0x23, &KbInt23); atexit(ResetInt); /* set the comms port 0 to 9600, no parity, 1 stop bit, 8 data bits */ // regs.h.ah = 0; // regs.h.al = 0xc7; /* 9600bd, 1stop, NoPar, 8bits */ // regs.w.dx = 0; // int86(14, ®s, ®s); outportb(0x3fb, 0x83); /* set msb of Line Ctrl Reg */ outportb(0x3f8, 12); /* set BRD = 6 for 19200, 12 for 9600 */ outportb(0x3fb, 0x03); /* reset msb of Line Ctrl Reg */ outportb(0x3fe, 0x00); /* Set UART Data Received interrupt on */ outportb(0x3fc, 0x0f); outportb(0x3f9, 0x01); /* Trap RS232 interrupt 0x0C */ _go32_dpmi_set_protected_mode_interrupt_vector(0x0C, &KbInt0C); /* unmask the PIC */ save21 = (char)inportb(0x21); outportb(0x21, save21 & 0xEF); /* Trap keyboard interrupt 0x09 */ _go32_dpmi_chain_protected_mode_interrupt_vector(0x09, &KbInt09); } } char hex(char ch) { if(ch >= 10) return('A'+ch-10); return('0'+ch); } void disp_kb_bfr(int period) // displays the buffer without updating anything { int pt; int head, tail; head = _farpeekw(_dos_ds, 0x41a)+0x400; tail = _farpeekw(_dos_ds, 0x41c)+0x400; ScreenSetCursor(4, 0); cprintf("\n\rHead = %02x Tail = %02x", head, tail); for(pt = 0x41e; pt <= 0x43c; ) { cprintf("\n\r %02x - %02x ",_farpeekb(_dos_ds, pt), _farpeekb(_dos_ds, (pt+1))); if(pt == tail) cprintf("< | %x", pt); else cprintf(" | %x", pt); if(pt == head) cprintf("\r >"); pt += 2; } sleep(period); } char kb_getch() // replaces getch() in your program (see 'main()' above) { int head, tail, chr_pt, scn_pt, base = 0x400; char hold, c_char, c_scan; static int special = 0, OldCommsMode; // cprintf("\nCommsMode - %02x",CommsMode); if(CommsMode != OldCommsMode) { diffs = 0; if(CommsMode == SLAVE) { outportb(0x03f9, 0x01); outportb(0x3fa, 0x00); // unhangs the RS232 when it gets hung up outportb(0x3fc, 0x0f); // (learned from analysis of other S/W) } OldCommsMode = CommsMode; } if(special) // 'specials' are function keys, arrows, ALT-key, etc { hold = (char)special; special = 0; goto ts_getch_end; // without updating 'head' } // wait till slave kb_buf contains less than 15 characters while(CommsMode == MASTER && diffs > 14) /* wait here */; // wait for key press then set pointers chr & scn get c_char, c_scan do { head = _farpeekw(_dos_ds, 0x41a); tail = _farpeekw(_dos_ds, 0x41c); } while(head == tail); chr_pt = base + head; scn_pt = chr_pt + 1; c_char = _farpeekb(_dos_ds, chr_pt); c_scan = _farpeekb(_dos_ds, scn_pt); if(c_char & 0x80 || c_char == 0) { special = c_scan; hold = 0; } else hold = c_char; head += 2; if(head > 0x3c) head = 0x1e; _farpokew(_dos_ds, 0x41a, head); ts_getch_end: // SLAVE sends diffs to master if(CommsMode == SLAVE) { diffs = tail - head; if(diffs<0) diffs += 34; { //cprintf("Point A"); rs232_send((char)diffs | 0x80); } } if(CommsMode == MASTER) // send it through the serial port - std DOS call { //cprintf("Point B"); rs232_send(hold); } return hold; } void kb_ungetch(char ch) // puts character back into the keyboard buffer { int chr_pt, scn_pt; static int special = 0; unsigned int head, tail, base = 0x400; head = _farpeekw(_dos_ds, 0x41a); tail = _farpeekw(_dos_ds, 0x41c); if(ch == '\0') { special = 1; return; } if((head -= 2) < 0x1e) head = 0x3c; chr_pt = base + head; scn_pt = chr_pt + 1; if(special) { _farpokeb(_dos_ds, chr_pt, '\0'); _farpokeb(_dos_ds, scn_pt, ch); special = 0; } else { _farpokeb(_dos_ds, chr_pt, ch); _farpokeb(_dos_ds, scn_pt, '\0'); } _farpokew(_dos_ds, 0x41a, head); } int kb_hit(void) // tests to see if 'next' and 'last' pointers are equal { int head, tail; head = _farpeekw(_dos_ds, 0x41a); tail = _farpeekw(_dos_ds, 0x41c); return(tail>=head ? tail-head : head - tail); } void kb_ungets(char *str) { char *pt; if(CommsMode != SLAVE) { if(str[0] == '\0') // if this is the first (zero) character of a function { kb_ungetch('\0');// key, there will only be two chars in all. Don't kb_ungetch(str[1]); // assume a zero length. } else { pt = str + strlen(str) - 1; // Otherwise, get ready to copy a string. while(pt >= str) kb_ungetch(*pt--); } } } -- Don't just hit "reply" - my E-mail address is bogus to avoid automatic browsers from sending junk mail. Please use collim'at'anubis'dot'network'dot'com Actually, even this doesn't stop all of them ...