typedef enum {
TS_AYT, TS_BRK, TS_SYNCH, TS_EC, TS_EL, TS_GA, TS_NOP, TS_ABORT,
- TS_AO, TS_IP, TS_SUSP, TS_EOR, TS_EOF, TS_LECHO, TS_RECHO
+ TS_AO, TS_IP, TS_SUSP, TS_EOR, TS_EOF, TS_LECHO, TS_RECHO, TS_PING
} Telnet_Special;
typedef enum {
enum { PROT_RAW, PROT_TELNET, PROT_SSH } protocol;
int close_on_exit;
int warn_on_close;
+ int ping_interval;
/* SSH options */
char remote_cmd[512];
int nopty;
}
write_setting_i (sesskey, "CloseOnExit", !!cfg->close_on_exit);
write_setting_i (sesskey, "WarnOnClose", !!cfg->warn_on_close);
+ write_setting_i (sesskey, "PingInterval", cfg->ping_interval);
write_setting_s (sesskey, "TerminalType", cfg->termtype);
write_setting_s (sesskey, "TerminalSpeed", cfg->termspeed);
{
gppi (sesskey, "CloseOnExit", 1, &cfg->close_on_exit);
gppi (sesskey, "WarnOnClose", 1, &cfg->warn_on_close);
+ gppi (sesskey, "PingInterval", 0, &cfg->ping_interval);
gpps (sesskey, "TerminalType", "xterm", cfg->termtype,
sizeof(cfg->termtype));
gpps (sesskey, "TerminalSpeed", "38400,38400", cfg->termspeed,
ssh2_pkt_send();
}
logevent("Sent EOF message");
+ } else if (code == TS_PING) {
+ if (ssh_version == 1) {
+ send_packet(SSH1_MSG_IGNORE, PKT_STR, "", PKT_END);
+ } else {
+ ssh2_pkt_init(SSH2_MSG_IGNORE);
+ ssh2_pkt_addstring_start();
+ ssh2_pkt_send();
+ }
} else {
/* do nothing */
}
case FD_CLOSE:
{
int clear_of_oob = 1;
- if (ioctlsocket (s, SIOCATMARK, &clear_of_oob) < 0 )
- return -20000-WSAGetLastError();
+
+ /* Don't check for error return; some shims don't support
+ * this ioctl.
+ */
+ ioctlsocket (s, SIOCATMARK, &clear_of_oob);
in_synch = !clear_of_oob;
send_opt (o_echo.nsend, o_echo.option);
}
break;
+ case TS_PING:
+ if (o_they_sga.state == ACTIVE) {
+ b[1] = NOP;
+ s_write (b, 2);
+ }
+ break;
}
}
#define CL_ANSI 0x2000 /* ANSI ECMA-48 not in the VT100..VT420 */
#define CL_OTHER 0x4000 /* Others, Xterm, linux, putty, dunno, etc */
-#define TM_ANSIMIN (CL_ANSIMIN)
#define TM_VT100 (CL_ANSIMIN|CL_VT100)
#define TM_VT100AVO (TM_VT100|CL_VT100AVO)
#define TM_VT102 (TM_VT100AVO|CL_VT102)
repeat_off = !state;
break;
case 25: /* enable/disable cursor */
- compatibility(VT220);
+ compatibility2(OTHER,VT220);
cursor_on = state;
seen_disp_event = TRUE;
break;
* DONT send TS_RECHO/TS_LECHO; the telnet daemon tries to fix the
* tty and _really_ confuses some programs.
*/
- compatibility(VT220);
+ compatibility2(OTHER,VT220);
ldisc = (state? &ldisc_simple : &ldisc_term);
break;
case 20: /* Return sends ... */
}
seen_disp_event = TRUE;
break;
+ case '\177': /* Destructive backspace
+ This does nothing on a real VT100 */
+ compatibility(OTHER);
+ if (curs_x && !wrapnext) curs_x--;
+ wrapnext = FALSE;
+ fix_cpos;
+ *cpos = (' ' | curr_attr | ATTR_ASCII);
+ break;
}
}
else switch (termstate) {
* we use the same font as well as the same encoding.
*/
case ATTR_LINEDRW:
- if (c<0x60 || c>0x7F)
+ if (c<0x5f || c>0x7F)
*cpos++ = xlat_tty2scr((unsigned char)c) | curr_attr |
ATTR_ASCII;
+ else if (c==0x5F)
+ *cpos++ = ' ' | curr_attr | ATTR_ASCII;
else
*cpos++ = ((unsigned char)c) | curr_attr | ATTR_LINEDRW;
break;
+ case ATTR_GBCHR:
+ /* If UK-ASCII, make the '#' a LineDraw Pound */
+ if (c == '#') {
+ *cpos++ = '}' | curr_attr | ATTR_LINEDRW;
+ break;
+ }
+ /*FALLTHROUGH*/
default:
*cpos++ = xlat_tty2scr((unsigned char)c) | curr_attr |
(c <= 0x7F ? cset_attr[cset] : ATTR_ASCII);
case 7: /* enable reverse video */
curr_attr |= ATTR_REVERSE; break;
case 22: /* disable bold */
- compatibility(VT220);
+ compatibility2(OTHER,VT220);
curr_attr &= ~ATTR_BOLD; break;
case 24: /* disable underline */
- compatibility(VT220);
+ compatibility2(OTHER,VT220);
curr_attr &= ~ATTR_UNDER; break;
case 25: /* disable blink */
- compatibility(VT220);
+ compatibility2(OTHER,VT220);
curr_attr &= ~ATTR_BLINK; break;
case 27: /* disable reverse video */
- compatibility(VT220);
+ compatibility2(OTHER,VT220);
curr_attr &= ~ATTR_REVERSE; break;
case 30: case 31: case 32: case 33:
case 34: case 35: case 36: case 37:
* This first appeared in the VT220, but we do need to get
* back to PuTTY mode so I won't check it.
*
- * The arg == 60 is a PuTTY extension.
- * The 2nd arg, 8bit vs 7bit is not obeyed.
+ * The arg in 40..42 are a PuTTY extension.
+ * The 2nd arg, 8bit vs 7bit is not checked.
*
* Setting VT102 mode should also change the Fkeys to
* generate PF* codes as a real VT102 has no Fkeys.
* Note ESC c will NOT change this!
*/
- if (esc_args[0] == 61) compatibility_level = TM_VT102;
- else if (esc_args[0] == 60) compatibility_level = TM_ANSIMIN;
- else compatibility_level = TM_PUTTY;
+ switch (esc_args[0]) {
+ case 61: compatibility_level &= ~TM_VTXXX;
+ compatibility_level |= TM_VT102; break;
+ case 62: compatibility_level &= ~TM_VTXXX;
+ compatibility_level |= TM_VT220; break;
+
+ default: if( esc_args[0] > 60 && esc_args[0] < 70 )
+ compatibility_level |= TM_VTXXX;
+ break;
+
+ case 40: compatibility_level &= TM_VTXXX; break;
+ case 41: compatibility_level = TM_PUTTY; break;
+ case 42: compatibility_level = TM_SCOANSI; break;
+
+ case ARG_DEFAULT:
+ compatibility_level = TM_PUTTY; break;
+ case 50: break;
+ }
+
+ /* Change the response to CSI c */
+ if (esc_args[0] == 50) {
+ int i;
+ char lbuf[64];
+ strcpy(id_string, "\033[?");
+ for (i=1; i<esc_nargs; i++) {
+ if (i!=1) strcat(id_string, ";");
+ sprintf(lbuf, "%d", esc_args[i]);
+ strcat(id_string, lbuf);
+ }
+ strcat(id_string, "c");
+ }
+
+#if 0
+ /* Is this a good idea ?
+ * Well we should do a soft reset at this point ...
+ */
+ if (!has_compat(VT420) && has_compat(VT100)) {
+ if (reset_132) request_resize (132, 24, 1);
+ else request_resize ( 80, 24, 1);
+ }
+#endif
break;
}
break;
ldisc->send ("\033/Z", 3);
break;
case '=':
- app_cursor_keys = TRUE;
+ app_keypad_keys = TRUE;
break;
case '>':
- app_cursor_keys = FALSE;
+ app_keypad_keys = FALSE;
break;
case '<':
/* XXX This should switch to VT100 mode not current or default
nl = TRUE;
}
while (q < nlpos && q < selend)
- *p++ = (unsigned char) (*q++ & CHAR_MASK);
+ {
+ /* VT Specials -> ISO8859-1 */
+ static const char poorman2[] =
+ "* # HTFFCRLF\xB0 \xB1 NLVT+ + + + + - - - - - + + + + | <=>=PI!=\xA3 \xB7 ";
+
+ int ch = (*q & CHAR_MASK);
+
+ if ((*q & ATTR_LINEDRW) && ch >= 0x60 && ch < 0x7F )
+ {
+ int x;
+ *p++ = poorman2[2*(ch-0x60)];
+ if ( (x = poorman2[2*(ch-0x60)+1]) != ' ')
+ *p++ = x;
+ }
+#if 0
+ else if ((*q & ATTR_GBCHR) && ch == '#')
+ *p++ = (unsigned char) 0xA3;
+#endif
+ else
+ *p++ = (unsigned char) ch;
+ q++;
+ }
if (nl) {
int i;
for (i=0; i<sizeof(sel_nl); i++)
/*
* An edit control on the right hand side, with a static to its left.
*/
-static void staticedit(struct ctlpos *cp, char *stext, int sid, int eid) {
+static void staticedit(struct ctlpos *cp, char *stext,
+ int sid, int eid, int percentedit) {
const int height = (EDITHEIGHT > STATICHEIGHT ?
EDITHEIGHT : STATICHEIGHT);
RECT r;
int lwid, rwid, rpos;
- rpos = GAPBETWEEN + (cp->width + GAPBETWEEN) / 2;
+ rpos = GAPBETWEEN + (100-percentedit) * (cp->width + GAPBETWEEN) / 100;
lwid = rpos - 2*GAPBETWEEN;
rwid = cp->width + GAPBETWEEN - rpos;
IDC0_SESSLOAD,
IDC0_SESSSAVE,
IDC0_SESSDEL,
- IDC0_CLOSEEXIT,
- IDC0_CLOSEWARN,
+ IDC0_PINGSTATIC,
+ IDC0_PINGEDIT,
connectionpanelend,
keyboardpanelstart,
IDC1_FUNCTILDE,
IDC1_FUNCLINUX,
IDC1_FUNCXTERM,
+ IDC1_FUNCVT400,
IDC1_KPSTATIC,
IDC1_KPNORMAL,
IDC1_KPAPPLIC,
IDC3_LOCKSIZE,
IDC3_WINTITLE,
IDC3_WINEDIT,
+ IDC3_CLOSEEXIT,
+ IDC3_CLOSEWARN,
windowpanelend,
telnetpanelstart,
CheckRadioButton (hwnd, IDC0_PROTRAW, IDC0_PROTSSH,
cfg.protocol==PROT_SSH ? IDC0_PROTSSH :
cfg.protocol==PROT_TELNET ? IDC0_PROTTELNET : IDC0_PROTRAW );
- CheckDlgButton (hwnd, IDC0_CLOSEEXIT, cfg.close_on_exit);
- CheckDlgButton (hwnd, IDC0_CLOSEWARN, cfg.warn_on_close);
+ SetDlgItemInt (hwnd, IDC0_PINGEDIT, cfg.ping_interval, FALSE);
CheckRadioButton (hwnd, IDC1_DEL008, IDC1_DEL127,
cfg.bksp_is_delete ? IDC1_DEL127 : IDC1_DEL008);
CheckRadioButton (hwnd, IDC1_HOMETILDE, IDC1_HOMERXVT,
cfg.rxvt_homeend ? IDC1_HOMERXVT : IDC1_HOMETILDE);
CheckRadioButton (hwnd, IDC1_FUNCTILDE, IDC1_FUNCXTERM,
- cfg.funky_type ?
- (cfg.funky_type==2 ? IDC1_FUNCXTERM
- : IDC1_FUNCLINUX )
- : IDC1_FUNCTILDE);
+ cfg.funky_type == 0 ? IDC1_FUNCTILDE :
+ cfg.funky_type == 1 ? IDC1_FUNCLINUX :
+ cfg.funky_type == 2 ? IDC1_FUNCXTERM :
+ cfg.funky_type == 3 ? IDC1_FUNCVT400 :
+ IDC1_FUNCTILDE );
CheckRadioButton (hwnd, IDC1_CURNORMAL, IDC1_CURAPPLIC,
cfg.app_cursor ? IDC1_CURAPPLIC : IDC1_CURNORMAL);
CheckRadioButton (hwnd, IDC1_KPNORMAL, IDC1_KPNH,
CheckDlgButton (hwnd, IDC3_BLINKCUR, cfg.blink_cur);
CheckDlgButton (hwnd, IDC3_SCROLLBAR, cfg.scrollbar);
CheckDlgButton (hwnd, IDC3_LOCKSIZE, cfg.locksize);
+ CheckDlgButton (hwnd, IDC3_CLOSEEXIT, cfg.close_on_exit);
+ CheckDlgButton (hwnd, IDC3_CLOSEWARN, cfg.warn_on_close);
SetDlgItemText (hwnd, IDC4_TTEDIT, cfg.termtype);
SetDlgItemText (hwnd, IDC4_TSEDIT, cfg.termspeed);
"&Save", IDC0_SESSSAVE,
"&Delete", IDC0_SESSDEL, NULL);
}
- checkbox(&cp, "Close Window on E&xit", IDC0_CLOSEEXIT);
- checkbox(&cp, "&Warn on Close", IDC0_CLOSEWARN);
+ staticedit(&cp, "Keepalive inter&val (minutes)",
+ IDC0_PINGSTATIC, IDC0_PINGEDIT, 25);
tab.mask = TCIF_TEXT; tab.pszText = "Connection";
TabCtrl_InsertItem (tabctl, i++, &tab);
radioline(&cp, "Action of Home and End:", IDC1_HOMESTATIC, 2,
"&Standard", IDC1_HOMETILDE,
"&rxvt", IDC1_HOMERXVT, NULL);
- radioline(&cp, "Function key and keypad layout:", IDC1_FUNCSTATIC, 3,
+ radioline(&cp, "Function key and keypad layout:", IDC1_FUNCSTATIC, 4,
"&VT400", IDC1_FUNCTILDE,
"&Linux", IDC1_FUNCLINUX,
- "&Xterm R6", IDC1_FUNCXTERM, NULL);
+ "&Xterm R6", IDC1_FUNCXTERM,
+ "&VT400", IDC1_FUNCVT400, NULL);
radioline(&cp, "Initial state of cursor keys:", IDC1_CURSTATIC, 2,
"&Normal", IDC1_CURNORMAL,
"A&pplication", IDC1_CURAPPLIC, NULL);
TabCtrl_InsertItem (tabctl, i++, &tab);
}
- /* The Terminal panel. Accelerators used: [aco] dghlmnprsw */
+ /* The Terminal panel. Accelerators used: [aco] dghlmnprsvw */
{
struct ctlpos cp;
ctlposinit(&cp, hwnd, 6, 30);
checkbox(&cp, "&Blinking cursor", IDC3_BLINKCUR);
checkbox(&cp, "Displa&y scrollbar", IDC3_SCROLLBAR);
checkbox(&cp, "Loc&k Window size", IDC3_LOCKSIZE);
+ checkbox(&cp, "Close Window on E&xit", IDC3_CLOSEEXIT);
+ checkbox(&cp, "&Warn on Close", IDC3_CLOSEWARN);
tab.mask = TCIF_TEXT; tab.pszText = "Window";
TabCtrl_InsertItem (tabctl, i++, &tab);
}
struct ctlpos cp;
ctlposinit(&cp, hwnd, 6, 30);
if (dlgtype == 0) {
- staticedit(&cp, "Terminal-&type string", IDC4_TTSTATIC, IDC4_TTEDIT);
- staticedit(&cp, "Terminal-&speed string", IDC4_TSSTATIC, IDC4_TSEDIT);
- staticedit(&cp, "Auto-login &username", IDC4_LOGSTATIC, IDC4_LOGEDIT);
+ staticedit(&cp, "Terminal-&type string", IDC4_TTSTATIC, IDC4_TTEDIT, 50);
+ staticedit(&cp, "Terminal-&speed string", IDC4_TSSTATIC, IDC4_TSEDIT, 50);
+ staticedit(&cp, "Auto-login &username", IDC4_LOGSTATIC, IDC4_LOGEDIT, 50);
envsetter(&cp, "Environment variables:", IDC4_ENVSTATIC,
"&Variable", IDC4_VARSTATIC, IDC4_VAREDIT,
"Va&lue", IDC4_VALSTATIC, IDC4_VALEDIT,
struct ctlpos cp;
ctlposinit(&cp, hwnd, 6, 30);
if (dlgtype == 0) {
- staticedit(&cp, "Terminal-&type string", IDC5_TTSTATIC, IDC5_TTEDIT);
- staticedit(&cp, "Auto-login &username", IDC5_LOGSTATIC, IDC5_LOGEDIT);
+ staticedit(&cp, "Terminal-&type string", IDC5_TTSTATIC, IDC5_TTEDIT, 50);
+ staticedit(&cp, "Auto-login &username", IDC5_LOGSTATIC, IDC5_LOGEDIT, 50);
multiedit(&cp,
"&Remote command:", IDC5_CMDSTATIC, IDC5_CMDEDIT, 100,
NULL);
{
HWND ctl;
ctl = GetDlgItem(hwnd, IDC0_HOST);
- if (!ctl) ctl = GetDlgItem(hwnd, IDC0_CLOSEEXIT);
+ if (!ctl) ctl = GetDlgItem(hwnd, IDC0_PINGEDIT);
SetFocus(ctl);
}
if (HIWORD(wParam) == EN_CHANGE)
MyGetDlgItemInt (hwnd, IDC0_PORT, &cfg.port);
break;
- case IDC0_CLOSEEXIT:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC0_CLOSEEXIT);
- break;
- case IDC0_CLOSEWARN:
- if (HIWORD(wParam) == BN_CLICKED ||
- HIWORD(wParam) == BN_DOUBLECLICKED)
- cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC0_CLOSEWARN);
- break;
case IDC0_SESSEDIT:
if (HIWORD(wParam) == EN_CHANGE) {
SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
SendDlgItemMessage (hwnd, IDC0_SESSLIST, LB_SETCURSEL,
(WPARAM) -1, 0);
}
+ case IDC0_PINGEDIT:
+ if (HIWORD(wParam) == EN_CHANGE)
+ MyGetDlgItemInt (hwnd, IDC0_PINGEDIT, &cfg.ping_interval);
+ break;
case IDC1_DEL008:
case IDC1_DEL127:
if (HIWORD(wParam) == BN_CLICKED ||
HIWORD(wParam) == BN_DOUBLECLICKED)
cfg.funky_type = 2;
break;
+ case IDC1_FUNCVT400:
+ if (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED)
+ cfg.funky_type = 3;
+ break;
case IDC1_FUNCTILDE:
case IDC1_FUNCLINUX:
if (HIWORD(wParam) == BN_CLICKED ||
GetDlgItemText (hwnd, IDC3_WINEDIT, cfg.wintitle,
sizeof(cfg.wintitle)-1);
break;
+ case IDC3_CLOSEEXIT:
+ if (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED)
+ cfg.close_on_exit = IsDlgButtonChecked (hwnd, IDC3_CLOSEEXIT);
+ break;
+ case IDC3_CLOSEWARN:
+ if (HIWORD(wParam) == BN_CLICKED ||
+ HIWORD(wParam) == BN_DOUBLECLICKED)
+ cfg.warn_on_close = IsDlgButtonChecked (hwnd, IDC3_CLOSEWARN);
+ break;
case IDC4_TTEDIT:
if (HIWORD(wParam) == EN_CHANGE)
GetDlgItemText (hwnd, IDC4_TTEDIT, cfg.termtype,
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
+#include <time.h>
#define PUTTY_DO_GLOBALS /* actually _define_ globals */
#include "putty.h"
static LPARAM pend_netevent_lParam = 0;
static void enact_pending_netevent(void);
+static time_t last_movement = 0;
+
#define FONT_NORMAL 0
#define FONT_BOLD 1
#define FONT_UNDERLINE 2
has_focus = (GetForegroundWindow() == hwnd);
UpdateWindow (hwnd);
+ if (GetMessage (&msg, NULL, 0, 0) == 1)
{
int timer_id = 0, long_timer = 0;
- while (GetMessage (&msg, NULL, 0, 0) == 1) {
+ while (msg.message != WM_QUIT) {
/* Sometimes DispatchMessage calls routines that use their own
* GetMessage loop, setup this timer so we get some control back.
*
timer_id = SetTimer(hwnd, 1, 20, NULL);
DispatchMessage (&msg);
- /* This is too fast, but I'll leave it for now 'cause it shows
- * how often term_update is called (far too often at times!)
- */
+ /* Make sure we blink everything that needs it. */
term_blink(0);
/* Send the paste buffer if there's anything to send */
* we've delayed, reading the socket, writing, and repainting
* the window.
*/
- if (!PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
- if (pending_netevent) {
- enact_pending_netevent();
+ if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+ continue;
- term_blink(1);
- }
- } else continue;
- if (!PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
- if (timer_id) {
- KillTimer(hwnd, timer_id);
- timer_id = 0;
- }
- HideCaret(hwnd);
- if (inbuf_head)
- term_out();
- term_update();
- ShowCaret(hwnd);
- if (!has_focus)
- timer_id = SetTimer(hwnd, 1, 2000, NULL);
- else if (cfg.blinktext)
- timer_id = SetTimer(hwnd, 1, 250, NULL);
- else
- timer_id = SetTimer(hwnd, 1, 500, NULL);
- long_timer = 1;
+ if (pending_netevent) {
+ enact_pending_netevent();
+
+ /* Force the cursor blink on */
+ term_blink(1);
+
+ if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+ continue;
}
+
+ /* Okay there is now nothing to do so we make sure the screen is
+ * completely up to date then tell windows to call us in a little
+ * while.
+ */
+ if (timer_id) {
+ KillTimer(hwnd, timer_id);
+ timer_id = 0;
+ }
+ HideCaret(hwnd);
+ if (inbuf_head)
+ term_out();
+ term_update();
+ ShowCaret(hwnd);
+ if (!has_focus)
+ timer_id = SetTimer(hwnd, 1, 59500, NULL);
+ else
+ timer_id = SetTimer(hwnd, 1, 250, NULL);
+ long_timer = 1;
+
+ /* There's no point rescanning everything in the message queue
+ * so we do an apperently unneccesary wait here
+ */
+ WaitMessage();
+ if (GetMessage (&msg, NULL, 0, 0) != 1)
+ break;
}
}
HideCaret(hwnd);
term_update();
ShowCaret(hwnd);
+ if (cfg.ping_interval > 0)
+ {
+ time_t now;
+ time(&now);
+ if (now-last_movement > cfg.ping_interval * 60 - 10)
+ {
+ back->special(TS_PING);
+ last_movement = now;
+ }
+ }
return 0;
case WM_CREATE:
break;
pending_netevent = TRUE;
pend_netevent_wParam=wParam;
pend_netevent_lParam=lParam;
+ time(&last_movement);
return 0;
case WM_SETFOCUS:
has_focus = TRUE;
}
}
- if (attr & ATTR_GBCHR) {
- int i;
- /*
- * GB mapping: map # to pound, and everything else stays
- * normal.
- */
- for (i=0; i<len; i++)
- if (text[i] == '#')
- text[i] = cfg.vtmode == VT_OEMONLY ? '\x9C' : '\xA3';
- } else if (attr & ATTR_LINEDRW) {
+ if (attr & ATTR_LINEDRW) {
int i;
/* ISO 8859-1 */
static const char poorman[] =
/*
* Line drawing mapping: map ` thru ~ (0x60 thru 0x7E) to
* VT100 line drawing chars; everything else stays normal.
+ *
+ * Actually '_' maps to space too, but that's done before.
*/
switch (cfg.vtmode) {
case VT_XWINDOWS:
if (!r) memset(keystate, 0, sizeof(keystate));
else
{
+#if 0
+ { /* Tell us all about key events */
+ static BYTE oldstate[256];
+ static int first = 1;
+ static int scan;
+ int ch;
+ if(first) memcpy(oldstate, keystate, sizeof(oldstate));
+ first=0;
+
+ if ((HIWORD(lParam)&(KF_UP|KF_REPEAT))==KF_REPEAT) {
+ debug(("+"));
+ } else if ((HIWORD(lParam)&KF_UP) && scan==(HIWORD(lParam) & 0xFF) ) {
+ debug((". U"));
+ } else {
+ debug((".\n"));
+ if (wParam >= VK_F1 && wParam <= VK_F20 )
+ debug(("K_F%d", wParam+1-VK_F1));
+ else switch(wParam)
+ {
+ case VK_SHIFT: debug(("SHIFT")); break;
+ case VK_CONTROL: debug(("CTRL")); break;
+ case VK_MENU: debug(("ALT")); break;
+ default: debug(("VK_%02x", wParam));
+ }
+ if(message == WM_SYSKEYDOWN || message == WM_SYSKEYUP)
+ debug(("*"));
+ debug((", S%02x", scan=(HIWORD(lParam) & 0xFF) ));
+
+ ch = MapVirtualKey(wParam, 2);
+ if (ch>=' ' && ch<='~') debug((", '%c'", ch));
+ else if (ch) debug((", $%02x", ch));
+
+ if (keys[0]) debug((", KB0=%02x", keys[0]));
+ if (keys[1]) debug((", KB1=%02x", keys[1]));
+ if (keys[2]) debug((", KB2=%02x", keys[2]));
+
+ if ( (keystate[VK_SHIFT]&0x80)!=0) debug((", S"));
+ if ( (keystate[VK_CONTROL]&0x80)!=0) debug((", C"));
+ if ( (HIWORD(lParam)&KF_EXTENDED) ) debug((", E"));
+ if ( (HIWORD(lParam)&KF_UP) ) debug((", U"));
+ }
+
+ if ((HIWORD(lParam)&(KF_UP|KF_REPEAT))==KF_REPEAT)
+ ;
+ else if ( (HIWORD(lParam)&KF_UP) )
+ oldstate[wParam&0xFF] ^= 0x80;
+ else
+ oldstate[wParam&0xFF] ^= 0x81;
+
+ for(ch=0; ch<256; ch++)
+ if (oldstate[ch] != keystate[ch])
+ debug((", M%02x=%02x", ch, keystate[ch]));
+
+ memcpy(oldstate, keystate, sizeof(oldstate));
+ }
+#endif
+
/* Note if AltGr was pressed and if it was used as a compose key */
if (wParam == VK_MENU && (HIWORD(lParam)&KF_EXTENDED))
{
compose_state = 0;
/* Nastyness with NUMLock - Shift-NUMLock is left alone though */
- if ( (cfg.funky_type == 0 || (cfg.funky_type == 1 && app_keypad_keys))
+ if ( (cfg.funky_type == 3 || (cfg.funky_type <= 1 && app_keypad_keys))
&& wParam==VK_NUMLOCK && !(keystate[VK_SHIFT]&0x80)) {
wParam = VK_EXECUTE;
/* Sanitize the number pad if not using a PC NumPad */
if( left_alt || (app_keypad_keys && cfg.funky_type != 2)
- || cfg.nethack_keypad || compose_state )
+ || cfg.funky_type == 3 || cfg.nethack_keypad || compose_state )
{
if ((HIWORD(lParam)&KF_EXTENDED) == 0)
{
SendMessage (hwnd, WM_SYSCOMMAND, SC_KEYMENU, 0);
return -1;
}
+ /* Control-Numlock for app-keypad mode switch */
+ if (wParam == VK_PAUSE && shift_state == 2) {
+ app_keypad_keys ^= 1;
+ return 0;
+ }
/* Nethack keypad */
if (cfg.nethack_keypad && !left_alt) {
if (!left_alt) {
int xkey = 0;
- if ( cfg.funky_type == 0 ||
- ( cfg.funky_type == 1 && app_keypad_keys)) switch(wParam) {
- case VK_EXECUTE: if (app_keypad_keys) xkey = 'P'; break;
+ if ( cfg.funky_type == 3 ||
+ ( cfg.funky_type <= 1 && app_keypad_keys)) switch(wParam) {
+ case VK_EXECUTE: xkey = 'P'; break;
case VK_DIVIDE: xkey = 'Q'; break;
case VK_MULTIPLY:xkey = 'R'; break;
case VK_SUBTRACT:xkey = 'S'; break;
case VK_NUMPAD9: xkey = 'y'; break;
case VK_DECIMAL: xkey = 'n'; break;
- case VK_ADD: if(shift_state) xkey = 'm';
- else xkey = 'l';
+ case VK_ADD: if(cfg.funky_type==2) {
+ if(shift_state) xkey = 'l';
+ else xkey = 'k';
+ } else if(shift_state) xkey = 'm';
+ else xkey = 'l';
break;
+
+ case VK_DIVIDE: if(cfg.funky_type==2) xkey = 'o'; break;
+ case VK_MULTIPLY:if(cfg.funky_type==2) xkey = 'j'; break;
+ case VK_SUBTRACT:if(cfg.funky_type==2) xkey = 'm'; break;
+
case VK_RETURN:
if (HIWORD(lParam)&KF_EXTENDED)
xkey = 'M';
case VK_PRIOR: code = 5; break;
case VK_NEXT: code = 6; break;
}
+ /* Reorder edit keys to physical order */
+ if (cfg.funky_type == 3 && code <= 6 ) code = "\0\2\1\4\5\3\6"[code];
+
if (cfg.funky_type == 1 && code >= 11 && code <= 15) {
p += sprintf((char *)p, "\x1B[[%c", code + 'A' - 11);
return p - output;
}
if (cfg.funky_type == 2 && code >= 11 && code <= 14) {
- p += sprintf((char *)p, "\x1BO%c", code + 'P' - 11);
+ if (vt52_mode)
+ p += sprintf((char *)p, "\x1B%c", code + 'P' - 11);
+ else
+ p += sprintf((char *)p, "\x1BO%c", code + 'P' - 11);
return p - output;
}
if (cfg.rxvt_homeend && (code == 1 || code == 4)) {
/* This stops ALT press-release doing a 'COMMAND MENU' function */
if (message == WM_SYSKEYUP && wParam == VK_MENU)
- {
- keystate[VK_MENU] = 0;
return 0;
- }
return -1;
}