Issue 4-34, August 25, 1999

Be Engineering Insights: The Input Server Part 3: Pointing Devices and Tablets

By Hiroshi Lockheimer

This is a tale of the Input Server and the devices it recognizes. I know you've heard this before, but today we're going to approach the topic from the point of view of "pointing devices" (mice, tablets, and the like), with a concentration on tablets. First, let's review:

Way back before we knew better, user input was handled by the Application Server. The user would move the mouse or type on the keyboard, and, in response to a notification from the mouse or keyboard driver, the Application Server would create a message and send it to the appropriate application. This was a closed system; the only place you could step into the input river was at the application level—well after all the important decisions had been made.

A couple of releases back, we decided to provide an "input spigot" that sat upstream of the Application Server. This new machinery, the Input Server, lets the developer create an input device add-on that listens to a particular driver (or drivers), and manufactures the messages that are then handed to the Application Server (which still delivers them to specific applications).

Currently, the Input Server recognizes two types of devices: keyboard devices and pointing devices. When you create an input device, you have to declare it to be one or the other. We chose the name "pointing device" (or, in Input Server parlance, B_POINTING_DEVICE) rather than "mouse device" because there's more than one way to point. Tablets, for example.

However, when we move from the Input Server into the Application Server, we see a bias towards mice. All B_POINTING_DEVICE devices are expected to communicate with the Application Server by creating and sending the messages B_MOUSE_UP, B_MOUSE_DOWN, and B_MOUSE_MOVED. We chose these messages, rather than create a new protocol, to ensure backward compatibility. And, as with most backwardly compatible decisions, a few modern details were left wanting. In the case of pointing devices, there are two problems with the messages, particularly the B_MOUSE_MOVED message:

To get around these problems, we've added new conventions to the B_MOUSE_MOVED protocol, as explained below.

The View Problem

The B_MOUSE_MOVED message contains a BPoint "where" field that, by convention, contains the cursor location in view coordinates. However, views live in the Application Server, which is downstream from the input device that has to create this message. In other words, the input device doesn't know anything about views, and so can't translate to view coordinates. To bridge this gap, we've modified the B_MOUSE_MOVED convention.

When creating a B_MOUSE_MOVED message from within an Input Server device, you add "x" and "y" fields, setting their values to either an offset relative to the cursor's previous position, or an absolute position in the range 0.0 to 1.0.

Mice always use relative locations; tablets can use either, although absolute locations are the norm (more on that later).

Relative Location

All mice and some tablets can express the pointer location relative to its previous position. If your pointing device is operating in relative coordinate mode, you add "x" and "y" as int32 values:

int32 xVal, yVal;
event->AddInt32("x", xVal);
event->AddInt32("y", yVal);

In this case, xVal and yVal are the horizontal and vertical distances, in device-defined units, that the cursor moved. These units are interpreted as pixels by the Application Server.

Absolute Location

To set the field to a location, you add "x" and "y" fields as floats. For example:

float xVal, yVal;
event->AddFloat("x", xVal);
event->AddFloat("y", yVal);

As mentioned above, xVal and yVal must be in the range 0.0 to 1.0. The values are then scaled, by the Application Server, to the screen's coordinate system such that (0.0, 0.0) is the top left of the screen, and (1.0, 1.0) is the bottom right. By using a 0.0 to 1.0 range, the pointer device can express the cursor location independent of screen resolution.

A Word on "where"

In both cases—i.e., relative and absolute location—the Application Server creates and adds a "where" field based on the "x" and "y" values translated to the target view's coordinate system, and throws away the original "x" and "y" fields. The fact that the "x" and "y" fields aren't retained is important, as explained below.

Tablets Are Smarter Than Mice

Tablets really feel the user. They supply a lot more information about the user's digital probing than a mouse does. Specifically, a tablet can track movement with much greater precision than a mouse, a tablet can include pressure and tilt information, and it can go into "eraser" mode.

To accommodate this information, the next release will introduce some conventions for tablet-specific fields in the B_MOUSE_MOVED message. These fields, described below, won't be acted upon by the Application Server, but they will be passed through to the application that receives the B_MOUSE_MOVED message. The application can decide whether it wants to use this information or not.

Tablet Precision

As mentioned above, a tablet can encode the pointer's absolute location through "x" and "y" fields, which the Application Server converts to a "where" field. Although the "where" precision (a BPoint) is sufficient for most applications, it's nowhere near as precise as the original "x" and "y" values. Some applications may be interested in the "real" tablet-precise location; but the original "x" and "y" fields are thrown away by the Application Server.

To get around this, your tablet should copy its absolute location values into the "be:tablet_x" and "be:tablet_y" fields. So the example shown above should actually look like this:

float xVal, yVal;
event->AddFloat("x", xVal);
event->AddFloat("y", yVal);
event->AddFloat("be:tablet x", xVal);
event->AddFloat("be:tablet y", yVal);

The additional fields are passed through without conversion; it's up to the application to interpret them properly.

Tablet Pressure

Tablet pressure is expressed as a float in the range 0.0 to 1.0 (minimum to maximum), and added as the "be:tablet_pressure" field:

float pressure;
event->AddFloat("be:tablet pressure", pressure);

Tablet Tilt

Tilt is in the range -1.0 to 1.0, where (-1.0, -1.0) tilts to the top left, (1.0, 1.0) tilts the bottom right, and (0.0, 0.0) is no tilt. The fields are "be:tablet tilt x" and "be:tablet tilt y":

float tilt_x, tilt_y;
event->AddFloat("be:tablet tilt x", tilt_x);
event->AddFloat("be:tablet tilt y", tilt_y);

Eraser Mode

Eraser mode is expressed as an int32 in the "be:tablet_eraser" field:

int32 eraser;
event->AddInt32("be:tablet_eraser", eraser);

The value is 1 when the pen is reversed (the eraser is on), and 0 otherwise. Other eraser modes may be defined in the future.

Hold Your Horses

BeOS Release 4.5 didn't include any tablet drivers—we hope to fill this void in the next release. The tablet device that's included will certainly use the conventions described here.

If you're writing a tablet device, you should use the new fields yourself. (Note that if you're writing a mouse device, you don't need to add these fields to the messages that you create.) More importantly, if you're writing an application that can benefit from a tablet's features, you should look for the new fields in the B_MOUSE_MOVED messages that you receive.

Past articles about the Input Server by Hiroshi Lockheimer:

Be Engineering Insights: An Introduction to the Input Server

Be Engineering Insights: An Introduction to Input Method Aware Views


Be Engineering Insights: Napoleon's Maxim

By Leo L. Schwab

Software engineering is a rewarding profession and a demanding one. "Multidisciplinary" only vaguely describes the variety of knowledge and skills a good engineer should have, especially at a place like Be. However, just as important as selecting the right algorithm, the right compiler, the optimum keymappings in the editor, is the ultimate choice an engineer must make: where to eat.

We are fortunate at Be to be located within 10 minutes walk of many excellent eateries, an often-overlooked contribution to the quality of work we're able to do here. Menlo Park—hardly a downscale town—is adjacent to upscale Palo Alto and Atherton, which affords us a broad spectrum of cuisine, from no-star fast food to four-star slow food.

Asian food seems to be the most popular in the Be lunchroom. Su Hong Chinese Restaurant (known as "The Hong") gets a lot of Be business. Our Fearless Leader JLG is often seen there ordering the Menlo Combo to go. If Su Hong is too clean for you, there's always Mr. Chau's, a bit further away. We have no less than *three* choices for sushi: Akasaka, Gombei, and Tokyo Subway ("Sokyo Tubway"), the last being the popular choice.

Other ethnicities are also well represented. Just up the road is Gaylord's Indian restaurant. For Mexican food you have your choice of burritos: MexToGo gets frequent visits, as does Una Mas, and 360° Burrito (where they go by their yuppie name, "wraps"). If you hanker for Swiss cuisine there's Amandine, where waiters maintain neutrality in not favoring one dish over another. For French food there's Le Pot Au Feu, though I don't see many Be regulars there. I enjoy Italian, at Florentines, Trattoria Buon Gusto, and Scala Mia, places that understand basil. (I love basil. Basil should be used in everything. Breast of chicken stuffed with sun-dried tomatoes and basil, dolmas wrapped in basil instead of grape leaves, basil bread, basil salad, basil sandwiches, basil ice cream, Basil Rathbone...the list goes on.)

Pizza, the long-standing basic food group for engineers, is available at Round Table, but if you're here in the evening, Applewood, open only for dinner, is a superior venue.

Deli-style sandwiches? No problem. Togos just opened next door, and Jan's is just on the other side of the tracks. But if you like great heaping eye-watering gobs of Dijon mustard, Le Boulanger ("Boolanger") serves up fancy sandwiches on fresh-baked bread, although some may prefer the less pretentious fare at The Oasis. All things chicken are found at the oddly named Koo-Koo-Roo ("The Koo").

Looking for a gimmicky restaurant with deep-fried everything? There's a Chili's right next door. If you prefer more "traditional" unhealthy food, like burgers, there's the ubiquitous McDonald's®©(BFD), or you can walk a bit further and get a real burger at Clark's. There's an Arby's across the street, a place so amazingly cheesy that their Web page is hosted on AOL. Fishier fare is just next door at Cook's Seafood, and coming soon is 3 Fish, under construction next to our building.

Looking for healthier cuisine? That's covered, too. Late For The Train is so healthful, you won't recognize it (it's organic, don'cha know). Hobee's in Palo Alto (my favorite place) is less austere, and they serve killer breakfasts all day.

If your goal isn't so much eating as hanging out and relaxing, then Caffe Borrone ("Cafe Baloney") may be your spot, conveniently located next to a Ricochet repeater for your laptop. Or you could hike up to the bistro above Draeger's supermarket, where you can order >from one of about fifteen teas and several dishes garnished with goat cheese.

If, like us, you just IPO'd (and if you haven't, what's the matter with you?), then you'll probably want to celebrate by visiting a fake-teak-and-crystal upscale place like Left Bank which opened a few months ago, or the even more recent Wild Hare, which actually serves hare and other game meats (their bison burger is very good). Or you could go to the long-established Dal Baffo, a place whose picture you see in the dictionary next to the term "exquisite dining."

If you need to get some shopping done over lunch, there are lots of places in Stanford Shopping Center, ranging from the mega-salad bar at Fresh Choice to Max's Opera Cafe, where they will sing Happy Birthday© to you in twelve-part harmony.

I'm sure after this article goes to press that I'll start hearing from everyone in the office about places I neglected to mention, or places I portrayed in an insufficiently flattering light. Such a response, I think, would confirm that we at Be take our food as seriously as our products. It's said that programmers are engines that turn pizza into code, but the quality of the code you get is only as good as the fuel you put in. So we're fortunate to be located where we are, with a full spectrum of dining options available. Though other factors—like a flair for programming—are just as important to the success of our company, I'm sure Napoleon would have agreed that, like an army, a software company travels on its stomach.

(Trademarks used above are the property of their respective owners. The mention or failure to mention a particular establishment should not be interpreted as an official endorsement or nonendorsement of said establishment by Be, Inc. The author cheerfully accepts bribes in exchange for mention in future articles.)


Developers' Workshop: Lights... Camera... Render!

By Chris Tate

Digital images are easy to create. Putting pixels into memory is a simple, well-understood art. Writing them to disk in a useful manner is a trifle more complex, but the BeOS Translation Kit provides a number of tools to help manage that complexity. All in all, putting still images on disk isn't something that causes headaches.

Digital movies are another story. As with still image files, there are a number of different file formats to choose from, but there are also choices of compression scheme, whether and how to provide a sound track, and so on. Creating animations means a lot of supporting code, especially if that support is duplicated in a number of different applications.

BeOS R4.5 introduced some new Media Kit classes designed to provide that support to all applications: BMediaTrack and BMediaFile. A BMediaTrack represents one coherent stream of data, for example a digital sound track or a sequence of images to be played at a specified rate. A BMediaFile contains one or more BMediaTracks, and represents the movie as a whole, providing the interface that determines the file format as well as other attributes of the movie file as a whole.

How do these two classes help you create digital movies? As I mentioned, still images are relatively easy to create. BMediaTrack provides an interface for putting a sequence of still images together, and BMediaFiles write BMediaTracks out to actual disk files in the proper manner. The Media Kit has functions for iterating over the list of all installed media file writers as well as the list of supported codecs for a given media format. All you need now is a simple way of hooking them all together.

That brings us to this week's sample class—BitmapMovie. This class provides a very simple interface for creating a movie file out of a sequence of BBitmaps. Before I describe it, I should point out that you can find the source code for BitmapWriter at this URL:

<ftp://ftp.be.com/pub/samples/media kit/BitmapWriter.zip>

When you construct a BitmapMovie object, you specify its dimensions and the color space that your BBitmaps will use (generally you'll use B_RGB32, since that's the most widely accepted color space on the BeOS). Then choose the file format, media format, and codec you want, and call BitmapMovie::CreateFile(). That creates the file on disk according to your specifications. Now all you need to do is call BitmapMovie::WriteFrame() repeatedly, passing in the BBitmaps representing successive frames of video, until you're finished. At that point you call BitmapMovie::CloseFile(), and your movie is safely ensconced on the disk.

The BitmapWriter sample program demonstrates the BitmapMovie class by creating a simple animation and writing it to disk. The application also demonstrates the mechanism for determining the available file formats and codecs, and presents a user interface for selecting any of the supported combinations. The code is pretty simple; I'll just go over a few highlights and important points to remember when you write your own code to handle BMediaFiles and BMediaTracks.


Bit By Bit: Resizing and Scroll Bars

By Stephen Beaulieu

Last week's installment of Rephrase showed you how to open large files. Now you need an easy way to view the file's contents. Although BTextView provides keyboard navigation (PageUp and PageDown), scroll bars and a resizable window are more useful, so we'll add them this week.

You'll find this version of Rephrase at:

<ftp://ftp.be.com/pub/samples/tutorials/rephrase/rephrase0.1d3.zip>

Rephrase 0.1d3
New Features
Resizable Windows
Scroll Bars
"Intelligent" Window Sizing

Programming Concepts

A frame rectangle is the size and position of a window or a view in its parent's coordinate space. For a window this is the screen; for a view it is its window or parent view. It is the rect where the object is responsible for displaying itself.

When the frame rectangle of a window or a view changes, a frame event message is sent. Windows and views that have the B_FRAME_EVENTS flag receive these messages and the FrameResized() or FrameMoved() hook functions are called. The functions themselves are straightforward: FrameResized() reports the new width and height of the rectangle; FrameMoved() informs the object of its new position in its parent's coordinates (the screen for a window or the view's parent).

Currently Rephrase doesn't care about FrameMoved() calls. FrameResized() calls are another matter. The phrase display window responds to FrameResized() calls to adjust the size of the text view's text rectangle. The BTextView also cares about FrameResized() messages; it uses them to update any scroll bars that might be targeting the view.

Scrolling a view changes the portion of its contents visible in a view's frame. BScrollBars are BViews that visually represent the section of the display view shown and provide a means to scroll that view. BViews and BScrollBars interact to keep in sync: BScrollBars call BView::ScrollTo() and BView::ScrollBy(), and BViews call BScrollBar::SetValue().

BTextView takes this interaction a bit further. When the content in a text view changes, it will update the value, proportions, and ranges of any BScrollBar targeting it. All the work is done by the BTextView; just create the BScrollBars and target the text view.

Implementation details:

  • pDisplay now has a BTextView* member, fEdit. This is used throughout the window to access the text view. [pDisplay.h:20]

  • pDisplay now creates its BWindow superclass with a document window look and removes previous restrictions on zooming and resizing. [pDisplay.cpp:27-28]

  • BuildMenus() is a new function that encapsulates building the main menu bar. It was introduced mainly for readability purposes. [pDisplay.cpp:209-232]

  • pDisplay::FrameResized() adjusts the size of the text rectangle in the text view. It remains a constant 4 pixels inset from the text view proper. The text flickers a bit, as the entire text view may need to be redrawn because of differing line wrap. [pDisplay.cpp:154-165]

  • Window size is determined dynamically, based on the default font and the current printer settings, rather than having a fixed rectangle size. The window's text rectangle is set to be 40 lines high, based on the font. The width of the text rect is either the width of the current printer's printable rectangle or 45 ems. An em is a typographical unit based on the width of an uppercase M. For roman character fonts it's considered a good estimate of the widest character in the font. [pDisplay.cpp: 31-82]

  • The BPrintJob class is used for interacting with the print server. We'll use it again in a future installment addressing printing issues. In this issue we use BPrintJob::PrintableRect() to return a BRect that represents the default printer's rectangle for printing. If a printer has been set up, Rephrase uses its printable rect's width for the width of the pDisplay text rectangle. If no printer has been set up, the rectangle will be invalid. [pDisplay.cpp:43-53]

  • The BFont class represents a font used to display text for a view. You can use the class to acquire information about the font. Three global font pointers are defined for the system: be_plain_font, be_bold_font, and be_fixed_font. You make these systemwide settings in the Font preferences panel. be_plain_font is the default font for all text views.

  • Rephrase uses BFont::GetHeight() to determine the height of a line of text. BFont::StringWidth() determines the size of an em (see number 5 above). This value is used to set the window's minimum width, and perhaps the default width if no printer is available. [pDisplay.cpp:35-41]

  • Window size limits are based on font and screen size. The minimum size is based on a text rect 12 ems wide and 10 lines deep. The maximum is the size of the screen. [pDisplay.cpp:74-82]

  • To enlarge a BRect by a specific amount on each side, pass negative values into BRect::InsetBy(). Be sure to remember to offset the rectangle to B_ORIGIN (BPoint(0,0)) if you're expecting the rectangle to start there. [pDisplay.cpp:58-59]

Next week: BFilePanels and saving files.


Going Public: Part I

By Jean-Louis Gassée

There are things I shouldn't say, at least not if I'm unprepared to see a throwaway remark bounce back and become a reality. I used to say, "Don't ask me 'When is our IPO?' My office overlooks the parking lot, and when I see the BMWs of investment bankers fighting for spaces, I'll know it's time."

Early this year, one of our friends in the banking community came to see us and flatly told us to get moving, to start preparing for an Initial Public Offering. "But, but, but," I stuttered. "I may have been abducted by aliens and raised in California by VCs, but I'm still a French Farmer at heart—too financially conservative to have debt or day-trading account. It's too soon, we don't have the revenues and earnings record to qualify for an IPO."

They said I should be ashamed of myself. How could I, a professed born-again capitalist, let the statist roots of my culture of birth corrupt my thinking? In other words, who was I to second guess the market?

Just as the simple and memorable catechism of the Universal Life Church states, "Only You Can Decide What The Good Is For You," only the market can decide what a good investment is. And the market's calculus of risk and reward has changed since the days of Standard Oil, General Motors, and General Electric. At each cycle of the market's evolution, there have been good and bad investments, fairly balanced between old school conservative companies and the New Age ones of the time. Not everyone felt that RCA or IBM was a good investment, or that they signalled a new era. And the same was true for Intel, Dell, or Microsoft.

Right now, the good banker said, the market has decided that "The Good" is in betting on the future of the Internet. You can do a Greenspan impersonation with a French accent and question the exuberance, but even the Fed Chairman now concedes that there are potential huge winners, future GMs, GEs, and Standard Oils in cyberspace.

I've seen what BeOS does, the good banker continued. With the huge investments in broadband, fat pipes to homes and offices everywhere, you have a role to play on both ends of these pipes, in the creation and consumption of digital media. It's hard to argue with a banker who's selling you your own product.

That's how we got started on the road to the IPO. And we found ourselves being sold our own ideas again when we began interviewing investment banking firms. By February of this year, the banking community was preparing what has become the most active IPO season ever, the Spring of 1999. It showed in the attention span of some, but the quality of discussions was generally pretty high, with a good consensus on the risk/reward proposition to present to investors.

In the end, I was impressed by the quality, the professionalism, and reaction time of the best presentations. In the case of the two that drove our choice, within 24 hours, the banking firm came back with a detailed analysis of our business, its place in the landscape, its competition, its risks and advantages. I know it's their business to do this, I know they have PowerPoint and Excel templates, but faking intelligence in person is harder.

With all due respect to the bankers (I'll come to their part later), it was the analysts who did it. In the case of Volpe Brown Whelan, the lead firm, it was Charlie Finnie (called Mr. Charles Finnie by the veddy British New Economist) and his encyclopedic knowledge of the world of digital media and the Internet. In the case of Needham, our New York-based firm, it was Brent Williams and his very assertive and articulate command of the world of operating systems and multimedia. Charlie and Brent sang our song better than we ever did—and under their tutelage we would learn how to best present ourselves to the investment community.

But before we got to the pitch, we had to meet the SEC's requirements -- that is, we had to file a prospectus and get clearance to proceed. For that phase of the process, see Going Public: Part II, next week.

Creative Commons License
Legal Notice
This work is licensed under a Creative Commons Attribution-Non commercial-No Derivative Works 3.0 License.