simplify/rewrite screen

git-svn-id: svn://qnap.local/TwoTerm/trunk@3170 5590a31f-7b70-45f8-8c82-aa3a8e5f4507
This commit is contained in:
Kelvin Sherlock 2017-02-17 03:57:16 +00:00
commit 93b24a5a4b
18 changed files with 1585 additions and 2174 deletions

View File

@ -19,18 +19,9 @@
B612F45012DD5DAD005D1B77 /* iGeometry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B612F44712DD5DAD005D1B77 /* iGeometry.cpp */; };
B612F45112DD5DAD005D1B77 /* Lock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B612F44912DD5DAD005D1B77 /* Lock.cpp */; };
B612F45212DD5DAD005D1B77 /* OutputChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B612F44B12DD5DAD005D1B77 /* OutputChannel.cpp */; };
B612F45312DD5DAD005D1B77 /* Screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B612F44D12DD5DAD005D1B77 /* Screen.cpp */; };
B612F46412DD5DF1005D1B77 /* Apple80.mm in Sources */ = {isa = PBXBuildFile; fileRef = B612F45712DD5DF1005D1B77 /* Apple80.mm */; };
B612F46512DD5DF1005D1B77 /* EmulatorManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = B612F45912DD5DF1005D1B77 /* EmulatorManager.mm */; };
B612F46612DD5DF1005D1B77 /* GNOConsole.mm in Sources */ = {isa = PBXBuildFile; fileRef = B612F45B12DD5DF1005D1B77 /* GNOConsole.mm */; };
B612F46712DD5DF1005D1B77 /* PTSE.mm in Sources */ = {isa = PBXBuildFile; fileRef = B612F45D12DD5DF1005D1B77 /* PTSE.mm */; };
B612F46812DD5DF1005D1B77 /* VT05.mm in Sources */ = {isa = PBXBuildFile; fileRef = B612F45F12DD5DF1005D1B77 /* VT05.mm */; };
B612F46912DD5DF1005D1B77 /* VT100.mm in Sources */ = {isa = PBXBuildFile; fileRef = B612F46112DD5DF1005D1B77 /* VT100.mm */; };
B612F46A12DD5DF1005D1B77 /* VT52.mm in Sources */ = {isa = PBXBuildFile; fileRef = B612F46312DD5DF1005D1B77 /* VT52.mm */; };
B612F47012DD5E02005D1B77 /* CurveView.m in Sources */ = {isa = PBXBuildFile; fileRef = B612F46D12DD5E02005D1B77 /* CurveView.m */; };
B612F47112DD5E02005D1B77 /* EmulatorView.mm in Sources */ = {isa = PBXBuildFile; fileRef = B612F46F12DD5E02005D1B77 /* EmulatorView.mm */; };
B612F47412DDEBA9005D1B77 /* Screen_obsolete.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B612F47212DDEBA9005D1B77 /* Screen_obsolete.cpp */; };
B612F47512DDEBA9005D1B77 /* Screen_TextPort.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B612F47312DDEBA9005D1B77 /* Screen_TextPort.cpp */; };
B61D0D60125B7ACA001C713B /* NewTerminalWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = B61D0D5F125B7ACA001C713B /* NewTerminalWindowController.mm */; };
B61D0D69125B8E06001C713B /* Defaults.m in Sources */ = {isa = PBXBuildFile; fileRef = B61D0D68125B8E06001C713B /* Defaults.m */; };
B61EF7C51481561E008C1891 /* titlebar-corner.png in Resources */ = {isa = PBXBuildFile; fileRef = B61EF7C31481561E008C1891 /* titlebar-corner.png */; };
@ -43,13 +34,16 @@
B61EF7D91482FB6D008C1891 /* titlebar-right.png in Resources */ = {isa = PBXBuildFile; fileRef = B61EF7D61482FB6D008C1891 /* titlebar-right.png */; };
B638188214A179D60027D007 /* ColorView.m in Sources */ = {isa = PBXBuildFile; fileRef = B638188114A179D60027D007 /* ColorView.m */; };
B66412391480A070003BC8D3 /* EmulatorWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = B66412381480A070003BC8D3 /* EmulatorWindow.m */; };
B675F4A81E540394004B0D9C /* Screen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B612F44D12DD5DAD005D1B77 /* Screen.cpp */; };
B675F4A91E561D20004B0D9C /* Apple80.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B612F45712DD5DF1005D1B77 /* Apple80.mm.ragel */; };
B675F4AA1E562159004B0D9C /* GNOConsole.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B612F45B12DD5DF1005D1B77 /* GNOConsole.mm.ragel */; };
B675F4AC1E56A7F2004B0D9C /* GSOSConsole.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B6C173911D31D2B80024E360 /* GSOSConsole.mm.ragel */; };
B676063B11DEAD3500D6B66C /* TermWindowController.mm in Sources */ = {isa = PBXBuildFile; fileRef = B676063A11DEAD3500D6B66C /* TermWindowController.mm */; };
B676065111DEBAE900D6B66C /* TermWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = B676065011DEBAE900D6B66C /* TermWindow.xib */; };
B67B3CE512B6FA040033AE07 /* a2-charset-40.png in Resources */ = {isa = PBXBuildFile; fileRef = B67B3CE312B6FA040033AE07 /* a2-charset-40.png */; };
B67B3CE612B6FA040033AE07 /* a2-charset-80.png in Resources */ = {isa = PBXBuildFile; fileRef = B67B3CE412B6FA040033AE07 /* a2-charset-80.png */; };
B6801BD912EB549300B22E9E /* vt100-charset.png in Resources */ = {isa = PBXBuildFile; fileRef = B6801BD812EB549300B22E9E /* vt100-charset.png */; };
B68E632A12FF909D00EAFF5F /* ExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = B68E632912FF909C00EAFF5F /* ExampleView.m */; };
B6C173921D31D2B80024E360 /* GSOSConsole.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B6C173911D31D2B80024E360 /* GSOSConsole.mm.ragel */; };
B6C704EF15CCC64100CC0401 /* titlebar-center@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C704EC15CCC64100CC0401 /* titlebar-center@2x.png */; };
B6C704F015CCC64100CC0401 /* titlebar-left@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C704ED15CCC64100CC0401 /* titlebar-left@2x.png */; };
B6C704F115CCC64100CC0401 /* titlebar-right@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B6C704EE15CCC64100CC0401 /* titlebar-right@2x.png */; };
@ -119,11 +113,11 @@
B612F44D12DD5DAD005D1B77 /* Screen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Screen.cpp; sourceTree = "<group>"; };
B612F44E12DD5DAD005D1B77 /* Screen.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Screen.h; sourceTree = "<group>"; };
B612F45612DD5DF1005D1B77 /* Apple80.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Apple80.h; sourceTree = "<group>"; };
B612F45712DD5DF1005D1B77 /* Apple80.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = Apple80.mm; sourceTree = "<group>"; };
B612F45712DD5DF1005D1B77 /* Apple80.mm.ragel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Apple80.mm.ragel; sourceTree = "<group>"; };
B612F45812DD5DF1005D1B77 /* Emulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Emulator.h; sourceTree = "<group>"; };
B612F45912DD5DF1005D1B77 /* EmulatorManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EmulatorManager.mm; sourceTree = "<group>"; };
B612F45A12DD5DF1005D1B77 /* GNOConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GNOConsole.h; sourceTree = "<group>"; };
B612F45B12DD5DF1005D1B77 /* GNOConsole.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = GNOConsole.mm; sourceTree = "<group>"; };
B612F45B12DD5DF1005D1B77 /* GNOConsole.mm.ragel */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = GNOConsole.mm.ragel; sourceTree = "<group>"; };
B612F45C12DD5DF1005D1B77 /* PTSE.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTSE.h; sourceTree = "<group>"; };
B612F45D12DD5DF1005D1B77 /* PTSE.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PTSE.mm; sourceTree = "<group>"; };
B612F45E12DD5DF1005D1B77 /* VT05.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VT05.h; sourceTree = "<group>"; };
@ -136,8 +130,6 @@
B612F46D12DD5E02005D1B77 /* CurveView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CurveView.m; sourceTree = "<group>"; };
B612F46E12DD5E02005D1B77 /* EmulatorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EmulatorView.h; sourceTree = "<group>"; };
B612F46F12DD5E02005D1B77 /* EmulatorView.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EmulatorView.mm; sourceTree = "<group>"; };
B612F47212DDEBA9005D1B77 /* Screen_obsolete.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Screen_obsolete.cpp; sourceTree = "<group>"; };
B612F47312DDEBA9005D1B77 /* Screen_TextPort.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Screen_TextPort.cpp; sourceTree = "<group>"; };
B61D0D5E125B7ACA001C713B /* NewTerminalWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NewTerminalWindowController.h; sourceTree = "<group>"; };
B61D0D5F125B7ACA001C713B /* NewTerminalWindowController.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NewTerminalWindowController.mm; sourceTree = "<group>"; };
B61D0D67125B8E06001C713B /* Defaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Defaults.h; sourceTree = "<group>"; };
@ -296,8 +288,6 @@
B612F44C12DD5DAD005D1B77 /* OutputChannel.h */,
B612F44D12DD5DAD005D1B77 /* Screen.cpp */,
B612F44E12DD5DAD005D1B77 /* Screen.h */,
B612F47212DDEBA9005D1B77 /* Screen_obsolete.cpp */,
B612F47312DDEBA9005D1B77 /* Screen_TextPort.cpp */,
);
path = cpp;
sourceTree = "<group>";
@ -306,11 +296,11 @@
isa = PBXGroup;
children = (
B612F45612DD5DF1005D1B77 /* Apple80.h */,
B612F45712DD5DF1005D1B77 /* Apple80.mm */,
B612F45712DD5DF1005D1B77 /* Apple80.mm.ragel */,
B612F45812DD5DF1005D1B77 /* Emulator.h */,
B612F45912DD5DF1005D1B77 /* EmulatorManager.mm */,
B612F45A12DD5DF1005D1B77 /* GNOConsole.h */,
B612F45B12DD5DF1005D1B77 /* GNOConsole.mm */,
B612F45B12DD5DF1005D1B77 /* GNOConsole.mm.ragel */,
B6C173901D31D2B80024E360 /* GSOSConsole.h */,
B6C173911D31D2B80024E360 /* GSOSConsole.mm.ragel */,
B612F45C12DD5DF1005D1B77 /* PTSE.h */,
@ -447,7 +437,9 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B6C173921D31D2B80024E360 /* GSOSConsole.mm.ragel in Sources */,
B675F4A91E561D20004B0D9C /* Apple80.mm.ragel in Sources */,
B675F4AA1E562159004B0D9C /* GNOConsole.mm.ragel in Sources */,
B675F4AC1E56A7F2004B0D9C /* GSOSConsole.mm.ragel in Sources */,
8D11072D0486CEB800E47090 /* main.m in Sources */,
256AC3DA0F4B6AC300CF3369 /* TwoTermAppDelegate.mm in Sources */,
B676063B11DEAD3500D6B66C /* TermWindowController.mm in Sources */,
@ -459,18 +451,10 @@
B612F45012DD5DAD005D1B77 /* iGeometry.cpp in Sources */,
B612F45112DD5DAD005D1B77 /* Lock.cpp in Sources */,
B612F45212DD5DAD005D1B77 /* OutputChannel.cpp in Sources */,
B612F45312DD5DAD005D1B77 /* Screen.cpp in Sources */,
B612F46412DD5DF1005D1B77 /* Apple80.mm in Sources */,
B612F46512DD5DF1005D1B77 /* EmulatorManager.mm in Sources */,
B612F46612DD5DF1005D1B77 /* GNOConsole.mm in Sources */,
B612F46712DD5DF1005D1B77 /* PTSE.mm in Sources */,
B612F46812DD5DF1005D1B77 /* VT05.mm in Sources */,
B612F46912DD5DF1005D1B77 /* VT100.mm in Sources */,
B612F46A12DD5DF1005D1B77 /* VT52.mm in Sources */,
B612F47012DD5E02005D1B77 /* CurveView.m in Sources */,
B675F4A81E540394004B0D9C /* Screen.cpp in Sources */,
B612F47112DD5E02005D1B77 /* EmulatorView.mm in Sources */,
B612F47412DDEBA9005D1B77 /* Screen_obsolete.cpp in Sources */,
B612F47512DDEBA9005D1B77 /* Screen_TextPort.cpp in Sources */,
B68E632A12FF909D00EAFF5F /* ExampleView.m in Sources */,
B66412391480A070003BC8D3 /* EmulatorWindow.m in Sources */,
B612870E1480B4F6002E04DF /* TermContentView.m in Sources */,
@ -563,7 +547,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
@ -596,7 +580,7 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++0x";
CLANG_CXX_LANGUAGE_STANDARD = "c++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;

View File

@ -10,13 +10,14 @@
#import "Emulator.h"
#include "iGeometry.h"
#include "Screen.h"
@interface Apple80 : NSObject <Emulator> {
unsigned _state;
iPoint _dca;
unsigned cs;
int _scratch[4];
context _context;
}
@end

View File

@ -1,312 +0,0 @@
//
// Apple80.mm
// 2Term
//
// Created by Kelvin Sherlock on 12/23/2010.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
/*
* See Apple IIe Tech Ref page 273.
* See Apple IIgs Firmware Reference page 77
*
*
*/
#import "Apple80.h"
#include <sys/ttydefaults.h>
#include "OutputChannel.h"
#include "Screen.h"
@implementation Apple80
enum {
StateText,
StateDCAX,
StateDCAY
};
+(void)load
{
[EmulatorManager registerClass: self];
}
+(NSString *)name
{
return @"Apple 80";
}
-(NSString *)name
{
return @"Apple 80";
}
-(const char *)termName
{
return "appleIIe";
}
-(void)reset
{
_state = StateText;
}
-(BOOL)resizable
{
return NO;
}
-(struct winsize)defaultSize
{
struct winsize ws = { 24, 80, 0, 0 };
return ws;
}
-(void)initTerm: (struct termios *)term
{
// Control-U is used by the up-arrow key.
term->c_cc[VKILL] = CTRL('X');
}
-(void)processCharacter:(uint8_t)c screen:(Screen *)screen output:(OutputChannel *)output
{
if (_state == StateText)
{
switch (c)
{
case CTRL('E'):
// cursor on
break;
case CTRL('F'):
//cursor off
break;
case CTRL('G'):
// beep 1000 hz for .1 seconds.
NSBeep();
break;
case CTRL('H'):
// decrement x. moves to end of previous line...
screen->decrementX(true);
break;
case CTRL('I'):
// tab
screen->tabTo((screen->x() + 8) & ~0x07);
break;
case CTRL('J'):
// down 1 line.
screen->lineFeed();
break;
case CTRL('K'):
// clear to end of screen
screen->erase(Screen::EraseAfterCursor);
break;
case CTRL('L'):
// clear screen, go home.
screen->erase(Screen::EraseAll);
screen->setCursor(0, 0, true, true);
break;
case CTRL('M'):
// move to left edge.
// IIe also did a linefeed. [?]
screen->setX(0, true);
break;
case CTRL('N'):
// normal text.
screen->clearFlagBit(Screen::FlagInverse);
break;
case CTRL('O'):
// inverse text.
screen->setFlagBit(Screen::FlagInverse);
break;
case CTRL('Q'):
// 40 column mode.
break;
case CTRL('R'):
// 80 column mode
break;
case CTRL('S'):
// stop listing until another key pressed.
break;
case CTRL('U'):
// deactivate 80 column firmware
break;
case CTRL('V'):
// scroll down 1 line, leaving cursor at current position.
screen->deleteLine(0);
break;
case CTRL('W'):
// scroll up 1 line, leaving cursor at current position.
screen->insertLine(0);
break;
case CTRL('X'):
//mouse text off
screen->clearFlagBit(Screen::FlagMouseText);
break;
case CTRL('Y'):
// cursor home
screen->setCursor(0, 0, true, true);
break;
case CTRL('Z'):
// clear entire line
screen->erase(Screen::EraseLineAll);
break;
case CTRL('['):
// mouse text on
screen->setFlagBit(Screen::FlagMouseText);
break;
case CTRL('\\'):
// move cursor 1 character to the right
// TODO -- should wrap to next line.
screen->incrementX(true);
break;
case CTRL(']'):
// clear to end of line.
// TODO -- should also clear cursor.
screen->erase(Screen::EraseLineAfterCursor);
break;
case CTRL('^'):
// goto x y
_state = StateDCAX;
break;
case CTRL('_'):
// move up 1 line, no scroll.
screen->decrementY(true);
break;
default:
if (c >= 0x20 && c < 0x7f)
{
screen->putc(c);
}
break;
}
return;
}
switch (_state)
{
case StateDCAX:
_dca.x = c - 32;
_state = StateDCAY;
break;
case StateDCAY:
_dca.y = c - 32;
screen->setCursor(_dca);
_state = StateText;
break;
}
}
-(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output
{
NSEventModifierFlags flags = [event modifierFlags];
NSString *chars = [event charactersIgnoringModifiers];
NSUInteger length = [chars length];
for (unsigned i = 0; i < length; ++i)
{
unichar uc = [chars characterAtIndex: i];
switch (uc)
{
case NSEnterCharacter:
output->write(CTRL('M'));
break;
/*
case NSDeleteCharacter:
output->write(0x7f);
break;
*/
// the Apple II keyboard had a delete where the backspace key was.
// it functions as a backspace key.
case NSBackspaceCharacter:
output->write(0x7f);
break;
case NSLeftArrowFunctionKey:
output->write(CTRL('H'));
break;
case NSRightArrowFunctionKey:
output->write(CTRL('U'));
break;
case NSUpArrowFunctionKey:
output->write(CTRL('K'));
break;
case NSDownArrowFunctionKey:
output->write(CTRL('J'));
break;
default:
if (uc <= 0x7f)
{
char c = uc;
//NSLog(@"%@", event);
if (flags & NSAlphaShiftKeyMask)
{
c = flags & NSShiftKeyMask ? tolower(c) : toupper(c);
}
if (flags & NSControlKeyMask)
c = CTRL(c);
output->write(c);
}
break;
}
}
}
@end

396
Emulators/Apple80.mm.ragel Normal file
View File

@ -0,0 +1,396 @@
//
// Apple80.mm
// 2Term
//
// Created by Kelvin Sherlock on 12/23/2010.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
/*
* See Apple IIe Tech Ref page 273.
* See Apple IIgs Firmware Reference page 77
* See Apple IIe Extended 80-Column TextCard (revision B) appendix C.
*
*/
#import "Apple80.h"
#include <sys/ttydefaults.h>
#include "OutputChannel.h"
#include "Screen.h"
#include "algorithm.h"
%%{
machine console;
alphtype unsigned int;
action nop {}
action advance {
// advance cursor
if (++cursor.x == 80) {
cursor.x = 0;
if (cursor.y >= 24-1) {
screen->scrollUp();
} else cursor.y++;
}
}
arg1 = any ${ _scratch[0] = (fc - 32); };
arg2 = any ${ _scratch[1] = (fc - 32); };
main := (
0x00 $nop
| 0x01 $nop
| 0x02 $nop
| 0x03 $nop
| 0x04 $nop
| 0x05 ${
/* E - $05 - Turns cursor on (enables cursor display) */
screen->setCursorType(Screen::CursorTypeUnderscore);
}
| 0x06 ${
/* F - $06 - Turns cursor off (disables cursor display) */
screen->setCursorType(Screen::CursorTypeNone);
}
| 0x07 ${
/* G - $07 - beep 1000 hz for .1 seconds. */
NSBeep();
}
| 0x08 ${
/* H - $08 - Moves cursor left one column;
if cursor was at beginning of line, moves
it to end of previous line
*/
if (cursor.x) cursor.x--;
else {
cursor.x = 80-1;
// go up, possibly scrolling.
if (cursor.y) cursor.y--;
}
}
| 0x09 ${
// control-I
// tab -- todo, verify.
cursor.x = (cursor.x + 8) & ~7;
cursor.x = std::min(cursor.x, 79);
}
| 0x0a ${
/* J - $0A - Moves cursor down one row; scrolls if needed */
if (cursor.y >= 24-1) {
screen->scrollUp();
} else cursor.y++;
}
| 0x0b ${
/* K - $0B - Clears to end of screen */
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(80 - cursor.x, 1);
screen->eraseRect(tmp);
tmp = iRect(0, 0, 80, 24);
tmp.origin.y = cursor.y+1;
tmp.size.height -= cursor.y+1;
screen->eraseRect(tmp);
}
| 0x0c ${
// control-L
/* clear text port and home */
screen->eraseScreen();
cursor = iPoint(0,0);
}
| 0x0d ${
// control-M
/* carriage return */
// BASIC also moves to next line, PASCAL does not.
cursor.x = 0;
}
| 0x0e ${
// control-N
/* set normal display */
_context.clearFlagBit(Screen::FlagInverse);
}
| 0x0f ${
// control-O
/* set inverse display */
_context.setFlagBit(Screen::FlagInverse);
}
| 0x10 $nop
| 0x11 ${ /* ^Q 40 column mode */ }
| 0x12 ${ /* ^R 80 column mode */ }
| 0x13 ${ /* ^S - stop listing until any keypress. */ }
| 0x14 $nop
| 0x15 ${
/* ^U - deactivate 80 column? */
}
| 0x16 ${ /* CTRL('V') */ screen->scrollDown(); }
| 0x17 ${ /* CTRL('W') */ screen->scrollUp(); }
| 0x18 ${
// CTRL('X'):
/* disable mouse text */
_context.clearFlagBit(Screen::FlagMouseText);
}
| 0x19 ${
// CTRL('Y'):
/* home cursor */
cursor = iPoint(0,0);
}
| 0x1a ${
// CTRL('Z'):
/* clear line */
iRect tmp;
tmp.origin = iPoint(0, cursor.y);
tmp.size = iSize(80, 1);
screen->eraseRect(tmp);
}
| 0x1b ${
// CTRL('['):
/* ^[ enable mouse text mapping */
_context.setFlagBit(Screen::FlagMouseText);
}
| 0x1c ${
// CTRL('\\'):
/* Moves cursor right one column; if at end of line, does Control-M */
// n.b. - BASIC ^M also moves to next line.
cursor.x++;
if (cursor.x == 80) cursor.x = 0;
}
| 0x1d ${
// CTRL(']'):
/* clear to end of line */
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(80 - cursor.x, 1);
screen->eraseRect(tmp);
}
| 0x1e arg1 arg2 ${
// CTRL('^'):
/* goto x y */
// todo - verify behavior for illegal values.
cursor.x = clamp(_scratch[0], 0, 80 - 1);
cursor.y = clamp(_scratch[1], 0, 24 - 1);
}
| 0x1f ${
// CTRL('_'):
/* move cursor up */
if (cursor.y) cursor.y--;
}
| 0x20 .. 0x7f ${
screen->putc(fc, _context);
} $advance
| 0x80 .. 0x9f ${
/* uppercase inverse/normal */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
screen->putc(fc - 0x40, _context.cursor, flag);
} $advance
| 0xa0 .. 0xbf ${
/* special inverse/normal */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
screen->putc(fc - 0x80, _context.cursor, flag);
} $advance
| 0xc0 .. 0xdf ${
/* uppercase normal / mouse text. */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
if (flag) flag |= Screen::FlagMouseText;
screen->putc(fc - 0x80, _context.cursor, flag);
} $advance
| 0xe0 .. 0xff ${
/* special inverse/normal */
uint8_t flag = ~(_context.flags & Screen::FlagInverse);
screen->putc(fc - 0x80, _context.cursor, flag);
} $advance
)* $err{ fgoto main; };
write data;
}%%
@implementation Apple80
+(void)load
{
[EmulatorManager registerClass: self];
}
+(NSString *)name
{
return @"Apple 80";
}
-(NSString *)name
{
return @"Apple 80";
}
-(const char *)termName
{
return "appleIIe";
}
-(void)reset
{
%%write init;
_context.window = iRect(0, 0, 80, 24);
_context.cursor = iPoint(0,0);
_context.flags = 0;
}
-(BOOL)resizable
{
return NO;
}
-(struct winsize)defaultSize
{
struct winsize ws = { 24, 80, 0, 0 };
return ws;
}
-(void)initTerm: (struct termios *)term
{
// Control-U is used by the up-arrow key.
term->c_cc[VKILL] = CTRL('X');
}
-(id)init
{
if ((self = [super init]))
{
[self reset];
}
return self;
}
-(void)processData:(const uint8_t *)data length: (size_t)length screen:(Screen *)screen output:(OutputChannel *)output
{
const uint8_t *eof = nullptr;
const uint8_t *p = data;
const uint8_t *pe = data + length;
auto &cursor = _context.cursor;
%%write exec;
screen->setCursor(cursor);
}
-(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output
{
NSEventModifierFlags flags = [event modifierFlags];
NSString *chars = [event charactersIgnoringModifiers];
NSUInteger length = [chars length];
for (unsigned i = 0; i < length; ++i)
{
unichar uc = [chars characterAtIndex: i];
switch (uc)
{
case NSEnterCharacter:
output->write(CTRL('M'));
break;
/*
case NSDeleteCharacter:
output->write(0x7f);
break;
*/
// the Apple II keyboard had a delete where the backspace key was.
// it functions as a backspace key.
case NSBackspaceCharacter:
output->write(0x7f);
break;
case NSLeftArrowFunctionKey:
output->write(CTRL('H'));
break;
case NSRightArrowFunctionKey:
output->write(CTRL('U'));
break;
case NSUpArrowFunctionKey:
output->write(CTRL('K'));
break;
case NSDownArrowFunctionKey:
output->write(CTRL('J'));
break;
default:
if (uc <= 0x7f)
{
char c = uc;
//NSLog(@"%@", event);
if (flags & NSAlphaShiftKeyMask)
{
c = flags & NSShiftKeyMask ? tolower(c) : toupper(c);
}
if (flags & NSControlKeyMask)
c = CTRL(c);
output->write(c);
}
break;
}
}
}
@end

View File

@ -15,17 +15,11 @@
@interface GNOConsole : NSObject <Emulator>
{
unsigned _state;
TextPort _textPort;
iPoint _dca;
int _vp[4];
unsigned cs;
context _context;
Screen::CursorType _cursorType;
int _scratch[4];
}

View File

@ -1,497 +0,0 @@
//
// GNOConsole.mm
// 2Term
//
// Created by Kelvin Sherlock on 7/9/2010.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#include <sys/ttydefaults.h>
#import "GNOConsole.h"
#include "OutputChannel.h"
#include "Screen.h"
/*
* The GNO Console Driver.
* this was gleaned from the source code.
*
* 0x00 n/a
* 0x01 ^A - enable overstrike mode (IODP_gInsertFlag = 0)
* 0x02 ^B - enable insert mode (IODP_gInsertFlag = 1)
* 0x03 ^C - setport (IODP_GotoFlag = 3)
* 0x04 n/a
* 0x05 ^E - turn on cursor
* 0x06 ^F - turn off cursor
* 0x07 ^G - beep
* 0x08 ^H - left arrow
* 0x09 ^I - tab
* 0x0a ^J - Line Feed (checks IODP_Scroll)
* 0x0b ^K - clear EOP ???? up arrow???
* 0x0c ^L - form feed - clear screen
* 0x0d ^M - carriage return cursor = left margin
* 0x0e ^N - inverse off - invert flag &= 0x7fff
* 0x0f ^O - inverse on - invert flag |= 0x8000
* 0x10 n/a
* 0x11 ^Q - insert line
* 0x12 ^R - Delete Line
* 0x13 n/a
* 0x14 n/a
* 0x15 ^U - right arrow
* 0x16 ^V - scroll down 1 line
* 0x17 ^W - scroll up 1 line
* 0x18 ^X - mouse text off.
* 0x19 ^Y - cursor home.
* 0x1a ^Z - clear line
* 0x1b ^[ - mouse text on (inv flag | 0x4000)
* 0x1c ^\ - increment IODP_CH (kill?)
* 0x1d ^] -clear EOL
* 0x1e ^^ - goto xy (IODP_GotoFlag = 1)
* 0x1f ^_ - up arrow
*
* mouse text only applies if mouse text and inverse are on.
* set port - 0x03 '[' left-margin right-margin top-margin bottom-margin [any printable character]
*/
/*
this was gleaned from the kernel reference manual.
The new console driver supports all the features of the old 80-column Pascal firmware,
and adds a few extensions, with one exception - the codes that switched between 40 and
80 columns modes are not supported. It is not compatible with the GS/OS '.console'
driver. The control codes supported are as follows:
Hex ASCII Action
01 CTRL-A set cursor to flashing block
02 CTRL-B set cursor to flashing underscore
03 CTRL-C Begin "Set Text Window" sequence
05 CTRL-E Cursor on
06 CTRL-F Cursor off
07 CTRL-G Perform FlexBeep
08 CTRL-H Move left one character
09 CTRL-I Tab
0A CTRL-J Move down a line
0B CTRL-K Clear to EOP (end of screen)
0C CTRL-L Clear screen, home cursor
0D CTRL-M Move cursor to left edge of line
0E CTRL-N Normal text
0F CTRL-O Inverse text
11 CTRL-Q Insert a blank line at the current cursor position
12 CTRL-R Delete the line at the current cursor position.
15 CTRL-U Move cursor right one character
16 CTRL-V Scroll display down one line
17 CTRL-W Scroll display up one line
18 CTRL-X Normal text, mousetext off
19 CTRL-Y Home cursor
1A CTRL-Z Clear entire line
1B CTRL-[ MouseText on
1C CTRL-\ Move cursor one character to the right
1D CTRL-] Clear to end of line
1E CTRL-^ Goto XY
1F CTRL-_ Move up one line
(Note: the Apple IIgs Firmware Reference incorrectly has codes 05 and 06 reversed. The
codes listed here are correct for both GNO/ME and the Apple IIgs 80-column firmware)
The Set Text Window sequence (begun by a $03 code) works as follows:
CTRL-C '[' LEFT RIGHT TOP BOTTOM
CTRL-C is of course hex $03, and '[' is the open bracket character ($5B). TOP, BOTTOM,
LEFT, and RIGHT are single-byte ASCII values that represent the margin settings. Values
for TOP and BOTTOM range from 0 to 23; LEFT and RIGHT range from 0 to 79. TOP must be
numerically less than BOTTOM; LEFT must be less than RIGHT. Any impossible settings are
ignored, and defaults are used instead. The extra '[' in the sequence helps prevent the
screen from becoming confused in the event that random data is printed to the screen.
After a successful Set Text Window sequence, only the portion of the screen inside the
'window' will be accessible, and only the window will scroll; any text outside the
window is not affected.
*/
@implementation GNOConsole
enum {
StateText,
StateDCAX,
StateDCAY,
StateSetPort1,
StateSetPort2,
StateSetPort3,
StateSetPort4,
StateSetPort5
};
+(void)load
{
[EmulatorManager registerClass: self];
}
+(NSString *)name
{
return @"GNO Console";
}
-(NSString *)name
{
return @"GNO Console";
}
-(const char *)termName
{
return "gno-console";
}
-(void)reset
{
_state = StateText;
_textPort.frame = iRect(0, 0, 80, 24);
_textPort.cursor = iPoint(0,0);
_textPort.scroll = true;
_textPort.advanceCursor = true;
_textPort.leftMargin = TextPort::MarginWrap;
_textPort.rightMargin = TextPort::MarginWrap;
_cursorType = Screen::CursorTypeUnderscore;
// set flags to plain text.
}
-(BOOL)resizable
{
return NO;
}
-(struct winsize)defaultSize
{
struct winsize ws = { 24, 80, 0, 0 };
return ws;
}
-(void)initTerm: (struct termios *)term
{
// Control-U is used by the up-arrow key.
term->c_cc[VKILL] = CTRL('X');
}
-(id)init
{
if ((self = [super init]))
{
[self reset];
}
return self;
}
-(void)processCharacter:(uint8_t)c screen:(Screen *)screen output:(OutputChannel *)output
{
if (_state == StateText)
{
switch (c)
{
case CTRL('A'):
// set cursor to flashing block.
_cursorType = Screen::CursorTypeBlock;
screen->setCursorType(_cursorType);
break;
case CTRL('B'):
_cursorType = Screen::CursorTypeUnderscore;
screen->setCursorType((Screen::CursorType)_cursorType);
// set cursor to flashing underscore.
break;
case CTRL('C'):
// begin set text window sequence
_state = StateSetPort1;
break;
case CTRL('E'):
// cursor on
screen->setCursorType(_cursorType);
break;
case CTRL('F'):
//cursor off
screen->setCursorType(Screen::CursorTypeNone);
break;
case CTRL('G'):
NSBeep();
break;
case CTRL('H'):
screen->decrementX(&_textPort);
//screen->decrementX(true);
break;
case CTRL('I'):
// tab
screen->tabTo(&_textPort, (_textPort.cursor.x + 8) & ~0x07);
//screen->tabTo((screen->x() + 8) & ~0x07);
break;
case CTRL('J'):
// down 1 line.
screen->lineFeed(&_textPort);
break;
case CTRL('K'):
// clear to end of screen
screen->erase(&_textPort, Screen::EraseAfterCursor);
break;
case CTRL('L'):
// clear screen, go home.
screen->erase(&_textPort, Screen::EraseAll);
screen->setCursor(&_textPort, 0, 0);
break;
case CTRL('M'):
// move to left edge.
screen->setX(&_textPort, 0);
break;
case CTRL('N'):
// normal text.
screen->clearFlagBit(Screen::FlagInverse);
break;
case CTRL('O'):
// inverse text.
screen->setFlagBit(Screen::FlagInverse);
break;
case CTRL('Q'):
// insert line.
// TODO -- verify textPort
screen->insertLine(&_textPort, _textPort.cursor.y);
break;
case CTRL('R'):
// delete line
// TODO -- verify textPort
screen->deleteLine(&_textPort, _textPort.cursor.y);
break;
case CTRL('U'):
// right arrow.
screen->incrementX(&_textPort);
break;
case CTRL('V'):
// scroll down 1 line.
screen->insertLine(&_textPort, 0);
break;
case CTRL('W'):
// scroll up 1 line.
screen->deleteLine(&_textPort, 0);
break;
case CTRL('X'):
//mouse text off
screen->clearFlagBit(Screen::FlagMouseText);
break;
case CTRL('Y'):
// cursor home
screen->setCursor(&_textPort, 0, 0);
break;
case CTRL('Z'):
// clear entire line
screen->erase(&_textPort, Screen::EraseLineAll);
break;
case CTRL('['):
// mouse text on
// inverse must also be on.
screen->setFlagBit(Screen::FlagMouseText);
break;
case CTRL('\\'):
// move cursor 1 character to the right
screen->incrementX(&_textPort);
break;
case CTRL(']'):
// clear to end of line.
screen->erase(&_textPort, Screen::EraseLineAfterCursor);
break;
case CTRL('^'):
// goto x y
_state = StateDCAX;
break;
case CTRL('_'):
// move up 1 line
screen->decrementY(&_textPort);
break;
default:
if (c >= 0x20 && c < 0x7f)
{
screen->putc(&_textPort, c);
}
break;
}
return;
}
switch (_state)
{
case StateDCAX:
_dca.x = (c & 0x7f) - 32;
_state = StateDCAY;
break;
case StateDCAY:
_dca.y = (c & 0x7f) - 32;
// goto xy does not respect the text window.
if (_dca.x >= 80) _dca.x = 0;
if (_dca.y >= 24) _dca.y = 0;
screen->setCursor(&_textPort, _dca);
//screen->setCursor(_dca);
_state = StateText;
break;
case StateSetPort1:
// [
if (c == '[')
_state++;
else
_state = StateText;
break;
case StateSetPort2:
// left
_vp[0] = (c & 0x7f) - 32;
_state++;
break;
case StateSetPort3:
// right
_vp[1] = (c & 0x7f) - 32 + 1;
_state++;
break;
case StateSetPort4:
// top
_vp[2] = (c & 0x7f) - 32;
_state++;
break;
case StateSetPort5:
// bottom
// and validation.
_vp[3] = (c & 0x7f) - 32 + 1;
_vp[0] = std::max(0, _vp[0]);
_vp[2] = std::max(0, _vp[2]);
_vp[1] = std::min(80, _vp[1]);
_vp[3] = std::min(24, _vp[3]);
if (_vp[1] <= _vp[0]) _vp[1] = 80;
if (_vp[3] <= _vp[2]) _vp[3] = 24;
_textPort.frame = iRect(_vp[0], _vp[2], _vp[1] - _vp[0], _vp[3] - _vp[2]);
// move the cursor to the top left
// gnome clamps the horizontal, doesn't adjust the vertical.
screen->setCursor(&_textPort, iPoint(0,0));
_state = StateText;
}
}
-(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output
{
NSEventModifierFlags flags = [event modifierFlags];
NSString *chars = [event charactersIgnoringModifiers];
NSUInteger length = [chars length];
for (unsigned i = 0; i < length; ++i)
{
unichar uc = [chars characterAtIndex: i];
switch (uc)
{
case NSEnterCharacter:
output->write(CTRL('M'));
break;
/*
case NSDeleteCharacter:
output->write(0x7f);
break;
*/
case NSBackspaceCharacter:
output->write(0x7f);
break;
case NSLeftArrowFunctionKey:
output->write(CTRL('H'));
break;
case NSRightArrowFunctionKey:
output->write(CTRL('U'));
break;
case NSUpArrowFunctionKey:
output->write(CTRL('K'));
break;
case NSDownArrowFunctionKey:
output->write(CTRL('J'));
break;
default:
if (uc <= 0x7f)
{
char c = uc;
if (flags & (NSShiftKeyMask | NSAlphaShiftKeyMask))
{
c = toupper(c);
}
if (flags & NSControlKeyMask)
c = CTRL(c);
output->write(c);
}
break;
}
}
}
@end

View File

@ -0,0 +1,536 @@
//
// GNOConsole.mm
// 2Term
//
// Created by Kelvin Sherlock on 7/9/2010.
// Copyright 2010 __MyCompanyName__. All rights reserved.
//
#include <sys/ttydefaults.h>
#import "GNOConsole.h"
#include "OutputChannel.h"
#include "Screen.h"
/*
* The GNO Console Driver.
* this was gleaned from the source code.
*
* 0x00 n/a
* 0x01 ^A - enable overstrike mode (IODP_gInsertFlag = 0)
* 0x02 ^B - enable insert mode (IODP_gInsertFlag = 1)
* 0x03 ^C - setport (IODP_GotoFlag = 3)
* 0x04 n/a
* 0x05 ^E - turn on cursor
* 0x06 ^F - turn off cursor
* 0x07 ^G - beep
* 0x08 ^H - left arrow
* 0x09 ^I - tab
* 0x0a ^J - Line Feed (checks IODP_Scroll)
* 0x0b ^K - clear EOP ???? up arrow???
* 0x0c ^L - form feed - clear screen
* 0x0d ^M - carriage return cursor = left margin
* 0x0e ^N - inverse off - invert flag &= 0x7fff
* 0x0f ^O - inverse on - invert flag |= 0x8000
* 0x10 n/a
* 0x11 ^Q - insert line
* 0x12 ^R - Delete Line
* 0x13 n/a
* 0x14 n/a
* 0x15 ^U - right arrow
* 0x16 ^V - scroll down 1 line
* 0x17 ^W - scroll up 1 line
* 0x18 ^X - mouse text off.
* 0x19 ^Y - cursor home.
* 0x1a ^Z - clear line
* 0x1b ^[ - mouse text on (inv flag | 0x4000)
* 0x1c ^\ - increment IODP_CH (kill?)
* 0x1d ^] -clear EOL
* 0x1e ^^ - goto xy (IODP_GotoFlag = 1)
* 0x1f ^_ - up arrow
*
* mouse text only applies if mouse text and inverse are on.
* set port - 0x03 '[' left-margin right-margin top-margin bottom-margin [any printable character]
*/
/*
this was gleaned from the kernel reference manual.
The new console driver supports all the features of the old 80-column Pascal firmware,
and adds a few extensions, with one exception - the codes that switched between 40 and
80 columns modes are not supported. It is not compatible with the GS/OS '.console'
driver. The control codes supported are as follows:
Hex ASCII Action
01 CTRL-A set cursor to flashing block
02 CTRL-B set cursor to flashing underscore
03 CTRL-C Begin "Set Text Window" sequence
05 CTRL-E Cursor on
06 CTRL-F Cursor off
07 CTRL-G Perform FlexBeep
08 CTRL-H Move left one character
09 CTRL-I Tab
0A CTRL-J Move down a line
0B CTRL-K Clear to EOP (end of screen)
0C CTRL-L Clear screen, home cursor
0D CTRL-M Move cursor to left edge of line
0E CTRL-N Normal text
0F CTRL-O Inverse text
11 CTRL-Q Insert a blank line at the current cursor position
12 CTRL-R Delete the line at the current cursor position.
15 CTRL-U Move cursor right one character
16 CTRL-V Scroll display down one line
17 CTRL-W Scroll display up one line
18 CTRL-X Normal text, mousetext off
19 CTRL-Y Home cursor
1A CTRL-Z Clear entire line
1B CTRL-[ MouseText on
1C CTRL-\ Move cursor one character to the right
1D CTRL-] Clear to end of line
1E CTRL-^ Goto XY
1F CTRL-_ Move up one line
(Note: the Apple IIgs Firmware Reference incorrectly has codes 05 and 06 reversed. The
codes listed here are correct for both GNO/ME and the Apple IIgs 80-column firmware)
The Set Text Window sequence (begun by a $03 code) works as follows:
CTRL-C '[' LEFT RIGHT TOP BOTTOM
CTRL-C is of course hex $03, and '[' is the open bracket character ($5B). TOP, BOTTOM,
LEFT, and RIGHT are single-byte ASCII values that represent the margin settings. Values
for TOP and BOTTOM range from 0 to 23; LEFT and RIGHT range from 0 to 79. TOP must be
numerically less than BOTTOM; LEFT must be less than RIGHT. Any impossible settings are
ignored, and defaults are used instead. The extra '[' in the sequence helps prevent the
screen from becoming confused in the event that random data is printed to the screen.
After a successful Set Text Window sequence, only the portion of the screen inside the
'window' will be accessible, and only the window will scroll; any text outside the
window is not affected.
*/
%%{
machine console;
alphtype unsigned int;
action nop {}
action forward {
if (cursor.x > window.maxX()-1) {
cursor.x = window.minX();
if (cursor.y >= window.maxY()-1) {
screen->scrollUp(window);
} else cursor.y++;
}
}
arg1 = any ${ _scratch[0] = ((fc & 0x7f) - 32); };
arg2 = any ${ _scratch[1] = ((fc & 0x7f) - 32); };
arg3 = any ${ _scratch[2] = ((fc & 0x7f) - 32); };
arg4 = any ${ _scratch[3] = ((fc & 0x7f) - 32); };
main := (
0x00 $nop
| 0x01 ${
// CTRL(A)
// set cursor to flashing block.
_cursorType = Screen::CursorTypeBlock;
screen->setCursorType(_cursorType);
}
| 0x02 ${
// CTRL('B')
// set cursor to flashing underscore.
_cursorType = Screen::CursorTypeUnderscore;
screen->setCursorType((Screen::CursorType)_cursorType);
}
| 0x03 '[' arg1 arg2 arg3 arg4 ${
// CTRL('C'):
// '[' left right top bottom
// n.b. - 0, 79, 0, 23 is full screen.
_scratch[0] = std::max(0, _scratch[0]);
_scratch[2] = std::max(0, _scratch[2]);
_scratch[1] = std::min(80-1, _scratch[1])+1;
_scratch[3] = std::min(24-1, _scratch[3])+1;
if (_scratch[1] <= _scratch[0]) _scratch[1] = 80;
if (_scratch[3] <= _scratch[2]) _scratch[3] = 24;
window = iRect(
iPoint(_scratch[0], _scratch[2]),
iPoint(_scratch[1], _scratch[3])
);
// move the cursor to the top left
// gnome clamps the horizontal, doesn't adjust the vertical.
//screen->setCursor(&_textPort, iPoint(0,0));
if (cursor.x < _scratch[0]) cursor.x = _scratch[0];
if (cursor.x >= _scratch[1]) cursor.x = _scratch[1] - 1;
}
| 0x04 $nop
| 0x05 ${
// CTRL('E'):
// cursor on
screen->setCursorType(_cursorType);
}
| 0x06 ${
//CTRL('F'):
//cursor off
screen->setCursorType(Screen::CursorTypeNone);
}
| 0x07 ${
//CTRL('G'):
NSBeep();
}
| 0x08 ${
// CTRL('H'):
if (cursor.x == window.minX()) {
cursor.x = window.maxX()-1;
// go up, possibly scrolling.
if (cursor.y != window.minY()) cursor.y--;
}
else cursor.x--;
}
| 0x09 ${
// CTRL('I'):
// tab
cursor.x = (cursor.x + 8) & ~ 0x07;
} $forward
| 0x0a ${
// CTRL('J'):
// down 1 line.
if (cursor.y >= window.maxY()-1) {
screen->scrollUp(window);
} else cursor.y++;
}
| 0x0b ${
// CTRL('K'):
// clear to end of screen
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(window.size.width - cursor.x, 1);
screen->eraseRect(tmp);
tmp = window;
tmp.origin.y = cursor.y+1;
tmp.size.height -= cursor.y+1;
screen->eraseRect(tmp);
}
| 0x0c ${
// CTRL('L'):
// clear screen, go home.
screen->eraseRect(window);
cursor = window.origin;
}
| 0x0d ${
// CTRL('M'):
// move to left edge.
cursor.x = window.minX();
}
| 0x0e ${
// CTRL('N'):
// normal text.
_context.clearFlagBit(Screen::FlagInverse);
}
| 0x0f ${
// CTRL('O'):
// inverse text.
_context.setFlagBit(Screen::FlagInverse);
}
| 0x10 $nop
| 0x11 ${
// CTRL('Q'):
// insert line.
iRect tmp(iPoint(window.minX(), cursor.y), window.bottomRight());
screen->scrollDown(tmp);
}
| 0x12 ${
// CTRL('R'):
// delete line
iRect tmp(iPoint(window.minX(), cursor.y), window.bottomRight());
screen->scrollUp(tmp);
}
| 0x13 $nop
| 0x14 $nop
| 0x15 $forward ${
// CTRL('U'):
// right arrow.
cursor.x++;
} $forward
| 0x16 ${
// CTRL('V'):
// scroll down 1 line.
screen->scrollDown(window);
}
| 0x17 ${
// CTRL('W'):
// scroll up 1 line.
screen->scrollUp(window);
}
| 0x18 ${
// CTRL('X'):
//mouse text off
_context.clearFlagBit(Screen::FlagMouseText);
}
| 0x19 ${
// CTRL('Y'):
// cursor home
cursor.x = 0;
cursor.y = 0;
}
| 0x1a ${
// CTRL('Z'):
// clear entire line
iRect tmp;
tmp.origin = iPoint(window.origin.x, cursor.y);
tmp.size = iSize(window.size.width, 1);
screen->eraseRect(tmp);
}
| 0x1b ${
// CTRL('['):
// mouse text on
// inverse must also be on.
_context.setFlagBit(Screen::FlagMouseText);
}
| 0x1c ${
// CTRL('\\'):
// move cursor 1 character to the right
cursor.x++;
}
| 0x1d ${
// CTRL(']'):
// clear to end of line.
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(window.size.width - cursor.x, 1);
screen->eraseRect(tmp);
}
| 0x1e arg1 arg2 ${
// CTRL('^'):
// goto x y
// goto xy does not respect the text window.
if (_scratch[0] >= 80) _scratch[0] = 0;
if (_scratch[1] >= 24) _scratch[1] = 0;
cursor = iPoint(_scratch[0], _scratch[1]);
}
| 0x1f ${
// CTRL('_'):
// move up 1 line
if (cursor.y != window.minY()) cursor.y--;
}
| 0x20 .. 0x7f $forward ${
screen->putc(fc, _context);
cursor.x++;
}
| 0x80 .. 0xff $nop
)* $err{ fgoto main; };
write data;
}%%
@implementation GNOConsole
+(void)load
{
[EmulatorManager registerClass: self];
}
+(NSString *)name
{
return @"GNO Console";
}
-(NSString *)name
{
return @"GNO Console";
}
-(const char *)termName
{
return "gno-console";
}
-(void)reset
{
%%write init;
_context.flags = 0;
_context.window = iRect(0, 0, 80, 24);
_context.cursor = iPoint(0,0);
_cursorType = Screen::CursorTypeUnderscore;
// set flags to plain text.
}
-(BOOL)resizable
{
return NO;
}
-(struct winsize)defaultSize
{
struct winsize ws = { 24, 80, 0, 0 };
return ws;
}
-(void)initTerm: (struct termios *)term
{
// Control-U is used by the up-arrow key.
term->c_cc[VKILL] = CTRL('X');
}
-(id)init
{
if ((self = [super init]))
{
[self reset];
}
return self;
}
-(void)processData:(const uint8_t *)data length: (size_t)length screen:(Screen *)screen output:(OutputChannel *)output
{
const uint8_t *eof = nullptr;
const uint8_t *p = data;
const uint8_t *pe = data + length;
iPoint &cursor = _context.cursor;
iRect &window = _context.window;
%%write exec;
if (cursor.x == 80) screen->setCursor(iPoint(79, cursor.y));
else screen->setCursor(cursor);
}
-(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output
{
NSEventModifierFlags flags = [event modifierFlags];
NSString *chars = [event charactersIgnoringModifiers];
NSUInteger length = [chars length];
for (unsigned i = 0; i < length; ++i)
{
unichar uc = [chars characterAtIndex: i];
switch (uc)
{
case NSEnterCharacter:
output->write(CTRL('M'));
break;
/*
case NSDeleteCharacter:
output->write(0x7f);
break;
*/
case NSBackspaceCharacter:
output->write(0x7f);
break;
case NSLeftArrowFunctionKey:
output->write(CTRL('H'));
break;
case NSRightArrowFunctionKey:
output->write(CTRL('U'));
break;
case NSUpArrowFunctionKey:
output->write(CTRL('K'));
break;
case NSDownArrowFunctionKey:
output->write(CTRL('J'));
break;
default:
if (uc <= 0x7f)
{
char c = uc;
if (flags & (NSShiftKeyMask | NSAlphaShiftKeyMask))
{
c = toupper(c);
}
if (flags & NSControlKeyMask)
c = CTRL(c);
output->write(c);
}
break;
}
}
}
@end

View File

@ -12,18 +12,26 @@
#include "iGeometry.h"
#include "Screen.h"
struct gsos_context : public context {
bool consWrap = true;
bool consAdvance = true;
bool consLF = true;
bool consScroll = true;
bool consVideo = true;
bool consDLE = true;
bool consMouse = false;
uint8_t consFill = 0xa0;
};
@interface GSOSConsole : NSObject <Emulator> {
gsos_context _context;
std::vector<gsos_context> _context_stack;
unsigned cs;
TextPort _textPort;
std::vector<TextPort> _tpStack;
int _scratch[4];
int _cursorType;
bool _consLF;
bool _consDLE;
}
@end

View File

@ -13,6 +13,22 @@
#include "algorithm.h"
// currently no way to set consFill :-)
static char_info remap_fill(const gsos_context &ctx) { return char_info(' ', 0); }
static void advance(Screen *screen, gsos_context &ctx) {
if (ctx.consAdvance) {
if (ctx.cursor.x < ctx.window.maxX() - 1) ctx.cursor.x++;
else if (ctx.consWrap) {
ctx.cursor.x = ctx.window.minX();
if (ctx.cursor.y < ctx.window.maxY() - 1) ctx.cursor.y++;
else if (ctx.consScroll) screen->scrollUp(ctx.window);
}
}
}
%%{
machine console;
alphtype unsigned int;
@ -24,21 +40,32 @@
arg3 = any ${ _scratch[2] = (fc - 32); };
arg4 = any ${ _scratch[3] = (fc - 32); };
action advance_if {
if (_context.consAdvance) advance(screen, _context);
}
main := (
0x00 $nop
| 0x01 ${
/* save current textport and reset text port to default. */
/*
Save Current Text Port and Reset Default Text Port
Saves the current text port and resets to the default text port. If the system is out of memory, no error is returned, and the text port is simply reset.
*/
_tpStack.push_back(_textPort);
// todo -- consLF, consDLE?
_textPort = TextPort();
_context_stack.push_back(_context);
_context = gsos_context();
_context.cursor = iPoint(0,0);
_context.window = iRect(0, 0, 80, 24);
}
| 0x02 arg1 arg2 arg3 arg4 ${
/* set the current text port */
/*
Set Text Port Size
// left, top, right, bottom
Accepts the next four bytes as absolute screen coordinates + 32. Sets the current text port to the new parameters. The parameters are in the following order: windLeft, windTop, windRight, windBottom. Any parameter outside the screen boundaries is clipped to a legal value. The cursor is set to the upper-left corner of the new text port.
*/
_scratch[0] = clamp(_scratch[0], 0, 80-1);
_scratch[1] = clamp(_scratch[1], 0, 24-1);
@ -47,101 +74,193 @@
_scratch[3] = clamp(_scratch[3], 0, 24-1)+1;
iRect r(_scratch[0],
window = iRect(_scratch[0],
_scratch[1],
_scratch[2] - _scratch[0],
_scratch[3] - _scratch[1]
);
_textPort.frame = r;
screen->setCursor(&_textPort, 0, 0);
cursor = window.origin;
}
| 0x03 ${
/* clear from beginning of line */
// todo -- should also include the cursor.
screen->erase(&_textPort, Screen::EraseLineBeforeCursor);
}
| 0x04 ${
/* pop text port */
if (!_tpStack.empty()) {
_textPort = _tpStack.back();
_tpStack.pop_back();
| 0x03 ${
/*
Clear from Beginning of Line
Clears all characters from the left edge to and including the cursor. Sets them to the current consFill character.
*/
char_info ci = remap_fill(_context);
iRect tmp(
iPoint(window.minX(), cursor.y),
iPoint(cursor.x+1, cursor.y+1)
);
screen->fillRect(tmp, ci);
}
| 0x04 ${
/*
Pop Text Port
Restores the text port to the most recently saved value (see code $01). If no saved ports exist, resets the text port to the default values. If an 80-column text port is pushed and subsequently restored in 40-column mode, the text port may be altered to fit in the 40-column screen (see code $11, Set 40-Column Mode).
*/
if (!_context_stack.empty()) {
_context = _context_stack.back();
_context_stack.pop_back();
} else {
_textPort = TextPort();
_context = gsos_context();
}
}
| 0x05 any ${
/* horizontal scroll */
/*
Horizontal Scroll
Interprets the next byte as an 8-bit signed integer depicting the number (N) of
columns to shift. N equal to zero is a null operation. If N is less than zero, the text
port is shifted to the left; A greater than zero shifts to the right. If the shift magnitude is equal to or greater than windWidth, the text port is cleared.
The shifted characters are moved directly to their destination location. The space vacated by the shifted characters is set to the current consFill character (see the description of consFill earlier in this chapter). Characters shifted out of the text port are removed from the screen and are not recoverable.
*/
int8_t n = fc;
// ....
// .... TODO
}
| 0x06 any ${
/* set vertical position */
unsigned n = clamp(fc - 32, 0, 24-1);
screen->setY(&_textPort, n);
/*
Set Vertical Position
Interprets the next byte as a text port-relative vertical position + 32. If the destination is outside the current text port, the cursor is moved to the nearest edge.
*/
unsigned n = clamp(fc - 32, 0, window.height()-1);
cursor.y = window.minY() + n;
}
| 0x07 ${
/*
Ring Bell
Causes the System Beep to be played. It has no effect on the screen.
*/
NSBeep();
}
| 0x08 ${
/* back space */
screen->decrementX(&_textPort);
/*
Backspace
Moves the cursor one position to the left. If the cursor was on the left edge of the
text port and consWrap is TRUE, the cursor is placed one row higher and at the right edge. If the cursor was also on the topmost row and consScroll is TRUE, thetext port will scroll backward one line.
*/
if (cursor.x > window.minX()) cursor.x--;
else if (_context.consWrap) {
cursor.x = window.maxX() - 1;
if (cursor.y > window.minY()) cursor.y--;
else if (_context.consScroll) screen->scrollDown(window);
}
}
| 0x09 $nop
| 0x0a ${
/* line feed */
screen->lineFeed(&_textPort);
/*
Line Feed
Causes the cursor to move down one line. If the cursor was at the bottom edge of the text port and consScroll is TRUE, the text port scrolls up one line.
*/
if (cursor.y < window.maxY()-1) cursor.y++;
else if (_context.consScroll)
screen->scrollUp(window);
}
| 0x0b ${
/* clear to end of text port */
/* actually sets them to consFill */
screen->erase(&_textPort, Screen::EraseAfterCursor);
/*
Clear to End of Text Port
Clears all characters from the cursor to the end of the current text port and sets them to be equal to the current consFill character.
*/
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(window.size.width - cursor.x, 1);
screen->eraseRect(tmp);
tmp = window;
tmp.origin.y = cursor.y+1;
tmp.size.height -= cursor.y+1;
screen->eraseRect(tmp);
}
| 0x0c ${
/* clear text port and home */
screen->erase(&_textPort, Screen::EraseAll);
screen->setCursor(&_textPort, 0, 0);
/*
Clear Text Port and Home Cursor
Clears the entire text port and resets the cursor to windLeft, windTop.
*/
screen->eraseRect(window);
cursor = window.origin;
}
| 0x0d ${
/* carriage return */
screen->setX(&_textPort, 0);
if (_consLF) {
screen->lineFeed(&_textPort);
/*
Carriage Return
Resets the cursor to the left edge of the text port; if consLF is TRUE, performs a line feed (see $0A, Line Feed).
*/
cursor.x = window.minX();
if (_context.consLF) {
if (cursor.y < window.maxY() - 1) cursor.y++;
else if (_context.consScroll) screen->scrollUp(window);
}
}
| 0x0e ${
/* set normal display */
screen->clearFlagBit(Screen::FlagInverse);
/*
Set Normal Display Mode
After this character, displays all subsequent characters in normal mode,
*/
_context.clearFlagBit(Screen::FlagInverse);
_context.consFill = 0xa0;
_context.consVideo = true;
}
| 0x0f ${
/* set inverse display */
screen->setFlagBit(Screen::FlagInverse);
/*
Set Inverse Display Mode
After this character, displays all subsequent characters in inverse mode.
*/
_context.setFlagBit(Screen::FlagInverse);
_context.consFill = 0x20;
_context.consVideo = false;
}
| 0x10 any ${
/* DLE expansion */
if (_consDLE) {
/*
DLE Space Expansion
If consDLE is TRUE, interprets the next character as number of spaces + 32, and the
correct number of spaces is issued to die screen. If consDLE is FALSE, the DLE character is ignored and the following character is processed normally.
*/
if (_context.consDLE) {
unsigned count = (fc - 32) & 0xff;
while (count--) screen->putc(&_textPort, ' ');
char_info ci = remap_fill(_context);
if (_context.consAdvance) {
while (count--) {
screen->putc(' ', _context);
if (_context.consAdvance) advance(screen, _context);
}
}
else {
if (count) screen->putc(' ', _context);
}
}
else { fhold; }
}
@ -150,110 +269,173 @@
| 0x12 ${ /* 80 column mode */ }
| 0x13 ${
/* clear from beginning of text port */
screen->erase(&_textPort, Screen::EraseBeforeCursor);
// todo -- clears up to and including cursor location!
}
| 0x14 any ${
/* set horizontal position */
unsigned n = clamp(fc - 32, 0, 80 - 1);
screen->setX(&_textPort, n);
/*
Set Horizontal Position
Interprets the next byte as a text port-relative horizontal position + 32. If the destination is outside the current text port, the cursor is moved to the nearest edge.
*/
unsigned n = clamp(fc - 32, 0, window.width() - 1);
cursor.x = window.minX() + n;
}
| 0x15 any ${
/* set cursor movement */
/*
Set Cursor Movement Word
Interprets the next byte as cursor movement control, and sets the values of these Boolean flags:
*/
unsigned flags = fc;
_textPort.advanceCursor = flags & 0x01;
_consLF = flags & 0x02;
if (flags & 0x04) {
_textPort.leftMargin = TextPort::MarginWrap;
_textPort.rightMargin = TextPort::MarginWrap;
} else {
_textPort.leftMargin = TextPort::MarginTruncate;
_textPort.rightMargin = TextPort::MarginTruncate;
}
_textPort.scroll = flags & 0x08;
_consDLE = flags & 0x10;
_context.consAdvance = flags & 0x01;
_context.consLF = flags & 0x02;
_context.consWrap = flags & 0x04;
_context.consScroll = flags & 0x08;
_context.consDLE = flags & 0x10;
}
| 0x16 ${ /* scroll down 1 line */ }
| 0x16 ${
/*
Scroll Down One Line
Scrolls the text port down one line. Does not move the cursor.
*/
screen->scrollDown(window);
}
| 0x17 ${ /* scroll up one line */ }
| 0x16 ${
/*
Scroll Up One Line
Scrolls the text port up one line. Does not move the cursor.
*/
screen->scrollUp(window);
}
| 0x18 ${
/* disable mouse text */
screen->clearFlagBit(Screen::FlagMouseText);
/*
Disable MouseText Mapping
When MouseText is disabled, uppercase inverse characters are displayed as such (see the section "Character Set Mapping" earlier in this chapter).
*/
_context.clearFlagBit(Screen::FlagMouseText);
_context.consMouse = false;
}
| 0x19 ${
/* home cursor */
screen->setCursor(&_textPort, 0, 0);
/*
Home Cursor
Resets the cursor to the upper-left corner of the text port.
*/
cursor = window.origin;
}
| 0x1a ${
/* clear line */
screen->erase(&_textPort, Screen::EraseLineAll);
screen->setX(&_textPort, 0);
/*
Clear Line
Clears the line that the cursor is on. Resets the cursor to the leftmost column in the window.
*/
iRect tmp;
tmp.origin = iPoint(window.origin.x, cursor.y);
tmp.size = iSize(window.size.width, 1);
screen->eraseRect(tmp);
}
| 0x1b ${
/* enable mouse text mapping */
screen->setFlagBit(Screen::FlagMouseText);
/*
Enable MouseText Mapping
When MouseText is enabled, uppercase inverse letters are displayed as MouseText symbols (see the section "Character Set Mapping" earlier in this chapter).
*/
_context.setFlagBit(Screen::FlagMouseText);
_context.consMouse = true;
}
| 0x1c ${
/* move cursor right */
screen->incrementX(&_textPort);
/*
Move Cursor Right
Performs a nondestructive forward-space of the cursor. If consWrap is TRUE,
the cursor may go to the next line; if consScroll is TRUE, the screen may scroll up one line.
*/
advance(screen, _context);
}
| 0x1d ${
/* clear to end of line */
screen->erase(&_textPort, Screen::EraseLineAfterCursor);
/*
Clear to End of Line
Clears from the position underneath the cursor to the end of the current line.
*/
iRect tmp;
tmp.origin = cursor;
tmp.size = iSize(window.size.width - cursor.x, 1);
screen->eraseRect(tmp);
}
| 0x1e arg1 arg2
${ /* goto x y */
| 0x1e arg1 arg2 ${
/*
Go to X,Y
Adjusts the cursor position relative to the text port. The parameters passed are X+32
and Y+32. If the new locations are outside the current text port, the cursor is placed on the nearest edge.
*/
iPoint dca;
dca.x = clamp(_scratch[0], 0, 80 - 1);
dca.y = clamp(_scratch[1], 0, 24 - 1);
screen->setCursor(&_textPort, dca);
dca.x = clamp(_scratch[0], 0, window.width() - 1);
dca.y = clamp(_scratch[1], 0, window.height() - 1);
cursor.x = dca.x + window.minX();
cursor.y = dca.y + window.minY();
cursor = dca;
}
| 0x1f ${
/* move cursor up */
screen->reverseLineFeed(&_textPort);
/*
Move Cursor Up
Moves the cursor up one line (reverse line feed). If the cursor is already on the
uppermost line of the textport and consScroll isTRUE, it will cause a reverse scroll.
*/
if (cursor.y > window.minY()) cursor.y--;
else if (_context.consScroll) screen->scrollDown(window);
}
| 0x20 .. 0x7f ${
screen->putc(&_textPort, fc);
}
screen->putc(fc, _context);
} $advance_if
| 0x80 .. 0x9f ${
/* uppercase inverse/normal */
uint8_t flag = ~(screen->flag() & Screen::FlagInverse);
screen->putc(&_textPort, fc - 0x40, flag);
}
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
screen->putc(fc - 0x40, cursor, flags);
} $advance_if
| 0xa0 .. 0xbf ${
/* special inverse/normal */
uint8_t flag = ~(screen->flag() & Screen::FlagInverse);
screen->putc(&_textPort, fc - 0x80, flag);
}
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
screen->putc(fc - 0x80, cursor, flags);
} $advance_if
| 0xc0 .. 0xdf ${
/* uppercase normal / mouse text. */
uint8_t flag = ~(screen->flag() & Screen::FlagInverse);
if (flag) flag |= Screen::FlagMouseText;
screen->putc(&_textPort, fc - 0x80, flag);
}
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
if (flags) flags |= Screen::FlagMouseText;
screen->putc(fc - 0x80, cursor, flags);
} $advance_if
| 0xe0 .. 0xff ${
/* special inverse/normal */
uint8_t flag = ~(screen->flag() & Screen::FlagInverse);
screen->putc(&_textPort, fc - 0x80, flag);
}
uint8_t flags = ~(_context.flags & Screen::FlagInverse);
screen->putc(fc - 0x80, cursor, flags);
} $advance_if
)* $err{ fgoto main; };
@ -319,21 +501,24 @@
%%write init;
_textPort.frame = iRect(0, 0, 80, 24);
_textPort.cursor = iPoint(0,0);
_textPort.scroll = true;
_textPort.advanceCursor = true;
_textPort.leftMargin = TextPort::MarginWrap;
_textPort.rightMargin = TextPort::MarginWrap;
_context.window = iRect(0, 0, 80, 24);
_context.cursor = iPoint(0,0);
_context.consWrap = true;
_context.consAdvance = true;
_context.consLF = true;
_context.consScroll = true;
_context.consVideo = true;
_context.consDLE = true;
_context.consMouse = false;
_context.consFill = 0xa0;
_cursorType = Screen::CursorTypeUnderscore;
_consLF = true;
_consDLE = true;
// set flags to plain text.
}
-(void)processData:(const uint8_t *)data length: (size_t)length screen:(Screen *)screen output:(OutputChannel *)output
{
@ -341,8 +526,10 @@
const uint8_t *p = data;
const uint8_t *pe = data + length;
auto &cursor = _context.cursor;
auto &window = _context.window;
%%write exec;
screen->setCursor(cursor);
}
-(void)keyDown:(NSEvent *)event screen:(Screen *)screen output:(OutputChannel *)output

View File

@ -11,8 +11,8 @@
#import "CurveView.h"
#import "EmulatorWindow.h"
#import "VT52.h"
#import "PTSE.h"
//#import "VT52.h"
//#import "PTSE.h"
#import "Defaults.h"
@ -309,7 +309,8 @@
klass = [_parameters objectForKey: kClass];
if (!klass || ![klass conformsToProtocol: @protocol(Emulator)])
{
klass = [VT52 class];
klass = Nil;
//klass = [VT52 class];
}
o = [_parameters objectForKey: kForegroundColor];

View File

@ -101,7 +101,17 @@
}
else
{
unsigned char c;
switch (cursorType) {
default:
case Screen::CursorTypeUnderscore: c = '_'; break;
case Screen::CursorTypePipe: c = '|'; break;
case Screen::CursorTypeBlock: c = 0x80; break;
}
[_cursorImg release];
_cursorImg = [[_charGen imageForCharacter: c] retain];
[self startCursorTimer];
}
@ -341,7 +351,7 @@
{
NSRect charRect = NSMakeRect(_paddingLeft + x * _charWidth, _paddingTop + y *_charHeight, _charWidth, _charHeight);
//NSImage *img;
CharInfo ci = _screen.getc(x, y);
char_info ci = _screen.getc(iPoint(x, y));
unsigned flag = ci.flag;
uint8_t c = ci.c;
@ -374,7 +384,14 @@
std::swap(currentBack, currentFront);
}
}
if (_cursorType == Screen::CursorTypeBlock && _cursorOn && _screen.cursor() == iPoint(x, y)) {
std::swap(currentBack, currentFront);
}
if (currentBack != _backgroundColor)
{
[currentBack setFill];
@ -417,14 +434,18 @@
// cursor.
iPoint cursor = _screen.cursor();
if (_cursorOn && iRect(minX, minY, maxX - minX, maxY - minY).contains(cursor))
if (_cursorOn && iRect(minX, minY, maxX - minX, maxY - minY).contains(cursor) && _cursorType != Screen::CursorTypeBlock)
{
NSRect charRect = NSMakeRect(_paddingLeft + cursor.x * _charWidth, _paddingTop + cursor.y *_charHeight, _charWidth, _charHeight);
[_foregroundColor setFill];
NSCompositingOperation op = NSCompositingOperationCopy;
//if (_cursorType == Screen::CursorTypeBlock) op = NSCompositingOperationXOR;
[_cursorImg drawInRect: charRect
fromRect: NSZeroRect operation: NSCompositeCopy
fromRect: NSZeroRect
operation: op
fraction: 1.0
respectFlipped: YES
hints: nil];
@ -514,6 +535,7 @@
//[self stopCursorTimer];
//_screen.setCursorType(Screen::CursorTypeNone);
#if 0
_screen.beginUpdate();
_screen.setX(0);
@ -524,11 +546,11 @@
_screen.putc(*cp);
}
updateRect = _screen.endUpdate();
[self invalidateIRect: updateRect];
#endif
//[_emulator writeLine: @"[Process completed]"];
@ -570,7 +592,7 @@
std::string rv;
int offset = 0;
while (offset < bytes.size()) {
int max = bytes.size() - offset;
size_t max = bytes.size() - offset;
if (max > 16) max = 16;
rv.append(hex.data() + offset * 3, max * 3);
@ -940,6 +962,7 @@ void ViewScreen::setSize(unsigned width, unsigned height, bool resizeView)
void ViewScreen::setCursorType(CursorType cursorType)
{
Screen::setCursorType(cursorType);
[_view setCursorType: cursorType];
}

File diff suppressed because it is too large Load Diff

View File

@ -17,45 +17,27 @@
typedef struct CharInfo {
typedef struct char_info {
CharInfo() = default;
CharInfo(uint8_t cc, uint8_t ff) : c(cc), flag(ff) {}
char_info() = default;
char_info(uint8_t cc, uint8_t ff) : c(cc), flag(ff) {}
uint8_t c = 0;
uint8_t flag = 0;
} CharInfo;
} char_info;
typedef struct TextPort {
enum MarginBehavior {
MarginTruncate,
MarginWrap,
MarginOverwrite
};
iRect frame;
typedef struct context {
uint8_t flags = 0;
iRect window;
iPoint cursor;
void setFlagBit(unsigned x) { flags |= x; }
void clearFlagBit(unsigned x) { flags &= ~x; }
} context;
MarginBehavior leftMargin = MarginTruncate;
MarginBehavior rightMargin = MarginTruncate;
bool advanceCursor = true;
bool scroll = true;
// clamp setCursor calls.
bool clampX = true;
bool clampY = true;
iPoint absoluteCursor() const;
} TextPort;
class Screen {
@ -72,7 +54,7 @@ public:
static const unsigned FlagSelected = 0x8000;
/*
enum EraseRegion {
EraseAll,
EraseBeforeCursor,
@ -82,7 +64,7 @@ public:
EraseLineBeforeCursor,
EraseLineAfterCursor
};
*/
enum CursorType {
CursorTypeNone,
CursorTypeUnderscore,
@ -101,85 +83,42 @@ public:
int y() const;
iPoint cursor() const;
uint8_t flag() const;
int height() const;
int width() const;
int incrementX(bool clamp = true);
int decrementX(bool clamp = true);
int incrementY(bool clamp = true);
int decrementY(bool clamp = true);
void setX(int x, bool clamp = true);
void setY(int y, bool clamp = true);
void setCursor(iPoint point, bool clampX = true, bool clampY = true);
void setCursor(int x, int y, bool clampX = true, bool clampY = true);
void setCursor(iPoint point);
int setX(TextPort *textPort, int x);
int setY(TextPort *textPort, int y);
void putc(uint8_t c, iPoint cursor, uint8_t flags = 0);
void putc(uint8_t c, const context &ctx) { putc(c, ctx.cursor, ctx.flags); }
char_info getc(iPoint p) const;
int incrementX(TextPort *textPort);
int incrementY(TextPort *textPort);
int decrementX(TextPort *textPort);
int decrementY(TextPort *textPort);
void setCursor(TextPort *textPort, iPoint point);
void setCursor(TextPort *textPort, int x, int y);
void setFlag(uint8_t flag);
void setFlagBit(uint8_t bit);
void clearFlagBit(uint8_t bit);
void putc(uint8_t c, bool incrementX = true);
void putc(TextPort *textPort, uint8_t c);
void putc(TextPort *textPort, uint8_t c, uint8_t flags);
CharInfo getc(int x, int y) const;
void deletec();
void insertc(uint8_t c);
void tabTo(unsigned x);
void tabTo(TextPort *textPort, unsigned x);
void erase(EraseRegion);
void erase(TextPort *, EraseRegion);
void eraseLine();
void eraseScreen();
void eraseRect(iRect rect);
void fillScreen(char_info ci);
void fillRect(iRect rect, char_info ci);
void lineFeed();
int lineFeed(TextPort *textPort);
void reverseLineFeed();
int reverseLineFeed(TextPort *textPort);
void scrollUp();
void scrollUp(iRect window);
void scrollDown();
void scrollDown(iRect window);
void deleteLine(unsigned line);
void insertLine(unsigned line);
void insertLine(TextPort *textPort, int line);
void deleteLine(TextPort *textPort, int line);
//void deletec();
//void insertc(uint8_t c);
void insertc(TextPort *textPort, uint8_t c);
void deletec(TextPort *textPort);
void beginUpdate();
iRect endUpdate();
@ -187,36 +126,32 @@ public:
void lock();
void unlock();
void setTextPort(const TextPort& textPort);
virtual void setSize(unsigned width, unsigned height);
virtual void setCursorType(CursorType cursor);
CursorType cursorType() const;
private:
TextPort _port;
uint8_t _flag;
iRect _frame;
iPoint _cursor;
CursorType _cursorType;
Lock _lock;
std::vector< std::vector< CharInfo > > _screen;
std::vector< std::vector< char_info > > _screen;
std::vector<iPoint> _updates;
iPoint _updateCursor;
typedef std::vector< std::vector< CharInfo > >::iterator ScreenIterator;
typedef std::vector< std::vector< CharInfo > >::reverse_iterator ReverseScreenIterator;
typedef std::vector< std::vector< char_info > >::iterator ScreenIterator;
typedef std::vector< std::vector< char_info > >::reverse_iterator ReverseScreenIterator;
typedef std::vector<CharInfo>::iterator CharInfoIterator;
typedef std::vector<char_info>::iterator CharInfoIterator;
typedef std::vector<iPoint>::iterator UpdateIterator;
};
@ -224,23 +159,19 @@ private:
inline int Screen::x() const
{
return _port.cursor.x;
return _cursor.x;
}
inline int Screen::y() const
{
return _port.cursor.y;
return _cursor.y;
}
inline iPoint Screen::cursor() const
{
return _port.cursor;
return _cursor;
}
inline uint8_t Screen::flag() const
{
return _flag;
}
inline Screen::CursorType Screen::cursorType() const
{
@ -249,24 +180,20 @@ inline Screen::CursorType Screen::cursorType() const
inline int Screen::height() const
{
return _port.frame.size.height;
return _frame.size.height;
}
inline int Screen::width() const
{
return _port.frame.size.width;
return _frame.size.width;
}
inline void Screen::setCursor(iPoint point, bool clampX, bool clampY)
inline void Screen::setCursor(iPoint point)
{
setX(point.x, clampX);
setY(point.y, clampY);
}
inline void Screen::setCursor(int x, int y, bool clampX, bool clampY)
{
setX(x, clampX);
setY(y, clampY);
if (point.x >= _frame.width()) point.x = _frame.width() - 1;
if (point.y >= _frame.height()) point.y = _frame.height() - 1;
_cursor = point;
}
@ -281,12 +208,10 @@ inline void Screen::unlock()
}
inline CharInfo Screen::getc(int x, int y) const
inline char_info Screen::getc(iPoint p) const
{
if (x < 0 || y < 0) return CharInfo();
if (x >= width() || y >= height()) return CharInfo(0,0);
return _screen[y][x];
if (_frame.contains(p)) return _screen[p.y][p.x];
return char_info();
}
#endif

View File

@ -1,124 +0,0 @@
//
// Screen_TextPort.cpp
// 2Term
//
// Created by Kelvin Sherlock on 1/11/2011.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#include "Screen.h"
void Screen::setTextPort(const TextPort& textPort)
{
TextPort tmp(textPort);
// call virtual method...
setSize(textPort.frame.width(), textPort.frame.height());
tmp.frame.origin = iPoint(0, 0);
_port = tmp;
}
/*
* Non-destructive tab.
* Sets the horizontal cursor position, may wrap and scroll
*
*
*/
void Screen::tabTo(TextPort *textPort, unsigned xPos)
{
if (!textPort) textPort = &_port;
iRect frame = textPort->frame;
// best case -- no wrapping needed.
if (xPos < frame.width())
{
textPort->cursor.x = xPos;
}
else if (textPort->rightMargin == TextPort::MarginWrap)
{
// worst case -- wrapping needed.
textPort->cursor.x = 0;
incrementY(textPort);
if (textPort != &_port) _port.cursor = textPort->absoluteCursor();
return;
}
else
{
// clamp to right margin.
textPort->cursor.x = frame.width() - 1;
}
if (textPort != &_port) _port.cursor = textPort->absoluteCursor();
return;
}
// insert a character at the current cursor position,
// moving all characters right 1.
// no wrapping is performed.
void Screen::insertc(TextPort *textPort, uint8_t c)
{
if (!textPort) textPort = &_port;
iRect frame = textPort->frame;
iPoint cursor = textPort->cursor;
iPoint absoluteCursor = textPort->absoluteCursor();
if (cursor.x >= frame.width()) return;
if (cursor.y >= frame.height()) return;
CharInfoIterator iter = _screen[absoluteCursor.y].begin();
CharInfoIterator begin = iter + absoluteCursor.x;
CharInfoIterator end = iter + frame.maxX();
CharInfo ci(c, _flag);
// move all chars forward 1.
for (iter = begin; iter < end; ++iter)
{
std::swap(ci, *iter);
}
_updates.push_back(absoluteCursor);
_updates.push_back(iPoint(frame.maxX(), absoluteCursor.y));
}
// delete the character at the current cursor position,
// moving any character to the right left 1 spot
// the final position is blank filled.
// no wrapping is performed.
void Screen::deletec(TextPort *textPort)
{
if (!textPort) textPort = &_port;
iRect frame = textPort->frame;
iPoint cursor = textPort->cursor;
iPoint absoluteCursor = textPort->absoluteCursor();
if (cursor.x >= frame.width()) return;
if (cursor.y >= frame.height()) return;
CharInfoIterator iter = _screen[absoluteCursor.y].begin();
CharInfoIterator begin = iter + absoluteCursor.x;
CharInfoIterator end = iter + frame.maxX() - 1;
for (iter = begin; iter < end; ++iter)
{
iter[0] = iter[1];
}
// not sure about the flag situation...
*iter = CharInfo(' ', _flag);
_updates.push_back(absoluteCursor);
_updates.push_back(iPoint(frame.maxX(), absoluteCursor.y));
}

View File

@ -1,183 +0,0 @@
//
// Screen_obsolete.cpp
// 2Term
//
// Created by Kelvin Sherlock on 1/11/2011.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//
#include "Screen.h"
void Screen::setX(int x, bool clamp)
{
if (x < 0)
{
if (clamp) _port.cursor.x = 0;
return;
}
if (x >= width())
{
if (clamp) _port.cursor.x = width() - 1;
return;
}
_port.cursor.x = x;
}
void Screen::setY(int y, bool clamp)
{
if (y < 0)
{
if (clamp) _port.cursor.y = 0;
return;
}
if (y >= height())
{
if (clamp) _port.cursor.y = height() - 1;
return;
}
_port.cursor.y = y;
}
int Screen::incrementX(bool clamp)
{
setX(_port.cursor.x + 1, clamp);
return _port.cursor.x;
}
int Screen::decrementX(bool clamp)
{
setX(_port.cursor.x - 1, clamp);
return _port.cursor.x;
}
int Screen::incrementY(bool clamp)
{
setY(_port.cursor.y + 1, clamp);
return _port.cursor.y;
}
int Screen::decrementY(bool clamp)
{
setY(_port.cursor.y - 1, clamp);
return _port.cursor.y;
}
void Screen::tabTo(unsigned xPos)
{
CharInfo clear(' ', _flag);
CharInfoIterator iter;
xPos = std::min((int)xPos, width() - 1);
_updates.push_back(_port.cursor);
_updates.push_back(iPoint(xPos, _port.cursor.y));
for (unsigned x = _port.cursor.x; x < xPos; ++x)
{
_screen[_port.cursor.y][x] = clear;
}
_port.cursor.x = xPos;
}
void Screen::putc(uint8_t c, bool incrementX)
{
if (_port.cursor.x < width())
{
_updates.push_back(_port.cursor);
_screen[_port.cursor.y][_port.cursor.x] = CharInfo(c, _flag);
if (incrementX && _port.cursor.x < width() - 1) ++_port.cursor.x;
}
}
void Screen::deletec()
{
// delete character at cursor.
// move following character up
// set final character to ' ' (retaining flags from previous char)
if (_port.cursor.x >= width()) return;
_updates.push_back(_port.cursor);
_updates.push_back(iPoint(width() - 1, _port.cursor.y));
CharInfoIterator end = _screen[_port.cursor.y].end() - 1;
CharInfoIterator iter = _screen[_port.cursor.y].begin() + _port.cursor.x;
for ( ; iter != end; ++iter)
{
iter[0] = iter[1];
}
// retain the flags previously there.
end->c = ' ';
}
void Screen::insertc(uint8_t c)
{
// insert character at cursor.
// move following characters up (retaining flags).
if (_port.cursor.x >= width()) return;
_updates.push_back(_port.cursor);
_updates.push_back(iPoint(width() - 1, _port.cursor.y));
CharInfoIterator end = _screen[_port.cursor.y].end() - 1;
CharInfoIterator iter = _screen[_port.cursor.y].begin() + _port.cursor.x;
for ( ; iter != end; ++iter)
{
iter[1] = iter[0];
}
iter->c = ' ';
}
void Screen::eraseLine()
{
// erases everything to the right of, and including, the cursor
for (CharInfoIterator ciIter = _screen[y()].begin() + x(); ciIter < _screen[y()].end(); ++ciIter)
{
*ciIter = CharInfo(0, _flag);
}
_updates.push_back(cursor());
_updates.push_back(iPoint(width() - 1, y()));
}
void Screen::eraseScreen()
{
// returns everything to the right of, and including, the cursor as well as all subsequent lines.
eraseLine();
if (y() == height() -1) return;
for (ScreenIterator iter = _screen.begin() + y(); iter < _screen.end(); ++iter)
{
for (CharInfoIterator ciIter = iter->begin(); ciIter < iter->end(); ++ciIter)
{
*ciIter = CharInfo(0, _flag);
}
}
_updates.push_back(iPoint(0, y() + 1));
_updates.push_back(iPoint(width() - 1, height() - 1));
}

View File

@ -9,7 +9,7 @@
#include "iGeometry.h"
#include <algorithm>
bool iRect::contains(const iPoint aPoint) const
{
@ -30,4 +30,19 @@ bool iRect::contains(const iRect aRect) const
bool iRect::intersects(const iRect aRect) const
{
return aRect.contains(origin) || aRect.contains(origin.offset(size));
}
}
iRect iRect::intersection(const iRect &rhs) const {
iPoint topLeft;
iPoint bottomRight;
topLeft.x = std::max(origin.x, rhs.origin.x);
topLeft.y = std::max(origin.y, rhs.origin.y);
bottomRight.x = std::min(maxX(), rhs.maxX());
bottomRight.y = std::min(maxY(), rhs.maxY());
if (bottomRight.x <= topLeft.x) return iRect();
if (bottomRight.y <= topLeft.y) return iRect();
return iRect(topLeft, bottomRight);
}

View File

@ -23,10 +23,10 @@ typedef struct iSize {
iSize &operator=(const iSize &) = default;
bool operator==(const iSize &aSize)
bool operator==(const iSize &aSize) const
{ return width == aSize.width && height == aSize.height; }
bool operator!=(const iSize& aSize)
bool operator!=(const iSize& aSize) const
{ return !(*this == aSize); }
} iSize;
@ -43,10 +43,10 @@ typedef struct iPoint {
iPoint &operator=(const iPoint &) = default;
bool operator==(const iPoint &aPoint)
bool operator==(const iPoint &aPoint) const
{ return x == aPoint.x && y == aPoint.y; }
bool operator!=(const iPoint &aPoint)
bool operator!=(const iPoint &aPoint) const
{ return !(*this == aPoint); }
iPoint offset(int dx, int dy) const
@ -80,6 +80,23 @@ typedef struct iRect {
bool intersects(const iRect aRect) const;
iRect intersection(const iRect &rhs) const;
bool operator==(const iRect &rhs) const {
return origin == rhs.origin && size == rhs.size;
}
bool operator!=(const iRect &rhs) const {
return !(*this == rhs);
}
explicit operator bool() const { return size.height >= 0 && size.width >= 0; }
bool operator!() const { return size.height < 0 || size.width < 0; }
bool valid() const { return size.height >= 0 && size.width >= 0; }
iPoint topLeft() const { return origin; }
iPoint bottomRight() const { return iPoint(maxX(), maxY()); }
void setBottomLeft(iPoint &p);
int height() const
{ return size.height; }

View File

@ -56,7 +56,7 @@ public:
_capacity = 0;
// fill up the end, then wrap around to start.
if (_ptr + dsize > Size) {
int amt = Size - _ptr;
size_t amt = Size - _ptr;
memcpy(_buffer + _ptr, data, amt);
_ptr = 0;
dsize -= amt;