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;