mirror of
https://github.com/ksherlock/TwoTerm.git
synced 2025-04-06 09:37:46 +00:00
redo ptse
git-svn-id: svn://qnap.local/TwoTerm/trunk@3173 5590a31f-7b70-45f8-8c82-aa3a8e5f4507
This commit is contained in:
parent
f941f462fb
commit
a34341dd69
@ -47,6 +47,7 @@
|
||||
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 */; };
|
||||
B6D1CD071E577E7D00C4A6BC /* PTSE.mm.ragel in Sources */ = {isa = PBXBuildFile; fileRef = B612F45D12DD5DF1005D1B77 /* PTSE.mm.ragel */; };
|
||||
B6EBE2B511E0EA9100EA0458 /* CharacterGenerator.mm in Sources */ = {isa = PBXBuildFile; fileRef = B6EBE2B411E0EA9100EA0458 /* CharacterGenerator.mm */; };
|
||||
B6ECFF271D2EEA2B00871A81 /* TextLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = B6ECFF261D2EEA2B00871A81 /* TextLabel.m */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -119,7 +120,7 @@
|
||||
B612F45A12DD5DF1005D1B77 /* GNOConsole.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GNOConsole.h; 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>"; };
|
||||
B612F45D12DD5DF1005D1B77 /* PTSE.mm.ragel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = PTSE.mm.ragel; sourceTree = "<group>"; };
|
||||
B612F45E12DD5DF1005D1B77 /* VT05.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VT05.h; sourceTree = "<group>"; };
|
||||
B612F45F12DD5DF1005D1B77 /* VT05.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = VT05.mm; sourceTree = "<group>"; };
|
||||
B612F46012DD5DF1005D1B77 /* VT100.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VT100.h; sourceTree = "<group>"; };
|
||||
@ -295,16 +296,16 @@
|
||||
B612F45512DD5DF1005D1B77 /* Emulators */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B612F45612DD5DF1005D1B77 /* Apple80.h */,
|
||||
B612F45712DD5DF1005D1B77 /* Apple80.mm.ragel */,
|
||||
B612F45812DD5DF1005D1B77 /* Emulator.h */,
|
||||
B612F45912DD5DF1005D1B77 /* EmulatorManager.mm */,
|
||||
B612F45612DD5DF1005D1B77 /* Apple80.h */,
|
||||
B612F45712DD5DF1005D1B77 /* Apple80.mm.ragel */,
|
||||
B612F45A12DD5DF1005D1B77 /* GNOConsole.h */,
|
||||
B612F45B12DD5DF1005D1B77 /* GNOConsole.mm.ragel */,
|
||||
B6C173901D31D2B80024E360 /* GSOSConsole.h */,
|
||||
B6C173911D31D2B80024E360 /* GSOSConsole.mm.ragel */,
|
||||
B612F45C12DD5DF1005D1B77 /* PTSE.h */,
|
||||
B612F45D12DD5DF1005D1B77 /* PTSE.mm */,
|
||||
B612F45D12DD5DF1005D1B77 /* PTSE.mm.ragel */,
|
||||
B612F45E12DD5DF1005D1B77 /* VT05.h */,
|
||||
B612F45F12DD5DF1005D1B77 /* VT05.mm */,
|
||||
B612F46012DD5DF1005D1B77 /* VT100.h */,
|
||||
@ -440,6 +441,7 @@
|
||||
B675F4A91E561D20004B0D9C /* Apple80.mm.ragel in Sources */,
|
||||
B675F4AA1E562159004B0D9C /* GNOConsole.mm.ragel in Sources */,
|
||||
B675F4AC1E56A7F2004B0D9C /* GSOSConsole.mm.ragel in Sources */,
|
||||
B6D1CD071E577E7D00C4A6BC /* PTSE.mm.ragel in Sources */,
|
||||
8D11072D0486CEB800E47090 /* main.m in Sources */,
|
||||
256AC3DA0F4B6AC300CF3369 /* TwoTermAppDelegate.mm in Sources */,
|
||||
B676063B11DEAD3500D6B66C /* TermWindowController.mm in Sources */,
|
||||
|
@ -17,15 +17,11 @@
|
||||
|
||||
@interface PTSE : NSObject <Emulator>
|
||||
{
|
||||
unsigned _state;
|
||||
|
||||
iPoint _dca;
|
||||
uint8_t _repeatChar;
|
||||
|
||||
#ifdef __cplusplus
|
||||
TextPort _textPort;
|
||||
#endif
|
||||
|
||||
context _context;
|
||||
|
||||
unsigned cs;
|
||||
int _scratch[4];
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,376 +0,0 @@
|
||||
//
|
||||
// PTSE.mm
|
||||
// 2Term
|
||||
//
|
||||
// Created by Kelvin Sherlock on 7/9/2010.
|
||||
// Copyright 2010 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#include <sys/ttydefaults.h>
|
||||
|
||||
|
||||
#import "PTSE.h"
|
||||
|
||||
#include "OutputChannel.h"
|
||||
#include "Screen.h"
|
||||
|
||||
|
||||
|
||||
@implementation PTSE
|
||||
|
||||
enum {
|
||||
StateText,
|
||||
|
||||
StateDCAX,
|
||||
StateDCAY,
|
||||
|
||||
StateRepeatChar,
|
||||
StateRepeatCount,
|
||||
|
||||
StateTone1,
|
||||
StateTone2,
|
||||
StateToneDuration
|
||||
|
||||
};
|
||||
|
||||
+(void)load
|
||||
{
|
||||
[EmulatorManager registerClass: self];
|
||||
}
|
||||
|
||||
+(NSString *)name
|
||||
{
|
||||
return @"Proterm Special Emulation";
|
||||
}
|
||||
|
||||
-(NSString *)name
|
||||
{
|
||||
return @"Proterm Special Emulation";
|
||||
}
|
||||
|
||||
-(const char *)termName
|
||||
{
|
||||
return "proterm-special";
|
||||
}
|
||||
|
||||
-(void)reset: (Screen *)screen
|
||||
{
|
||||
[self reset];
|
||||
|
||||
if (screen)
|
||||
{
|
||||
screen->setFlag(Screen::FlagNormal);
|
||||
screen->setTextPort(_textPort);
|
||||
screen->erase(Screen::EraseAll);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
-(void)reset
|
||||
{
|
||||
struct winsize ws = [self defaultSize];
|
||||
_state = StateText;
|
||||
|
||||
_textPort.cursor = iPoint(0, 0);
|
||||
_textPort.frame = iRect(0, 0, ws.ws_col, ws.ws_row);
|
||||
|
||||
_textPort.scroll = true;
|
||||
_textPort.advanceCursor = true;
|
||||
_textPort.clampX = true;
|
||||
_textPort.clampY = true;
|
||||
_textPort.leftMargin = TextPort::MarginWrap;
|
||||
_textPort.rightMargin = TextPort::MarginWrap;
|
||||
|
||||
}
|
||||
|
||||
-(BOOL)resizable
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(struct winsize)defaultSize
|
||||
{
|
||||
struct winsize ws = { 24, 80, 0, 0 };
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
-(id)init
|
||||
{
|
||||
[self reset];
|
||||
return self;
|
||||
}
|
||||
|
||||
-(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('N'):
|
||||
//Set: inverse off, mousetext off.
|
||||
screen->setFlag(Screen::FlagNormal);
|
||||
break;
|
||||
case CTRL('O'):
|
||||
//Set: inverse on, mousetext off.
|
||||
screen->setFlag(Screen::FlagInverse);
|
||||
break;
|
||||
case CTRL('P'):
|
||||
//Set inverse off, mousetext on.
|
||||
screen->setFlag(Screen::FlagMouseText | Screen::FlagInverse);
|
||||
break;
|
||||
|
||||
|
||||
case CTRL('H'):
|
||||
//Move cursor left one character.
|
||||
screen->decrementX(&_textPort);
|
||||
break;
|
||||
case CTRL('U'):
|
||||
//Move cursor right one character.
|
||||
screen->incrementX(&_textPort);
|
||||
break;
|
||||
case CTRL('K'):
|
||||
//Move cursor up one line.
|
||||
screen->decrementY(&_textPort);
|
||||
break;
|
||||
case CTRL('J'):
|
||||
//Move cursor down one line.
|
||||
//screen->incrementY();
|
||||
screen->lineFeed(&_textPort);
|
||||
break;
|
||||
case CTRL('I'):
|
||||
//Move cursor to next tab stop (every 8 chars).
|
||||
screen->tabTo(&_textPort, (_textPort.cursor.x + 8) & ~0x07);
|
||||
break;
|
||||
case CTRL('A'):
|
||||
//Move cursor to beginning of line.
|
||||
screen->setX(&_textPort, 0);
|
||||
break;
|
||||
case CTRL('B'):
|
||||
//Move cursor to end of line.
|
||||
screen->setX(&_textPort, _textPort.frame.width() - 1);
|
||||
break;
|
||||
case CTRL('X'):
|
||||
//Move cursor to upper-left corner.
|
||||
screen->setCursor(&_textPort, 0, 0);
|
||||
break;
|
||||
case CTRL('^'):
|
||||
// CONTROL-^, X + 32, Y + 32
|
||||
//Position cursor to the X, Y coordinates.
|
||||
_state = StateDCAX;
|
||||
break;
|
||||
|
||||
case CTRL('M'):
|
||||
//screen->lineFeed();
|
||||
screen->setX(&_textPort, 0);
|
||||
break;
|
||||
|
||||
|
||||
case CTRL('D'):
|
||||
//Delete current character (under cursor).
|
||||
// TODO -- does this shift the rest of the row? Assuming yes.
|
||||
screen->deletec(&_textPort);
|
||||
break;
|
||||
case CTRL('F'):
|
||||
//Insert space at cursor.
|
||||
// TODO -- does this wrap? Assuming no.
|
||||
screen->insertc(&_textPort, ' ');
|
||||
break;
|
||||
|
||||
case CTRL('Z'):
|
||||
//Delete current line.
|
||||
// TODO -- textPort
|
||||
screen->deleteLine(&_textPort, _textPort.cursor.y);
|
||||
break;
|
||||
case CTRL('V'):
|
||||
//Insert blank line.
|
||||
// TODO -- verify if the line is before or after the current line,
|
||||
// TODO -- verify if x/y change
|
||||
// TODO -- verify scrolling behavior.
|
||||
// TODO -- textPort
|
||||
screen->insertLine(&_textPort, _textPort.cursor.y);
|
||||
break;
|
||||
case CTRL('Y'):
|
||||
//Clear to end of line.
|
||||
screen->erase(&_textPort, Screen::EraseLineAfterCursor);
|
||||
break;
|
||||
case CTRL('W'):
|
||||
//Clear to end of screen.
|
||||
screen->erase(&_textPort, Screen::EraseAfterCursor);
|
||||
break;
|
||||
case CTRL('L'):
|
||||
//Clear the screen (and home cursor)
|
||||
screen->setCursor(&_textPort, 0, 0);
|
||||
screen->erase(&_textPort, Screen::EraseAll);
|
||||
break;
|
||||
|
||||
|
||||
case CTRL('E'):
|
||||
//Inquire if using ProTERM Special Emulation
|
||||
/*
|
||||
* When you send out [CONTROL-E] to a caller using ProTERM
|
||||
* Special, the caller’s ProTERM will send back [CONTROL-“]”]
|
||||
* (ASCII code 29). This allows a BBS to transparently
|
||||
* detect the use of PSE.
|
||||
*/
|
||||
output->write(29);
|
||||
break;
|
||||
|
||||
case CTRL('R'):
|
||||
//CONTROL-R, character, count
|
||||
//Display character, count times.
|
||||
/*
|
||||
* This allows a three character code to be used to display
|
||||
* multiple characters. For example, to display a window frame,
|
||||
* it is necessary to show the top and bottom borders which are
|
||||
* long lines of the same character (dashes, underlines, etc.).
|
||||
* To draw a 64-character line consisting of equal signs, send
|
||||
* [CONTROL-R = @] where “@” is the ASCII code for 64.
|
||||
*/
|
||||
_state = StateRepeatChar;
|
||||
break;
|
||||
|
||||
case CTRL('G'):
|
||||
//Sound the Bell.
|
||||
NSBeep();
|
||||
break;
|
||||
|
||||
case CTRL('T'):
|
||||
//Sound single/dual-tone for duration.
|
||||
/*
|
||||
* The tone command has two forms. The first invokes the single-tone
|
||||
* generator, which produces relatively pure tones. The second
|
||||
* invokes the dual-tone generator, which produces some rather
|
||||
* interesting sounds. The three parameters, tone1, tone2, and
|
||||
* duration, can all take values from 1 through 127. There is
|
||||
* currently no known translation between pitch/duration values
|
||||
* and actual frequencies/times.
|
||||
*/
|
||||
//NB - parsed but ignored, for now.
|
||||
_state = StateTone1;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (c >= 0x20 && c < 0x7f)
|
||||
{
|
||||
screen->putc(&_textPort, c);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (_state)
|
||||
{
|
||||
case StateDCAX:
|
||||
_dca.x = c - 32;
|
||||
_state = StateDCAY;
|
||||
break;
|
||||
|
||||
case StateDCAY:
|
||||
_dca.y = c - 32;
|
||||
screen->setCursor(&_textPort, _dca);
|
||||
|
||||
_state = StateText;
|
||||
break;
|
||||
|
||||
case StateRepeatChar:
|
||||
_repeatChar = c;
|
||||
_state = StateRepeatCount;
|
||||
break;
|
||||
|
||||
case StateRepeatCount:
|
||||
for (unsigned i = 0; i < c; ++i)
|
||||
{
|
||||
screen->putc(&_textPort, _repeatChar);
|
||||
}
|
||||
_state = StateText;
|
||||
break;
|
||||
|
||||
case StateTone1:
|
||||
_state = StateTone2;
|
||||
break;
|
||||
case StateTone2:
|
||||
// CONTROL-A indicates same as tone1.
|
||||
_state = StateToneDuration;
|
||||
break;
|
||||
case StateToneDuration:
|
||||
_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;
|
||||
|
||||
|
||||
// backspace and left arrow use the same code, alas.
|
||||
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 & NSControlKeyMask)
|
||||
c = CTRL(c);
|
||||
|
||||
output->write(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
422
Emulators/PTSE.mm.ragel
Normal file
422
Emulators/PTSE.mm.ragel
Normal file
@ -0,0 +1,422 @@
|
||||
//
|
||||
// PTSE.mm
|
||||
// 2Term
|
||||
//
|
||||
// Created by Kelvin Sherlock on 7/9/2010.
|
||||
// Copyright 2010 __MyCompanyName__. All rights reserved.
|
||||
//
|
||||
|
||||
#include <sys/ttydefaults.h>
|
||||
|
||||
|
||||
#import "PTSE.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; };
|
||||
arg2 = any ${ _scratch[1] = fc; };
|
||||
|
||||
|
||||
|
||||
|
||||
main := (
|
||||
0x00 $nop
|
||||
| 0x01 ${
|
||||
// A - $01 Move cursor to beginning of line.
|
||||
cursor.x = 0;
|
||||
}
|
||||
| 0x02 ${
|
||||
// B - $02 Move cursor to end of line.
|
||||
cursor.x = 79;
|
||||
}
|
||||
| 0x03 $nop
|
||||
| 0x04 ${
|
||||
// D - Delete current character (under cursor)
|
||||
iRect tmp;
|
||||
tmp.origin = cursor;
|
||||
tmp.size = iSize(80 - cursor.x, 1);
|
||||
screen->scrollLeft(tmp);
|
||||
}
|
||||
|
||||
| 0x05 ${
|
||||
/* E - $05 */
|
||||
//Inquire if using ProTERM Special Emulation
|
||||
/*
|
||||
* When you send out [CONTROL-E] to a caller using ProTERM
|
||||
* Special, the caller’s ProTERM will send back [CONTROL-“]”]
|
||||
* (ASCII code 29). This allows a BBS to transparently
|
||||
* detect the use of PSE.
|
||||
*/
|
||||
output->write(29);
|
||||
}
|
||||
|
||||
| 0x06 ${
|
||||
/* F - $06 */
|
||||
// Insert space at cursor
|
||||
iRect tmp;
|
||||
tmp.origin = cursor;
|
||||
tmp.size = iSize(80 - cursor.x, 1);
|
||||
screen->scrollRight(tmp);
|
||||
}
|
||||
|
||||
| 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;
|
||||
if (cursor.y) cursor.y--;
|
||||
else screen->scrollDown();
|
||||
}
|
||||
}
|
||||
|
||||
| 0x09 ${
|
||||
// control-I
|
||||
cursor.x = (cursor.x + 8) & ~7;
|
||||
cursor.x = std::min(cursor.x, 72); // verified.
|
||||
}
|
||||
|
||||
| 0x0a ${
|
||||
/* J - $0A - Moves cursor down one row; scrolls if needed */
|
||||
|
||||
if (cursor.y >= 24-1) {
|
||||
screen->scrollUp();
|
||||
} else cursor.y++;
|
||||
|
||||
}
|
||||
|
||||
| 0x0b ${
|
||||
/* K - $0B - Move cursor up one line */
|
||||
|
||||
if (cursor.y == 0) {
|
||||
screen->scrollDown();
|
||||
} else cursor.y--;
|
||||
|
||||
}
|
||||
|
||||
| 0x0c ${
|
||||
// control-L
|
||||
/* clear text port and home */
|
||||
// n.b - PT "home" is 0, 1
|
||||
screen->eraseScreen();
|
||||
cursor = iPoint(0,0);
|
||||
}
|
||||
|
||||
| 0x0d ${
|
||||
// control-M
|
||||
/* carriage return */
|
||||
cursor.x = 0;
|
||||
}
|
||||
|
||||
| 0x0e ${
|
||||
// control-N
|
||||
//Set: inverse off, mousetext off.
|
||||
_context.flags = Screen::FlagNormal;
|
||||
}
|
||||
|
||||
| 0x0f ${
|
||||
// control-O
|
||||
//Set: inverse on, mousetext off.
|
||||
_context.flags = Screen::FlagInverse;
|
||||
}
|
||||
|
||||
| 0x10 ${
|
||||
// control-P
|
||||
//Set inverse off, mousetext on.
|
||||
_context.flags = Screen::FlagInverse | Screen::FlagMouseText;
|
||||
}
|
||||
|
||||
| 0x11 $nop
|
||||
| 0x12 arg1 arg2 ${
|
||||
/* ^R */
|
||||
|
||||
/*
|
||||
* This allows a three character code to be used to display
|
||||
* multiple characters. For example, to display a window frame,
|
||||
* it is necessary to show the top and bottom borders which are
|
||||
* long lines of the same character (dashes, underlines, etc.).
|
||||
* To draw a 64-character line consisting of equal signs, send
|
||||
* [CONTROL-R = @] where “@” is the ASCII code for 64.
|
||||
*/
|
||||
|
||||
uint8_t c = _scratch[0] & 0x7f;
|
||||
int count = _scratch[1];
|
||||
while (count--) {
|
||||
screen->putc(c, _context);
|
||||
if (cursor.x++ >= 80) {
|
||||
cursor.x = 0;
|
||||
if (cursor.y < 23) cursor.y++;
|
||||
else screen->scrollUp();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
| 0x13 $nop
|
||||
|
||||
| 0x14 any any any ${
|
||||
//Sound single/dual-tone for duration.
|
||||
// [Control-T Tl Control-A D] Sound tone Tl, for duration D
|
||||
// [Control-T Tl T2 D] Sound dual tone Tl, T2 for duration D
|
||||
/*
|
||||
* The tone command has two forms. The first invokes the single-tone
|
||||
* generator, which produces relatively pure tones. The second
|
||||
* invokes the dual-tone generator, which produces some rather
|
||||
* interesting sounds. The three parameters, tone1, tone2, and
|
||||
* duration, can all take values from 1 through 127. There is
|
||||
* currently no known translation between pitch/duration values
|
||||
* and actual frequencies/times.
|
||||
*/
|
||||
}
|
||||
|
||||
| 0x15 ${
|
||||
/* ^U - Move cursor right one character */
|
||||
} $advance
|
||||
|
||||
| 0x16 ${
|
||||
/* CTRL('V') */
|
||||
// Insert blank line
|
||||
iRect tmp;
|
||||
tmp.origin = iPoint(0, cursor.y);
|
||||
tmp.size = iSize(80, 24 - cursor.y);
|
||||
screen->scrollDown(tmp);
|
||||
}
|
||||
|
||||
| 0x17 ${
|
||||
/* CTRL('W') */
|
||||
// Clear 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);
|
||||
}
|
||||
|
||||
| 0x18 ${
|
||||
// CTRL('X'):
|
||||
// Home cursor (move to upper left corner)
|
||||
// n.b. -- Proterm status bar on line 1. "home" is y=1.
|
||||
cursor = iPoint(0,0);
|
||||
|
||||
}
|
||||
|
||||
| 0x19 ${
|
||||
// CTRL('Y'):
|
||||
/* clear to end of line. */
|
||||
|
||||
iRect tmp;
|
||||
tmp.origin = cursor;
|
||||
tmp.size = iSize(80 - cursor.x, 1);
|
||||
|
||||
screen->eraseRect(tmp);
|
||||
}
|
||||
|
||||
| 0x1a ${
|
||||
// CTRL('Z'):
|
||||
/* Delete current line */
|
||||
iRect tmp;
|
||||
tmp.origin = iPoint(0, cursor.y);
|
||||
tmp.size = iSize(80, 24 - cursor.y);
|
||||
screen->scrollUp(tmp);
|
||||
|
||||
}
|
||||
|
||||
| 0x1b $nop
|
||||
|
||||
| 0x1c $nop
|
||||
|
||||
| 0x1d $nop
|
||||
|
||||
| 0x1e arg1 arg2 ${
|
||||
// CTRL('^'):
|
||||
/* goto x y */
|
||||
// todo - verify behavior for illegal values.
|
||||
cursor.x = clamp(_scratch[0]-32, 0, 80 - 1);
|
||||
cursor.y = clamp(_scratch[1]-32, 0, 24 - 1);
|
||||
}
|
||||
|
||||
| 0x1f $nop
|
||||
|
||||
| 0x20 .. 0x7f ${
|
||||
screen->putc(fc, _context);
|
||||
} $advance
|
||||
|
||||
| 0x80..0xff $nop
|
||||
|
||||
)* $err{ fgoto main; };
|
||||
|
||||
write data;
|
||||
}%%
|
||||
|
||||
|
||||
@implementation PTSE
|
||||
|
||||
+(void)load
|
||||
{
|
||||
[EmulatorManager registerClass: self];
|
||||
}
|
||||
|
||||
+(NSString *)name
|
||||
{
|
||||
return @"Proterm Special Emulation";
|
||||
}
|
||||
|
||||
-(NSString *)name
|
||||
{
|
||||
return @"Proterm Special Emulation";
|
||||
}
|
||||
|
||||
-(const char *)termName
|
||||
{
|
||||
return "proterm-special";
|
||||
}
|
||||
|
||||
-(void)reset: (Screen *)screen
|
||||
{
|
||||
[self reset];
|
||||
|
||||
if (screen) screen->eraseScreen();
|
||||
}
|
||||
|
||||
-(void)reset
|
||||
{
|
||||
%%write init;
|
||||
|
||||
_context.cursor = iPoint(0,0);
|
||||
_context.window = iRect(0,0,80,24);
|
||||
_context.flags = 0;
|
||||
}
|
||||
|
||||
-(BOOL)resizable
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
-(struct winsize)defaultSize
|
||||
{
|
||||
struct winsize ws = { 24, 80, 0, 0 };
|
||||
|
||||
return ws;
|
||||
}
|
||||
|
||||
-(id)init
|
||||
{
|
||||
[self reset];
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void)initTerm: (struct termios *)term
|
||||
{
|
||||
// Control-U is used by the up-arrow key.
|
||||
term->c_cc[VKILL] = CTRL('X');
|
||||
}
|
||||
|
||||
-(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;
|
||||
|
||||
|
||||
// backspace and left arrow use the same code, alas.
|
||||
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 & NSControlKeyMask)
|
||||
c = CTRL(c);
|
||||
|
||||
output->write(c);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
Loading…
x
Reference in New Issue
Block a user