/* * keyboard.c * * This file is part of Emu48 * * Copyright (C) 1995 Sebastien Carlier * */ #include "pch.h" #include "Emu48.h" #include "io.h" // I/O definitions DWORD dwKeyMinDelay = 50; // minimum time for key hold static WORD Keyboard_GetIR(VOID) { WORD r = 0; // OR[0:8] are wired on Clarke/Yorke chip if (Chipset.out==0) return 0; if (Chipset.out&0x001) r|=Chipset.Keyboard_Row[0]; if (Chipset.out&0x002) r|=Chipset.Keyboard_Row[1]; if (Chipset.out&0x004) r|=Chipset.Keyboard_Row[2]; if (Chipset.out&0x008) r|=Chipset.Keyboard_Row[3]; if (Chipset.out&0x010) r|=Chipset.Keyboard_Row[4]; if (Chipset.out&0x020) r|=Chipset.Keyboard_Row[5]; if (Chipset.out&0x040) r|=Chipset.Keyboard_Row[6]; if (Chipset.out&0x080) r|=Chipset.Keyboard_Row[7]; if (Chipset.out&0x100) r|=Chipset.Keyboard_Row[8]; return r; } VOID ScanKeyboard(BOOL bActive, BOOL bReset) { // bActive = TRUE -> function called by direct read (A=IN, C=IN, RSI) // FALSE -> function called by 1ms keyboard poll simulation // bReset = TRUE -> Reset Chipset.in interrupt state register // FALSE -> generate interrupt only for new pressed keys // keyboard read not active? if (!( bActive || Chipset.Shutdn || Chipset.IR15X || (Chipset.intk && (Chipset.IORam[TIMER2_CTRL]&RUN) != 0))) { EnterCriticalSection(&csKeyLock); { Chipset.in &= ~0x8000; // remove ON key } LeaveCriticalSection(&csKeyLock); return; } EnterCriticalSection(&csKeyLock); // synchronize { BOOL bKbdInt; WORD wOldIn = Chipset.in; // save old Chipset.in state UpdateKdnBit(); // update KDN bit Chipset.dwKdnCycles = (DWORD) (Chipset.cycles & 0xFFFFFFFF); Chipset.in = Keyboard_GetIR(); // update Chipset.in register Chipset.in |= Chipset.IR15X; // add ON key // interrupt for any new pressed keys? bKbdInt = (Chipset.in && (wOldIn & 0x1FF) == 0) || Chipset.IR15X || bReset; // update keyboard interrupt pending flag when 1ms keyboard scan is disabled Chipset.intd = Chipset.intd || (bKbdInt && !Chipset.intk); // keyboard interrupt enabled? bKbdInt = bKbdInt && Chipset.intk; // interrupt at ON key pressed bKbdInt = bKbdInt || Chipset.IR15X != 0; // no interrupt if still inside interrupt service routine bKbdInt = bKbdInt && Chipset.inte; if (Chipset.in != 0) // any key pressed { if (bKbdInt) // interrupt enabled { Chipset.SoftInt = TRUE; // interrupt request bInterrupt = TRUE; // exit emulation loop } if (Chipset.Shutdn) // cpu sleeping { Chipset.bShutdnWake = TRUE; // wake up from SHUTDN mode SetEvent(hEventShutdn); // wake up emulation thread } } else { Chipset.intd = FALSE; // no keyboard interrupt pending } } LeaveCriticalSection(&csKeyLock); return; } VOID KeyboardEvent(BOOL bPress, UINT out, UINT in) { if (nState != SM_RUN) // not in running state return; // ignore key KeyMacroRecord(bPress,out,in); // save all keyboard events if (in == 0x8000) // ON key ? { Chipset.IR15X = bPress?0x8000:0x0000; // refresh special ON key flag } else { // "out" is outside Keyboard_Row if (out >= ARRAYSIZEOF(Chipset.Keyboard_Row)) return; // in &= 0x1FF; // only IR[0:8] are wired on Clarke/Yorke chip _ASSERT(out < ARRAYSIZEOF(Chipset.Keyboard_Row)); if (bPress) // key pressed Chipset.Keyboard_Row[out] |= in; // set key marker in keyboard row else Chipset.Keyboard_Row[out] &= (~in); // clear key marker in keyboard row } AdjKeySpeed(); // adjust key repeat speed ScanKeyboard(FALSE,FALSE); // update Chipset.in register by 1ms keyboard poll Sleep(dwKeyMinDelay); // hold key state for a definite time return; }