Newton 2.x Q&A Category: Text and Ink Input and Display

Copyright © 1997 Newton, Inc. All Rights Reserved. Newton, Newton Technology, Newton Works, the Newton, Inc. logo, the Newton Technology logo, the Light Bulb logo and MessagePad are trademarks of Newton, Inc. and may be registered in the U.S.A. and other countries. Windows is a registered trademark of Microsoft Corp. All other trademarks and company names are the intellectual property of their respective owners.


For the most recent version of the Q&As on the World Wide Web, check the URL: http://www.newton-inc.com/dev/techinfo/qa/qa.htm
If you've copied this file locally, click here to go to the main Newton Q&A page.
This document was exported on 7/23/97.

Text and Ink Input and Display


ProtoPhoneExpando Bug in Setup1 Method (2/6/96)

Q: I am having a problem using protoPhoneExpando under Newton 2.0 OS. Something is going wrong in the setup1 method. Is this a known bug?

A: Yes, this is a known bug. protoPhoneExpando (and the entire expando user interface) have been deprecated in the Newton 2.0 OS, and are only supported for backward compatibility. If possible, you should redesign your application to avoid the expandos.

The problem seems to be that the expando shell is sending the setup1 and setup2 messages to the template in the lines array. These methods in protoPhoneExpando rely on information that isn't created until the view is actually opened.

We're investigating solutions to this problem. You can usually hack around the problem by placing a labelCommands slot in the template which has an array of one element, that element being the label you want to appear in the phone line. For example: labelCommands: ["phone"].

This hack works only if your protoPhoneExpando doesn't use the phoneIndex feature. If it does, you'll have problems that are harder to work around.


Pictures in clEditViews (2/6/96)

Q: Is there a API or procedure that allows an application to write objects such as shapes, PICTs, or bitmaps to a note in the Notes application?

A: There is no API for Notes specifically. The Notes "Note" view is basically a plain old clEditView, and clEditViews can contain pictures (in addition to ink, polygons, and text) in the Newton 2.0 OS.

The Newton Programmer's Guide 2.0 (in the "Built-In Applications and System Data" chapter) contains a description of the types of children you can create in the Notes application.

This is really a description of the frames you need to put in the 'viewChildren slot of a clEditView to create editable items. 'para templates are text and ink text, 'poly templates are drawings and sketch ink, and 'pict templates are images.

To add a picture to a clEditView, you need to create an appropriate template and then add it to the viewChildren array (and open the view or call RedoChildren) or use the AddView method to add it to an existing view (then Dirty the view.) See the item "Adding Editable Text to a clEditView" elsewhere in the Q&As for details.

The template for 'pict items needs to contain these slots:
viewStationery: Must have the symbol 'pict
viewBounds
: A bounds frame, like RelBounds(0,0,40,40)
icon
: A bitmap frame, see clPictureView docs

For other slots, see the documentation for the clPictureView view class.


Horizontal Scrolling, Clipping, and Text Views (2/7/96)

Q: I want to draw 80 columns in a clParagraphView that's inside a smaller view and be able to scroll back and forth. When I try this, it always wraps at the bounds of the parent. How can I create a horizontal scrolling text view?

A: Normal paragraph views are written so that their right edge will never go beyond their parent. This is done to avoid the circumstance where a user could select and delete some text from the left part of a paragraph in a clEditView, leaving the rest of it off screen and unselectable.

What happens is the viewBounds of the clParagraphView are modified during creation of the view so that the view's right edge is aligned with the parent's right edge. After that, wrapping is automatic.

The so-called "lightweight" text views do not work this way. You can force a paragraph to be lightweight by: 1) Making sure the viewFlag vReadOnly is set, 2) making sure vCalculateBounds and vGesturesAllowed, are off, and 3) not using tabs or styles. Lightweight text views are not editable, but you can use SetValue to change their text slots dynamically.

If you must use an editable clParagraphView or if tabs or styles are required, there is another workaround. The code to check for clipping only looks one or two levels up the parent chain, so you could nest the paragraph in a couple of otherwise useless views which were large enough to prevent clipping, and let the clipping happen several layers up the parent chain.


How to Intercept Keyboard Events (5/6/96)

Q: How do I intercept hardware keyboard events or "soft" keyboard events?

A: You can implement view methods that are called whenever the user presses a key on software or external (hardware) keyboards.. There are two keyboard-related methods associated with views based on the clParagraphView view class:
the viewKeyDownScript message is sent when a key is pressed.
the viewKeyUpScript message is sent when a key is released.

Both methods receive two arguments: the character that was pressed on the keyboard and a keyboard flags integer. The keyboard flags integer encodes which modifier keys were in effect for the key event, the unmodified key value, and the keycode. The layout of the keyboard flags integer is shown in the section below, "Keyboard Flags Integer". The modifier key constants are shown in the section "Keyboard Modifier Keys".

ViewKeyUpScript and ViewKeyDownScript are currently called using parent inheritance. Do not rely on this behavior: it may change in future ROMs.

If you want the default action to occur, these method must return nil. The default action for ViewKeyDownScript is usually to insert the character into the paragraph. (There may be other default actions in the future.) If you return a non-nil value, the default action will not occur.

You must include the vSingleKeyStrokes flag in the textFlags slot of your view for the system to send the ViewKeyDownScript or ViewKeyUpScript message for every key stroke. If you do not specify vSingleKeyStrokes, keyboard input may be dropped if a lot of key strokes are coming in.

The hard keyboard auto repeats with the following event sequence:

keydown -- keydown -- keydown -- keydown...

The soft keyboard auto repeats with this sequence:

keydown -- keyup -- keydown -- keyup -- keydown -- keyup...

Do not rely on this order, it may change in future ROMs.

ViewKeyDownScript

    ViewKeyDownScript(char, flags)

This message is sent to the key view when the user presses down on a keyboard key. This applies to a hardware keyboard or an on-screen keyboard.

char The character that was entered on the keyboard. Note that if a modifier key is the only key pressed (for example, the Shift key), this value will be 0.

flags An integer that specifies which modifier keys were pressed, the unmodified key value, and the keycode. The modifier key constants are shown in the section "Keyboard Modifier Keys".


ViewKeyUpScript

    ViewKeyUpScript(char, flags)

This message is sent to the key view whenever the user releases a keyboard key that was depressed. This applies to a hardware keyboard or an on-screen keyboard.

char The character that was entered on the keyboard. Note that if a modifier key is the only key pressed (for example, the Shift key), this value will be 0.

flags An integer that specifies which modifier keys were pressed, the unmodified key value, and the keycode. The modifier key constants are shown in the section "Keyboard Modifier Keys".

Keyboard Flags Integer

Bits Description
0 to 7 The keycode.
8 to 23 Original keycode. The 16-bit character that would result if none of the
modifier keys were pressed.
24 Indicates that the key was from an on-screen keyboard. (kIsSoftKeyboard)
25 Indicates that the Command key was in effect. (kCommandModifier)
26 Indicates that the Shift key was in effect. (kShiftModifier)
27 Indicates that the Caps Lock key was in effect. (kCapsLockModifier)
28 Indicates that the Option key was in effect. (kOptionsModifier)
29 Indicates that the Control key was in effect. (kControlModifier)


Keyboard Modifier Keys

You use the keyboard modifier key constants to determine which modifier keys were in effect when a keyboard event occurs.
Constant Value
kIsSoftKeyboard (1 << 24)
kCommandModifier (1 << 25)
kShiftModifier (1 << 26)
kCapsLockModifier (1 << 27)
kOptionsModifier (1 << 28)
kControlModifier (1 << 29)


How to Keep Multiple Keyboards Open (8/30/96)

Q: I want my protoKeyboard-based keyboard to be open at the same time as other keyboards. When my keyboard opens, it seems like any other keyboard closes. How do I keep multiple keyboards open?

A: When a protoKeyboard-based view opens, it closes the last-opened protoKeyboard-based view. However, you need not use protoKeyboard.

Instead, you can base your keyboard on a different view type (for instance, protoDragger) and use the RegisterOpenKeyboard view message to register the keyboard with the system. Using RegisterOpenKeyboard will ensure that the caret is set up properly and allows you to track the caret changes with the viewCaretChangedScript view message if desired.


Adding a Local Keyboard to a ProtoKeyboardButton-based Button (1/14/97)

Q: I have an application-specific keyboard that I would like to have appear only in my application's protoKeyboardButton-based keyboard list. Is this possible?

A: Yes, protoKeyboardButton has a method called SetKeyboardList that lets you do this. SetKeyboardList takes two arguments. The first argument is an array of keyboard symbols to add to the list. The second argument is an array of keyboard symbols to remove from the list. Note that the keyboard symbols of the built-in keyboards are listed on pages pages 8-26 and 8-27 of the Newton Programmer's Guide.

To create a local keyboard, your keyboard view must be declared either to the keyboard button view or to a view within in its parent view chain. It is common to declare the keyboard view in your application's base view. When you declare the keyboard view, it must be declared using the keyboard's keyboardSymbol.

There are three additional slots that your keyboard template must have:
1) a preallocatedContext slot with the symbol of the keyboard
2) a userName slot with the name that will appear in the protoKeyboardButton popup
3) a keyboardSymbol slot with your keyboard's symbol

The preallocatedContext slot and the keyboardSymbol slot must be the same symbol. Note that the keyboardSymbol slot is required, but the preallocatedContext slot is additionally necessary to avoid exceptions on devices prior to Newton 2.1 OS.

Next, in the viewSetupDoneScript of the protoKeyboardButton-based view, send the button a SetKeyboardList message with your keyboard's symbol. For instance, you might have the following viewSetupDoneScript:

viewSetupDoneScript: func()
    begin
        :SetKeyboardList( [kMyKeyboardSymbol], nil );

        // Be sure to call the inherited viewSetupDoneScript method!
        inherited:?viewSetupDoneScript();

end;


If you want to dynamically change the keyboard list, you can also override the buttonClickScript. You must first call SetKeyboardList, then call the inherited buttonClickScript.

All additions and subtractions are removed from the list when your protoKeyboardButton-based view is closed.


Getting Digital Ink to the Desktop (1/17/97)

Q: I want to get ink (for instance, a signature) from my Newton device to a desktop machine. How do I do that?

A: The easiest way to get digital ink to the desktop is to convert it into a bitmap on the Newton device, and send the bitmap up to the desktop via the Desktop Integration Libraries (DILs). Another common technique is to convert the ink into an array of (x,y) points and send that array to the desktop for it to convert into whatever format is suitable.

Take a look at the DTS Sample Code projects, "InkForm" and "InkTranslate". They offer some pointers on how to do this. Depending on how and when you want to do the translation, you'll either want to use the view method ViewIntoBitmap, or the global function GetPointsArray, or a set of functions from the Recognition chapter, particularly GetStroke and GetStrokePointsArray.

If you need DIL sample code, the DTS Sample Code project "SoupDrink" may be helpful to you.


Constraints on Keyboards Sizing to the View (4/7/97)

Q: I am having a problem with dynamically adjusting the size of keyboards. According to the documentation, adjusting the size of my keyboard view should cause the keys to size correctly to the bounds of the view. This does not happen. If I set the viewbounds of the keyboard (a full alphanumeric keyboard) to anything less than 224x80, the keys scrunch up only taking up about half the view (horizontally). They seem to size fine vertically. This happens even if I set the viewbounds to 222 (only 2 pixels shorter.) What is going on?

A: It turns out the the documentation does not give the full story. The final size of the keys in a keyboard is constrained by the smallest fractional key unit width you specify in the keyboard. To understand key units and key dimensions, read the "Key Dimensions" section of the Newton Programmer's Guide (pages 8-35,6). You can also find this information in the "Key Descriptor Constants" section of the Newton Programmer's Reference.

In addition to calculating the size (in key units) of the longest key row, the clKeyboardView also finds the smallest key unit specified in the keyboard and uses this to constrain the final horizontal size. It calculates a minimal pixel size for the keyboard and makes sure that the final keyboard size is an integral multiple of this value. For example, if the smallest size is 10 pixels, then the final keyboard can be 10 pixels or 20 pixels, but not 15 pixels. If the view is 15 pixels, the keyboard will be 10 pixels.

The calculation for this minimal size is:
    m = w * (1/s)


m - minimal size
w - width of the longest keyboard row in key units
s   - numeric equivelent for smallest keyboard unit specified in the keyboard:
    (keyHUnit = 1,  keyHHalf = 0.5, keyHQuarter = 0.25, keyHEighth = 0.125)


For the built-in ASCII keyboard in current ROMs, the longest row is 14 key units, the smallest key unit used is keyHQuarter, so the minimal width for the ASCII keyboard is:

    m = 14 * (1 / 0.25) = 14 * 4 = 56 pixels.


The keyboard will always be an integral multiple of 56 pixels in width. Note that 224 pixels is exactly 4 * 56. By changing the width to 223, the keyboard now becomes 168 pixels wide.


NEW: Using a Keyboard Equivalent to Close a Subview (5/12/97)

Q: In my application, I have a linked subview that is linked to a floater view. If I open that linked subview, then use a key command to close the view (on current devices, command-W), my application closes instead of the floater. How do I make the floater respond to a "close" key command?

A: There is a very subtle implementation detail of key-closing a view that is causing your problem. If you close a view using the keyboard, the following algorithm is used.

The children of each view, starting at the root view, are searched in reverse order for a close box.

The order of your base view's children can affect which view is first closed. If your close box or status bar child is after the linked layout child, then your application will be closed instead of the linked layout. If your close box or status bar child is before the linked layout child, then the linked layout will be closed first.

You can override this behavior by adding a _DoCloseButton method to your application's base view. The _DoCloseButton method is called when a keyboard equivalent is used to close a view. This method takes no arguments and must return true if you handled the close, or return nil to let the system continue to search for a close box in other applications.

Alternately, instead of creating your child as a linked subview, you could create it using the global function BuildContext. This guarantees that it will be searched for a close box before your application is searched.


NEW: Finding a KeyCommand by KeyMessage (6/16/97)

Q: How do I find a keyCommand if all I have is the keyMessage symbol?

A: There is a global function called MatchKeyMessage that will do what you want. However, the documentation was inadvertently left out of the current version of the Newton Programmers Guide for Newton 2.1 OS. The documentation should be:
    MatchKeyMessage(startView, keyMessage)


Finds the keyCommand frame for the specified message starting with the specified view.

startView - The view from which to start searching for the message
keyMessage - A symbol for the command message that will be searched for. This must be the same message that is specified in the keyMessage slot of the keyCommand frame

return value - Either nil or a keyCommand frame

The MatchKeyMessage function searches for the message using the same lookup rules that are used when the system handles a key command.