Back to index

lightning-sunbird  0.9+nobinonly
nsBidiKeyboard.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is IBM code.
00017  *
00018  * The Initial Developer of the Original Code is
00019  * IBM. Portions created by IBM are Copyright (C) International Business Machines Corporation, 2000.  All Rights Reserved.
00020  * Portions created by the Initial Developer are Copyright (C) 2001
00021  * the Initial Developer. All Rights Reserved.
00022  *
00023  * Contributor(s):
00024  *   Simon Montagu
00025  *
00026  * Alternatively, the contents of this file may be used under the terms of
00027  * either the GNU General Public License Version 2 or later (the "GPL"), or
00028  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00029  * in which case the provisions of the GPL or the LGPL are applicable instead
00030  * of those above. If you wish to allow use of your version of this file only
00031  * under the terms of either the GPL or the LGPL, and not to allow others to
00032  * use your version of this file under the terms of the MPL, indicate your
00033  * decision by deleting the provisions above and replace them with the notice
00034  * and other provisions required by the GPL or the LGPL. If you do not delete
00035  * the provisions above, a recipient may use your version of this file under
00036  * the terms of any one of the MPL, the GPL or the LGPL.
00037  *
00038  * ***** END LICENSE BLOCK ***** */
00039 
00040 #include <stdio.h>
00041 #include "nsBidiKeyboard.h"
00042 #include "prmem.h"
00043 
00044 NS_IMPL_ISUPPORTS1(nsBidiKeyboard, nsIBidiKeyboard)
00045 
00046 nsBidiKeyboard::nsBidiKeyboard() : nsIBidiKeyboard()
00047 {
00048   mDefaultsSet = PR_FALSE;
00049   mLTRKeyboard[0] = '\0';
00050   mRTLKeyboard[0] = '\0';
00051   mCurrentLocaleName[0] = '\0';
00052 }
00053 
00054 nsBidiKeyboard::~nsBidiKeyboard()
00055 {
00056 }
00057 
00058 NS_IMETHODIMP nsBidiKeyboard::SetLangFromBidiLevel(PRUint8 aLevel)
00059 {
00060   if (!mDefaultsSet) {
00061     nsresult result = EnumerateKeyboards();
00062     if (NS_SUCCEEDED(result))
00063       mDefaultsSet = PR_TRUE;
00064     else
00065       return result;
00066   }
00067 
00068   // call LoadKeyboardLayout() only if the target keyboard layout is different from the current
00069   char currentLocaleName[KL_NAMELENGTH];
00070   strncpy(currentLocaleName, (aLevel & 1) ? mRTLKeyboard : mLTRKeyboard, KL_NAMELENGTH);
00071   currentLocaleName[KL_NAMELENGTH-1] = '\0'; // null terminate
00072 
00073   NS_ASSERTION(*currentLocaleName, 
00074     "currentLocaleName has string length == 0");
00075 
00076 #if 0
00077   /* This implementation of automatic keyboard layout switching is too buggy to be useful
00078      and the feature itself is inconsistent with Windows. See Bug 162242 */
00079   if (strcmp(mCurrentLocaleName, currentLocaleName)) {
00080     if (!::LoadKeyboardLayout(currentLocaleName, KLF_ACTIVATE | KLF_SUBSTITUTE_OK)) {
00081       return NS_ERROR_FAILURE;
00082     }
00083   }
00084 #endif
00085 
00086   return NS_OK;
00087 }
00088 
00089 NS_IMETHODIMP nsBidiKeyboard::IsLangRTL(PRBool *aIsRTL)
00090 {
00091   *aIsRTL = PR_FALSE;
00092   HKL  currentLocale;
00093  
00094   currentLocale = ::GetKeyboardLayout(0);
00095   *aIsRTL = IsRTLLanguage(currentLocale);
00096   
00097   if (!::GetKeyboardLayoutName(mCurrentLocaleName))
00098     return NS_ERROR_FAILURE;
00099 
00100   NS_ASSERTION(*mCurrentLocaleName, 
00101     "GetKeyboardLayoutName return string length == 0");
00102   NS_ASSERTION((strlen(mCurrentLocaleName) < KL_NAMELENGTH), 
00103     "GetKeyboardLayoutName return string length >= KL_NAMELENGTH");
00104 
00105   // The language set by the user overrides the default language for that direction
00106   if (*aIsRTL) {
00107     strncpy(mRTLKeyboard, mCurrentLocaleName, KL_NAMELENGTH);
00108     mRTLKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
00109   } else {
00110     strncpy(mLTRKeyboard, mCurrentLocaleName, KL_NAMELENGTH);
00111     mLTRKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
00112   }
00113 
00114   NS_ASSERTION((strlen(mRTLKeyboard) < KL_NAMELENGTH), 
00115     "mLTRKeyboard has string length >= KL_NAMELENGTH");
00116   NS_ASSERTION((strlen(mLTRKeyboard) < KL_NAMELENGTH), 
00117     "mRTLKeyboard has string length >= KL_NAMELENGTH");
00118   return NS_OK;
00119 }
00120 
00121 
00122 // Get the list of keyboard layouts available in the system
00123 // Set mLTRKeyboard to the first LTR keyboard in the list and mRTLKeyboard to the first RTL keyboard in the list
00124 // These defaults will be used unless the user explicitly sets something else.
00125 nsresult nsBidiKeyboard::EnumerateKeyboards()
00126 {
00127   int keyboards;
00128   HKL far* buf;
00129   HKL locale;
00130   char localeName[KL_NAMELENGTH];
00131   PRBool isLTRKeyboardSet = PR_FALSE;
00132   PRBool isRTLKeyboardSet = PR_FALSE;
00133   
00134   // GetKeyboardLayoutList with 0 as first parameter returns the number of keyboard layouts available
00135   keyboards = ::GetKeyboardLayoutList(0, nsnull);
00136   if (!keyboards)
00137     return NS_ERROR_FAILURE;
00138 
00139   // allocate a buffer to hold the list
00140   buf = (HKL far*) PR_Malloc(keyboards * sizeof(HKL));
00141   if (!buf)
00142     return NS_ERROR_OUT_OF_MEMORY;
00143 
00144   // Call again to fill the buffer
00145   if (::GetKeyboardLayoutList(keyboards, buf) != keyboards) {
00146     PR_Free(buf);
00147     return NS_ERROR_UNEXPECTED;
00148   }
00149 
00150   // Go through the list and pick a default LTR and RTL keyboard layout
00151   while (keyboards--) {
00152     locale = buf[keyboards];
00153     if (IsRTLLanguage(locale)) {
00154       sprintf(mRTLKeyboard, "%.*x", KL_NAMELENGTH - 1, LANGIDFROMLCID(locale));
00155       isRTLKeyboardSet = PR_TRUE;
00156     }
00157     else {
00158       sprintf(mLTRKeyboard, "%.*x", KL_NAMELENGTH - 1, LANGIDFROMLCID(locale));
00159       isLTRKeyboardSet = PR_TRUE;
00160     }
00161   }
00162   PR_Free(buf);
00163 
00164   // Get the current keyboard layout and use it for either mRTLKeyboard or
00165   // mLTRKeyboard as appropriate. If the user has many keyboard layouts
00166   // installed this prevents us from arbitrarily resetting the current
00167   // layout (bug 80274)
00168 
00169   // If one or other keyboard is still not initialized, copy the
00170   // initialized keyboard to the uninitialized (bug 85813)
00171   locale = ::GetKeyboardLayout(0);
00172   if (!::GetKeyboardLayoutName(localeName))
00173     return NS_ERROR_FAILURE;
00174 
00175   NS_ASSERTION(*localeName, 
00176     "GetKeyboardLayoutName return string length == 0");
00177   NS_ASSERTION((strlen(localeName) < KL_NAMELENGTH), 
00178     "GetKeyboardLayout return string length >= KL_NAMELENGTH");
00179 
00180   if (IsRTLLanguage(locale)) {
00181     strncpy(mRTLKeyboard, localeName, KL_NAMELENGTH);
00182     mRTLKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
00183     if (! isLTRKeyboardSet) {
00184       strncpy(mLTRKeyboard, localeName, KL_NAMELENGTH);
00185       mLTRKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
00186     }
00187   }
00188   else {
00189     strncpy(mLTRKeyboard, localeName, KL_NAMELENGTH);
00190     mLTRKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
00191     if (! isRTLKeyboardSet) {
00192       strncpy(mRTLKeyboard, localeName, KL_NAMELENGTH);
00193       mRTLKeyboard[KL_NAMELENGTH-1] = '\0'; // null terminate
00194     }
00195   }
00196 
00197   NS_ASSERTION(*mRTLKeyboard, 
00198     "mLTRKeyboard has string length == 0");
00199   NS_ASSERTION(*mLTRKeyboard, 
00200     "mLTRKeyboard has string length == 0");
00201 
00202   return NS_OK;
00203 }
00204 
00205 // Test whether the language represented by this locale identifier is a right-to-left language
00206 PRBool nsBidiKeyboard::IsRTLLanguage(HKL aLocale)
00207 {
00208   // This macro extracts the primary language id (low 10 bits) from the locale id
00209   switch (PRIMARYLANGID(aLocale)){
00210     case LANG_ARABIC:
00211     case LANG_FARSI:
00212     case LANG_HEBREW:
00213       return PR_TRUE;
00214       break;
00215 
00216     default:
00217       return PR_FALSE;
00218   }
00219 }