vt(4): Save/restore keyboard mode & LED states when switching window
(MFC of r272416) Add new functions to manipulate these mode & state, instead of calling kbdd_ioctl() everyhere. This fixes at least two bugs: 1. The state of the Scroll Lock LED and the state of scroll mode could be out-of-sync. For instance, if one enables scroll mode on window #1 and switches to window #2, the LED would remain on, but the window wouldn't be in scroll mode. Similarily, when switching between a console and an X.Org session, the LED states could be inconsistent with the real state. 2. When exiting from an X.Org session, the user could be unable to type anything. The workaround was to switch to another console window and come back. Differential Revision: https://reviews.freebsd.org/D821 Reviewed by: ray@ Approved by: ray@ Tested by: kwm@
This commit is contained in:
parent
ed67dea7a4
commit
6981999a42
@ -261,6 +261,7 @@ struct vt_window {
|
||||
unsigned int vw_number; /* (c) Window number. */
|
||||
int vw_kbdmode; /* (?) Keyboard mode. */
|
||||
int vw_prev_kbdmode;/* (?) Previous mode. */
|
||||
int vw_kbdstate; /* (?) Keyboard state. */
|
||||
int vw_grabbed; /* (?) Grab count. */
|
||||
char *vw_kbdsq; /* Escape sequence queue*/
|
||||
unsigned int vw_flags; /* (d) Per-window flags. */
|
||||
|
@ -297,6 +297,97 @@ vt_switch_timer(void *arg)
|
||||
vt_late_window_switch((struct vt_window *)arg);
|
||||
}
|
||||
|
||||
static int
|
||||
vt_save_kbd_mode(struct vt_window *vw, keyboard_t *kbd)
|
||||
{
|
||||
int mode, ret;
|
||||
|
||||
mode = 0;
|
||||
ret = kbdd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode);
|
||||
if (ret == ENOIOCTL)
|
||||
ret = ENODEV;
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
vw->vw_kbdmode = mode;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
vt_update_kbd_mode(struct vt_window *vw, keyboard_t *kbd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = kbdd_ioctl(kbd, KDSKBMODE, (caddr_t)&vw->vw_kbdmode);
|
||||
if (ret == ENOIOCTL)
|
||||
ret = ENODEV;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
vt_save_kbd_state(struct vt_window *vw, keyboard_t *kbd)
|
||||
{
|
||||
int state, ret;
|
||||
|
||||
state = 0;
|
||||
ret = kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state);
|
||||
if (ret == ENOIOCTL)
|
||||
ret = ENODEV;
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
vw->vw_kbdstate &= ~LOCK_MASK;
|
||||
vw->vw_kbdstate |= state & LOCK_MASK;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
vt_update_kbd_state(struct vt_window *vw, keyboard_t *kbd)
|
||||
{
|
||||
int state, ret;
|
||||
|
||||
state = vw->vw_kbdstate & LOCK_MASK;
|
||||
ret = kbdd_ioctl(kbd, KDSKBSTATE, (caddr_t)&state);
|
||||
if (ret == ENOIOCTL)
|
||||
ret = ENODEV;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
vt_save_kbd_leds(struct vt_window *vw, keyboard_t *kbd)
|
||||
{
|
||||
int leds, ret;
|
||||
|
||||
leds = 0;
|
||||
ret = kbdd_ioctl(kbd, KDGETLED, (caddr_t)&leds);
|
||||
if (ret == ENOIOCTL)
|
||||
ret = ENODEV;
|
||||
if (ret != 0)
|
||||
return (ret);
|
||||
|
||||
vw->vw_kbdstate &= ~LED_MASK;
|
||||
vw->vw_kbdstate |= leds & LED_MASK;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
vt_update_kbd_leds(struct vt_window *vw, keyboard_t *kbd)
|
||||
{
|
||||
int leds, ret;
|
||||
|
||||
leds = vw->vw_kbdstate & LED_MASK;
|
||||
ret = kbdd_ioctl(kbd, KDSETLED, (caddr_t)&leds);
|
||||
if (ret == ENOIOCTL)
|
||||
ret = ENODEV;
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static int
|
||||
vt_window_preswitch(struct vt_window *vw, struct vt_window *curvw)
|
||||
{
|
||||
@ -409,7 +500,11 @@ vt_window_switch(struct vt_window *vw)
|
||||
mtx_lock(&Giant);
|
||||
kbd = kbd_get_keyboard(vd->vd_keyboard);
|
||||
if (kbd != NULL) {
|
||||
kbdd_ioctl(kbd, KDSKBMODE, (void *)&vw->vw_kbdmode);
|
||||
if (curvw->vw_kbdmode == K_XLATE)
|
||||
vt_save_kbd_state(curvw, kbd);
|
||||
|
||||
vt_update_kbd_mode(vw, kbd);
|
||||
vt_update_kbd_state(vw, kbd);
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
DPRINTF(10, "%s(ttyv%d) done\n", __func__, vw->vw_number);
|
||||
@ -602,7 +697,6 @@ static int
|
||||
vt_processkey(keyboard_t *kbd, struct vt_device *vd, int c)
|
||||
{
|
||||
struct vt_window *vw = vd->vd_curwindow;
|
||||
int state = 0;
|
||||
|
||||
#if VT_ALT_TO_ESC_HACK
|
||||
if (c & RELKEY) {
|
||||
@ -665,10 +759,9 @@ vt_processkey(keyboard_t *kbd, struct vt_device *vd, int c)
|
||||
vt_proc_window_switch(vw);
|
||||
return (0);
|
||||
case SLK: {
|
||||
|
||||
kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state);
|
||||
vt_save_kbd_state(vw, kbd);
|
||||
VT_LOCK(vd);
|
||||
if (state & SLKED) {
|
||||
if (vw->vw_kbdstate & SLKED) {
|
||||
/* Turn scrolling on. */
|
||||
vw->vw_flags |= VWF_SCROLL;
|
||||
VTBUF_SLCK_ENABLE(&vw->vw_buf);
|
||||
@ -1201,13 +1294,11 @@ vtterm_cngetc(struct terminal *tm)
|
||||
struct vt_window *vw = tm->tm_softc;
|
||||
struct vt_device *vd = vw->vw_device;
|
||||
keyboard_t *kbd;
|
||||
int state;
|
||||
u_int c;
|
||||
|
||||
if (vw->vw_kbdsq && *vw->vw_kbdsq)
|
||||
return (*vw->vw_kbdsq++);
|
||||
|
||||
state = 0;
|
||||
/* Make sure the splash screen is not there. */
|
||||
if (vd->vd_flags & VDF_SPLASH) {
|
||||
/* Remove splash */
|
||||
@ -1223,8 +1314,8 @@ vtterm_cngetc(struct terminal *tm)
|
||||
return (-1);
|
||||
|
||||
/* Force keyboard input mode to K_XLATE */
|
||||
c = K_XLATE;
|
||||
kbdd_ioctl(kbd, KDSKBMODE, (void *)&c);
|
||||
vw->vw_kbdmode = K_XLATE;
|
||||
vt_update_kbd_mode(vw, kbd);
|
||||
|
||||
/* Switch the keyboard to polling to make it work here. */
|
||||
kbdd_poll(kbd, TRUE);
|
||||
@ -1243,8 +1334,8 @@ vtterm_cngetc(struct terminal *tm)
|
||||
if (c & SPCLKEY) {
|
||||
switch (c) {
|
||||
case SPCLKEY | SLK:
|
||||
kbdd_ioctl(kbd, KDGKBSTATE, (caddr_t)&state);
|
||||
if (state & SLKED) {
|
||||
vt_save_kbd_state(vw, kbd);
|
||||
if (vw->vw_kbdstate & SLKED) {
|
||||
/* Turn scrolling on. */
|
||||
vw->vw_flags |= VWF_SCROLL;
|
||||
VTBUF_SLCK_ENABLE(&vw->vw_buf);
|
||||
@ -1311,7 +1402,7 @@ vtterm_cngrab(struct terminal *tm)
|
||||
/* We shall always use the keyboard in the XLATE mode here. */
|
||||
vw->vw_prev_kbdmode = vw->vw_kbdmode;
|
||||
vw->vw_kbdmode = K_XLATE;
|
||||
(void)kbdd_ioctl(kbd, KDSKBMODE, (caddr_t)&vw->vw_kbdmode);
|
||||
vt_update_kbd_mode(vw, kbd);
|
||||
|
||||
kbdd_poll(kbd, TRUE);
|
||||
}
|
||||
@ -1336,7 +1427,7 @@ vtterm_cnungrab(struct terminal *tm)
|
||||
kbdd_poll(kbd, FALSE);
|
||||
|
||||
vw->vw_kbdmode = vw->vw_prev_kbdmode;
|
||||
(void)kbdd_ioctl(kbd, KDSKBMODE, (caddr_t)&vw->vw_kbdmode);
|
||||
vt_update_kbd_mode(vw, kbd);
|
||||
kbdd_disable(kbd);
|
||||
}
|
||||
|
||||
@ -1890,12 +1981,8 @@ vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data,
|
||||
case SETFKEY:
|
||||
case KDGKBINFO:
|
||||
case KDGKBTYPE:
|
||||
case KDSKBSTATE: /* set keyboard state (locks) */
|
||||
case KDGKBSTATE: /* get keyboard state (locks) */
|
||||
case KDGETREPEAT: /* get keyboard repeat & delay rates */
|
||||
case KDSETREPEAT: /* set keyboard repeat & delay rates (new) */
|
||||
case KDSETLED: /* set keyboard LED status */
|
||||
case KDGETLED: /* get keyboard LED status */
|
||||
case KBADDKBD: /* add/remove keyboard to/from mux */
|
||||
case KBRELKBD: {
|
||||
error = 0;
|
||||
@ -1915,18 +2002,101 @@ vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data,
|
||||
}
|
||||
return (error);
|
||||
}
|
||||
case KDGKBMODE: {
|
||||
int mode = -1;
|
||||
case KDGKBSTATE: { /* get keyboard state (locks) */
|
||||
error = 0;
|
||||
|
||||
mtx_lock(&Giant);
|
||||
kbd = kbd_get_keyboard(vd->vd_keyboard);
|
||||
if (kbd != NULL) {
|
||||
kbdd_ioctl(kbd, KDGKBMODE, (void *)&mode);
|
||||
if (vw == vd->vd_curwindow) {
|
||||
mtx_lock(&Giant);
|
||||
kbd = kbd_get_keyboard(vd->vd_keyboard);
|
||||
if (kbd != NULL)
|
||||
error = vt_save_kbd_state(vw, kbd);
|
||||
mtx_unlock(&Giant);
|
||||
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
mtx_unlock(&Giant);
|
||||
DPRINTF(20, "mode %d, vw_kbdmode %d\n", mode, vw->vw_kbdmode);
|
||||
*(int *)data = mode;
|
||||
return (0);
|
||||
|
||||
*(int *)data = vw->vw_kbdstate & LOCK_MASK;
|
||||
|
||||
return (error);
|
||||
}
|
||||
case KDSKBSTATE: { /* set keyboard state (locks) */
|
||||
int state;
|
||||
|
||||
state = *(int *)data;
|
||||
if (state & ~LOCK_MASK)
|
||||
return (EINVAL);
|
||||
|
||||
vw->vw_kbdstate &= ~LOCK_MASK;
|
||||
vw->vw_kbdstate |= state;
|
||||
|
||||
error = 0;
|
||||
if (vw == vd->vd_curwindow) {
|
||||
mtx_lock(&Giant);
|
||||
kbd = kbd_get_keyboard(vd->vd_keyboard);
|
||||
if (kbd != NULL)
|
||||
error = vt_update_kbd_state(vw, kbd);
|
||||
mtx_unlock(&Giant);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
case KDGETLED: { /* get keyboard LED status */
|
||||
error = 0;
|
||||
|
||||
if (vw == vd->vd_curwindow) {
|
||||
mtx_lock(&Giant);
|
||||
kbd = kbd_get_keyboard(vd->vd_keyboard);
|
||||
if (kbd != NULL)
|
||||
error = vt_save_kbd_leds(vw, kbd);
|
||||
mtx_unlock(&Giant);
|
||||
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
|
||||
*(int *)data = vw->vw_kbdstate & LED_MASK;
|
||||
|
||||
return (error);
|
||||
}
|
||||
case KDSETLED: { /* set keyboard LED status */
|
||||
int leds;
|
||||
|
||||
leds = *(int *)data;
|
||||
if (leds & ~LED_MASK)
|
||||
return (EINVAL);
|
||||
|
||||
vw->vw_kbdstate &= ~LED_MASK;
|
||||
vw->vw_kbdstate |= leds;
|
||||
|
||||
error = 0;
|
||||
if (vw == vd->vd_curwindow) {
|
||||
mtx_lock(&Giant);
|
||||
kbd = kbd_get_keyboard(vd->vd_keyboard);
|
||||
if (kbd != NULL)
|
||||
error = vt_update_kbd_leds(vw, kbd);
|
||||
mtx_unlock(&Giant);
|
||||
}
|
||||
|
||||
return (error);
|
||||
}
|
||||
case KDGKBMODE: {
|
||||
error = 0;
|
||||
|
||||
if (vw == vd->vd_curwindow) {
|
||||
mtx_lock(&Giant);
|
||||
kbd = kbd_get_keyboard(vd->vd_keyboard);
|
||||
if (kbd != NULL)
|
||||
error = vt_save_kbd_mode(vw, kbd);
|
||||
mtx_unlock(&Giant);
|
||||
|
||||
if (error != 0)
|
||||
return (error);
|
||||
}
|
||||
|
||||
*(int *)data = vw->vw_kbdmode;
|
||||
|
||||
return (error);
|
||||
}
|
||||
case KDSKBMODE: {
|
||||
int mode;
|
||||
@ -1937,19 +2107,17 @@ vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data,
|
||||
case K_RAW:
|
||||
case K_CODE:
|
||||
vw->vw_kbdmode = mode;
|
||||
if (vw == vd->vd_curwindow) {
|
||||
keyboard_t *kbd;
|
||||
error = 0;
|
||||
|
||||
error = 0;
|
||||
if (vw == vd->vd_curwindow) {
|
||||
mtx_lock(&Giant);
|
||||
kbd = kbd_get_keyboard(vd->vd_keyboard);
|
||||
if (kbd != NULL) {
|
||||
error = kbdd_ioctl(kbd, KDSKBMODE,
|
||||
(void *)&mode);
|
||||
}
|
||||
if (kbd != NULL)
|
||||
error = vt_update_kbd_mode(vw, kbd);
|
||||
mtx_unlock(&Giant);
|
||||
}
|
||||
return (0);
|
||||
|
||||
return (error);
|
||||
default:
|
||||
return (EINVAL);
|
||||
}
|
||||
@ -1977,8 +2145,17 @@ vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data,
|
||||
return (0);
|
||||
case CONS_GETINFO: {
|
||||
vid_info_t *vi = (vid_info_t *)data;
|
||||
if (vi->size != sizeof(struct vid_info))
|
||||
return (EINVAL);
|
||||
|
||||
if (vw == vd->vd_curwindow) {
|
||||
kbd = kbd_get_keyboard(vd->vd_keyboard);
|
||||
if (kbd != NULL)
|
||||
vt_save_kbd_state(vw, kbd);
|
||||
}
|
||||
|
||||
vi->m_num = vd->vd_curwindow->vw_number + 1;
|
||||
vi->mk_keylock = vw->vw_kbdstate & LOCK_MASK;
|
||||
/* XXX: other fields! */
|
||||
return (0);
|
||||
}
|
||||
@ -2093,13 +2270,14 @@ vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data,
|
||||
(void *)vd, vt_kbdevent, vd);
|
||||
if (i >= 0) {
|
||||
if (vd->vd_keyboard != -1) {
|
||||
vt_save_kbd_state(vd->vd_curwindow, kbd);
|
||||
kbd_release(kbd, (void *)vd);
|
||||
}
|
||||
kbd = kbd_get_keyboard(i);
|
||||
vd->vd_keyboard = i;
|
||||
|
||||
(void)kbdd_ioctl(kbd, KDSKBMODE,
|
||||
(caddr_t)&vd->vd_curwindow->vw_kbdmode);
|
||||
vt_update_kbd_mode(vd->vd_curwindow, kbd);
|
||||
vt_update_kbd_state(vd->vd_curwindow, kbd);
|
||||
} else {
|
||||
error = EPERM; /* XXX */
|
||||
}
|
||||
@ -2115,6 +2293,7 @@ vtterm_ioctl(struct terminal *tm, u_long cmd, caddr_t data,
|
||||
mtx_unlock(&Giant);
|
||||
return (EINVAL);
|
||||
}
|
||||
vt_save_kbd_state(vd->vd_curwindow, kbd);
|
||||
error = kbd_release(kbd, (void *)vd);
|
||||
if (error == 0) {
|
||||
vd->vd_keyboard = -1;
|
||||
|
Loading…
Reference in New Issue
Block a user