Allow arrow keys in WB Chat Box to access command history
[xboard.git] / winboard / wchat.c
index eb5179f..8d53d7c 100644 (file)
@@ -43,6 +43,7 @@
 int chatCount;\r
 extern char chatPartner[MAX_CHAT][MSG_SIZ];\r
 HANDLE chatHandle[MAX_CHAT];\r
+static WNDPROC chatInputWindowProc;\r
 \r
 void SendToICS P((char *s));\r
 void ChatPopUp P((char *s));\r
@@ -52,6 +53,9 @@ void ChatPopDown();
 extern int opponentKibitzes;\r
 \r
 /* Imports from winboard.c */\r
+VOID SaveInHistory(char *cmd);\r
+char *PrevInHistory(char *cmd);\r
+char *NextInHistory();\r
 extern HWND ChatDialog;\r
 \r
 extern HINSTANCE hInst;\r
@@ -132,6 +136,42 @@ static void InsertIntoMemo( HANDLE hDlg, char * text )
     SendMessage( hMemo, EM_SCROLLCARET, 0, 0);\r
 }\r
 \r
+LRESULT CALLBACK\r
+InterceptArrowKeys(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)\r
+{\r
+  char buf[MSG_SIZ];\r
+  char *p;\r
+  CHARRANGE sel;\r
+\r
+  switch (message) {\r
+  case WM_KEYDOWN: // cloned from ConsoleInputSubClass()\r
+    switch (wParam) {\r
+    case VK_UP:\r
+      GetWindowText(hwnd, buf, MSG_SIZ);\r
+      p = PrevInHistory(buf);\r
+      if (p != NULL) {\r
+       SetWindowText(hwnd, p);\r
+       sel.cpMin = 999999;\r
+       sel.cpMax = 999999;\r
+       SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+        return 0;\r
+      }\r
+      break;\r
+    case VK_DOWN:\r
+      p = NextInHistory();\r
+      if (p != NULL) {\r
+       SetWindowText(hwnd, p);\r
+       sel.cpMin = 999999;\r
+       sel.cpMax = 999999;\r
+       SendMessage(hwnd, EM_EXSETSEL, 0, (LPARAM)&sel);\r
+        return 0;\r
+      }\r
+      break;\r
+    }\r
+  }\r
+  return (*chatInputWindowProc)(hwnd, message, wParam, lParam);\r
+}\r
+\r
 // This seems pure front end\r
 LRESULT CALLBACK ChatProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )\r
 {\r
@@ -139,6 +179,8 @@ LRESULT CALLBACK ChatProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam
     char buf[MSG_SIZ], mess[MSG_SIZ];\r
     int partner = -1, i;\r
     static BOOL filterHasFocus[MAX_CHAT];\r
+    WORD wMask;\r
+    HWND hMemo;\r
 \r
     for(i=0; i<MAX_CHAT; i++) if(hDlg == chatHandle[i]) { partner = i; break; }\r
 \r
@@ -158,8 +200,31 @@ LRESULT CALLBACK ChatProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam
            filterHasFocus[partner] = FALSE;\r
            SetFocus( GetDlgItem(hDlg, OPT_ChatInput) );\r
        }\r
+       hMemo = GetDlgItem(hDlg, IDC_ChatMemo);\r
+       wMask = (WORD) SendMessage(hMemo, EM_GETEVENTMASK, 0, 0L);\r
+       SendMessage(hMemo, EM_SETEVENTMASK, 0, wMask | ENM_LINK);\r
+       SendMessage(hMemo, EM_AUTOURLDETECT, TRUE, 0L);\r
+       chatInputWindowProc = (WNDPROC) // cloned from ConsoleWndProc(). Assume they all share same proc.\r
+             SetWindowLong(GetDlgItem(hDlg, OPT_ChatInput), GWL_WNDPROC, (LONG) InterceptArrowKeys);\r
         return FALSE;\r
 \r
+    case WM_NOTIFY:\r
+      if (((NMHDR*)lParam)->code == EN_LINK)\r
+      {\r
+       ENLINK *pLink = (ENLINK*)lParam;\r
+       if (pLink->msg == WM_LBUTTONUP)\r
+       {\r
+         TEXTRANGE tr;\r
+\r
+         tr.chrg = pLink->chrg;\r
+         tr.lpstrText = malloc(1+tr.chrg.cpMax-tr.chrg.cpMin);\r
+         SendMessage( GetDlgItem(hDlg, IDC_ChatMemo), EM_GETTEXTRANGE, 0, (LPARAM)&tr);\r
+         ShellExecute(NULL, "open", tr.lpstrText, NULL, NULL, SW_SHOW);\r
+         free(tr.lpstrText);\r
+       }\r
+      }\r
+    break;\r
+\r
     case WM_COMMAND:\r
       /* \r
         [AS]\r
@@ -204,11 +269,12 @@ LRESULT CALLBACK ChatProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam
            GetDlgItemText(hDlg, OPT_ChatInput, mess, MSG_SIZ);\r
            SetDlgItemText(hDlg, OPT_ChatInput, "");\r
            // from here on it could be back-end\r
+           SaveInHistory(mess);\r
            if(!strcmp("WHISPER", chatPartner[partner]))\r
                sprintf(buf, "whisper %s\n", mess); // WHISPER box uses "whisper" to send\r
            else {\r
                if(!atoi(chatPartner[partner])) {\r
-                   sprintf(buf, "> %s\n", mess); // echo only tells to handle, not channel\r
+                   sprintf(buf, "> %s\r\n", mess); // echo only tells to handle, not channel\r
                InsertIntoMemo(hDlg, buf);\r
                sprintf(buf, "xtell %s %s\n", chatPartner[partner], mess);\r
                } else\r
@@ -287,5 +353,7 @@ void OutputChatMessage(int partner, char *text)
 {\r
        if(!chatHandle[partner]) return;\r
 \r
+       int n = strlen(text);\r
+       text[n+1] = 0; text[n] = '\n'; text[n-1] = '\r'; // Needs CR to not lose line breaks on copy-paste\r
        InsertIntoMemo(chatHandle[partner], text);\r
 }\r