openstenoproject / plover

Open source stenotype engine
http://opensteno.org/plover
GNU General Public License v2.0
2.36k stars 277 forks source link

Support palantype #53

Closed balshetzer closed 6 years ago

balshetzer commented 12 years ago

Henry writes:

Hello, everyone!

I haven’t posted here for a while, but I am glad to be doing so again!

I’m posting to ask for some help with coding a new aspect of Plover. I would like to tell you that my coding skills are non-existent, so please be aware of this!

I use a version of steno that was mostly used in Britain called palantype. Here is a copy of the layout: http://www.spellingsociety.org/journals/j16/images/palantype4.gif

Anyway, it is a bit like steno – we have briefs, substitution cords for letters, so MF is W, for example, but the theory is different as there is a different layout of keys and the keys are assigned to different letters.

So, I’d really like it if Plover could support palan. I don’t know if it would be at all possible, but I’d really love it to be. I currently use a student version of the very expensive Total Eclipse, but if there is free software, I would be very happy to use it.

I have some instructions from a programmer of a certain piece of steno software who shall remain unnamed – he very kindly provided me with them. I don’t really understand them, but they’re here:

“I'm afraid that integrating the code for interfacing the Palantype into any sort of program would be difficult, even for an experienced software developer. Just so you can appreciate the difficulty, though, I'll forward you the pertinent information on how to interface the writer.

To begin with, I will assume that you already familiar with the following basic programming skills:

  1. How to open and close files and read and write data to them so that once you receive the data you can do something with it by storing it in a simple text file.
  2. If you actually want your program to type text directly into another program such as a word processor, you will have to use the Windows JournalPlaybackHook and convert the text to keystroke commands to be processed by the other application.
  3. How to open and close COM ports and how to read and write data to them.
  4. How to spawn background threads or otherwise execute periodic continuous functions. Some languages prefer using short-duration timer messages for this. Either one will work.
  5. Finally, I will assume that you are capable of writing code that takes a pattern of bits and converts it into text, since all chording keyboard data structures are usually stored in binary rather than text. So, for example, if an 8-key keyboard had the keys "STRAOLNP" and was represented by a single byte of data, the hexadecimal byte 0xC9 would be the binary 11101001, which would be "STOP". You will have to write the code the do that data conversion.

All of the above items are relatively trivial for an experienced programmer. The difficult part was figuring out the protocol that the Palantype uses to communicate data to and from the software: figuring out what the actual commands were that it understood and what the data format was for the data that came back. So here's all you need to know about how the Palantype works, in C++ code, with a few notes to follow. I've left in some important notes in C++ comment fields. Note that you could easily adapt this to any other language if you're more familiar with something like Python, Visual Basic, etc.

/*
To command writer:
0x81 and 0x91 to get attention

0x90, 0x93, 0xAA to start realtime
While writing realtime, send 0x80 continuously
send 0x95 when quitting,
*/

void PalantypeWriter::Initialize()
{
        // handshake with the Palantype writer
        m_Serial.Write(0x81);
        Sleep(500); // wait half a second between each command byte
        m_Serial.Write(0x91);
        Sleep(500);
        m_Serial.Write(0x90);
        Sleep(500);
        m_Serial.Write(0x93);
        Sleep(500);
        m_Serial.Write(0xAA);
        Sleep(500);
        m_nByte = -1;
        m_anST[0] = 0;
        m_anST[1] = 0;
        m_anST[2] = 0;
        m_anST[3] = 0;

        // begin executing the writer thread
        ResumeThread();
}

// this function should run be continuously by a thread or timer
function elsewhere
void PalantypeWriter::WriterThreadProc()
{
    // check for incoming data and process it
    Sleep(10);
    if (!m_Serial.IsDataWaiting()) {
        m_Serial.Write(0x80);
        Sleep(200); // send the 0x80 byte approximately five times per second
        return;
    }
    BYTE b1, b2, b3, b4;
    BYTE b = m_Serial.Read();
    if ((b < 0x10) && (m_nByte != 1) && (m_nByte != 2)) {
        m_nByte = 0; // start over with a new stroke
        return;
    }
    if ((m_nByte > 3) || (m_nByte < 0)) return;
    m_anST[m_nByte] = b;
    if (m_nByte++ < 3) return;
    m_nByte = 0;
    b1 = m_anST[0];
    b2 = m_anST[1];
    b3 = m_anST[2];
    b4 = m_anST[3];

/*
The Palantype bit pattern desired:
xx11 1111  1111 1111  1111 1111  1111 1111
  SC PTH+  MFRN LYOE  AUI^ NLCM  FRPT +SH

S FD 00 00 00   1111 1101  C FE 00 00 00   1111 1110
P FB 00 00 00   1111 1011  T F7 00 00 00   1111 0111  H EF 00 00 00   1110 1111

+(left) DF 00 00 00   1101 1111  +(right) BF 00 00 00  1011 1111

M 7F 00 00 00   0111 1111  F 00 FE 00 00   1111 1110  R 00 FD 00 00   1111 1101
N 00 FB 00 00   1111 1011  L 00 F7 00 00   1111 0111  Y 00 EF 00 00   1110 1111

O 00 DF 00 00   1101 1111  E 00 BF 00 00   1011 1111
A 00 7F 00 00   0111 1111  U 00 00 FE 00   1111 1110
I 00 00 FD 00   1111 1101

^(left) 00 00 FB 00   1111 1011  ^(right) 00 00 F7 00  1111 0111

N 00 00 EF 00   1110 1111  L 00 00 DF 00   1101 1111  C 00 00 BF 00   1011 1111
M 00 00 7F 00   0111 1111  F 00 00 00 FE   1111 1110  R 00 00 00 FD   1111 1101
P 00 00 00 FB   1111 1011  T 00 00 00 F7   1111 0111  + 00 00 00 EF   1110 1111
S 00 00 00 BF   1011 1111  H 00 00 00 DF   1101 1111

Flipped and xor'd:

b1 CSPT H++M
b2 FRNL YOEA
b3 UI^^ NLCM
b4 FRPT +HS*

Desired:

s1 ..SC PTH+
s2 MFRN LYOE
s3 AUI^ NLCM
s4 FRPT +SH*
*/

    b1 = BitFlip(b1 ^ 0xFF);
    b2 = BitFlip(b2 ^ 0xFF);
    b3 = BitFlip(b3 ^ 0xFF);
    b4 = BitFlip(b4 ^ 0xFF);
    s1 = // b1: CSPT H++M goal: ..SC PTH+
       ((b1 & 0x80) >> 3) | // 0b10000000
       ((b1 & 0x40) >> 1) | // 0b01000000
       ((b1 & 0x38) >> 2) | // 0b00111000
       (((b1 & 0x06) != 0) ? 0x01 : 0); // 0b00000110
    s2 = // b2: FRNL YOEA goal: MFRN LYOE
        ((b1 & 0x01) << 7) | // 0b00000001
        (b2 >> 1);
    s3 = // b3: UI^^ NLCM goal: AUI^ NLCM
        ((b2 & 0x01) << 7) | // 0b00000001
        ((b3 & 0xC0) >> 1) | // 0b11000000
        (b3 & 0x0F) | // 0b00001111
        (((b3 & 0x30) != 0) ? 0x10 : 0); // 0b00110000
    s4 = // b4: FRPT +HS* goal: FRPT +SH*
        (b4 & 0xF9) | // 0b11111001
        ((b4 & 0x04) >> 1) | // 0b00000100
        ((b4 & 0x02) << 1); // 0b00000010

    AddStroke(s1, s2, s3, s4);
}

Some further explanation for missing functions:

m_Serial is the COM port class. m_Serial.Write writes a single byte to the COM port. m_Serial.Read reads a single byte from the COM port. m_Serial.IsDataWaiting() tells if there is data ready to be received. Replace this with whatever the COM port handling code is in the language you're going to use.

Sleep(n) is the Widows C++ function to pause for n milliseconds.

BitFlip(x) is a function that returns a byte which is the original byte with the bits flipped over, so 11001010 becomes 01010011. You need to write this function for whatever language you're using.

AddStroke is a function that takes the Palantype stroke and does whatever you need to do. You will need to write this function to interpret the binary data into text and send it wherever you need it.”

I just don’t understand any of that really!

If anyone can help with this, it would be fantastic, but I am sure you are all very busy!

Thanks,

Henry

marnanel commented 9 years ago

I was talking to Mirabai about this, and volunteered to investigate.

morinted commented 9 years ago

Palantype has ~29 keys, it would require very deep changes, I think. Sounds exciting :) do you use a palantype?

stenoknight commented 9 years ago

I've received a Palantype protocol spec from A Shadowy And Mysterious Source and will be sending it on to you today, Marn. Apparently it shouldn't be too hard to implement! Also, a testing machine might be forthcoming soon. Fingers crossed. On Sep 28, 2015 1:44 AM, "Ted Morin" notifications@github.com wrote:

Palantype has ~29 keys, it would require very deep changes, I think. Sounds exciting :) do you use a palantype?

— Reply to this email directly or view it on GitHub https://github.com/openstenoproject/plover/issues/53#issuecomment-143645333 .

marnanel commented 9 years ago

Exciting news! LMK if/when you need my mailing address.

chajadan commented 9 years ago

Because of plover, I was able to create a couple custom chorded keyboards I wanted to try (one using only thu 4-9 keys of the keypad). I was thinking about making a program for arbitrary chorded keyboards and then realized it makes much more sense to just add a different engine type to plover. Then anyone who wanted to make a custom chord system for their NKRO keyboard could just specify the relationships.

On Mon, Sep 28, 2015 at 11:20 AM, Thomas Thurman notifications@github.com wrote:

Exciting news! LMK if/when you need my mailing address.

— Reply to this email directly or view it on GitHub https://github.com/openstenoproject/plover/issues/53#issuecomment-143833196 .

marnanel commented 8 years ago

@stenoknight What happened about the palantype? I don't seem to have received it.

stenoknight commented 8 years ago

Jason never got back to me after I offered to give him your mailing address. :'/

Sorry about that. I think he must have just dropped the ball. I'll ping him again.

On Fri, Jan 8, 2016 at 2:31 PM, Thomas Thurman notifications@github.com wrote:

@stenoknight https://github.com/stenoknight What happened about the stenotype? I don't seem to have received it.

— Reply to this email directly or view it on GitHub https://github.com/openstenoproject/plover/issues/53#issuecomment-170100583 .

Mirabai Knight, CRC, RDR StenoKnight CART Services 917 576 4989 mkk@stenoknight.com http://stenoknight.com

marnanel commented 8 years ago

An actual palantype machine has been found and will be on its way to me soon.

@chajadan, I'd be interested in seeing anything you've already come up with.

I think this issue contains a number of sub-issues:

Sanity check? If that makes sense, I'll raise separate issues.

These are the stenotype features I assume hold for palantype as well; I've emailed this list to Georgina to check: 1) it's operated by pressing chords of one or more keys simultaneously 2) the keys must all be released for the chord to be considered complete 3) there is a standard way to write down a chord 4) we are primarily concerned with producing English-language text here 5) there is some sort of consensus on what many of the chords mean, and there is a dictionary of these chords available for newbies (where "dictionary" means a mapping of chords to what they represent) 6) some chords are "briefs" and produce an entire word or more, of arbitrary complexity 7) some chords produce standard prefixes or suffixes, or punctuation or symbols 8) there is one particular chord used for correcting mistakes 9) but in general a chord represents a syllable in a systematic way, and the dictionary is used to combine these syllables into English words

morinted commented 8 years ago

I've edited the sample code in the post because the formatting made it hard to understand. It's actually relatively simple. I think I could get a Palantype "machine" going in a couple hours working with someone who has a machine. @tthurman does the edited code make more sense to you? Also, can we link the dictionary that Samuel sent you to the issue?

morinted commented 8 years ago

Seems to me like the bit flipping and reordering logic and all that is unnecessary. We can just act on the bytes themselves and assemble a list of keys like in treal.py:

# Note that in the returned data, 0 means the key is down, 1 means it is up.
byte_layout = (
    ('M-', '+2-', '+1-', 'H-', 'T-', 'P-', 'S-', 'C-'),
    ('-A', 'E-', 'O-', 'Y-', 'L-', 'N-', 'R-', 'F-'),
    ('-M', '-C', '-L', '-N', '-^2' '-^1', 'I', '-U'),
    ('', '-S', '-H', '-+', '-T', '-P', '-R', '-F'),
)

# The Palantype layout
'''
   P- M- N-         -N -M -P
C- T- F- L-         -L -F -T -H
S- H- R- Y- O- I -A -C -R -+ -S
  +1-  +2-  E- I -U  -^1  -^2
'''

Seems that, functionally, +1 and +2 both map to "+-" and -^1 and -^2 both map to "-^". It's kind of like the number bar in steno where they split it apart to be easier to hit.

marnanel commented 8 years ago

Samuel Belli sent me a Palantype dictionary, as promised. Here it is, in .dix format.

Can anyone covert .dix to JSON or RTF? I've played around building a converter in tha past, but the format is undocumented. I could probably finish it if I could get hold of a .dix file along with the JSON or RTF equivalent. Maybe I'll open another issue about that?

palantype-dictionary.zip

SamuelBelli commented 8 years ago

Palantype, just as an FYI has no prepackaged theory + dictionary like say , Phoenix our StenEd. Not that I'm aware of anyway. Most Palan Jedi that I know built their own dictionary and created their own shortforms.
So there is only one theory, it allows you to write virtually any word but has a limited dictionary.

morinted commented 8 years ago

So apparently the bytes are close to palanorder:

SCPTH+MFRNLYOEAUI^NLCMFRPT+SH

versus the protocol's CSPTH++MFRNLYOEAUI^^NLCMFRPT+HS

Of note: there's no number bar. Everything is a dictionary. I don't have the number strokes yet but I know how to generate them if need be.

I got Samuel to convert the dictionary to RTF, which I think we should use as a base for now. It seems that the Palantype doesn't have standard "theories" like steno. Rather, the number of keys allows for all sounds to come out of each hand through certain combinations, and it's up to the student to develop their own briefs and shortcuts from there.

palantype-rtf zip

morinted commented 8 years ago

@SamuelBelli and I had good luck tonight! We got his Palantype working with Plover relatively easily thanks to @benoit-pierre's refactoring of the code base to make systems possible.

Here's the branch I was working on: https://github.com/morinted/plover/tree/palantype

And here's a sample build for Palantype users. They will need to remove the main dictionaries and replace them with RTF exports of their existing dictionaries.

plover-palantest.exe.zip

SamuelBelli commented 8 years ago

Seems to be working so far.

Will continue to test but seems ok so far

SamuelBelli commented 8 years ago

Morning all. So plover for palan is working well. The only issue I can see is in dictionary, you can only look up words using steno, you can't type in "before" for example and it give you all corresponding matches. You can only search by inputting raw steno. "PFOR"

morinted commented 8 years ago

Here's my QWERTY to palan mapping qwertytopalanmapping

morinted commented 8 years ago

I made a vector of the layout proper:

Palantype.pdf

SamuelBelli commented 8 years ago

That's perfect !

morinted commented 8 years ago

Here's a visualization of palan order

Visualization of the palanorder
morinted commented 8 years ago

http://openstenoproject.org/palantype is now up with a tiny guide on how the Palantype works.

morinted commented 7 years ago

Most recently, I've moved this into a system & machine plugin: https://github.com/morinted/plover_palantype_system

@SamuelBelli has been using it for a couple days now

morinted commented 6 years ago

This is released as a plugin now in the Plover weeklies.