feat: extend kmain with injectKeyPress and injectShiftedKeyPress
This commit is contained in:
1 parent
b4f8d5215f
commit
750354f099
1 file changed
+173
+173
@@ -504,6 +504,179 @@ static void pgroupInjectorThread(void)
|
||||
#define scancodeMakeP 0x19
|
||||
#define scancodeMakeI 0x17
|
||||
#define scancodeMakeE 0x12
|
||||
#define scancodeMakeS 0x1F
|
||||
#define scancodeMakeR 0x13
|
||||
#define scancodeMakeN 0x31
|
||||
#define scancodeMakeK 0x25
|
||||
#define scancodeMakeBackslash 0x2B
|
||||
|
||||
static void injectKeyPress(uint8 makeCode)
|
||||
{
|
||||
keyboardHandleScancode(makeCode);
|
||||
keyboardHandleScancode(makeCode | scancodeBreakBit);
|
||||
}
|
||||
|
||||
/* '&' is shift+7 on a real US keyboard -- keyboard.c's scancodeUpper table
|
||||
maps index scancodeMakeSeven to '&' only while shiftHeld is true. */
|
||||
static void injectShiftedKeyPress(uint8 makeCode)
|
||||
{
|
||||
keyboardHandleScancode(scancodeLeftShiftMake);
|
||||
keyboardHandleScancode(makeCode);
|
||||
keyboardHandleScancode(makeCode | scancodeBreakBit);
|
||||
keyboardHandleScancode(scancodeLeftShiftBreak);
|
||||
}
|
||||
|
||||
/* A single bare Enter, unconditionally, before typing anything this thread
|
||||
actually cares about: every keystroke keyboardHandleScancode decodes is
|
||||
broadcast to EVERY open console reader (keyboard.c), the shell's own
|
||||
included, so consoleInjectorThread's single synthetic 'k' (well before
|
||||
this thread ever runs) is still sitting unflushed in the shell's own
|
||||
line buffer -- there is no way for this thread to tell "a stray
|
||||
character from an earlier, unrelated demo" apart from "something a real
|
||||
user typed". One Enter here executes that "k" as a harmless unknown
|
||||
command (shell.c's execute()) and guarantees an empty line buffer before
|
||||
the real commands below, exactly like pressing Enter at a real prompt to
|
||||
clear a garbled line. */
|
||||
static void jobctlTypeFlushLine(void)
|
||||
{
|
||||
injectKeyPress(scancodeMakeEnter);
|
||||
}
|
||||
|
||||
static void jobctlTypeBackgroundCommand(void)
|
||||
{
|
||||
injectKeyPress(scancodeMakeJ);
|
||||
injectKeyPress(scancodeMakeO);
|
||||
injectKeyPress(scancodeMakeB);
|
||||
injectKeyPress(scancodeCPressMake);
|
||||
injectKeyPress(scancodeMakeT);
|
||||
injectKeyPress(scancodeMakeL);
|
||||
injectKeyPress(scancodeMakeB);
|
||||
injectKeyPress(scancodeMakeG);
|
||||
injectKeyPress(scancodeMakeSpace);
|
||||
injectShiftedKeyPress(scancodeMakeSeven);
|
||||
injectKeyPress(scancodeMakeEnter);
|
||||
}
|
||||
|
||||
static void jobctlTypeForegroundCommand(void)
|
||||
{
|
||||
injectKeyPress(scancodeMakeJ);
|
||||
injectKeyPress(scancodeMakeO);
|
||||
injectKeyPress(scancodeMakeB);
|
||||
injectKeyPress(scancodeCPressMake);
|
||||
injectKeyPress(scancodeMakeT);
|
||||
injectKeyPress(scancodeMakeL);
|
||||
injectKeyPress(scancodeMakeF);
|
||||
injectKeyPress(scancodeMakeG);
|
||||
injectKeyPress(scancodeMakeEnter);
|
||||
}
|
||||
|
||||
#define jobctlDriverInitialDelayMs 900
|
||||
#define jobctlDriverTypeSettleMs 150
|
||||
#define jobctlDriverForegroundSettleMs 350
|
||||
#define jobctlDriverSignalSettleMs 150
|
||||
|
||||
static void jobctlDriverThread(void)
|
||||
{
|
||||
threadSleep(jobctlDriverInitialDelayMs);
|
||||
while (currentThread()->state == threadSleeping)
|
||||
halt();
|
||||
|
||||
kprintf("[kbd] typing shell commands for the on-demand job-control demo\n");
|
||||
jobctlTypeFlushLine();
|
||||
|
||||
/* "jobctlbg &" -- backgrounded, so shell.c's runProgram never blocks
|
||||
on it: jobctlSpawnForeground/jobctlRunBackground's own load+spawn
|
||||
work is synchronous kernel code, so by the time the shell has
|
||||
actually consumed all of these buffered bytes (needs its own
|
||||
timeslice; keyboardHandleScancode above only enqueues them) its
|
||||
shellLastSpawnedPid() is already this job's real pid, not stale. */
|
||||
jobctlTypeBackgroundCommand();
|
||||
threadSleep(jobctlDriverTypeSettleMs);
|
||||
while (currentThread()->state == threadSleeping)
|
||||
halt();
|
||||
uint32 jobctlbgPid = shellLastSpawnedPid();
|
||||
|
||||
/* "jobctlfg" -- foreground, so the shell thread itself parks inside
|
||||
jobctlWaitForeground (threadJoin) the moment it processes this
|
||||
line's own trailing Enter. shellLastSpawnedPid() is still safe to
|
||||
read afterward: shell.c's runProgram sets it right after
|
||||
jobctlSpawnForeground returns, BEFORE ever calling
|
||||
jobctlWaitForeground, precisely so a live demo like this one is
|
||||
never stuck waiting for a foreground job to exit before it can even
|
||||
learn that job's own pid. The longer settle here (vs. the
|
||||
background command above) gives jobctlfg.c itself real scheduler
|
||||
time to reach its own blocking pipe read before Ctrl-C below --
|
||||
the same margin ratio pgroupInjectDelayMs/pgroupSettleDelayMs above
|
||||
already established for an equivalent single-process case. */
|
||||
jobctlTypeForegroundCommand();
|
||||
threadSleep(jobctlDriverForegroundSettleMs);
|
||||
while (currentThread()->state == threadSleeping)
|
||||
halt();
|
||||
uint32 jobctlfgPid = shellLastSpawnedPid();
|
||||
|
||||
if (jobctlbgPid == threadInvalidId || jobctlfgPid == threadInvalidId ||
|
||||
jobctlbgPid == jobctlfgPid) {
|
||||
kprintf("[kbd] on-demand job-control demo skipped: jobctlbg/jobctlfg never started\n");
|
||||
for (;;)
|
||||
halt();
|
||||
}
|
||||
|
||||
kprintf("[kbd] injecting synthetic ctrl-c for the on-demand job-control demo\n");
|
||||
keyboardHandleScancode(scancodeLeftCtrlMake);
|
||||
keyboardHandleScancode(scancodeCPressMake);
|
||||
keyboardHandleScancode(scancodeCPressBreak);
|
||||
keyboardHandleScancode(scancodeLeftCtrlBreak);
|
||||
|
||||
/* Give the scheduler a real timeslice to actually deliver the
|
||||
resulting sigInt to jobctlfg (early-wake + return-to-ring3), let
|
||||
the now-parked shell thread's own threadJoin notice it Dead, and let
|
||||
jobctlWaitForeground's reclaim (jobctl.c) run -- all real scheduled
|
||||
work, not instantaneous. */
|
||||
threadSleep(jobctlDriverSignalSettleMs);
|
||||
while (currentThread()->state == threadSleeping)
|
||||
halt();
|
||||
|
||||
/* The direct, causal proof that shell.c's runProgram/jobctl.c's
|
||||
jobctlWaitForeground actually reclaimed the terminal for the shell's
|
||||
OWN group the instant jobctlfg died, rather than leaving it
|
||||
permanently pointed at a now-dead pgid the way nothing in this
|
||||
kernel ever un-claimed it before this subsystem existed: if the
|
||||
reclaim never ran (or ran against the wrong pgid), the foreground
|
||||
would still equal jobctlfg's own now-meaningless pid forever. */
|
||||
uint32 fgAfterReclaim = keyboardForegroundPgid();
|
||||
bool reclaimed = (fgAfterReclaim != jobctlfgPid);
|
||||
kprintf("[user] jobctl demo: jobctlfg pid=%u foreground pgid now=%u -> %s\n",
|
||||
jobctlfgPid, fgAfterReclaim,
|
||||
reclaimed ? "shell-foreground-reclaimed-ok" : "FAIL");
|
||||
|
||||
/* Proves jobctlbg (never granted the terminal at all, per shell.c's
|
||||
`&` handling) is still genuinely alive and running real code after
|
||||
the Ctrl-C above -- if the shell's background path ever put it in
|
||||
jobctlfg's group (or granted it the foreground itself), it would
|
||||
already be Dead by now and this sigRaise would silently do nothing,
|
||||
so jobctlbg.c's own "still-alive-after-ctrlc-ok" needle would simply
|
||||
never appear in the boot log, failing the gate. */
|
||||
sigRaise(jobctlbgPid, sigUsr1);
|
||||
|
||||
for (;;)
|
||||
halt();
|
||||
}
|
||||
|
||||
#define pipelineDriverInitialDelayMs 2500
|
||||
#define pipelineDriverSettleMs 500
|
||||
|
||||
static void pipelineTypeCommand(void)
|
||||
{
|
||||
injectKeyPress(scancodeMakeP);
|
||||
injectKeyPress(scancodeMakeI);
|
||||
injectKeyPress(scancodeMakeP);
|
||||
injectKeyPress(scancodeMakeE);
|
||||
injectKeyPress(scancodeMakeS);
|
||||
injectKeyPress(scancodeMakeR);
|
||||
injectKeyPress(scancodeCPressMake);
|
||||
injectKeyPress(scancodeMakeSpace);
|
||||
injectShiftedKeyPress(scancodeMakeBackslash);
|
||||
injectKeyPress(scancodeMakeSpace);
|
||||
}
|
||||
|
||||
void kmain(uint32 magic, uint64 multibootInfo)
|
||||
|
||||
Reference in new issue
Block a user