10 June 2017, 15:22 | #1 |
Registered User
Join Date: Dec 2016
Location: london
Posts: 178
|
Trying the get bold, italic and coloured text out to the shell window.
Hi,
I am currently trying to see how the Amiga changes its text decoration (bold, italic, underline etc) and text colour in the shell window. I had hoped it would simply be a matter of selecting a pen colour, or issuing a simple command - but I was wrong on all counts. I found the following example on the internet - Code:
/* * Console.c * * Example of opening a window and using the console device * to send text and control sequences to it. The example can be * easily modified to do additional control sequences. * * Compile with SAS C 5.10: LC -b1 -cfistq -v -y -L * * Run from CLI only. */ #include <exec/types.h> #include <exec/io.h> #include <exec/memory.h> #include <intuition/intuition.h> #include <libraries/dos.h> #include <devices/console.h> #include <clib/exec_protos.h> #include <clib/alib_protos.h> #include <clib/dos_protos.h> #include <clib/intuition_protos.h> #include <stdio.h> #ifdef LATTICE int CXBRK(void) { return(0); } /* Disable Lattice CTRL/C handling */ int chkabort(void) { return(0); } /* really */ #endif /* Note - using two character <CSI> ESC[. Hex 9B could be used instead */ #define RESETCON "\033c" #define CURSOFF "\033[0 p" #define CURSON "\033[ p" #define DELCHAR "\033[P" /* SGR (set graphic rendition) */ #define COLOR02 "\033[32m" #define COLOR03 "\033[33m" #define ITALICS "\033[3m" #define BOLD "\033[1m" #define UNDERLINE "\033[4m" #define NORMAL "\033[0m" /* our functions */ void cleanexit(UBYTE *,LONG); void cleanup(void); BYTE OpenConsole(struct IOStdReq *,struct IOStdReq *, struct Window *); void CloseConsole(struct IOStdReq *); void QueueRead(struct IOStdReq *, UBYTE *); UBYTE ConGetChar(struct MsgPort *, UBYTE *); LONG ConMayGetChar(struct MsgPort *, UBYTE *); void ConPuts(struct IOStdReq *, UBYTE *); void ConWrite(struct IOStdReq *, UBYTE *, LONG); void ConPutChar(struct IOStdReq *, UBYTE); void main(int argc, char **argv); struct NewWindow nw = { 10, 10, /* starting position (left,top) */ 620,180, /* width, height */ -1,-1, /* detailpen, blockpen */ CLOSEWINDOW, /* flags for idcmp */ WINDOWDEPTH|WINDOWSIZING| WINDOWDRAG|WINDOWCLOSE| SMART_REFRESH|ACTIVATE, /* window flags */ NULL, /* no user gadgets */ NULL, /* no user checkmark */ "Console Test", /* title */ NULL, /* pointer to window screen */ NULL, /* pointer to super bitmap */ 100,45, /* min width, height */ 640,200, /* max width, height */ WBENCHSCREEN /* open on workbench screen */ }; /* Opens/allocations we'll need to clean up */ struct Library *IntuitionBase = NULL; struct Window *win = NULL; struct IOStdReq *writeReq = NULL; /* IORequest block pointer */ struct MsgPort *writePort = NULL; /* replyport for writes */ struct IOStdReq *readReq = NULL; /* IORequest block pointer */ struct MsgPort *readPort = NULL; /* replyport for reads */ BOOL OpenedConsole = FALSE; BOOL FromWb; void main(argc, argv) int argc; char **argv; { struct IntuiMessage *winmsg; ULONG signals, conreadsig, windowsig; LONG lch; SHORT InControl = 0; BOOL Done = FALSE; UBYTE ch, ibuf; UBYTE obuf[200]; BYTE error; FromWb = (argc==0L) ? TRUE : FALSE; if(!(IntuitionBase=OpenLibrary("intuition.library",0))) cleanexit("Can't open intuition\n",RETURN_FAIL); /* Create reply port and io block for writing to console */ if(!(writePort = CreatePort("RKM.console.write",0))) cleanexit("Can't create write port\n",RETURN_FAIL); if(!(writeReq = (struct IOStdReq *) CreateExtIO(writePort,(LONG)sizeof(struct IOStdReq)))) cleanexit("Can't create write request\n",RETURN_FAIL); /* Create reply port and io block for reading from console */ if(!(readPort = CreatePort("RKM.console.read",0))) cleanexit("Can't create read port\n",RETURN_FAIL); if(!(readReq = (struct IOStdReq *) CreateExtIO(readPort,(LONG)sizeof(struct IOStdReq)))) cleanexit("Can't create read request\n",RETURN_FAIL); /* Open a window */ if(!(win = OpenWindow(&nw))) cleanexit("Can't open window\n",RETURN_FAIL); /* Now, attach a console to the window */ if(error = OpenConsole(writeReq,readReq,win)) cleanexit("Can't open console.device\n",RETURN_FAIL); else OpenedConsole = TRUE; /* Demonstrate some console escape sequences */ ConPuts(writeReq,"Here's some normal text\n"); sprintf(obuf,"%s%sHere's text in color 3 & italics\n",COLOR03,ITALICS); ConPuts(writeReq,obuf); ConPuts(writeReq,NORMAL); Delay(50); /* Delay for dramatic demo effect */ ConPuts(writeReq,"We will now delete this asterisk =*="); Delay(50); ConPuts(writeReq,"\b\b"); /* backspace twice */ Delay(50); ConPuts(writeReq,DELCHAR); /* delete the character */ Delay(50); QueueRead(readReq,&ibuf); /* send the first console read request */ ConPuts(writeReq,"\n\nNow reading console\n"); ConPuts(writeReq,"Type some keys. Close window when done.\n\n"); conreadsig = 1 << readPort->mp_SigBit; windowsig = 1 << win->UserPort->mp_SigBit; while(!Done) { /* A character, or an IDCMP msg, or both could wake us up */ signals = Wait(conreadsig|windowsig); /* If a console signal was received, get the character */ if (signals & conreadsig) { if((lch = ConMayGetChar(readPort,&ibuf)) != -1) { ch = lch; /* Show hex and ascii (if printable) for char we got. * If you want to parse received control sequences, such as * function or Help keys,you would buffer control sequences * as you receive them, starting to buffer whenever you * receive 0x9B (or 0x1B[ for user-typed sequences) and * ending when you receive a valid terminating character * for the type of control sequence you are receiving. * For CSI sequences, valid terminating characters * are generally 0x40 through 0x7E. * In our example, InControl has the following values: * 0 = no, 1 = have 0x1B, 2 = have 0x9B OR 0x1B and [, * 3 = now inside control sequence, -1 = normal end esc, * -2 = non-CSI(no [) 0x1B end esc * NOTE - a more complex parser is required to recognize * other types of control sequences. */ /* 0x1B ESC not followed by '[', is not CSI seq */ if (InControl==1) { if(ch=='[') InControl = 2; else InControl = -2; } if ((ch==0x9B)||(ch==0x1B)) /* Control seq starting */ { InControl = (ch==0x1B) ? 1 : 2; ConPuts(writeReq,"=== Control Seq ===\n"); } /* We'll show value of this char we received */ if (((ch >= 0x1F)&&(ch <= 0x7E))||(ch >= 0xA0)) sprintf(obuf,"Received: hex %02x = %c\n",ch,ch); else sprintf(obuf,"Received: hex %02x\n",ch); ConPuts(writeReq,obuf); /* Valid ESC sequence terminator ends an ESC seq */ if ((InControl==3)&&((ch >= 0x40) && (ch <= 0x7E))) { InControl = -1; } if (InControl==2) InControl = 3; /* ESC sequence finished (-1 if OK, -2 if bogus) */ if (InControl < 0) { InControl = 0; ConPuts(writeReq,"=== End Control ===\n"); } } } /* If IDCMP messages received, handle them */ if (signals & windowsig) { /* We have to ReplyMsg these when done with them */ while (winmsg = (struct IntuiMessage *)GetMsg(win->UserPort)) { switch(winmsg->Class) { case CLOSEWINDOW: Done = TRUE; break; default: break; } ReplyMsg((struct Message *)winmsg); } } } /* We always have an outstanding queued read request * so we must abort it if it hasn't completed, * and we must remove it. */ if(!(CheckIO(readReq))) AbortIO(readReq); WaitIO(readReq); /* clear it from our replyport */ cleanup(); exit(RETURN_OK); } void cleanexit(UBYTE *s,LONG n) { if(*s & (!FromWb)) printf(s); cleanup(); exit(n); } void cleanup() { if(OpenedConsole) CloseConsole(writeReq); if(readReq) DeleteExtIO(readReq); if(readPort) DeletePort(readPort); if(writeReq) DeleteExtIO(writeReq); if(writePort) DeletePort(writePort); if(win) CloseWindow(win); if(IntuitionBase) CloseLibrary(IntuitionBase); } /* Attach console device to an open Intuition window. * This function returns a value of 0 if the console * device opened correctly and a nonzero value (the error * returned from OpenDevice) if there was an error. */ BYTE OpenConsole(writereq, readreq, window) struct IOStdReq *writereq; struct IOStdReq *readreq; struct Window *window; { BYTE error; writereq->io_Data = (APTR) window; writereq->io_Length = sizeof(struct Window); error = OpenDevice("console.device", 0, writereq, 0); readreq->io_Device = writereq->io_Device; /* clone required parts */ readreq->io_Unit = writereq->io_Unit; return(error); } void CloseConsole(struct IOStdReq *writereq) { CloseDevice(writereq); } /* Output a single character to a specified console */ void ConPutChar(struct IOStdReq *writereq, UBYTE character) { writereq->io_Command = CMD_WRITE; writereq->io_Data = (APTR)&character; writereq->io_Length = 1; DoIO(writereq); /* command works because DoIO blocks until command is done * (otherwise ptr to the character could become invalid) */ } /* Output a stream of known length to a console */ void ConWrite(struct IOStdReq *writereq, UBYTE *string, LONG length) { writereq->io_Command = CMD_WRITE; writereq->io_Data = (APTR)string; writereq->io_Length = length; DoIO(writereq); /* command works because DoIO blocks until command is done * (otherwise ptr to string could become invalid in the meantime) */ } /* Output a NULL-terminated string of characters to a console */ void ConPuts(struct IOStdReq *writereq,UBYTE *string) { writereq->io_Command = CMD_WRITE; writereq->io_Data = (APTR)string; writereq->io_Length = -1; /* means print till terminating null */ DoIO(writereq); } /* Queue up a read request to console, passing it pointer * to a buffer into which it can read the character */ void QueueRead(struct IOStdReq *readreq, UBYTE *whereto) { readreq->io_Command = CMD_READ; readreq->io_Data = (APTR)whereto; readreq->io_Length = 1; SendIO(readreq); } /* Check if a character has been received. * If none, return -1 */ LONG ConMayGetChar(struct MsgPort *msgport, UBYTE *whereto) { register temp; struct IOStdReq *readreq; if (!(readreq = (struct IOStdReq *)GetMsg(msgport))) return(-1); temp = *whereto; /* get the character */ QueueRead(readreq,whereto); /* then re-use the request block */ return(temp); } /* Wait for a character */ UBYTE ConGetChar(struct MsgPort *msgport, UBYTE *whereto) { register temp; struct IOStdReq *readreq; WaitPort(msgport); readreq = (struct IOStdReq *)GetMsg(msgport); temp = *whereto; /* get the character */ QueueRead(readreq,whereto); /* then re-use the request block*/ return((UBYTE)temp); } Code:
In file included from console.c:43: /gg/os-include/clib/dos_protos.h:128: warning: `struct ExAllControl' declared inside parameter list /gg/os-include/clib/dos_protos.h:128: warning: its scope is only this definition or declaration, which is probably not what you want. /gg/os-include/clib/dos_protos.h:128: warning: `struct ExAllData' declared inside parameter list /gg/os-include/clib/dos_protos.h:243: warning: `struct ExAllControl' declared inside parameter list /gg/os-include/clib/dos_protos.h:243: warning: `struct ExAllData' declared inside parameter list console.c: In function `main': console.c:479: warning: passing arg 1 of `CheckIO' from incompatible pointer type console.c:479: warning: passing arg 1 of `AbortIO' from incompatible pointer type console.c:481: warning: passing arg 1 of `WaitIO' from incompatible pointer type console.c:183: warning: return type of `main' is not `int' console.c: In function `cleanup': console.c:513: warning: passing arg 1 of `DeleteExtIO' from incompatible pointer type console.c:517: warning: passing arg 1 of `DeleteExtIO' from incompatible pointer type console.c: In function `OpenConsole': console.c:559: warning: passing arg 3 of `OpenDevice' from incompatible pointer type console.c: In function `CloseConsole': console.c:575: warning: passing arg 1 of `CloseDevice' from incompatible pointer type console.c: In function `ConPutChar': console.c:595: warning: passing arg 1 of `DoIO' from incompatible pointer type console.c: In function `ConWrite': console.c:623: warning: passing arg 1 of `DoIO' from incompatible pointer type console.c: In function `ConPuts': console.c:651: warning: passing arg 1 of `DoIO' from incompatible pointer type console.c: In function `QueueRead': console.c:673: warning: passing arg 1 of `SendIO' from incompatible pointer type Can someone point me at a simple example that I can play with? Thanks in advance. Last edited by chocsplease; 10 June 2017 at 15:47. |
10 June 2017, 16:03 | #2 |
Amigan
Join Date: Feb 2012
Location: London
Posts: 1,309
|
Change this:
Code:
#include <clib/exec_protos.h> #include <clib/alib_protos.h> #include <clib/dos_protos.h> #include <clib/intuition_protos.h> Code:
#include <proto/exec.h> #include <proto/alib.h> #include <proto/dos.h> #include <proto/intuition.h> |
10 June 2017, 22:14 | #3 | |
Registered User
Join Date: Aug 2004
Location:
Posts: 3,333
|
Quote:
You don't need to open your own window and use console.device directly. The CLI/Shell itself uses console.device, so you can use console.device "select graphic rendition" sequences when outputting text. See the ROM Kernel Manual: Devices page about that. Taking the example from that page: Code:
For example, to select bold face, with color 3 as the character color, and color 0 as the character cell color and the background color, send the hex sequence: 9B 31 3B 33 33 3B 34 30 3B 3E 30 6D representing the ASCII sequence: <CSI>1;33;40;>0m where <CSI> is the control sequence introducer, here used as the single character value 0x9B. Code:
printf("\x9B1;33;40;>0m OMG this is soooo easy."); |
|
11 June 2017, 13:17 | #4 | |
Registered User
Join Date: Dec 2016
Location: london
Posts: 178
|
Quote:
Unfortunately I cannot get this - Code:
printf("\x9B1;33;40;>0m OMG this is soooo easy."); I get a Warning 'escape sequence out of range for character' and the output - ±;33;40;>0m OMG this is soooo easy. So sorry it ain't Anyone know why it's not working for me? I've tried in KingCon and the standard shell. Noggin, I tried your suggestion and sadly it still won't compile - I'm getting the following - Code:
gcc -s -lamiga -noixemul -O2 console2.c console2.c:81: conflicting types for `IntuitionBase' /gg/os-include/proto/intuition.h:17: previous declaration of `IntuitionBase' console2.c: In function `main': console2.c:240: warning: initialization from incompatible pointer type console2.c:240: warning: initialization from incompatible pointer type console2.c:241: warning: initialization from incompatible pointer type console2.c:92: warning: return type of `main' is not `int' console2.c: In function `cleanup': console2.c:257: warning: passing arg 1 of `DeleteExtIO' from incompatible pointer type console2.c:259: warning: passing arg 1 of `DeleteExtIO' from incompatible pointer type console2.c: In function `OpenConsole': console2.c:280: warning: initialization from incompatible pointer type console2.c: In function `CloseConsole': console2.c:288: warning: initialization from incompatible pointer type console2.c: In function `ConPutChar': console2.c:298: warning: initialization from incompatible pointer type console2.c: In function `ConWrite': console2.c:312: warning: initialization from incompatible pointer type console2.c: In function `ConPuts': console2.c:326: warning: initialization from incompatible pointer type console2.c: In function `QueueRead': console2.c:337: warning: initialization from incompatible pointer type Last edited by chocsplease; 11 June 2017 at 13:33. |
|
11 June 2017, 13:38 | #5 | |
Registered User
Join Date: Aug 2004
Location:
Posts: 3,333
|
Quote:
If you just split the string it should work fine: Code:
printf("\x9B" "1;33;40;>0m OMG this is soooo easy."); Code:
printf("\033[1;33;40;>0m OMG this is soooo easy."); Code:
printf(BOLD "This is bold text!\n" NORMAL); Last edited by mark_k; 11 June 2017 at 13:43. |
|
11 June 2017, 13:53 | #6 | ||
Amigan
Join Date: Feb 2012
Location: London
Posts: 1,309
|
Quote:
Quote:
main() should return an int as it's the result code for the OS. You can use this in a shell script for example. |
||
11 June 2017, 18:04 | #7 |
Registered User
Join Date: Dec 2010
Location: Athens/Greece
Age: 53
Posts: 719
|
ansi.c
Code:
#include <stdio.h> /* Note - using two character <CSI> ESC[. Hex 9B could be used instead */ #define RESETCON "\033c" #define CURSOFF "\033[0 p" #define CURSON "\033[ p" #define DELCHAR "\033[P" /* SGR (set graphic rendition) */ #define COLOR02 "\033[32m" #define COLOR03 "\033[33m" #define ITALICS "\033[3m" #define BOLD "\033[1m" #define UNDERLINE "\033[4m" #define NORMAL "\033[0m" int main(int argc, char *argv[]) { printf(BOLD "This is bold text!\n" NORMAL); return 0; } Code:
m68k-amigaos-gcc -Os -s -noixemul -o ansi ansi.c |
15 June 2017, 12:25 | #8 |
Registered User
Join Date: Dec 2016
Location: london
Posts: 178
|
Many thanks for the replies - yes the compile works but I have really had to fiddle with it.
Anyway I have now hit a very odd problem to do with how the Amiga assigns colours on a screen with more than 4. I'm running a 32 colour Workbench, but the Shell will only use 8 of these (0 - 7). I thought that it would simply use the first 8, since this would be the most obvious. HA! Wrong. My WB Palette prefs are as follows - Code:
Colour number Red Green Blue 0 155 155 155 1 255 255 255 2 0 0 0 3 80 120 160 4 238 68 68 5 85 221 85 6 0 68 221 7 238 153 0 Code:
Colour number Red Green Blue 0 155 155 155 1 255 255 255 2 0 0 0 3 80 120 160 4 120 120 120 5 175 175 175 6 170 145 125 7 255 170 150 Here's an exert of the code I'm using, not pretty but it should work (I think) Code:
struct Screen *screen; unsigned char screenName[] = "Workbench"; unsigned long colorTable[256 *3 ]; struct ViewPort *viewPort; struct ColorMap *colorMap; unsigned long red,green,blue; screen = LockPubScreen(screenName); if (screen) /*locked the screen so we can now read info */ { viewPort = &screen->ViewPort; colorMap = viewPort->ColorMap; GetRGB32(colorMap,0,colorMap->Count, colorTable); UnlockPubScreen(NULL,screen); numcolours=colorMap->Count; } if (numcolours>2) /*don't bother for failed or 2 colur screen*/ { for (i=0;i<numcolours;i++) { red = colorTable[i * 3 + 0] >> 24 ; green = colorTable[i * 3 +1] >> 24; blue = colorTable[i * 3 +2] >> 24; /*find reddest*/ if ((red >= red_r) && ((green <= red_g) || (blue <= red_b))) { colour_red=i; red_r=red;red_g=green;red_b=blue; } /*find greenest*/ if ((green >= green_g) && ((red <= green_r) || (blue <= green_b))) { colour_green=i; green_r=red;green_g=green;green_b=blue; } /*find blueest - eventually yellow */ if ((blue >= blue_b) && (red <= blue_r) && ((red <=blue_r) || (green <= blue_g))) { colour_blue=i; blue_r=red;blue_g=green;blue_b=blue; } } } I worked out some code that finds the most red, green etc colour but it fails as its not seeing the same numbers as the system is actually using and I have no idea how to get it to do so. Anyone got any ideas on this? Last edited by chocsplease; 15 June 2017 at 12:36. |
15 June 2017, 14:28 | #9 |
Registered User
Join Date: Aug 2004
Location:
Posts: 3,333
|
I think you might find console colours 4-7 are taken from the highest four palette entries (so for a 32-colour screen, colours 28-31).
|
15 June 2017, 15:47 | #10 |
Registered User
Join Date: Oct 2009
Location: Germany
Posts: 3,303
|
Have you changed the first 4 (0-3) colors? If not they seem to not the usual what I guess are 0 to 3 = grey, black, white, blue (or similar). The colors 4 to 7 seems to be MagicWB colors what might be the last 4 colors of a palette. There are some tools/hacks that set/lock them.
Shell colors are the first 8 (0-7) and I`ve never heard that this is not the case. Do you use FullPalette to set/change/check your palette? |
17 June 2017, 00:29 | #11 | |
Registered User
Join Date: Dec 2016
Location: london
Posts: 178
|
Quote:
I didn't know that the colours are different to the default as the A1200 I am using is 2nd hand from EBay. It came with a lot of WB enhancements, but I don't think it is running MagicWB. In any case my code needs to allow for users to have changed the colours to whatever they wish - hence my feeble attempts to find the most red, green etc. I don't use fullpalette (just Googled it - useful tool )just the stock prefs. I basically have 2 problems here. First my code is getting different colours from those I expect so I'll see if fullpaltte can show me where colours 4-7 are coming from. Second its setting the most red to colour 6 (which is a sort of orange) and is very close in gamma to the grey background - making it almost impossible to read any figures using it. I think I'm going to have to work out how to calculate the grey equivalent of a colour so this does not happen but have no idea how to do this - I suspect finding the simple average of red,green and blue wont work. Does anyone have any ideas how I can find the grey scale equivalent of a colour? |
|
17 June 2017, 01:15 | #12 | |
Registered User
Join Date: Jan 2002
Location: Germany
Posts: 6,985
|
Quote:
Palette prefs sets the first four and the last four pens of the screen. So if your screen has a depth of eight colours, you can define all eight pens. But if your screen has more colours, pens 4 - 7 are random. If you don't want to dictate the screen's palette, then you should stick with 0 = background / transparent 1 = black 2 = white 3 = some color |
|
17 June 2017, 12:59 | #13 |
Registered User
Join Date: Aug 2004
Location:
Posts: 3,333
|
|
17 June 2017, 13:36 | #14 | |
Registered User
Join Date: Dec 2016
Location: london
Posts: 178
|
Many thanks for the replies.
Getting a nice looking output is proving a real mission. Quote:
I suspect I'm either going to force the output background to be white (or as close to white as the user has) or force the percentage background to be white - playing around at present to see which looks best. |
|
18 June 2017, 03:17 | #15 |
Registered User
Join Date: Sep 2007
Location: Stockholm
Posts: 4,332
|
I think you're overstretching it. Do you really need that many colours?
|
22 June 2017, 13:21 | #16 | |
Registered User
Join Date: Dec 2016
Location: london
Posts: 178
|
Quote:
Well part of the reason I am doing this is to learn how the Amiga does stuff, including colours, graphics windows etc. So to be blunt I don't but wanted to see if it was possible to display a disks percentage used in different colours depending on how much was actually used. So green for < 75% yellow for < 90% red for 90% plus. When I started I assumed that the shell used the same colours that the workbench screen did - it does not. As a result the final code probably wont be that colourful at all, but I have improved my knowledge which is half the reason for doing this |
|
22 June 2017, 14:58 | #17 |
Registered User
Join Date: Aug 2004
Location:
Posts: 3,333
|
If you don't mind having your program open a custom screen, you can set its palette to whatever you want.
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Clear background color for Shell window- Shell-StartUp | fc.studio | support.Apps | 13 | 25 March 2022 18:52 |
Closing current Shell window programmatically? | tygre | Coders. General | 5 | 06 September 2015 06:24 |
Snapshot Amiga Shell window? | TenLeftFingers | support.Apps | 3 | 15 June 2015 16:38 |
Cannot configurate cd32 coloured buttons | danny-666 | support.WinUAE | 2 | 15 June 2011 02:32 |
Multi-coloured A500 | Jim | Nostalgia & memories | 8 | 08 January 2002 22:56 |
|
|