Modified the key input redirection so that it captures and

handles Control-u in the same way that tkcon does, so that when
typing via redirection into the console, Control-u will delete
the entire command back to the prompt. (See github issue #456.)
This commit is contained in:
R. Timothy Edwards 2025-10-10 10:39:40 -04:00
parent 27c423c2ed
commit c42db8e71b
4 changed files with 87 additions and 53 deletions

View File

@ -1 +1 @@
8.3.560 8.3.561

View File

@ -546,7 +546,7 @@ XEvent *xevent;
break; break;
case KeyPress: case KeyPress:
{ {
int keywstate, keymod, idx, idxmax; int keywstate, keymod, modifier, idx, idxmax;
char inChar[10]; char inChar[10];
Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT); Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT);
@ -569,6 +569,7 @@ keys_and_buttons:
#else #else
keymod |= (Mod1Mask & KeyPressedEvent->state); keymod |= (Mod1Mask & KeyPressedEvent->state);
#endif #endif
modifier = keymod;
if (nbytes == 0) /* No ASCII equivalent */ if (nbytes == 0) /* No ASCII equivalent */
{ {
@ -631,71 +632,81 @@ keys_and_buttons:
if ((LocRedirect == TX_INPUT_REDIRECTED) && TxTkConsole) if ((LocRedirect == TX_INPUT_REDIRECTED) && TxTkConsole)
{ {
#if TCL_MAJOR_VERSION < 9 #if TCL_MAJOR_VERSION < 9
Tcl_SavedResult state; Tcl_SavedResult state;
#else #else
Tcl_InterpState state; Tcl_InterpState state;
#endif #endif
static char outstr[] = "::tkcon::Insert .text \"x\" "; static char outstr[] = "::tkcon::Insert .text \"x\" ";
switch (keysym) switch (keysym)
{ {
case XK_Return: case XK_Return:
TxSetPoint(KeyPressedEvent->x, TxSetPoint(KeyPressedEvent->x,
grXtransY(mw, KeyPressedEvent->y), grXtransY(mw, KeyPressedEvent->y),
mw->w_wid); mw->w_wid);
TxInputRedirect = TX_INPUT_PROCESSING; TxInputRedirect = TX_INPUT_PROCESSING;
Tcl_EvalEx(consoleinterp, "::tkcon::Eval .text", Tcl_EvalEx(consoleinterp, "::tkcon::Eval .text",
19, 0); 19, 0);
TxInputRedirect = TX_INPUT_NORMAL; TxInputRedirect = TX_INPUT_NORMAL;
TxSetPrompt('%'); TxSetPrompt('%');
#if TCL_MAJOR_VERSION < 9 #if TCL_MAJOR_VERSION < 9
Tcl_SaveResult(magicinterp, &state); Tcl_SaveResult(magicinterp, &state);
#else #else
state = Tcl_SaveInterpState(magicinterp, TCL_OK); state = Tcl_SaveInterpState(magicinterp, TCL_OK);
#endif #endif
Tcl_EvalEx(magicinterp, "history event 0", 15, 0); Tcl_EvalEx(magicinterp, "history event 0", 15, 0);
MacroDefine(mw->w_client, (int)'.', MacroDefine(mw->w_client, (int)'.',
Tcl_GetStringResult(magicinterp), NULL, Tcl_GetStringResult(magicinterp), NULL,
FALSE); FALSE);
#if TCL_MAJOR_VERSION < 9 #if TCL_MAJOR_VERSION < 9
Tcl_RestoreResult(magicinterp, &state); Tcl_RestoreResult(magicinterp, &state);
#else #else
Tcl_RestoreInterpState(magicinterp, state); Tcl_RestoreInterpState(magicinterp, state);
#endif #endif
break; break;
case XK_Up: case XK_Up:
Tcl_EvalEx(consoleinterp, "::tkcon::Event -1", Tcl_EvalEx(consoleinterp, "::tkcon::Event -1",
17, 0); 17, 0);
break; break;
case XK_Down: case XK_Down:
Tcl_EvalEx(consoleinterp, "::tkcon::Event 1", Tcl_EvalEx(consoleinterp, "::tkcon::Event 1",
16, 0); 16, 0);
break; break;
case XK_Left: case XK_Left:
Tcl_EvalEx(consoleinterp, ".text mark set insert " Tcl_EvalEx(consoleinterp, ".text mark set insert "
"insert-1c ; .text see insert", 50, 0); "insert-1c ; .text see insert", 50, 0);
break; break;
case XK_Right: case XK_Right:
Tcl_EvalEx(consoleinterp, ".text mark set insert " Tcl_EvalEx(consoleinterp, ".text mark set insert "
"insert+1c ; .text see insert", 50, 0); "insert+1c ; .text see insert", 50, 0);
break; break;
case XK_BackSpace: case XK_Delete: case XK_BackSpace: case XK_Delete:
Tcl_EvalEx(consoleinterp, ".text delete insert-1c ;" Tcl_EvalEx(consoleinterp, ".text delete insert-1c ;"
".text see insert", 40, 0); ".text see insert", 40, 0);
break; break;
case XK_quotedbl: case XK_backslash: case XK_bracketleft: case XK_quotedbl: case XK_backslash: case XK_bracketleft:
outstr[23] = '\\'; outstr[23] = '\\';
outstr[24] = inChar[idx]; outstr[24] = inChar[idx];
outstr[25] = '\"'; outstr[25] = '\"';
Tcl_EvalEx(consoleinterp, outstr, 26, 0); Tcl_EvalEx(consoleinterp, outstr, 26, 0);
outstr[24] = '\"'; outstr[24] = '\"';
outstr[25] = '\0'; outstr[25] = '\0';
/* fall through */
default: default:
/* Handle Ctrl-u: Delete entire command */
if ((keysym == XK_u) && (modifier == ControlMask))
{
Tcl_EvalEx(consoleinterp, ".text delete limit end",
22, 0);
}
else
{
outstr[23] = inChar[idx]; outstr[23] = inChar[idx];
Tcl_EvalEx(consoleinterp, outstr, 25, 0); Tcl_EvalEx(consoleinterp, outstr, 25, 0);
break; }
} break;
}
} }
else if (LocRedirect == TX_INPUT_REDIRECTED) { else if (LocRedirect == TX_INPUT_REDIRECTED) {
int tl; int tl;

View File

@ -550,7 +550,7 @@ TOGLEventProc(clientData, xevent)
break; break;
case KeyPress: case KeyPress:
{ {
int keywstate, keymod, idx, idxmax; int keywstate, keymod, modifier, idx, idxmax;
char inChar[10]; char inChar[10];
Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT); Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT);
@ -573,6 +573,7 @@ keys_and_buttons:
#else #else
keymod |= (Mod1Mask & KeyPressedEvent->state); keymod |= (Mod1Mask & KeyPressedEvent->state);
#endif #endif
modifier = keymod;
if (nbytes == 0) /* No ASCII equivalent */ if (nbytes == 0) /* No ASCII equivalent */
{ {
@ -588,6 +589,7 @@ keys_and_buttons:
} }
else /* ASCII-valued character */ else /* ASCII-valued character */
{ {
/* Remove single modifier (Control or Shift) */
if (!(keymod & (LockMask | Mod1Mask))) { if (!(keymod & (LockMask | Mod1Mask))) {
if (!(keymod & ControlMask)) if (!(keymod & ControlMask))
keymod &= ~ShiftMask; keymod &= ~ShiftMask;
@ -627,7 +629,7 @@ keys_and_buttons:
case XK_Pointer_Button3: case XK_Pointer_Button3:
case XK_Pointer_Button4: case XK_Pointer_Button4:
case XK_Pointer_Button5: case XK_Pointer_Button5:
LocRedirect = TX_INPUT_NORMAL;; LocRedirect = TX_INPUT_NORMAL;
break; break;
} }
} }
@ -695,9 +697,19 @@ keys_and_buttons:
Tcl_EvalEx(consoleinterp, outstr, 26, 0); Tcl_EvalEx(consoleinterp, outstr, 26, 0);
outstr[24] = '\"'; outstr[24] = '\"';
outstr[25] = '\0'; outstr[25] = '\0';
/* fall through */
default: default:
outstr[23] = inChar[idx]; /* Handle Ctrl-u like tkcon: Delete entire command */
Tcl_EvalEx(consoleinterp, outstr, 25, 0); if ((keysym == XK_u) && (modifier == ControlMask))
{
Tcl_EvalEx(consoleinterp, ".text delete limit end",
22, 0);
}
else
{
outstr[23] = inChar[idx];
Tcl_EvalEx(consoleinterp, outstr, 25, 0);
}
break; break;
} }
} }

View File

@ -793,7 +793,7 @@ MagicEventProc(clientData, xevent)
break; break;
case KeyPress: case KeyPress:
{ {
int keywstate, keymod, idx, idxmax; int keywstate, keymod, modifier, idx, idxmax;
char inChar[10]; char inChar[10];
Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT); Tcl_Channel outChannel = Tcl_GetStdChannel(TCL_STDOUT);
@ -820,6 +820,7 @@ keys_and_buttons:
#else #else
keymod |= (Mod1Mask & KeyPressedEvent->state); keymod |= (Mod1Mask & KeyPressedEvent->state);
#endif #endif
modifier = keymod;
if (nbytes == 0) if (nbytes == 0)
{ {
@ -951,9 +952,19 @@ keys_and_buttons:
Tcl_EvalEx(consoleinterp, outstr, 26, 0); Tcl_EvalEx(consoleinterp, outstr, 26, 0);
outstr[24] = '\"'; outstr[24] = '\"';
outstr[25] = '\0'; outstr[25] = '\0';
/* fall through */
default: default:
outstr[23] = inChar[idx]; /* Handle Ctrl-u: Delete entire command */
Tcl_EvalEx(consoleinterp, outstr, 25, 0); if ((keysym == XK_u) && (modifier == ControlMask))
{
Tcl_EvalEx(consoleinterp, ".text delete limit end",
22, 0);
}
else
{
outstr[23] = inChar[idx];
Tcl_EvalEx(consoleinterp, outstr, 25, 0);
}
break; break;
} }
} }