1/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6#include "nsISupports.idl"
7
8interface mozIDOMWindow;
9interface nsITextInputProcessorCallback;
10
11webidl Event;
12
13/**
14 * An nsITextInputProcessor instance is associated with a top level widget which
15 * handles native IME.  It's associated by calling beginInputTransaction() or
16 * beginInputTransactionForTests().  While an instance has composition, nobody
17 * can steal the rights to make composition on the top level widget.  In other
18 * words, if another instance is composing on a top level widget, either
19 * beginInputTransaction() or beginInputTransactionForTests() returns false
20 * (i.e., not throws an exception).
21 *
22 * NOTE: See nsITextInputProcessorCallback.idl for examples of |callback| in
23 *       following examples,
24 *
25 * Example #1 JS-IME can start composition like this:
26 *
27 *   var TIP = Components.classes["@mozilla.org/text-input-processor;1"].
28 *               createInstance(Components.interfaces.nsITextInputProcessor);
29 *   if (!TIP.beginInputTransaction(window, callback)) {
30 *     return; // You failed to get the rights to make composition
31 *   }
32 *   // Create a keyboard event if the following compositionc change is caused
33 *   // by a key event.
34 *   var keyEvent =
35 *     new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz });
36 *   // Set new composition string first
37 *   TIP.setPendingCompositionString("some-words-are-inputted");
38 *   // Set clause information.
39 *   TIP.appendClauseToPendingComposition(23, TIP.ATTR_RAW_CLAUSE);
40 *   // Set caret position, this is optional.
41 *   TIP.setCaretInPendingComposition(23);
42 *   // Flush the pending composition
43 *   if (!TIP.flushPendingComposition(keyEvent)) {
44 *     // If it returns false, it fails to start composition.
45 *     return;
46 *   }
47 *
48 * Example #2 JS-IME can separate composition string to two or more clauses:
49 *
50 *   // Create a keyboard event if the following compositionc change is caused
51 *   // by a key event.
52 *   var keyEvent =
53 *     new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz });
54 *   // First, set composition string again
55 *   TIP.setPendingCompositionString("some-words-are-inputted");
56 *   // Then, if "are" is selected to convert, there are 3 clauses:
57 *   TIP.appendClauseToPendingComposition(11, TIP.ATTR_CONVERTED_CLAUSE);
58 *   TIP.appendClauseToPendingComposition(3,  TIP.ATTR_SELECTED_CLAUSE);
59 *   TIP.appendClauseToPendingComposition(9,  TIP.ATTR_CONVERTED_CLAUSE);
60 *   // Show caret at the beginning of the selected clause
61 *   TIP.setCaretInPendingComposition(11);
62 *   // Flush the pending composition.  Note that if there is a composition,
63 *   // flushPendingComposition() won't return false.
64 *   TIP.flushPendingComposition(keyEvent);
65 *
66 * Example #3 JS-IME can commit composition with specific string with this:
67 *
68 *   // Create a keyboard event if the following compositionc change is caused
69 *   // by a key event.
70 *   var keyEvent1 =
71 *     new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz });
72 *   // First, there is a composition.
73 *   TIP.setPendingCompositionString("some-words-directly-inputted");
74 *   TIP.appendClauseToPendingComposition(28, TIP.ATTR_RAW_CLAUSE);
75 *   TIP.flushPendingComposition(keyEvent1);
76 *   // Create a keyboard event if the following commit composition is caused
77 *   // by a key event.
78 *   var keyEvent2 =
79 *     new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz });
80 *   // This is useful when user selects a commit string from candidate list UI
81 *   // which is provided by JS-IME.
82 *   TIP.commitCompositionWith("selected-words-from-candidate-list", keyEvent2);
83 *
84 * Example #4 JS-IME can commit composition with the last composition string
85 *            without specifying commit string:
86 *
87 *   // Create a keyboard event if the following compositionc change is caused
88 *   // by a key event.
89 *   var keyEvent1 =
90 *     new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz });
91 *   // First, there is a composition.
92 *   TIP.setPendingCompositionString("some-words-will-be-commited");
93 *   TIP.appendClauseToPendingComposition(27, TIP.ATTR_RAW_CLAUSE);
94 *   TIP.flushPendingComposition(keyEvent1);
95 *   // Create a keyboard event if the following commit is caused by a key
96 *   // event.
97 *   var keyEvent2 =
98 *     new KeyboardEvent("", { key: "Enter", code: "Enter",
99                               keyCode: KeyboardEvent.DOM_VK_RETURN });
100 *   // This is useful when user just type Enter key.
101 *   TIP.commitComposition(keyEvent2);
102 *
103 * Example #5 JS-IME can cancel composition with this:
104 *
105 *   // Create a keyboard event if the following composition change is caused
106 *   // by a key event.
107 *   var keyEvent1 =
108 *     new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz });
109 *   // First, there is a composition.
110 *   TIP.setPendingCompositionString("some-words-will-be-canceled");
111 *   TIP.appendClauseToPendingComposition(27, TIP.ATTR_RAW_CLAUSE);
112 *   TIP.flushPendingComposition(keyEvent1);
113 *   // Create a keyboard event if the following canceling composition is
114 *   // caused by a key event.
115 *   var keyEvent2 =
116 *     new KeyboardEvent("", { key: "Escape", code: "Escape",
117                               keyCode: KeyboardEvent.DOM_VK_ESCAPE });
118 *   // This is useful when user doesn't want to commit the composition.
119 *   // FYI: This is same as TIP.commitCompositionWith("") for now.
120 *   TIP.cancelComposition(keyEvent2);
121 *
122 * Example #6 JS-IME can insert text only with commitCompositionWith():
123 *
124 *   // Create a keyboard event if the following inserting text is caused by a
125 *   // key event.
126 *   var keyEvent1 =
127 *     new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz });
128 *   if (!TIP.beginInputTransaction(window, callback)) {
129 *     return; // You failed to get the rights to make composition
130 *   }
131 *   TIP.commitCompositionWith("Some words", keyEvent1);
132 *
133 * Example #7 JS-IME can start composition explicitly:
134 *
135 *   if (!TIP.beginInputTransaction(window, callback)) {
136 *     return; // You failed to get the rights to make composition
137 *   }
138 *   // Create a keyboard event if the following starting composition is caused
139 *   // by a key event.
140 *   var keyEvent1 =
141 *     new KeyboardEvent("", { key: "foo", code: "bar", keyCode: buzz });
142 *   // If JS-IME don't want to show composing string in the focused editor,
143 *   // JS-IME can dispatch only compositionstart event with this.
144 *   if (!TIP.startComposition(keyEvent1)) {
145 *     // Failed to start composition.
146 *     return;
147 *   }
148 *   // And when user selects a result from UI of JS-IME, commit with it.
149 *   // Then, the key event should be null.
150 *   TIP.commitCompositionWith("selected-words");
151 *
152 * Example #8 JS-IME or JS-Keyboard should dispatch key events even during
153 *            composition (non-printable key case):
154 *
155 *   if (!TIP.beginInputTransaction(window, callback)) {
156 *     return; // You failed to get the rights to dispatch key events
157 *   }
158 *
159 *   // You don't need to specify .keyCode value if it's non-printable key
160 *   // because it can be computed from .key value.
161 *   // If you specify non-zero value to .keyCode, it'll be used.
162 *   var keyEvent = new KeyboardEvent("", { code: "Enter", key: "Enter" });
163 *   if (TIP.keydown(keyEvent)) {
164 *     // Handle its default action
165 *   }
166 *
167 *   // Even if keydown event was consumed, keyup event should be dispatched.
168 *   if (TIP.keyup(keyEvent)) {
169 *     // Handle its default action
170 *   }
171 *
172 * Example #9 JS-IME or JS-Keyboard should dispatch key events even during
173 *            composition (printable key case):
174 *
175 *   if (!TIP.beginInputTransaction(window, callback)) {
176 *     return; // You failed to get the rights to dispatch key events
177 *   }
178 *
179 *   // You need to specify .keyCode value if it's printable key.
180 *   // The rules of .keyCode value is documented in MDN:
181 *   //   https://developer.mozilla.org/docs/Web/API/KeyboardEvent.keyCode
182 *   //
183 *   //   #1 If the key location is DOM_KEY_LOCATION_NUMPAD and NumLock is
184 *   //      active, you should specify DOM_VK_NUMPAD[0-9], DOM_VK_MULTIPLY,
185 *   //      DOM_VK_ADD, DOM_VK_SEPARATOR, DOM_VK_SUBTRACT, DOM_VK_DECIMAL or
186 *   //      DOM_VK_DIVIDE.
187 *   //   #2 If the key is Spacebar, use DOM_VK_SPACE.
188 *   //
189 *   //   Following rules are printable keys in DOM_KEY_LOCATION_STANDARD.
190 *   //   .keyCode value for a key shouldn't be changed by modifier states:
191 *   //     #1 If the key can input [0-9] with any modifier state (except
192 *   //        NumLock state), the value should be DOM_VK_[0-9].
193 *   //     #2 Otherwise, and if the key inputs an ASCII alphabet with no
194 *   //        active modifiers, use DOM_VK_[A-Z].
195 *   //     #3 Otherwise, and if the key inputs an ASCII alphabet with no
196 *   //        active modifiers except Shift key state, use DOM_VK_[A-Z] for
197 *   //        the shifted character.  E.g., if a key causes non-alphabet
198 *   //        character such as "@" or a Unicode character without Shift key
199 *   //        but "a" is inputted when Shift key is pressed, the proper
200 *   //        keyCode is DOM_VK_A.
201 *   //     #4 Otherwise, and if the key inputs another ASCII character with
202 *   //        no modifier states, use a proper value for the character.  E.g.,
203 *   //        if the key inputs "*" without Shift key state, it should be
204 *   //        DOM_VK_ASTERISK.
205 *   //     #5 Otherwise, and if the key inputs another ASCII character with
206 *   //        Shift key state, use a proper value for the character.  E.g.,
207 *   //        if a key causes a Unicode character without Shift key but "&"
208 *   //        is inputted when Shift key is pressed, the proper keyCode is
209 *   //        DOM_VK_AMPERSAND.
210 *   //     See above document for the other cases.
211 *   //
212 *   // NOTE: If the software keyboard is 10-key like simple phone,
213 *   //       We don't have common rules to decide its .keyCode value.
214 *   //       Above rules should be used when the JS-Keyboard emulates PC
215 *   //       keyboard.
216 *   // .key value should be inputting character by the key with current
217 *   // modifier state.
218 *   // .code value should be empty string if the JS-Keyboard isn't emulating
219 *   // physical keyboard.  Otherwise, use same value with physical keyboard's
220 *   // same key.
221 *   var keyEvent = new KeyboardEvent("", { code: "KeyA", key: "a",
222 *                                          keyCode: KeyboardEvent.DOM_VK_A });
223 *   if (TIP.keydown(keyEvent)) {
224 *     // Handle its default action
225 *   }
226 *
227 *   // Even if keydown event was consumed, keyup event should be dispatched.
228 *   if (TIP.keyup(keyEvent)) {
229 *     // Handle its default action
230 *   }
231 *
232 * Example #10 JS-Keyboard doesn't need to initialize modifier states at
233 *             calling either keydown() or keyup().
234 *
235 *   // Neither beginInputTransaction() nor beginInputTransactionForTests()
236 *   // resets modifier state.
237 *   if (!TIP.beginInputTransaction(window, callback)) {
238 *     return; // You failed to get the rights to dispatch key events
239 *   }
240 *
241 *   var leftShift = new KeyboardEvent("", { code: "ShiftLeft", key: "Shift" });
242 *
243 *   // This causes following key events will be shifted automatically.
244 *   TIP.keydown(leftShift);
245 *
246 *   var rightShift =
247 *     new KeyboardEvent("", { code: "ShiftRight", key: "Shift" });
248 *
249 *   TIP.keydown(rightShift);
250 *
251 *   // keyup of one of shift key doesn't cause inactivating "Shift" state.
252 *   TIP.keyup(rightShift);
253 *
254 *   // This causes inactivating "Shift" state completely.
255 *   TIP.keyup(leftShift);
256 */
257
258[scriptable, builtinclass, uuid(47ae2181-2e98-4d58-84a2-b8db6764ce9a)]
259interface nsITextInputProcessor : nsISupports
260{
261  /**
262   * Returns true if this instance was dispatched compositionstart but hasn't
263   * dispatched compositionend yet.
264   */
265  readonly attribute boolean hasComposition;
266
267  /**
268   * When you create an instance, you must call beginInputTransaction() first
269   * except when you created the instance for automated tests.
270   *
271   * @param aWindow         A DOM window.  The instance will look for a top
272   *                        level widget from this.
273   * @param aCallback       Callback interface which handles requests to
274   *                        IME and notifications to IME.  This must not be
275   *                        null.
276   * @return                If somebody uses internal text input service for a
277   *                        composition, this returns false.  Otherwise, returns
278   *                        true.  I.e., only your TIP can create composition
279   *                        when this returns true.  If this returns false,
280   *                        your TIP should wait next chance.
281   */
282  boolean beginInputTransaction(in mozIDOMWindow aWindow,
283                                in nsITextInputProcessorCallback aCallback);
284
285  /**
286   * When you create an instance for automated test, you must call
287   * beginInputTransaction(), first.  See beginInputTransaction() for more
288   * detail of this.
289   * Note that aCallback can be null.  If it's null, nsITextInputProcessor
290   * implementation will handle them automatically.
291   */
292  [optional_argc] boolean
293    beginInputTransactionForTests(
294      in mozIDOMWindow aWindow,
295      [optional] in nsITextInputProcessorCallback aCallback);
296
297  /**
298   * startComposition() dispatches compositionstart event explicitly.
299   * IME does NOT need to call this typically since compositionstart event
300   * is automatically dispatched by sendPendingComposition() if
301   * compositionstart event hasn't been dispatched yet.  If this is called
302   * when compositionstart has already been dispatched, this throws an
303   * exception.
304   *
305   * @param aKeyboardEvent  Key event which causes starting composition.
306   *                        If its type value is "keydown", this method
307   *                        dispatches only keydown event first.  Otherwise,
308   *                        dispatches keydown first and keyup at last.
309   *                        key value and keyCode values of keydown event
310   *                        are set to "Process" and DOM_VK_PROCESSKEY
311   *                        automatically.  You can prevent this behavior
312   *                        with KEY_DONT_MARK_KEYDOWN_AS_PROCESSED.
313   * @param aKeyFlags       See KEY_* constants.
314   * @return                Returns true if composition starts normally.
315   *                        Otherwise, returns false because it might be
316   *                        canceled by the web application.
317   */
318  [can_run_script, optional_argc]
319    boolean startComposition([optional] in Event aKeyboardEvent,
320                             [optional] in unsigned long aKeyFlags);
321
322  /**
323   * Set new composition string.  Pending composition will be flushed by
324   * a call of flushPendingComposition().  However, if the new composition
325   * string isn't empty, you need to call appendClauseToPendingComposition() to
326   * fill all characters of aString with one or more clauses before flushing.
327   * Note that if you need to commit or cancel composition, use
328   * commitComposition(), commitCompositionWith() or cancelComposition().
329   */
330  void setPendingCompositionString(in AString aString);
331
332  // ATTR_RAW_CLAUSE means that the clause hasn't been selected nor converted
333  // yet.
334  const unsigned long ATTR_RAW_CLAUSE           = 0x02;
335  // ATTR_SELECTED_RAW_CLAUSE means that the clause hasn't been converted yet
336  // but is selected for converting to the other string.
337  const unsigned long ATTR_SELECTED_RAW_CLAUSE  = 0x03;
338  // ATTR_CONVERTED_CLAUSE means that the clause has already been converted but
339  // is not selected.  This does NOT mean that this clause isn't modifiable.
340  const unsigned long ATTR_CONVERTED_CLAUSE     = 0x04;
341  // ATTR_SELECTED_CLAUSE means that the clause has already been converted and
342  // is selected.  In other words, the clause is being converted.
343  const unsigned long ATTR_SELECTED_CLAUSE      = 0x05;
344
345  /**
346   * Append a clause to the pending composition.
347   *
348   * If you need to fill the pending composition string with a clause, you
349   * should call this once.  For example:
350   *   appendClauseToPendingComposition(compositionString.length,
351   *                                    ATTR_RAW_CLAUSE);
352   * is enough.  If you need to separate the pending composition string to
353   * multiple clauses, you need to call this multiple times. For example,
354   * if your pending composition string has three clauses and the second clause
355   * is being converted:
356   *  appendClauseToPendingComposition(firstClauseLength,
357   *                                   ATTR_CONVERTED_CLAUSE);
358   *  appendClauseToPendingComposition(secondClauseLength,
359   *                                   ATTR_SELECTED_CLAUSE);
360   *  appendClauseToPendingComposition(thirdClauseLength,
361   *                                   ATTR_CONVERTED_CLAUSE);
362   * Note that if sum of aLength mismatches length of the pending composition
363   * string, flushPendingComposition() will throw an exception.  I.e.,
364   * |firstClauseLength + secondClauseLength + thirdClauseLength| must be
365   * same as the length of pending composition string.
366   *
367   * TODO: Should be able to specify custom clause style.
368   *
369   * @param aLength         Length of the clause.
370   * @param aAttribute      One of ATTR_* constants.
371   */
372  void appendClauseToPendingComposition(in unsigned long aLength,
373                                        in unsigned long aAttribute);
374
375  /**
376   * Set caret offset in the pending composition string.  If you don't need to
377   * show a caret, you don't need to call this.
378   *
379   * @param aOffset         Caret offset in the pending composition string.
380   *                        This must be between 0 and length of the pending
381   *                        composition string.
382   */
383  void setCaretInPendingComposition(in unsigned long aOffset);
384
385  /**
386   * flushPendingComposition() must be called after
387   * setPendingCompositionString() and appendClauseToPendingComposition()
388   * (setCaretInPendingComposition() is optional) are called.
389   *
390   * Note that compositionstart will be automatically dispatched if this is
391   * called when there is no composition.
392   *
393   * Note that if sum of lengths of appended clauses are not same as composition
394   * string or caret offset is larger than the composition string length, this
395   * throws an exception.
396   *
397   * @param aKeyboardEvent  Key event which causes the composition string.
398   *                        If its type value is "keydown", this method
399   *                        dispatches only keydown event first.  Otherwise,
400   *                        dispatches keydown first and keyup at last.
401   *                        key value and keyCode values of keydown event
402   *                        are set to "Process" and DOM_VK_PROCESSKEY
403   *                        automatically.  You can prevent this behavior
404   *                        with KEY_DONT_MARK_KEYDOWN_AS_PROCESSED.
405   * @param aKeyFlags       See KEY_* constants.
406   * @return                Returns true if there is a composition already or
407   *                        starting composition automatically.
408   *                        Otherwise, i.e., if it cannot start composition
409   *                        automatically, e.g., canceled by web apps, returns
410   *                        false.
411   */
412  [can_run_script, optional_argc]
413    boolean flushPendingComposition(
414      [optional] in Event aKeyboardEvent,
415      [optional] in unsigned long aKeyFlags);
416
417  /**
418   * commitComposition() will commit composition with the last composition
419   * string.  If there is no composition, this will throw an exception.
420   *
421   * @param aKeyboardEvent  Key event which causes the commit composition.
422   *                        If its type value is "keydown", this method
423   *                        dispatches only keydown event first.  Otherwise,
424   *                        dispatches keydown first and keyup at last.
425   *                        key value and keyCode values of keydown event
426   *                        are set to "Process" and DOM_VK_PROCESSKEY
427   *                        automatically.  You can prevent this behavior
428   *                        with KEY_DONT_MARK_KEYDOWN_AS_PROCESSED.
429   * @param aKeyFlags       See KEY_* constants.
430   */
431  [can_run_script, optional_argc]
432    void commitComposition([optional] in Event aKeyboardEvent,
433                           [optional] in unsigned long aKeyFlags);
434
435  /**
436   * commitCompositionWith() will commit composition with the specific string.
437   * If there is no composition, this will start composition and commit it
438   * with the specified string.
439   *
440   * @param aCommitString   The string to be committed.
441   * @param aKeyboardEvent  Key event which causes the commit composition.
442   *                        If its type value is "keydown", this method
443   *                        dispatches only keydown event first.  Otherwise,
444   *                        dispatches keydown first and keyup at last.
445   *                        key value and keyCode values of keydown event
446   *                        are set to "Process" and DOM_VK_PROCESSKEY
447   *                        automatically.  You can prevent this behavior
448   *                        with KEY_DONT_MARK_KEYDOWN_AS_PROCESSED.
449   * @param aKeyFlags       See KEY_* constants.
450   * @return                Returns true if there is a composition already or
451   *                        starting composition automatically.
452   *                        Otherwise, i.e., if it cannot start composition
453   *                        automatically, e.g., canceled by web apps, returns
454   *                        false.
455   */
456  [can_run_script, optional_argc]
457    boolean commitCompositionWith(in AString aCommitString,
458                                  [optional] in Event aKeyboardEvent,
459                                  [optional] in unsigned long aKeyFlags);
460
461  /**
462   * cancelComposition() will cancel composition.  This is for now the same as
463   * calling commitComposition("").  However, in the future, this might work
464   * better.  If your IME needs to cancel composition, use this instead of
465   * commitComposition().
466   *
467   * Note that if you tries to cancel composition when there is no composition,
468   * this throws an exception.
469   *
470   * @param aKeyboardEvent  Key event which causes the canceling composition.
471   *                        If its type value is "keydown", this method
472   *                        dispatches only keydown event first.  Otherwise,
473   *                        dispatches keydown first and keyup at last.
474   *                        key value and keyCode values of keydown event
475   *                        are set to "Process" and DOM_VK_PROCESSKEY
476   *                        automatically.  You can prevent this behavior
477   *                        with KEY_DONT_MARK_KEYDOWN_AS_PROCESSED.
478   * @param aKeyFlags       See KEY_* constants.
479   */
480  [can_run_script, optional_argc]
481    void cancelComposition([optional] in Event aKeyboardEvent,
482                           [optional] in unsigned long aKeyFlags);
483
484  // Specifying KEY_DEFAULT_PREVENTED can dispatch key events whose
485  // defaultPrevented are true.  Note that if this is specified, keypress event
486  // won't be fired.
487  const unsigned long KEY_DEFAULT_PREVENTED                        = 0x00000001;
488  // If KEY_NON_PRINTABLE_KEY is specified and the .key value isn't valid
489  // key name, the methods will throws an exception.  In other words, this
490  // flag prevents to dispatch key events with wrong key values and to cause
491  // such key events input the key values as text.
492  const unsigned long KEY_NON_PRINTABLE_KEY                        = 0x00000002;
493  // If KEY_FORCE_PRINTABLE_KEY is specified and even if the .key value is a
494  // registered key name, it's treated as inputting text value.
495  const unsigned long KEY_FORCE_PRINTABLE_KEY                      = 0x00000004;
496  // If KEY_KEEP_KEY_LOCATION_STANDARD is specified when its .location is not
497  // initialized or initialized with 0, the value isn't computed with .code
498  // value.  Note that if .location is initialized with non-zero value,
499  // this flag causes throwing an exception.
500  // NOTE: This is not recommended to use except for tests.
501  const unsigned long KEY_KEEP_KEY_LOCATION_STANDARD               = 0x00000008;
502  // If KEY_KEEP_KEYCODE_ZERO is specified when its .keyCode is not initialized
503  // or initialized with 0, the value isn't computed with .key value when it
504  // represents non-printable key.  Note that if .keyCode is initialized with
505  // non-zero value, this flag causes throwing an exception.
506  const unsigned long KEY_KEEP_KEYCODE_ZERO                        = 0x00000010;
507  // If KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT is specified when the key event is
508  // a modifier key's, keydown() and keyup() only modifies its modifier state
509  // without dispatching key events.  This is useful for testing odd behavior
510  // or emulating legacy API behavior.
511  const unsigned long KEY_DONT_DISPATCH_MODIFIER_KEY_EVENT         = 0x00000020;
512  // If KEY_DONT_MARK_KEYDOWN_AS_PROCESSED is specified, key value and keyCode
513  // value of keydown event are not changed to "Process" and DOM_VK_PROCESSKEY.
514  const unsigned long KEY_DONT_MARK_KEYDOWN_AS_PROCESSED           = 0x00000040;
515  // If KEY_MARK_KEYUP_AS_PROCESSED is specified, key value and keyCode value
516  // of keyup event are changed to "Process" and DOM_VK_PROCESSKEY.
517  const unsigned long KEY_MARK_KEYUP_AS_PROCESSED                  = 0x00000080;
518
519  // These values can be used to do bitwise operation with the return value of
520  // the keydown() method.
521  const unsigned long KEYEVENT_NOT_CONSUMED                        = 0x00000000;
522  const unsigned long KEYDOWN_IS_CONSUMED                          = 0x00000001;
523  const unsigned long KEYPRESS_IS_CONSUMED                         = 0x00000002;
524
525  /**
526   * keydown() may dispatch a keydown event and some keypress events if
527   * preceding keydown event isn't consumed and they are necessary.
528   * Note that even if this is called during composition, key events may not
529   * be dispatched.  In this case, this returns false.
530   *
531   * You should initialize at least .key value and .code value of the event.
532   * Additionally, if you try to emulate a printable key, .keyCode value should
533   * be specified if there is proper key value.  See the comment of above
534   * example how to decide .keyCode value of a printable key.  On the other
535   * hand, .keyCode value is automatically computed when you try to emulate
536   * non-printable key.  However, if you try to emulate physical keyboard of
537   * desktop platform, you need to specify proper value explicitly because
538   * the mapping table of this API isn't enough to emulate the behavior of
539   * Gecko for desktop platforms.
540   *
541   * NOTE: Even if this has composition, JS-Keyboard should call keydown() and
542   *       keyup().  Although, with the default preferences and normal
543   *       conditions, DOM key events won't be fired during composition.
544   *       However, they MAY be dispatched for some reasons, e.g., the web
545   *       content listens only key events, or if the standard DOM event spec
546   *       will be changed in the future.
547   *
548   * @param aKeyboardEvent  Must be a keyboard event which should be dispatched
549   *                        as a keydown event and keypress events.
550   *                        #1 Note that you don't need to set charCode value
551   *                        because it's computed from its key value.
552   *                        #2 If code value is set properly and location value
553   *                        isn't specified (i.e., 0), the location value will
554   *                        be guessed from the code value.
555   *                        #3 Non-defined code names are not allowed. If your
556   *                        key isn't registered, file a bug. If your key isn't
557   *                        defined by any standards, use "" (empty string).
558   *                        #4 .keyCode is guessed from .key value if the key
559   *                        name is registered and .keyCode isn't initialized.
560   *                        #5 modifier key states, e.g., .shiftKey, are
561   *                        ignored.  Instead, modifier states are managed by
562   *                        each instance and set automatically.
563   * @param aKeyFlags       Special flags.  The values can be some of KEY_*
564   *                        constants.
565   * @return                KEYEVENT_NOT_CONSUMED, if the keydown event nor
566   *                        the following keypress event(s) are consumed.
567   *                        KEYDOWN_IS_CONSUMED, if the keydown event is
568   *                        consumed. No keypress event will be dispatched in
569   *                        this case.
570   *                        KEYPRESS_IS_CONSUMED, if the keypress event(s) is
571   *                        consumed when dispatched.
572   *                        Note that keypress event is always consumed by
573   *                        native code for the printable keys (indicating the
574   *                        default action has been taken).
575   */
576  [can_run_script, optional_argc]
577    unsigned long keydown(in Event aKeyboardEvent,
578                          [optional] in unsigned long aKeyFlags);
579
580  /**
581   * Similar to keydown(), but this dispatches only a keyup event.
582   */
583  [optional_argc]
584    boolean keyup(in Event aKeyboardEvent,
585                  [optional] in unsigned long aKeyFlags);
586
587  /**
588   * getModifierState() returns modifier state managed by this instance.
589   *
590   * @param aModifier       One of modifier key names.  This doesn't support
591   *                        virtual modifiers like "Accel".
592   * @return                true if the modifier key is active.  Otherwise,
593   *                        false.
594   */
595  boolean getModifierState(in AString aModifierKey);
596
597  /**
598   * shareModifierStateOf() makes the instance shares modifier state of
599   * another instance.  When this is called, the instance refers the modifier
600   * state of another instance.  After that, changes to either this and the
601   * other instance's modifier state is synchronized.
602   *
603   * @param aOther          Another instance which will be referred by the
604   *                        instance.  If this is null, the instance restarts
605   *                        to manage modifier state independently.
606   */
607  void shareModifierStateOf(in nsITextInputProcessor aOther);
608
609  /**
610   * Helper method to get usual |.code| value of non-printable keys.
611   *
612   * @param aKeyValue       A predefined key value such as "Enter".
613   *                        If this is not a proper non-printable key value
614   *                        or a proper key value but not in usual keyboard of
615   *                        the platform, this returns empty string.
616   * @param aLocation       The |.location| value.  This is important if
617   *                        the key may be in different location.
618   *                        E.g., Left vs. Right or Standard vs. Numpad.
619   *                        If this is undefined or null, it'll be treated
620   *                        as Standard or Left.
621   * @return                One of a code value of well-known key on usual
622   *                        keyboard on the platform, or empty string.
623   */
624  [optional_argc]
625    AString computeCodeValueOfNonPrintableKey(
626              in AString aKeyValue,
627              [optional] in jsval aLocation);
628
629  /**
630   * Helper method to guess |.code| value of a printable key which is in usual
631   * keyboard of the platform and when active keyboard layout is US-English.
632   * Note that this is not aware of option key mapping on macOS.
633   *
634   * @param aKeyValue          The key value. Must be a character which can
635   *                           be inputted with US-English keyboard layout.
636   * @param aLocation          The location of the key.  This is important
637   *                           to distinguish whether the key is in Standard
638   *                           or Numpad. If this is undefined or null, will
639   *                           be treated as Standard.
640   * @return                   Returns empty string if there is no proper key.
641   */
642  [optional_argc]
643    AString guessCodeValueOfPrintableKeyInUSEnglishKeyboardLayout(
644              in AString aKeyValue,
645              [optional] in jsval aLocation);
646
647  /**
648   * Helper method to guess |.keyCode| value of a printable key which is in
649   * usual keyboard of the platform and when active keyboard layout is
650   * US-English.
651   * Note that this is not aware of option key mapping on macOS.
652   *
653   * @param aKeyValue          The key value.  Must be a character which can
654   *                           be inputted with US-English keyboard layout.
655   * @param aLocation          The location of the key.  This is important
656   *                           to distinguish whether the key is in Standard
657   *                           our Numpad.  If this is undefined or null,
658   *                           will be treated as Standard.
659   * @return                   Returns 0 if there is no proper key to input
660   *                           aKeyValue with US-English keyboard layout.
661   */
662  [optional_argc]
663    unsigned long guessKeyCodeValueOfPrintableKeyInUSEnglishKeyboardLayout(
664                    in AString aKeyValue,
665                    [optional] in jsval aLocation);
666};
667
668%{C++
669#define TEXT_INPUT_PROCESSOR_CID \
670  { 0xcaaab47f, 0x1e31, 0x478e, \
671    { 0x89, 0x19, 0x97, 0x09, 0x04, 0xe9, 0xcb, 0x72 } }
672#define TEXT_INPUT_PROCESSOR_CONTRACTID \
673  "@mozilla.org/text-input-processor;1"
674%}
675