[comp.sys.amiga.tech] VANILLAKEYS and various other things

brianm@sco.COM (Brian Moffet) (11/17/88)

1) Well, I was sitting at my desk one day hacking together
a small program and wanted to get keyboard input from a 
custom window.  Now I didn't want to attach a console device
to this sucker, so I thought, "Hey, I can use Vanillakeys!"
(sounds sort of like an IceCream sold off the coast of florida).
However, I am able to recieve normal key strokes, but
not the function keys.  Does anyone know why this might be?
I don't appear to be getting a message even.

Note:  I am using ConMan (fantastic program by the way)
and I am not sure if that has made a difference.

2) 1 bitplane workbench.  Is it possible to just free the
bitmap and rearrange the WB screen structure to get this
to work?  Seems simple enough so that I'll try it.

3) In the same program as #1, I poll a windows IDCMP message
port using GetMsg(W->UserPort).  If I receive a message I will
take some action.   This action may be to go to a subroutine 
which does a Wait(1<<W->UserPort->mp_SigBit).
When this happens, the wait will succeed when there is no new
message.  It apparently sees that there was a message.  I do 
ReplyMsg() properly, so I am not sure what is going on.  

-=-=-=-=-sample code fragment-=-=-=-=-
	while((mp = GetMsg(up)) == NULL);
	ReplyMsg(mp);
	Wait(1<<up->mp_SigBit);	/* This returns immediatly */

Does this behaviour seem proper?  I would think the ReplyMsg
would clear things out.   Is there a proper way of clearing
the signal?

Again, thanks for all the help.  I look forward to the 2500
and possibly the 3000, maybe I'll upgrade my 1000.  

brian m.

PS Matt, could you get in touch with me?  I had a hard disk
crash and lost your latest version of dmouse.  I have the
source, but not the binary or a Manx compiler.  tanx
-- 
Brian Moffet			{uunet,decvax!microsoft,ucscc}!sco!brianm
 -or-				...sco!alar!brian
"Evil Geniuses for a better tomorrow!"  My fish and company have policies.
					I have opinions.

phil@titan.rice.edu (William LeFebvre) (11/18/88)

In article <1732@scolex> brianm@sco.COM (Brian Moffet) writes:
>3) In the same program as #1, I poll a windows IDCMP message
>port using GetMsg(W->UserPort).  If I receive a message I will
>take some action.   This action may be to go to a subroutine 
>which does a Wait(1<<W->UserPort->mp_SigBit).
>When this happens, the wait will succeed when there is no new
>message.  It apparently sees that there was a message.  I do 
>ReplyMsg() properly, so I am not sure what is going on.  
>
>-=-=-=-=-sample code fragment-=-=-=-=-
>	while((mp = GetMsg(up)) == NULL);
>	ReplyMsg(mp);
>	Wait(1<<up->mp_SigBit);	/* This returns immediatly */

That program fragment seems improper to me.  I don't have my RKM handy
(being at school right now), but I would guess that GetMsg returns NULL if
there is no message available.  That while loop then is basically busy
waiting.  This is a big no-no in a multitasking environment.  The proper
way to do this is to Wait first, then GetMsg.  This will take care of your
problem (the signal gets reset by the wait and doesn't need to be reset by
the reply) and will also keep your program from busy waiting.

Now if you just want to poll the port via GetMsg, and do something else if
no message was there, then that's different:
=-=-=-=-=-sample code fragment-=-=-=-=-
if ((mp = GetMsg(up)) == NULL) {
   ... something else ...
} else {
   ReplyMsg(mp);
   Wait(1<<up->mp_SigBit);  /* ??? */
   ...
}
Without the RKM's, I can't recall how one would go about clearing the
signal.  Doing a Wait after the GetMsg seems wrong to me, but that may be
the way to do it (I think that it would be guaranteed not to block in that
instance).

In my example, replacing "if" with "while" would be okay, provided that
the body of the loop was actually doing something constructive.

			William LeFebvre
			Department of Computer Science
			Rice University
			<phil@Rice.edu>

dillon@POSTGRES.BERKELEY.EDU (Matt Dillon) (11/20/88)

:In article <1732@scolex> brianm@sco.COM (Brian Moffet) writes:
:>3) In the same program as #1, I poll a windows IDCMP message
:>port using GetMsg(W->UserPort).  If I receive a message I will
:>take some action.   This action may be to go to a subroutine 
:>which does a Wait(1<<W->UserPort->mp_SigBit).
:>When this happens, the wait will succeed when there is no new
:>message.  It apparently sees that there was a message.  I do 
:>ReplyMsg() properly, so I am not sure what is going on.  
:>
:>-=-=-=-=-sample code fragment-=-=-=-=-
:>	while((mp = GetMsg(up)) == NULL);
:>	ReplyMsg(mp);
:>	Wait(1<<up->mp_SigBit);	/* This returns immediatly */

	Completely wrong, the program will freeze!

	(1) You busy wait in the while(), GetMsg() does NOT block, but returns
	    NULL if no message is ready.  This in itself is a big no-no.

	(2) You process just a single message and then you Wait().  Contrary
	    to your comment, Wait() will NOT return immediately every time
	    and you can get into a lockout situation

	Example:  Intuition sends three messages to you.  This causes the 
proper signal bit to be set.  Your while ends and returns the first message
which is then replied.  you then Wait() which returns immediately and CLEARS
the signal bit.  You then loop up to the top and do the while() again.

	The while returns the second message, you reply, but now since the
signal bit is cleared, the Wait() waits forever even though there is a 
third intuition message waiting.  (actually, if intuition queues a fifth
message it will unstick, but by this time it has gotten N messages off
and will never process all of them).
	
	Your code counts on intuition sending messages one at a time, 
which it does not do... intuition might queue any number of messages 
before your process has a chance to process any of them!

			PROPER CODE

	while (notdone) {
	    Wait(1 << up->mp_SigBit);
	    while (msg = GetMsg(up)) {
		<process the message>
		ReplyMsg(msg);
	    }
	}
	CloseWindow(window);	/* automagically removes any yet-to-be
				   GetMsg()d messages before closing down */

	Note that here I process ALL messages before looping.  In this case,
the only possibility of possibly incorrect operation occurs if I get a new
message while processing previous messages.  The new message sets the
signal bit, but it is also handled by the while() loop, which means when
the for(;;) loops up Wait() will return immediately and go through a 
'dummy-pass' on the GetMsg() (GetMsg() will return NULL and we will go
and Wait() again, this time Wait() really will Wait!).

						-Matt

brianm@sco.COM (Brian Moffet) (11/22/88)

In article <8811200120.AA29916@postgres.Berkeley.EDU> dillon@POSTGRES.BERKELEY.EDU (Matt Dillon) writes:
>:In article <1732@scolex> brianm@sco.COM (Brian Moffet) writes:
>:>3) In the same program as #1, I poll a windows IDCMP message
>:>port using GetMsg(W->UserPort).  If I receive a message I will
>:>take some action.   This action may be to go to a subroutine 
>:>which does a Wait(1<<W->UserPort->mp_SigBit).
>:>When this happens, the wait will succeed when there is no new
>:>message.  It apparently sees that there was a message.  I do 
>:>ReplyMsg() properly, so I am not sure what is going on.  
>:>
>:>-=-=-=-=-sample code fragment-=-=-=-=-
>:>	while((mp = GetMsg(up)) == NULL);
>:>	ReplyMsg(mp);
>:>	Wait(1<<up->mp_SigBit);	/* This returns immediatly */
>
>	Completely wrong, the program will freeze!
>
>	(1) You busy wait in the while(), GetMsg() does NOT block, but returns
>	    NULL if no message is ready.  This in itself is a big no-no.

I know it is a no-no.  However, in the hopes for small code fragments
it is okay.  The program will end when a message is recieved.

>
>	(2) You process just a single message and then you Wait().  Contrary
>	    to your comment, Wait() will NOT return immediately every time
>	    and you can get into a lockout situation
>
It will return immediately if there has been a GetMsg() loop
going on before hand (with appropriate ReplyMsg()ing) with
no Wait() calls.   This is my question: Why?

Hmm, people seem to have mistaken what was going on.  I will explain.
I have a program which is a graphics program.  It basically does
calculations etc, for each pixel.  After writing that pixel
I do a GetMsg().  This is for the closewindow gadget.  If this
has happened, I return from the subroutine which is doing the
calculating.   I then will do a Wait() for further action.

It is this wait that returns immediatly.  I then do a GetMsg()
to see what happened, and GetMsg() returns NULL.  the
only thing I can assume is the signal is not cleared.

A better *but longer* example is:

main()
{
	:
	:
	:
	Do_Calc();
	while (1)
	{
		/* this wait will return first time */
		Wait( 1 << mp->Sig_Bit );
		while ( (msg = GetMsg(up)) != NULL )
		{
			class = msg->Class;
			code = msg->Code;
			ReplyMsg(msg);
			Process_Msg(code, class);	/* this will exit */
		}
	}
	:
	:
}

Do_Calc()
{
	:
	:
	ret = 0;
	while (1)
	{
		:
		:
		while ((msg = GetMsg(up)) != NULL)
		{
			ret = 1;
			ReplyMsg(msg);
		}
		if (ret)	return;
	}
}

i had hoped that people would be able to figure out what I was
talking about without so much code, but ah well.   Now, why does the
wait return the first time, but the GetMsg() returns NULL?

brian moffet
-- 
Brian Moffet			{uunet,decvax!microsoft,ucscc}!sco!brianm
 -or-				...sco!alar!brian
"Evil Geniuses for a better tomorrow!"  My fish and company have policies.
					I have opinions.

cmcmanis%pepper@Sun.COM (Chuck McManis) (11/22/88)

Two problems that brian moffett is looking at and the solutions are
pretty general. 

1) VANILLAKEYS are just that, vanilla. No function keys, no help 
keys. I believe they are poorly defined and should be redefined but
that is up to jimm and company. 

The workaround is to use RAWKEYS and DeadKeyConvert() whose source
is around on Fish disks and various other places. Bryce Nesbitt
wrote an article for AmigaMail that had this information in it. 

2) The way he was reaping IntuiMessages was also incorrect, this will
definitely be one of the questions on the Intuition Merit Badge "test."

The key is that signals let you know when to look for messages, you then 
have to look for all messages that exist. Matt's code fragment was excellent, 
it is repeated (paraphrased?) here for completeness :

	WINDOWSIG = 1L << win->UserPort->mp_SigBit;
	SIGNALMASK = WINDOWSIG; /* Add any other signals to this mask */
	for (;;) {	/* for ever and ever */
		signals = Wait(SIGNALMASK);
		if ((signals & WINDOWSIG) != 0) {
			While ((msg = GetMessage(win->UserPort)) != NULL) {
				switch (msg->Class) {
					/* Process messages from Intuition */
				}
			ReplyMsg(msg); /* do this quickly */
			} /* fall through to check for other signals */
		} 
		if (/* check for each type of signal */) {
		}
	}	/* loop forever unless explicitly exit. */
	
The key features are that you wait first, this gives up the processor for
other tasks until something happens that your task should know about. Then
you process *all* of the messages waiting on your message port, and then you
*still* check to see if other signals were set. This allows one loop to 
process things like serial characters, window events, break signals  etc.

--Chuck McManis
uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@sun.com
These opinions are my own and no one elses, but you knew that didn't you.

cmcmanis%pepper@Sun.COM (Chuck McManis) (11/23/88)

In article <1769@scolex> brianm@sco.COM (Brian Moffet) writes:
>It is this wait that returns immediatly.  I then do a GetMsg()
>to see what happened, and GetMsg() returns NULL.  the
>only thing I can assume is the signal is not cleared.

Right-o. And you don't have to even assume it, it's documented that
Wait() clears signals and GetMsg() doesn't do anything to signals.

The CLOSEWINDOW message sets the signal, you read it before looking
at the signal, then when you go to check the signal with a Wait() it
returns immediately because the signal is set but the message has already 
been processed hence the null return from GetMsg().



--Chuck McManis
uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@sun.com
These opinions are my own and no one elses, but you knew that didn't you.

dillon@POSTGRES.BERKELEY.EDU (Matt Dillon) (11/23/88)

:Hmm, people seem to have mistaken what was going on.  I will explain.
:I have a program which is a graphics program.  It basically does
:calculations etc, for each pixel.  After writing that pixel
:I do a GetMsg().  This is for the closewindow gadget.  If this
:has happened, I return from the subroutine which is doing the
:calculating.   I then will do a Wait() for further action.
:
:It is this wait that returns immediatly.  I then do a GetMsg()
:to see what happened, and GetMsg() returns NULL.  the
:only thing I can assume is the signal is not cleared.

	Ohhh.. sorry.  Easy to explain:

	The GetMsg() call in itself does NOT clear the signal bit.
Thus, when intuition sends the CLOSEWINDOW IDCMP, this both sets the
signal and places the message on the UserPort.  You then GetMsg() it
(which does not clear the signal).

	You then Wait() on the signal, which returns immediately because
the signal was set.  A further GetMsg() results in NULL (unless intuition sent
you a second  message).  The Wait() call clears the signal.

	Now, you must ReplyMsg() ANY message you have successfully
retrieved via GetMsg().

main()
{
    short notdone = 1;
    ....
    while (notdone) {
	WriteThePixel()
	if (imess = GetMsg(UserPort)) {
	    long class = imess->Class;
	    ReplyMsg(imess);
	    if (class == CLOSEWINDOW)
		notdone = 0;
	}
    }
    CloseWindow(Win);
}

	Of course, once you finish rendering and are 'Idle' waiting
for the window to be closed you would put a Wait(1 << UserPort->mp_SigBit) in
the loop:

    while (notdone) {
	Wait(1 << UserPort->mp_SigBit); /* OR WaitPort(UserPort) */
	while (imess = GetMsg(UserPort)) {
	    /* process the message */
	    ReplyMsg(imess);	/* you must reply it */
	}
    }

	Where, due to timing, there are bound to be cases where the Wait()
returns and the GetMsg() comes back NULL the first time, but the way the loop 
is setup it doesn't matter.

	The most common mistake is to break out of the loop when you get the
CLOSEWINDOW IDCMP and forgetting to ReplyMsg() it.  By using a 'notdone'
variable you can avoid the mistake, because then all you would do when you
get the CLOSEWINDOW is clear the variable and continue normally (ReplyMsg()ing
it and handling any further messages).

				-Matt

ng@pur-phy (Nicholas J. Giordano) (11/23/88)

In article <78687@sun.uucp> cmcmanis@sun.UUCP (Chuck McManis) writes:
>Two problems that brian moffett is looking at and the solutions are
>pretty general. 
>
>1) VANILLAKEYS are just that, vanilla. No function keys, no help 
>keys. I believe they are poorly defined and should be redefined but
>that is up to jimm and company. 
>
>The workaround is to use RAWKEYS and DeadKeyConvert() whose source
>is around on Fish disks and various other places. Bryce Nesbitt
>wrote an article for AmigaMail that had this information in it. 

There is another way, which is not much work, but gets just about
all the keyboard information you USUALLY need.  It is to attach a console.device
to the window, and do all keyboard input/output through it.  This
gives you access to all the function keys, help keys, arrow keys,
etc., in an ANSI manner.  I think its easier to use than DeadKeyConvert(),
and the information that the console.device doesn't give (like when
a key is released) is often not needed anyway.

An example of this can be found in John Toebes (sp?) article in the
first (or second) Transactor issue, and in Matt Dillon's terminal
server for DNET.  They and others on the net put me on to this
approach, and its worked great for me.

Nick