WinHugs, interact support

Neil Mitchell <[email protected]>
Newsgroups gmane.comp.lang.haskell.cvs.hugs
Message-ID <[email protected]>
Hi,

This patch adds interact and getChar support to WinHugs. The
implementation in this version is superior to that in the old version
of WinHugs, including that the stop button now stops immediately (not
after one char is pressed) and the status bar changes to advise the
user that input is sought.

The appropach uses a Content semaphore to pause the calculating thread
when no input is available. Like all threading code, this is not
particularly fun to write or easy to understand.

Thanks

Neil

_______________________________________________
Cvs-hugs mailing list
[email protected]
http://www.haskell.org/mailman/listinfo/cvs-hugs
interact.patch (application/octet-stream, 5.5 KB)
Index: src/winhugs/DlgMain.c
===================================================================
RCS file: /cvs/hugs98/src/winhugs/DlgMain.c,v
retrieving revision 1.9
diff -u -r1.9 DlgMain.c
--- src/winhugs/DlgMain.c	7 Sep 2005 13:44:40 -0000	1.9
+++ src/winhugs/DlgMain.c	8 Sep 2005 13:06:33 -0000
@@ -180,6 +180,7 @@
 
     stringInput((LPSTR) Command);
     input(BREAK);
+    IORemapBegin();
     if (doCommand())
 	SendMessage(hThisWindow, WM_CLOSE, 0, 0);
 
@@ -240,6 +241,12 @@
     FireCommand(Command);
 }
 
+void AbortExecution()
+{
+    raise(SIGINT);
+    IORemapEnd();
+}
+
 void MainCommand(HWND hWnd, int ID)
 {
     switch (ID) {
@@ -279,7 +286,7 @@
 	/* Stop program execution */
 	case ID_STOP:
 	    MessageBeep(0xFFFFFFFF);
-	    raise(SIGINT);
+	    AbortExecution();
 	    break;
 
 	/* Evaluate main expression */
@@ -329,6 +336,11 @@
     return FALSE;
 }
 
+void SetStatusBar(LPCTSTR Str)
+{
+    SetDlgItemText(hThisWindow, ID_STATUS, Str);
+}
+
 void MainMenuSelect(HWND hWnd, int ID, int Flags)
 {
     CHAR Buffer[100];
@@ -339,7 +351,7 @@
     if (ID == 0 || !LoadString(hThisInstance, ID, Buffer, sizeof(Buffer)))
 	Buffer[0] = 0;
 
-    SetDlgItemText(hWnd, ID_STATUS, Buffer);
+    SetStatusBar(Buffer);
 }
 
 void MainDropFiles(HWND hWnd, HDROP hDrop)
@@ -425,7 +437,7 @@
 	case WM_CLOSE:
 	    RegistryWriteWindowPos(hWnd);
 	    if (Running)
-		raise(SIGINT);
+		AbortExecution();
 	    PostQuitMessage(0);
 	    break;
     }
Index: src/winhugs/Header.h
===================================================================
RCS file: /cvs/hugs98/src/winhugs/Header.h,v
retrieving revision 1.3
diff -u -r1.3 Header.h
--- src/winhugs/Header.h	7 Sep 2005 13:42:09 -0000	1.3
+++ src/winhugs/Header.h	8 Sep 2005 12:38:25 -0000
@@ -37,6 +37,8 @@
 void ExecutionFinished();
 void ShowMainDialog();
 void EnableButtons();
+void SetStatusBar(LPCTSTR Str);
+extern BOOL Running;
 
 // From MruFiles.c
 LPSTR MruGetItem(int i);
@@ -48,6 +50,11 @@
 LPSTR ExpandFileName(LPSTR what);
 LPCTSTR GetEditor(int Index, LPTSTR Buffer);
 
+// IORemap, for getChar support
+void WinHugsReceiveC(int c);
+void IORemapBegin();
+void IORemapEnd();
+
 // From WinBrowse2.c
 void DrawClassesHierarchy();
 void DoBrowseClasses();
Index: src/winhugs/IORemap.c
===================================================================
RCS file: /cvs/hugs98/src/winhugs/IORemap.c,v
retrieving revision 1.2
diff -u -r1.2 IORemap.c
--- src/winhugs/IORemap.c	6 Sep 2005 23:38:16 -0000	1.2
+++ src/winhugs/IORemap.c	8 Sep 2005 13:05:16 -0000
@@ -68,10 +68,85 @@
     return c;
 }
 
+/////////////////////////////////////////////////////////////////////
+// IMPLEMENT getChar and interact
+
+BOOL ValidMutexes = FALSE;
+CRITICAL_SECTION Mutex;
+HANDLE Contents;
+#define KeyboardBufferSize 25
+CHAR KeyboardBuffer[KeyboardBufferSize];
+int KeyboardBufferCount = 0;
+
+void EnterContents()
+{
+    WaitForSingleObject(Contents, INFINITE);
+}
+
+void ExitContents()
+{
+    ReleaseSemaphore(Contents, 1, NULL);
+}
+
+void IORemapBegin()
+{
+    // Put the mutexes in a sane state
+    // Kill then create them
+    if (ValidMutexes) {
+	DeleteCriticalSection(&Mutex);
+	CloseHandle(Contents);
+    }
+    InitializeCriticalSection(&Mutex);
+    Contents = CreateSemaphore(NULL, 0, 1, NULL);
+    ValidMutexes = TRUE;
+}
+
+void IORemapEnd()
+{
+    // Send a dead char, to wake up the semaphore if locked
+    WinHugsReceiveC(0);
+}
+
+// Called when a character gets sent to WinHugs while it is running
+void WinHugsReceiveC(int c)
+{
+    EnterCriticalSection(&Mutex);
+    if (KeyboardBufferCount != KeyboardBufferSize) {
+        KeyboardBuffer[KeyboardBufferCount] = c;
+	KeyboardBufferCount++;
+	if (KeyboardBufferCount == 1)
+	    ExitContents();
+    }
+    LeaveCriticalSection(&Mutex);
+}
+
 int WinHugsGetC(FILE* f)
 {
     if (f == stdin)
-	return 0; // no support for interact
+    {
+        int Res, i;
+
+	EnterCriticalSection(&Mutex);
+	if (KeyboardBufferCount == 0)
+	{
+            SetStatusBar("Waiting for user input");
+	    LeaveCriticalSection(&Mutex);
+	    EnterContents();
+	    EnterCriticalSection(&Mutex);
+	    SetStatusBar("");
+	}
+
+	Res = KeyboardBuffer[0];
+	for (i = 1; i < KeyboardBufferSize; i++)
+	    KeyboardBuffer[i-1] = KeyboardBuffer[i];
+	KeyboardBufferCount--;
+
+	if (KeyboardBufferCount > 0)
+	    ExitContents();
+	LeaveCriticalSection(&Mutex);
+
+	return Res; // no support for interact
+    }
     else
 	return fgetc(f);
 }
Index: src/winhugs/RtfWindow.c
===================================================================
RCS file: /cvs/hugs98/src/winhugs/RtfWindow.c,v
retrieving revision 1.4
diff -u -r1.4 RtfWindow.c
--- src/winhugs/RtfWindow.c	7 Sep 2005 15:40:32 -0000	1.4
+++ src/winhugs/RtfWindow.c	8 Sep 2005 13:04:48 -0000
@@ -186,7 +186,14 @@
 	}
     } else if (nmhdr->code == EN_MSGFILTER) {
 	MSGFILTER* mf = (MSGFILTER*) nmhdr;
-	if (mf->msg == WM_KEYDOWN) {
+	if (mf->msg == WM_CHAR && Running) {
+	    WinHugsReceiveC(mf->wParam == '\r' ? '\n' : mf->wParam);
+	    SetWindowLong(hDlg, DWL_MSGRESULT, 1);
+	    return TRUE;
+	} else if (Running && mf->msg == WM_KEYDOWN) {
+	    SetWindowLong(hDlg, DWL_MSGRESULT, 1);
+	    return TRUE;
+	} else if (mf->msg == WM_KEYDOWN && !Running) {
 	    BOOL History = (mf->wParam == VK_UP || mf->wParam == VK_DOWN);
 	    if (History && (mf->lParam & (1 << 24))) {
 		CHARRANGE cr;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.