Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2006-151
$eventId
ID of event: wwdc2006
$eventContentId
ID of session without event part: 151
$eventShortId
Shortened ID of event: wwdc06
$year
Year of session: 2006
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC06 • Session 151

Take Charge of Text Input

Application Technologies • 1:08:27

With Unicode-based text in Mac OS X, Apple is introducing a modern and powerful way to manage keyboard layouts, palettes, and input methods that replaces the Script Manager and scriptCode-based functions. Learn how to easily build input methods with the new Input Method Kit and learn how to manipulate input sources and programatically select them, receive notification of changes, constrain input in a particular text context, select inputs depending on languages, obtain input sources properties, register custom input sources, and much more.

Speakers: Peter Edberg, Mike Grady, Lee Collins

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

I'm Peter Edberg. I've been working at Apple for about 18 years on various aspects of system software internationalization. I'll be doing the first third of the talk today, but before that, I'd like to give you an overview of the whole presentation. I'm going to begin with some background information on the motivation for what we're doing in Leopard and some background information on the organization of the text input system as a whole.

Then on my portion of the talk, I'm going to focus on the Text Input Sources API. This is a new API for Leopard that allows you to find out information about text input sources, to get notifications of changes to text input sources, and to be able to programmatically manipulate them. Then Michael Grady is going to talk about some improvements to TSM and how TSM is adapting to changes in Leopard. Finally, Lee Collins is going to talk about it.

Lee Collins is going to talk about the new input method kit framework for creation of input methods, which finally allows you to create input methods that are applications instead of component manager components. Throughout, we're going to try and show you how the changes we're making are going to enable you to better address user expectations and needs in your applications and also hopefully make it simpler for you to write code.

Simply, making code simpler is not necessarily consistent with making changes because you'll have multiple platform targets. There has to be a good reason for making changes, and we think we have a few. First, of course, we've got some leopard-wide initiatives. The 64-bit ABI, the new binary interface, has no backward compatibility requirement.

Deprecated interfaces are not being carried forward to this new API or ABI, so it allows us the opportunity for some modernization, the opportunity to introduce new API that replace some of the deprecated functionality. Also, resolution independence affects the content of events that refer to screen position, and of course, there are a number of these events associated with TSM.

The second big reason has to do with a number of modernizations that we're making for the Text Input system. First, and you'll hear this throughout the presentation, the Script Manager is really, really deprecated, as are all of the types associated with it, script code, language code, region code, and so on. We've got modern replacements for all those that are better in many respects. So we're removing the Script Manager from the main parts of the control flow in Text Input and focusing on a Unicode-clean Text Input path.

The Script Manager will still exist in 32-bit ABI as a kind of compatibility adjunct to the main path. Second, we do have to enable new types of input methods, as I mentioned, and we have to have tokens that refer to not just component-based input methods, but a wider range of input methods, so we need a more abstract token type for these. Third, we have to enable new types of input methods, as I mentioned, and we need a more abstract token type for these.

We're also trying to do a lot of performance improvements and memory reductions, especially for App Launch and App Switch. And finally, the third big reason for changes is to respond to requests that a number of you have made. So let's dive into the Leopard Text Input system. There are two new pieces for Leopard, the highlighted ones here. And along with these two, there are several other areas that we're going to be focusing on in the talk.

Now, there's always been some capability for management of text input sources. It's been spread through the Script Manager and TSM, and a lot of it depended on the now-deprecated tokens, the script code, even component ID as a way to refer to input methods. It's not necessarily deprecated, but it's not general enough.

So anyway, we're extracting that functionality, expanding it, and modernizing it for Leopard as a separate module. This allows TSM to focus on its core tasks, which include management of input context state through the TSM document, handling text input from a variety of input sources using a variety of protocols, and mediating input source access to application documents. And this is important if you went to the latent semantic analysis. So, for example, we're going to use the TSM-TMS session for things like that to enable input methods to do a better job.

Now there are some dark brown or kind of reddish brown boxes over there on the right. Those represent input sources, some of which come from Apple and some of which come from some of you. And this brings me to the second new piece for Leopard, which is the Input Method Kit.

Now there are some dark brown or kind of reddish brown boxes over there on the right. Those represent input sources, some of which come from Apple and some of which come from some of you. And this brings me to the second new piece for Leopard, which is the Input Method Kit.

There are a few other boxes on this diagram. I'm not going to really focus on them today, but for example, the NS Text Field box is meant to indicate that AppKit will handle a lot of the text input system interaction on your behalf if you're a Cocoa app. The Text Input menu is an important user interface element for text input, but there's no programmatic interface for applications.

And of course, the reason that all these pieces are there is to make applications work. So the gray box in the diagram is meant to represent an application that does interact heavily with the text input system, which presumably some of you are writing. Now, one thing that some of these applications do is do a lot of key translation on their own and handle key layout data on their own, and that brings me to an important point for Leopard.

We're converting all of the Apple-supplied keyboard layouts to use the Unicode format, the U-char format. This is part of our Unicode clean text input path, and it has several implications. First, for those of you who are developing and providing keyboard layouts, you should know that this is the preferred format for keyboard layouts.

Also, if you're a developer who does access key layout data directly, you should not assume that data is available in the old K-chart format, which depended on Mac encodings and is associated with the Script Manager. And in fact, that's been true for many releases. It's been true for a long time that many keyboard layouts did not have K-chart data available, but there are still applications that depend on this.

Experimentally, in an earlier release of Leopard, we tried making all K-chart data unavailable through the key layout access APIs, and that did break a few applications. We filed bugs, so you know who you are, hopefully. But anyway, we may do that again. So you should not depend on having that K-chart data available. Now, it is still the case that, as a kind of a hedge, getResource for K-chart data will work as it did in Tiger.

And this is part of the Script Manager backward compatibility. The Script Manager uses that way to get keyboard layout data, but the rest of the system does not. So the keyboard layout access API do not, and the new input sources API do not get access to keyboard layout data that way. And you should not either.

Okay, so who are the people who might be interested in the Text Input Sources API? Well, any developer who wants to do direct processing of text input, any developer who wants to have some control over text input and may have been using some of the Script Manager functionality to do that in the past, developers who need information about text input, and there are facilities in the new TIS API also for developers of input methods. So it affects a large number of clients.

And why are we doing this? Well, I touched on a little bit of this before, but let me say a little more detail now. We've had a number of developer requests for things like notification of changes to input sources, such as changes to selection or changes to the set of enabled input sources, the capability for background manipulation.

If you're an app that wants to sit in the background processing text input in some way, but having some control over the input source used by the front app, that's a capability that's been requested. And the ability to have more information about input sources, such as what's an input source that's appropriate for a given language.

Also, as I mentioned, we do need this new unified notion of input source that can abstract away the particular architecture of the input method used, for example, and several other issues, and the TIS Input Source API provides that. Finally, this is another step in moving away from the Script Manager and moving away from the script codes and other types associated with the Script Manager. It provides some similar functionality, but using new, more modern types. And again, our primary path is for Unicode text.

There are a couple of important concepts you need to know or understand associated with text input sources. First of all, there are three categories. There are keyboard input sources, which include keyboard layouts, such as Swedish. There are input methods, such as Kotori. And there are input modes, which are particular ways of inputting text associated with an input method. So for example, Kotori has Hiragana, Katakana, Romaji, several other input modes associated with the parent input method, Kotori.

There are some input methods that are modeless and have only an input method with no associated modes. A second category is palette input sources, such as the character palette, keyboard viewer, and so on. And a third category is ink. And these all behave in slightly different ways, and I'll get to that in a second. Some input sources are invisible to the system user interface. These include things like private keyboard layouts that are used by an input method, and even private input modes.

Some input sources are visible, but not selectable. So parent input methods that have modes are typically not selectable in things like the text input menu. They are visible, however, in the international press panel. For example, you can enable or disable all the modes associated with an input method as a group. Now, in most cases, input sources are enabled and disabled using international preferences, although Inc. has its own preferences panel for that.

As I mentioned, there's some different behavior associated with the three different categories. At any moment, there's exactly one keyboard input source selected. It may be an input method. It may be a keyboard layout. You can have zero or more palette input sources selected. So you can have keyboard viewer and character palette up at the same time, or none of them. And for ink, you can only have one ink input source, and it can either be enabled and selected or not.

Okay, so enough of the background. This is the core token associated with the Text Input Source API, a TIS input source ref. This is a CF-type ref, and so it can be passed to all the normal polymorphic CF-based functions, and be put in collections and so on. This is our abstract representation of any type of input source. It's the modern token.

Having one of these, you can get a number of properties associated with it. We have a function TIS_GET_INPUT_SOURCE_PROPERTY. You pass your input source ref and the key for the property that you want to examine and get back a void star value. Typically, this value will be a CF type, but not always. In some cases, we return an icon ref or something else.

These properties generally fall into several categories. They're ones that help you identify the input source, such as our new input source ID, and more on that in a moment. You can find out the category or type of input source, the bundle ID. If it's a mode, you can find out the mode ID.

Now, more about the input source ID. This is a new property, a universal string that's going to uniquely identify input sources in Leopard. We are going to provide a plist key that will enable you to specify these. Absent that, we have a way of automatically constructing it, but we do want to make that plist key available. That's something that's not in your seed version, but we will publicize that shortly afterward. Peter Edberg, Mike Grady, Lee Collins There are other kinds of properties, like input source ID, which is a new property, a universal string that's going to uniquely identify input sources in Leopard.

We are going to provide a plist key that will enable you to specify these. Absent that, we have a way of automatically constructing it, but we do want to make that plist key available. That's something that's not in your seed version, but we will publicize that shortly afterward. There are other kinds of properties, like is it ASCII capable? Is it capable of entering ASCII? Is it selectable? The name? What are the languages it can support? Icon, etc. Key layout data, in this case, is only going to be Unicode format key layout data.

One property that's not on this list and is not in the seed but we realize we will have to make available is visibility, whether it's an invisible or visible input source. And finally, dynamic state: isn't currently enabled, isn't currently selected. Okay, well, how do you create these input source refs? There's one primitive function, TISCreateInputSourceList, and this takes a filter CFDictionary of keys and corresponding values and returns an array of input source refs that match that specified set of property keys and values. By default, this will just return information for enabled input sources. However, there's a Boolean parameter to this function that lets you find out information about all installed input sources.

In some cases, the CFArray will just have one element. If you pass a property key for a particular bundle ID, say, or input source ID, you can narrow it down to a single input source and get the input source ref that way. There are some primitive functions that build on this. You can get the current keyboard input source, as you see, the ASCII-capable keyboard input source, and various other things. Input source appropriate for a particular language. Here's an example of how you would use this.

And you've seen this kind of thing in other talks today and the day before about using CFDictionary's to create matching dictionaries of properties and values and using that information to obtain something. In this case, it's going to be an input source ref. So basically, the key elements are the CFDictionary create with your keys and values and the TIS create input source list. And I show all the releases here and so on.

Much simpler is if you just want to get an input source that's appropriate for a particular language. Say check in this case, you just pass the language code for that to TIS copy input source for language and get an input source ref. Now note here, we're not using the Script Manager language code or region code or anything.

We're using, actually what this is, is an RFC 3066 BIS language code, but this is the type of string that's used in CFLocale and ICU and elsewhere. It's the modern way that we indicate languages in the system. At its simplest form, it might just consist of an ISO 639 language code, and in fact, that's what this is.

Now for manipulating them, in most cases the API that's going to be important to you is select input source. So with a keyboard input source, that will deselect the previous keyboard input source, not keyboard layout as it says there. For other types of input sources, it has no effect on what other input sources may be selected.

Deselect input source is mainly useful for palette or ink input sources. And the enable or disable input source API are mainly intended for input methods that may want to bring up their own palettes and so forth. We also have a couple of notifications, one for changing the selected keyboard input source and one for changing the set of enabled keyboard input sources. Okay, well I'd like to go through a quick demo here.

Okay, so I threw together a quick Cocoa app here called TIS Demo just to show you some of the kinds of things you can do with this. There are a couple of little rough edges with it, and it's not meant to demonstrate a user interface. Basically, selecting a row in the table view here will give you additional information below, what its input source ID is, bundle ID, input mode if it has one, and some supported languages.

You can enable or disable input sources using this. You can also select them, and that will be reflected elsewhere in the UI. So, for example, if I go down here and, oh, let's see, let's pick something. Let me select Hiragana as my input source, and you can see that the Text Input menu changes it, changes there.

The boxes at the bottom always reflect the current keyboard input source and the current ASCII-capable keyboard input source, so that you see right now we've got Hiragana as our input source, but the ASCII-capable input source is still the US keyboard layout. If I go through here and, for example, I enable, or I can enable it in here as well, if I go through and enable French, say, you'll see that French is the current input source, but it's also the current ASCII-capable input source.

One fun little thing here that shows background manipulation is to cycle through enabled input sources, so, and this is going to cycle through them in the order that the table view is in here, so let me start this. This is going to cycle through every five seconds. It's going to pick a new, the next enabled input source in the list here. So let me start that, and then I'm going to switch over here to TextEdit, so I'm typing in TextEdit.

I've got some Arabic in there, and now we've got What have we got here? I guess that's... Oh, now we're on to French, so I've got the Azzurri keyboard here. And now we're on to German, so I've got the German keyboard, but it's got still QW in the upper left, and we're in Russian here, and so on. Let me stop that. Anyway, so that just gives you a sense of the kinds of things that you can do with that. Okay, so back to slides, please.

Okay, well, we're full of recommendations, do's and don'ts, so don't use the Script Manager, don't assume that key layouts have K-chart data available, and don't assume that input methods are components. And one way you can avoid a lot of these don'ts is by the first do, which is adopt the Text Input Sources API for manipulation of input sources. Also, I've alluded to this, is you can use more precise and more modern tokens for representation of a lot of the types you need.

And I've got a little cheat sheet in the next slide that goes into more detail on this. And finally, and very important, give us your feedback and suggestions. It's not too late to have an impact on the API for Leopard, so please do give us your feedback and suggestions, things that you want to add, or additional notifications, whatever you'd like to see. Okay, well, here's the promised cheat sheet. It shows you some of the ways that these older tokens have been used in the past.

Script Code, especially, has been used for many different purposes. And we'd like to have you replace most of those usages with something that's more appropriate for the way in which you were using the script code. So, CF Character Set, where you meant the script code to indicate a repertoire of characters. CFString Encoding, or Text Encoding, where you meant script code to indicate a text encoding. CFLocale, for language code, or CFLocale Language String, sorry, that's that language string I was referring to earlier, to refer to a language, etc.

And also the TIS Input Source Ref, where you mean to refer to other kinds of input sources, Keyboard Layout Ref, or the component where it was used to indicate input methods. Now, I'd like to bring up Michael Grady, Mr. TSM, to give you some more detail on what's happening with the Tech Services Manager.

Thank you, Peter, for that consideration of the new Text Input Sources API. Hello, everybody. My part of this symposium will be a low-level consideration of changes to the Text Services Manager in Leopard. In particular, I'll be addressing two types of developers. Application developers who provide your own text engine, so most likely you're programming to the Carbon API.

Certainly, developers using Cocoa or HIToolbox's HITextView are insulated from most of the information except for part of the text. I'll be presenting the first part at the end of my presentation that has to do with restricting input sources and input context. Another type of developer affected by the information I'll be presenting are input method developers.

The information will be three general areas: changes to TSM that affect you in your deployment of your applications to the 64-bit platform, as well as your input methods. Changes to TSM to support resolution independence and how they help you also support it in your apps and input methods. And finally, modernization in TSM itself and how that allows you to be more modern and hopefully write more maintainable code than you could in the past.

By far the biggest change to TSM in Leopard has been the large-scale deprecation of API. API that expose deprecated notions such as script code, API that exposed underlying types like the component ID, which is really a plugin architecture notion that has no business being exposed at the API level. All of these APIs mostly fall in one group.

They're APIs that attempt to control input sources, manage input sources, enable them, select them, and they're not really part of the core functionality of TSM, which is input context management, not input source management. So it's logical that these all have natural replacements in the Text Input Sources API.

Of particular note is the deprecation and death of key script. Please attend this funeral. It's mostly been used to select an input source via a script code. And so it has a natural replacement in the TIS API. There is one use of key script that does not have a replacement in TIS. And we'll be discussing that. It has to do with passing negative values, non-script code values, to it to restrict input sources in a given input context, like a text field. We'll see the replacement for that later.

Another API that's been deprecated, and when I mean deprecated here, I mean not available on 64-bit at all for all these APIs. A further example is the Keyboard Layout Access API, also known as the KL API. These APIs provided mostly iteration over keyboard layouts and property queries. These also all have natural replacements in the TIS API.

I mentioned one more thing here in the context of 64-bit, and that is the TSM support for an additional type of input method architecture. TSM still, even on 64-bit, continues to support component manager-based plugin input methods, in addition to application-based input methods developed to the Input Method Kit framework that will be discussed later by Lee Collins.

Why do I mention this in conjunction with 64-bit? Because it gives you, the input method developer, a choice on how to deploy your input method. If you're going to continue to be a component manager-based input method, you are a plugin. As a plugin, you are hosted in a parent process, and if that process is 64-bit, you need to be so as well. Alternatively, if you port your input method to the Input Method Kit, you are free from that requirement. 32-bit implementation is sufficient. for you. So all the deprecated API are in techservices.h. There are some more changes in the Carbon events realm.

TSM defines two Carbon event suites in the Carbon Event Manager. Some of those events use parameters whose event parameter types are problematic on 64-bit. One notable example is the use of type long integer as the event type for many different parameters. It might not be obvious why that type is problematic at first.

After all, on the LP64 data model, a long is 64 bits. The problem is that this event parameter type is an alias to type SN32, making it completely unsuitable for things that need to be 64 bit. For example, refcons. Refcons are usually an object reference of some sort or a pointer to data. It needs to be 64 bits.

Byte counts and byte offsets are also frequently used in TSM event parameters. Those need to be 64 bits on LP64 as well. So the Carbon Event Manager, not just for TSM events, but other events that have similar problems, have introduced three explicit Carbon event parameter types, type refcon, type byte count, type byte offset. Now, these event parameter types are new, separate event parameter types from type long integer.

They are source components, and they are not necessarily the same as the type long integer. They are compatible between 32-bit and 64-bit implementations, but there is a binary compatibility issue. If an input method, for example, sets a parameter with the type long integer, and you, the application, ask for a type refcon, how does that work? It's a different event parameter type.

The answer is that the Carbon Event Manager provides automatic type coercion for these types on 32-bit only. On 64-bit, you are required to use the new event parameter types in all cases. Of course, with these new event parameters, you can't use the new event parameter types. You'll want to use the corresponding data types, such as those found in MacTypes.h. The different variants of refcon, byte offset, and byte count are also defined in that header.

For the new parameter types, you'll want to use the corresponding data types, such as those found in MacTypes.h. The different variants of RefCon, ByteOffset, and ByteCounter are also defined in that header. You'll also want to use the point data in point space, or also known as 72 dpi virtual coordinate space.

The geometries for which you might want data in screen pixel coordinates are not limited to things like rectangles or points. There are things that are unidimensional in nature, like line height, line ascent, that might make sense for you to ask for in screen pixel coordinates as well. So we have a new type CG float screen pixel, a variant of another new event parameter type, type CG float, we'll be discussing in a bit.

So let's see how these new types affect TSM events. Some TSM events use some deprecated event parameter types, an example type QD point. This has been replaced in all cases by the type HI point. And of course, you're free to request that data using the new screen pixel variants of those event parameter types as well.

Some event parameter data in TSM events are scalar values. They've been typed in various ways. We have an example here of a reply point size parameter typed as type fix. We have a line height in one case typed as type SN16, a font size as a type float.

Wouldn't it be nice if all of the things that need to be floats were floats? And so we have the type CG float used in all cases for these parameters. And where it makes sense, such as line height, line ascent information, you can request those as type CG float screen pixel as well. And that coercion is all automatic.

TSM has undergone a lot of internal modernization. Upheaval is another word for it on Leopard. I mentioned already the support for several input method architectures. There's still full support, even on 64-bit, for component manager-based plugins, also application-based input methods implemented to the Input Method Kit. TSM has completely moved off of any notion of the Script Manager, in particular, any use of the Keyscript API. It uses the TIS API that Peter referred to. This API is really the way to go for you as well. It can do things that you just simply could not do with the old Keyscript API, especially from background apps, as Peter showed in the demo.

TSM has also modernized its event parameter content with modern event parameters with modern event types, but still supporting the existing event parameters in TSM events. So how does this work? How can you, a client of a modern event parameter, Get that data if the event parameter data in the event are the older types. This is not just a type coercion issue, it's a parameter set coercion issue of sorts. So TSM is able to solve this because you as input method developers are really good citizens.

And you are using the API we tell you to use, you always do so, right? While TSM is able to leverage off of this, consider what happens when an input method dispatches an event to an application. It always calls an API called SendTextInputEvent. This is a perfect bottleneck for TSM to inspect the event, see what parameter data is there, what parameter data it could promise.

and derive from the data that's present. If the application then requests the modern event parameter, TSM will coerce them using a promise mechanism on demand. Similarly, when an event is returned to TSM after being handled or not, but before being returned to the input method, TSM can again inspect the event, see what data is there, and promise additional data.

Here are some examples of the modern event parameter types that TSM is introducing. We have a typect fontref. This refers to a Cortex font. Some of you will have heard of this in the Cortex session this morning. An event parameter of this type can encapsulate information that was contained in various parameters in the past. We might have needed a font parameter like an ATS fontref, size, ascent, descent information. All of this information can be encapsulated in a single modern event parameter of this new type.

We have an example of this in the middle of the slide in the offset to pause event. It currently is introducing a replyct fontref parameter that can encapsulate the older parameters that contain font, point size, etc. There's a new typect glyph info ref that replaces the ATS type glyph selector. And a new typect attributed string ref.

And a parameter of this type can encapsulate data formerly found in different parameters that would contain Unicode text separate from font, separate from glyph info information. An example of this is the text input Unicode for key event. This is a new send attributed string parameter to replace the two or three parameters needed previously.

A bit more on the modernization front. Since TSM does support additional input method architectures, the type component instance event parameter type is being eliminated. In addition, the type Intel writing code is really a reference to a structure containing a script code and a language. In a Unicode world, that's been deprecated.

Some of you application developers who implement your own text engines, you may have used an API that's being deprecated, TSM Set Inline Input Region. This API was used to allow you to communicate to TSM the bounds on screen of an inline input session as a user is typing. That in turn allows TSM to filter out mouse events that have no need to be routed to an input method if they don't intersect those bounds. Well, that's kind of an expensive way to do it.

TSM doesn't always need the information, and that API required the application to constantly update the bounds in case TSM did need it. Also had to make sure to call the API in all the right places. So it's being replaced by a more convenient, more interesting to you, we hope, Carbon event, a text input event called IsMouseEventInAnInputArea. When TSM needs the information, it will call your callback.

I have another plea for application developers who provide your own text engines to please implement the TSM Document Access Protocol. This is another TSM event suite that essentially allows text services to interact with any part of your document, not just near the insertion point, but anywhere. Dictionary Services uses this to provide definitions of words that lie under the mouse, no matter where the insertion point is. The typography panel uses the protocol as well.

It has been available since Mac OS X 10.3. It's fully supported by Cocoa, fully supported by HIToolbox's HITextView. Essentially, it is a set of events that mimic the CFString API, treating your document as if it were one big CFString and accessing read-only access anywhere in that string. While the protocol does not implement write access anywhere in a document, it does define how this should be done. There is an auxiliary event parameter in the UpdateActiveInputArea event that's used for inline input in general that allows an input method or a text service to specify a replaced range at arbitrary locations in your document again, independent of where the insertion point is.

So what you need to do besides implement the handlers in the Document Access Protocol, simply in any TSM event that you create, indicate that you support this protocol with the TSM document property, support document access property. This will allow TSM to notify input methods that you do support that and enable a richer set of features for the users of your application.

The whole title of this session is Take Charge of Text Input. Developers have been asking for quite a while for more control in one area in particular, and that is more flexibility in restricting the set of input sources for a given input context or text field. For example, developers often want to restrict the set of input sources available to the user for a text field to ASCII only. Or once the application has identified an input source that really needs to be used, it may want to prevent the user from switching to something else, again, in the context of that text field.

This has traditionally been done with the KeyScript API with negative values, non-script code values passed to it. The big disadvantage with this API is that it's global in scope, at least global in the app's context. And this has required careful cleanup on your part to make sure that the effect of calling KeyScript with the intent of affecting input in only one input context does not spill over into another input context and affect the user there. So you had to carefully clean up.

Wouldn't it be nice if the input context could encapsulate that state? In particular, the TSM document associated with that input context. So the solution we're providing are two TSM document properties. One TSM document property allows you to specify a subset of all those input sources enabled by the user, such as in the international prefs panel.

And by default, any time your input context gets key focus, TSM would use the last used input source from the restricted list that you have specified. If you want more fine-grained control, again, this slide is all about control, you can yourself specify which input source specifically from that list you want to become current when your input context gets key focus. Now, there is a desire for minimal interference of this kind of restriction with input contexts that have no restriction.

For example, suppose you're typing away in Japanese in TextEdit, and you switch to another app temporarily, force is asking only input, you switch from US to French and back to TextEdit. Well, you would expect to continue to type in Japanese. So TSM solves this problem by saving and restoring all the input source state necessary around any restriction.

Here are some details on the two properties I mentioned. We have the new Enable Input Sources property. And again, by default, the behavior in TSM is to select from that list the last used input source when your input context gets focused. If you want more control, there is the new Input Source Override property.

Now, in the lifetime of a given login session, the user may, at several different points, enable and disable various input sources through the system, the international press pin. So you as a developer need to know from time to time when to perhaps adjust the subset, the restricted set of input sources you specified on various input contexts. We have a notification that will allow you to do this. The KTIS notify enabled keyboard input sources changed. It's dispatched through the CF Distributed Notification Center.

Some examples of the new document properties in use. We have the enabled input sources property in the first box. The value for this property is simply a CFArray of TIS input source refs. If you want that extra level of control, specify a preferred input source. We have the input source override property tag whose value is simply a TIS input source ref.

Now, one thing I want to point out with this is that unlike using key script, which had to be called around the time that an input context gets key focus, these properties can be set when your input context is created, and then you can forget about them. Set it, forget it, let TSM deal with the necessary synchronization as focus goes from one input context to the next.

By far the most common use of restricting input sources is ASCII only. To that end, we have a convenience API, TIS Create ASCII Capable Input Source List, that gives you back an array of TIS input sources that are ASCII capable, take that result, pass it directly as the value of the enabled input sources property, and of course release the result because it is a Create API.

By far the most common use of restricting input sources is ASCII only. To that end, we have a convenience API, TIS Create ASCII Capable Input Source List, that gives you back an array of TIS input sources that are ASCII capable, take that result, pass it directly as the value of the enabled input sources property, and of course release the result because it is a Create API.

The benefit of this is twofold. One, all key events are pre-translated by the system before they're delivered to your input method. That frees you, the developer, from having to do your own keyboard translation. Another benefit is that since the system now knows about your override explicitly, it can show it in system UI, such as keyboard layout palette.

And this again frees you, the input method, from having to implement your own keyboard layout palettes. Apple's own Chinese and Korean input methods have been using this mechanism since Mac OS X 10.4. And before we go on to the specifics of this new API I mentioned, I'd just like to call your attention briefly to those input methods that implement input modes, input mode savvy input methods. You are currently using TSM select input mode to switch between the input modes you implement. This has been deprecated in favor of the TIS select input source API, a very natural correspondence.

There are two lines here in blue that I really want you to look for in your code. If you see these two lines, please throw them away. Just look out for them, act aggressively, and throw them away. Replace them by the single line, single API call, TIS Set Input Method Keyboard Layout Override.

This will give you all the benefits I mentioned, key events pre-translated for free, and your private keyboard layouts will be visible in the system keyboard layout, keyboard viewer palette. Finally, there is, if you have a need to find out what the current override is, there is a copy function for that as well.

So, some takeaway points. Look at the headers, techservices.h, carbonevents.h, for all the deprecated API. Move off of Keyscript, please. You can do a whole lot more with the TIS API you could never do before. Adopt in your applications the TSM Document Access Protocol. This will benefit your users, give them access to a richer set of services to interact with your documents. And you'll notice the changes in the headers on 64-bit, Carbon events for resolution independence. And that's it. Next, I'd like to hand over the talk to Lee Collins, Manager of OS Engineering in Asia. Thank you.

Thank you, Michael. As Michael mentioned, I'm the manager of the team that does the system software engineering for our Asian products. That includes input methods for Chinese, Korean, and other languages. Not only do we implement input methods, but we also are designing new architectures to support them. I'll be talking about the Input Method Kit as one of those today.

So I think this part of the section will be of particular interest to those of you, like my team, who are developing input methods or are thinking about developing them for OS X. I'll be talking about four things that we're working on that will be of interest to you.

The big one is the input method kit, which is basically a new foundation-based framework for building input methods. Next, I'll talk to you about how you can use the keyboard layout overrides that Michael talked about to enhance your user experience and to eliminate a lot of code that you might have in your input method now for displaying your keyboard layout and doing keyboard mapping.

I'll talk briefly also about data-driven input methods, which are possibly the easiest way for you to deliver an input method, depending on how your input method is structured and what it needs to do, and finally, some changes in the way we're going to package and install input methods.

So what's the Input Method Kit? You no doubt know that our current way of building input methods was designed way back in the early 90s. It's been obvious to us for many years that it's very painful to develop an input method. We do it all the time. We have a lot of code that we have to maintain that is not really necessary because so much could be shared across input methods.

The Input Method Kit idea is to make it simpler both for you and for us to develop and maintain input methods. It's a foundation-based API, and we really think it's going to be a lot simpler. So, for example, if you've tried to look at our sample code now for building an input method, it's called the Basic Input Method. It's component manager-based. It requires at least 28 source files. We've reduced that in the new Input Method Kit sample. to five source files.

The Input Method Kit has a number of nice architectural features, one of which is that the input methods can now run as applications in their own address space. This has some advantages for security, performance, and robustness. And in addition, it has a big advantage for those of you who have input methods and are thinking about porting to 64-bit.

Because one of the drawbacks of the Component Manager-based input methods is that they run in the same space as does the client application. This means that you have to recompile your input method to get it to run in a 64-bit client. With the Input Method Kit, because the applications run in their own address space, you can be running as 32-bit.

Needless to say, the Input Method Kit is fully integrated with the TSM so you get all of the functionality that the TSM offers and it works with all applications, Cocoa, and Carbon that support the TSM. The Input Method Kit is based around a fairly simple and natural division of labor.

Basically, the Kit manages all of the UI and communications with client apps, the candidate window, input method modes, etc. What you, the developers, supply are the engine, the basic conversion engine. You also indicate how client input should be treated through key bindings or, if you really need to go into details, optional event handling.

[Transcript missing]

So all of these controllers will share one candidate window object. Candidate windows are, if you don't know what the technology is about, it's a way to present optional choices to the user when there's ambiguous input. The controllers will share the candidate, create one candidate, and bring it up whenever they want to display the options to the user. The candidate then points back to the server, which actually manages the candidate object.

So the most interesting class to you, of course, will be the IMK Input Controller. This is the hub, if you want to think about it. It takes input from the client application passes it to the engine and then passes it back into the application. This is where you'll do most of your work.

So when you're thinking about how you're going to handle input from client application, there are three basic approaches shown here in order of increasing control but also complexity. You can choose to use key binding, in which case you don't look directly at key codes or the modifiers attached to the key codes. You can do this by implementing the method inputText that only takes a string in a client and did command by selector.

If you actually need to look at individual key codes and modifiers, you take the second approach, which is to implement input text that also takes the modifiers and the key codes. Finally, if you need to look at an event in all of its glorious detail, just implement handleEvents.

Let's talk a little bit about the candidate window. Candidate windows are a way of presenting to the user different choices when you have ambiguous input. This is very common in Chinese, Korean, and Japanese. For an example, within UniCode, there are a number of characters that can be described as a kind of star. You might want to let your user input the word "star" and give them choices for all of the star variants. To do this, you would use a candidate window.

When you're using one of the Input Method Kit candidate windows, basically you supply the candidates. The IMK candidates object will handle selection of the candidate by the user, let you know which candidates have been selected, and all of the other stuff. For Leopard, you'll be able to choose up to three different flavors of window layout. The grid view shown up here in the top, a vertical view in the middle, and finally a horizontal view.

So if you want to use the candidate window, this is what you would do. Inside of your controller class, you implement two methods. The first method, candidates, is basically a way of feeding the candidates to the window. The simplest implementation would just be to pass back an array of all your candidates.

The second method is Candidate Selected. This is called whenever the user has gone through, looked at the list of candidates in the candidate window and decided to choose one. Something you might do in Candidate Selected is confirm the active input area, maybe update the state of your input method to rearrange the frequency with which you display characters in the candidate window.

Then you create the candidate object with initWithServer. You do this with the server because the server actually, your IMK, IMK Server actually is what's going to manage the candidate window for you. And then you also pass in the kind of candidate window you want, whether you want vertical, horizontal, or grid.

Then whenever you want to present the candidates to the user, you call update and show candidates. Finally, remember that your candidate selected method will be called whenever A candidate has been chosen, so make sure that you respond to that to do whatever you need to update the state of your input method.

Let's talk a little bit about modes. Michael and Peter both mentioned modes. Modes are basically a way of packaging related input sources in one input method. You can think, I mean a mode is basically, could be a standalone input method, but many of the so-called input methods will actually package sub-input methods. For example, Japanese contains Hiragana, Katakana, and Romaji. Previously, before OS X.3 Panther, each of our input methods had very elaborate machinery for managing these input method modes.

Then we observed that we could actually simplify this and have a common way of managing them, and we came up with this whole idea of modes, which we did make public in Panther. Basically, it's all driven through data in a plist. The IMK Kit makes this even easier for you to use. To use modes within the kit, first of all, you just provide information in the plist, which we've previously documented in Tech Note 2128 in the Component Input Mode Dictionary.

And then the kit will tell you each time that your mode has been selected by sending the message "set value." "Set value" sends a key and a value. The key in this case would be a key telling you that your mode has been selected with the name of the mode. So respond to this to do whatever you need to do to switch the mode. And that's pretty much all you need to do to add input method mode support using the IMK Kit.

Let's look at some things you add to your plist when you're building an IMK Kit-based input method. I just mentioned the component mode dict described in Tech Note 2128. You do that if you're a mode-based input method, and many are. Input methods are applications, but they need to run in the background. So set a key and value LS background only indicating that they are background applications.

Now the Kit needs to identify your controller class, so there's a key-value pair that lets you identify that for the Kit. Input Method Server Controller Class. This lets the Kit go into your bundle, find your controller object, and instantiate it whenever there needs to be a connection between the client application and your Input Method application. Finally, you need to add a string that indicates the connection name. This is how the IMK Kit talks to your server.

Now let's talk briefly about how you can improve your input method using keyboard layout overrides. The overrides basically let you associate a keyboard layout with any input method mode. The keyboard layouts, of course, are defined as XML and then rendered into Uchars, as was previously discussed. The beauty of doing it this way is twofold. You don't have to have elaborate mapping tables inside of your input method to map from virtual keys to the codes that you take as input in your input method.

Secondly, you don't have to have a lot of machinery to display Before we started using the layout overrides, all of the Chinese input methods, for example, had bitmaps of the layouts and they had key to character mapping tables built into them. Once we started using the layouts, we were able to rip all of that out and just specify an XML-based keyboard layout and let the keyboard viewer do all the drawing for us.

So this is how you would use the overrides with the IAM Kit. I previously mentioned that one of the methods you're going to want to implement is called setValue. This will be called whenever the user selects one of your modes in the Text Input menu or using Command Space or however.

In this case, Set value will contain, as the value, the name of your mode. In the example shown here, we assume that the name of the mode is the same as the keyboard layout. It doesn't have to be. The keyboard layout is going to be stored inside of your input method bundle. If you call override keyboard with keyboard named, the Input Method Kit will then go into your bundle, find the layout, set it as the current keyboard, and then you're off and running.

Now let's move briefly to data-driven input methods. If your input method can be described as a very simple mapping of one string to other strings, including candidates for strings that are ambiguous, then you might want to actually consider using the data-driven input methods. It's basically a text file with mapping rules.

And for Leopard, we plan on using two semi-standard formats. One, the .im plugin is the one we've been using in our Chinese input methods for a number of releases now. And .cin is used by an open source project called Open Vanilla. These are basically just text files with very simple mapping. You supply the text file and register it, and the system will handle everything else: input, a display of your input method in the text input menu, candidate window, etc.

Previously, these kind of data-driven input methods have been used for a lot of different languages, mostly Chinese languages like Cantonese. You see an example here. You take the string "DEU6" and map it to several Chinese candidate characters, but it could also be used for English. Take "Happy Face" and generate all the Unicode characters that look like a happy face.

So finally, I'd like to talk briefly about changes in how we're going to deliver input methods in Leopard. Previously, input methods were all based on the Component Manager, so they resided in the components folder in System Library, etc. The new input methods are going to be stored in an input methods folder that will be supported for three domains: System, Host, and User.

When you're going to install an input method, you can now call a new function called TISRegisterInputSource that will register it as you're installing so you don't have to log out and log back in for it to take effect. I think this will be useful for those of you writing input method installers.

And finally, just a note, your keyboard layouts need to be installed in your bundle. This is actually mostly a note for internal developers, but the basic message is if you don't install them in your bundle, then you have to do a little bit more elaborate searching in the system using the new TIS API to find your keyboard layouts. So the easiest thing is just keep them in the bundle.

Now I'd like to go to a brief demo. So my team has not only been designing and developing the Input Method Kit, But at the same time, we've been reimplementing all of our input methods using the kit. Our philosophy is that if the kit doesn't work for us, it's certainly not going to work for you. It's got to be good enough for us before we send it to you.

So, as of this point, we have two of our input methods are running inside of the Input Method Kit, Tamil and Korean. They're both somewhat simpler than the elaborate Chinese and Japanese, but those are going underway. So let's take a look. I'll also show you the advantage of using the keyboard layout overrides. So to see what we're doing, let's bring up the keyboard viewer.

So you probably-- I hope you're all familiar with the Keyboard Viewer and what it does. Let's see. Type some English. You can actually type directly from the Keyboard Viewer. Probably not very useful outside of demos. Now we pick Korean. Oops. Well, let's see. There is a bug. It was supposed to update. And the demo gods were not going with us today. Well, let's see. Let's try that again.

Well, like I said, I just finished building this last night, so I'm not going to be able to demo the overrides, but let's see if I can demo Korean. Ah, I got something there. OK, there. So now what I've done is I've specified a keyboard layout override inside my bundle.

So when I selected one of those two Korean modes, the keyboard viewer went in and-- and updated using the keyboard layout that I specified. So this has a great advantage so you can actually see the characters in the keyboard layout if you're not familiar with this layout. This is a Romanized layout, but not everybody starting to type Korean may be familiar with it.

So I can type some Korean here. And this is the Input Method Kit-based Korean input method. So all of this is being handled for me. The only thing I'm really doing is taking the Hangul input off the keyboard, converting it internally, and sending it back to the kit.

And the kit does everything, all the connection with the document, et cetera, to update the active area. And even provides an input method window. I can select. Notice that as I select the different candidates, they're being updated inside the document. That's just a couple lines of code to do all this. And that's it.

Okay, so I'd like to end my part of the session with a few recommendations. Use the Input Method Kit framework. We think it's really good. We're using it. We encourage you to use it also. Think about keyboard layout overrides. We found them very useful in practice. As I said, we were able to rip out a lot of code and just let the keyboard viewer do a lot of work for us. And finally, if your problem is simple enough, just consider data-driven input methods.

Now for those of you who are willing to spend a little bit extra effort and want to have a great opportunity to sit down with Apple engineers and bring your code and start working on porting the Input Method Kit, your input method to the Input Method Kit, we're doing a kitchen in China in the first week of September. If you're interested in that, there are some contacts here. You can also try contacting me. I'll be around tomorrow at the International Lab.

Some more information. I have to apologize about the sample code. The sample code contains some calls to ICU, the International Components for UniCode, which is an open source. We make wide use of it in the system, but it's not public. And it relies on internal headers that you don't have access to normally.

So if you actually want to get that sample code to compile, I suggest that you comment out the few lines that actually use ICU. It's not essential to the sample. It was just there as illustration. You do that and the sample should work fine. Modulo the bugs that are in the README. There will be a lab tomorrow if you want to come talk to me more or other people who are here, Peter, Michael, who are here giving the presentation.