Mercurial > projects > dwt-win
annotate dwt/internal/BidiUtil.d @ 237:e2affbeb686d
Making tango.sys.win32.Types and dwt.internal.win32.WINTYPES to match common declaration. Make ansi charactars of type ubyte.
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Thu, 19 Jun 2008 03:25:36 +0200 |
parents | 36f5cb12e1a2 |
children |
rev | line source |
---|---|
154 | 1 /******************************************************************************* |
2 * Copyright (c) 2000, 2007 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module dwt.internal.BidiUtil; | |
14 | |
15 | |
16 import dwt.DWT; | |
17 import dwt.graphics.GC; | |
18 import dwt.internal.win32.OS; | |
19 | |
213 | 20 import dwt.widgets.Control; |
154 | 21 import tango.util.Convert; |
22 import dwt.dwthelper.utils; | |
23 import dwt.dwthelper.Runnable; | |
24 | |
25 /* | |
26 * Wraps Win32 API used to bidi enable the StyledText widget. | |
27 */ | |
28 public class BidiUtil { | |
29 | |
30 // Keyboard language ids | |
31 public static const int KEYBOARD_NON_BIDI = 0; | |
32 public static const int KEYBOARD_BIDI = 1; | |
33 | |
34 // bidi flag | |
35 static int isBidiPlatform_ = -1; | |
36 | |
37 // getRenderInfo flag values | |
38 public static const int CLASSIN = 1; | |
39 public static const int LINKBEFORE = 2; | |
40 public static const int LINKAFTER = 4; | |
41 | |
42 // variables used for providing a listener mechanism for keyboard language | |
43 // switching | |
44 static Runnable[HWND] languageMap; | |
45 static Runnable[HWND] keyMap; | |
46 static WNDPROC[HWND] oldProcMap; | |
47 /* | |
48 * This code is intentionally commented. In order | |
49 * to support CLDC, .class cannot be used because | |
50 * it does not compile on some Java compilers when | |
51 * they are targeted for CLDC. | |
52 */ | |
53 // static Callback callback = new Callback (BidiUtil.class, "windowProc", 4); | |
212
ab60f3309436
reverted the char[] to String and use the an alias.
Frank Benoit <benoit@tionex.de>
parents:
197
diff
changeset
|
54 static const String CLASS_NAME = "org.eclipse.swt.internal.BidiUtil"; //$NON-NLS-1$ |
154 | 55 // static this() { |
56 // try { | |
57 // callback = new Callback (Class.forName (CLASS_NAME), "windowProc", 4); //$NON-NLS-1$ | |
58 // if (callback.getAddress () is 0) DWT.error (DWT.ERROR_NO_MORE_CALLBACKS); | |
59 // } catch (ClassNotFoundException e) {} | |
60 // } | |
61 | |
62 // GetCharacterPlacement constants | |
63 static const int GCP_REORDER = 0x0002; | |
64 static const int GCP_GLYPHSHAPE = 0x0010; | |
65 static const int GCP_LIGATE = 0x0020; | |
66 static const int GCP_CLASSIN = 0x00080000; | |
67 static const byte GCPCLASS_ARABIC = 2; | |
68 static const byte GCPCLASS_HEBREW = 2; | |
69 static const byte GCPCLASS_LOCALNUMBER = 4; | |
70 static const byte GCPCLASS_LATINNUMBER = 5; | |
71 static const int GCPGLYPH_LINKBEFORE = 0x8000; | |
72 static const int GCPGLYPH_LINKAFTER = 0x4000; | |
73 // ExtTextOut constants | |
74 static const int ETO_CLIPPED = 0x4; | |
75 static const int ETO_GLYPH_INDEX = 0x0010; | |
76 // Windows primary language identifiers | |
77 static const int LANG_ARABIC = 0x01; | |
78 static const int LANG_HEBREW = 0x0d; | |
79 // code page identifiers | |
212
ab60f3309436
reverted the char[] to String and use the an alias.
Frank Benoit <benoit@tionex.de>
parents:
197
diff
changeset
|
80 static const String CD_PG_HEBREW = "1255"; //$NON-NLS-1$ |
ab60f3309436
reverted the char[] to String and use the an alias.
Frank Benoit <benoit@tionex.de>
parents:
197
diff
changeset
|
81 static const String CD_PG_ARABIC = "1256"; //$NON-NLS-1$ |
154 | 82 // ActivateKeyboard constants |
83 static const int HKL_NEXT = 1; | |
84 static const int HKL_PREV = 0; | |
85 | |
86 /* | |
87 * Public character class constants are the same as Windows | |
88 * platform constants. | |
89 * Saves conversion of class array in getRenderInfo to arbitrary | |
90 * constants for now. | |
91 */ | |
92 public static const int CLASS_HEBREW = GCPCLASS_ARABIC; | |
93 public static const int CLASS_ARABIC = GCPCLASS_HEBREW; | |
94 public static const int CLASS_LOCALNUMBER = GCPCLASS_LOCALNUMBER; | |
95 public static const int CLASS_LATINNUMBER = GCPCLASS_LATINNUMBER; | |
96 public static const int REORDER = GCP_REORDER; | |
97 public static const int LIGATE = GCP_LIGATE; | |
98 public static const int GLYPHSHAPE = GCP_GLYPHSHAPE; | |
99 | |
100 /** | |
101 * Adds a language listener. The listener will get notified when the language of | |
102 * the keyboard changes (via Alt-Shift on Win platforms). Do this by creating a | |
103 * window proc for the Control so that the window messages for the Control can be | |
104 * monitored. | |
105 * <p> | |
106 * | |
107 * @param hwnd the handle of the Control that is listening for keyboard language | |
108 * changes | |
109 * @param runnable the code that should be executed when a keyboard language change | |
110 * occurs | |
111 */ | |
112 public static void addLanguageListener (HWND hwnd, Runnable runnable) { | |
113 languageMap[hwnd] = runnable; | |
114 subclass(hwnd); | |
115 } | |
213 | 116 public static void addLanguageListener (Control control, Runnable runnable) { |
117 addLanguageListener(control.handle, runnable); | |
118 } | |
154 | 119 /** |
120 * Proc used for OS.EnumSystemLanguageGroups call during isBidiPlatform test. | |
121 */ | |
122 static extern(Windows) int EnumSystemLanguageGroupsProc(uint lpLangGrpId, wchar* lpLangGrpIdString, wchar* lpLangGrpName, uint options, int lParam) { | |
123 if (lpLangGrpId is OS.LGRPID_HEBREW) { | |
124 isBidiPlatform_ = 1; | |
125 return 0; | |
126 } | |
127 if (lpLangGrpId is OS.LGRPID_ARABIC) { | |
128 isBidiPlatform_ = 1; | |
129 return 0; | |
130 } | |
131 return 1; | |
132 } | |
133 /** | |
134 * Wraps the ExtTextOut function. | |
135 * <p> | |
136 * | |
137 * @param gc the gc to use for rendering | |
138 * @param renderBuffer the glyphs to render as an array of characters | |
139 * @param renderDx the width of each glyph in renderBuffer | |
140 * @param x x position to start rendering | |
141 * @param y y position to start rendering | |
142 */ | |
143 public static void drawGlyphs(GC gc, wchar[] renderBuffer, int[] renderDx, int x, int y) { | |
144 int length_ = renderDx.length; | |
145 | |
146 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { | |
147 if (OS.GetLayout (gc.handle) !is 0) { | |
148 reverse(renderDx); | |
149 renderDx[length_-1]--; //fixes bug 40006 | |
150 reverse(renderBuffer); | |
151 } | |
152 } | |
153 // render transparently to avoid overlapping segments. fixes bug 40006 | |
154 int oldBkMode = OS.SetBkMode(gc.handle, OS.TRANSPARENT); | |
155 OS.ExtTextOutW(gc.handle, x, y, ETO_GLYPH_INDEX , null, renderBuffer.ptr, renderBuffer.length, renderDx.ptr); | |
156 OS.SetBkMode(gc.handle, oldBkMode); | |
157 } | |
158 /** | |
159 * Return ordering and rendering information for the given text. Wraps the GetFontLanguageInfo | |
160 * and GetCharacterPlacement functions. | |
161 * <p> | |
162 * | |
163 * @param gc the GC to use for measuring of this line, input parameter | |
164 * @param text text that bidi data should be calculated for, input parameter | |
165 * @param order an array of integers representing the visual position of each character in | |
166 * the text array, output parameter | |
167 * @param classBuffer an array of integers representing the type (e.g., ARABIC, HEBREW, | |
168 * LOCALNUMBER) of each character in the text array, input/output parameter | |
169 * @param dx an array of integers representing the pixel width of each glyph in the returned | |
170 * glyph buffer, output parameter | |
171 * @param flags an integer representing rendering flag information, input parameter | |
172 * @param offsets text segments that should be measured and reordered separately, input | |
173 * parameter. See org.eclipse.swt.custom.BidiSegmentEvent for details. | |
174 * @return buffer with the glyphs that should be rendered for the given text | |
175 */ | |
212
ab60f3309436
reverted the char[] to String and use the an alias.
Frank Benoit <benoit@tionex.de>
parents:
197
diff
changeset
|
176 public static char[] getRenderInfo(GC gc, String text, int[] order, byte[] classBuffer, int[] dx, int flags, int [] offsets) { |
154 | 177 auto fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle); |
178 auto hHeap = OS.GetProcessHeap(); | |
179 int[8] lpCs; | |
180 int cs = OS.GetTextCharset(gc.handle); | |
181 bool isRightOriented = false; | |
182 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { | |
183 isRightOriented = OS.GetLayout(gc.handle) !is 0; | |
184 } | |
185 OS.TranslateCharsetInfo( cast(uint*)cs, cast(CHARSETINFO*)lpCs.ptr, OS.TCI_SRCCHARSET); | |
186 TCHAR[] textBuffer = StrToTCHARs(lpCs[1], text, false); | |
187 int byteCount = textBuffer.length; | |
188 bool linkBefore = (flags & LINKBEFORE) is LINKBEFORE; | |
189 bool linkAfter = (flags & LINKAFTER) is LINKAFTER; | |
190 | |
191 GCP_RESULTS result; | |
192 result.lStructSize = GCP_RESULTS.sizeof; | |
193 result.nGlyphs = byteCount; | |
194 auto lpOrder = result.lpOrder = cast(uint*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4); | |
195 auto lpDx = result.lpDx = cast(int*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4); | |
237
e2affbeb686d
Making tango.sys.win32.Types and dwt.internal.win32.WINTYPES to match common declaration. Make ansi charactars of type ubyte.
Frank Benoit <benoit@tionex.de>
parents:
213
diff
changeset
|
196 auto lpClass = result.lpClass = cast(CHAR*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); |
154 | 197 auto lpGlyphs = result.lpGlyphs = cast(wchar*)OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 2); |
198 | |
199 // set required dwFlags | |
200 int dwFlags = 0; | |
201 int glyphFlags = 0; | |
202 // Always reorder. We assume that if we are calling this function we're | |
203 // on a platform that supports bidi. Fixes 20690. | |
204 dwFlags |= GCP_REORDER; | |
205 if ((fontLanguageInfo & GCP_LIGATE) is GCP_LIGATE) { | |
206 dwFlags |= GCP_LIGATE; | |
207 glyphFlags |= 0; | |
208 } | |
209 if ((fontLanguageInfo & GCP_GLYPHSHAPE) is GCP_GLYPHSHAPE) { | |
210 dwFlags |= GCP_GLYPHSHAPE; | |
211 if (linkBefore) { | |
212 glyphFlags |= GCPGLYPH_LINKBEFORE; | |
213 } | |
214 if (linkAfter) { | |
215 glyphFlags |= GCPGLYPH_LINKAFTER; | |
216 } | |
217 } | |
218 byte[] lpGlyphs2; | |
219 if (linkBefore || linkAfter) { | |
220 lpGlyphs2 = new byte[2]; | |
221 lpGlyphs2[0]=cast(byte)glyphFlags; | |
222 lpGlyphs2[1]=cast(byte)(glyphFlags >> 8); | |
223 } | |
224 else { | |
225 lpGlyphs2 = [cast(byte) glyphFlags]; | |
226 } | |
227 OS.MoveMemory(result.lpGlyphs, lpGlyphs2.ptr, lpGlyphs2.length); | |
228 | |
229 if ((flags & CLASSIN) is CLASSIN) { | |
230 // set classification values for the substring | |
231 dwFlags |= GCP_CLASSIN; | |
232 OS.MoveMemory(result.lpClass, classBuffer.ptr, classBuffer.length); | |
233 } | |
234 | |
235 wchar[] glyphBuffer = new wchar[result.nGlyphs]; | |
236 int glyphCount = 0; | |
237 for (int i=0; i<offsets.length-1; i++) { | |
238 int offset = offsets [i]; | |
239 int length_ = offsets [i+1] - offsets [i]; | |
240 | |
241 // The number of glyphs expected is <= length (segment length); | |
242 // the actual number returned may be less in case of Arabic ligatures. | |
243 result.nGlyphs = length_; | |
244 TCHAR[] textBuffer2 = StrToTCHARs(lpCs[1], text.substring(offset, offset + length_), false); | |
245 OS.GetCharacterPlacement(gc.handle, textBuffer2.ptr, textBuffer2.length, 0, &result, dwFlags); | |
246 | |
247 if (dx !is null) { | |
248 int [] dx2 = new int [result.nGlyphs]; | |
249 OS.MoveMemory(dx2.ptr, result.lpDx, dx2.length * 4); | |
250 if (isRightOriented) { | |
251 reverse(dx2); | |
252 } | |
253 System.arraycopy (dx2, 0, dx, glyphCount, dx2.length); | |
254 } | |
255 if (order !is null) { | |
256 int [] order2 = new int [length_]; | |
257 OS.MoveMemory(order2.ptr, result.lpOrder, order2.length * 4); | |
258 translateOrder(order2, glyphCount, isRightOriented); | |
259 System.arraycopy (order2, 0, order, offset, length_); | |
260 } | |
261 if (classBuffer !is null) { | |
262 byte [] classBuffer2 = new byte [length_]; | |
263 OS.MoveMemory(classBuffer2.ptr, result.lpClass, classBuffer2.length); | |
264 System.arraycopy (classBuffer2, 0, classBuffer, offset, length_); | |
265 } | |
266 wchar[] glyphBuffer2 = new wchar[result.nGlyphs]; | |
267 OS.MoveMemory(glyphBuffer2.ptr, result.lpGlyphs, glyphBuffer2.length * 2); | |
268 if (isRightOriented) { | |
269 reverse(glyphBuffer2); | |
270 } | |
271 System.arraycopy (glyphBuffer2, 0, glyphBuffer, glyphCount, glyphBuffer2.length); | |
272 glyphCount += glyphBuffer2.length; | |
273 | |
274 // We concatenate successive results of calls to GCP. | |
275 // For Arabic, it is the only good method since the number of output | |
276 // glyphs might be less than the number of input characters. | |
277 // This assumes that the whole line is built by successive adjacent | |
278 // segments without overlapping. | |
279 result.lpOrder += length_ * 4; | |
280 result.lpDx += length_ * 4; | |
281 result.lpClass += length_; | |
282 result.lpGlyphs += glyphBuffer2.length * 2; | |
283 } | |
284 | |
285 /* Free the memory that was allocated. */ | |
286 OS.HeapFree(hHeap, 0, lpGlyphs); | |
287 OS.HeapFree(hHeap, 0, lpClass); | |
288 OS.HeapFree(hHeap, 0, lpDx); | |
289 OS.HeapFree(hHeap, 0, lpOrder); | |
290 return WCHARsToStr(glyphBuffer); | |
291 } | |
292 /** | |
293 * Return bidi ordering information for the given text. Does not return rendering | |
294 * information (e.g., glyphs, glyph distances). Use this method when you only need | |
295 * ordering information. Doing so will improve performance. Wraps the | |
296 * GetFontLanguageInfo and GetCharacterPlacement functions. | |
297 * <p> | |
298 * | |
299 * @param gc the GC to use for measuring of this line, input parameter | |
300 * @param text text that bidi data should be calculated for, input parameter | |
301 * @param order an array of integers representing the visual position of each character in | |
302 * the text array, output parameter | |
303 * @param classBuffer an array of integers representing the type (e.g., ARABIC, HEBREW, | |
304 * LOCALNUMBER) of each character in the text array, input/output parameter | |
305 * @param flags an integer representing rendering flag information, input parameter | |
306 * @param offsets text segments that should be measured and reordered separately, input | |
307 * parameter. See org.eclipse.swt.custom.BidiSegmentEvent for details. | |
308 */ | |
212
ab60f3309436
reverted the char[] to String and use the an alias.
Frank Benoit <benoit@tionex.de>
parents:
197
diff
changeset
|
309 public static void getOrderInfo(GC gc, String text, int[] order, byte[] classBuffer, int flags, int [] offsets) { |
154 | 310 int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle); |
311 auto hHeap = OS.GetProcessHeap(); | |
312 int[8] lpCs; | |
313 int cs = OS.GetTextCharset(gc.handle); | |
314 OS.TranslateCharsetInfo( cast(uint*) cs, cast(CHARSETINFO*)lpCs.ptr, OS.TCI_SRCCHARSET); | |
315 TCHAR[] textBuffer = StrToTCHARs(lpCs[1], text, false); | |
316 int byteCount = textBuffer.length; | |
317 bool isRightOriented = false; | |
318 if (!OS.IsWinCE && OS.WIN32_VERSION >= OS.VERSION(4, 10)) { | |
319 isRightOriented = OS.GetLayout(gc.handle) !is 0; | |
320 } | |
321 | |
322 GCP_RESULTS result; | |
323 result.lStructSize = GCP_RESULTS.sizeof; | |
324 result.nGlyphs = byteCount; | |
325 auto lpOrder = result.lpOrder = cast(uint*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount * 4); | |
237
e2affbeb686d
Making tango.sys.win32.Types and dwt.internal.win32.WINTYPES to match common declaration. Make ansi charactars of type ubyte.
Frank Benoit <benoit@tionex.de>
parents:
213
diff
changeset
|
326 auto lpClass = result.lpClass = cast(CHAR*) OS.HeapAlloc(hHeap, OS.HEAP_ZERO_MEMORY, byteCount); |
154 | 327 |
328 // set required dwFlags, these values will affect how the text gets rendered and | |
329 // ordered | |
330 int dwFlags = 0; | |
331 // Always reorder. We assume that if we are calling this function we're | |
332 // on a platform that supports bidi. Fixes 20690. | |
333 dwFlags |= GCP_REORDER; | |
334 if ((fontLanguageInfo & GCP_LIGATE) is GCP_LIGATE) { | |
335 dwFlags |= GCP_LIGATE; | |
336 } | |
337 if ((fontLanguageInfo & GCP_GLYPHSHAPE) is GCP_GLYPHSHAPE) { | |
338 dwFlags |= GCP_GLYPHSHAPE; | |
339 } | |
340 if ((flags & CLASSIN) is CLASSIN) { | |
341 // set classification values for the substring, classification values | |
342 // can be specified on input | |
343 dwFlags |= GCP_CLASSIN; | |
344 OS.MoveMemory(result.lpClass, classBuffer.ptr, classBuffer.length); | |
345 } | |
346 | |
347 int glyphCount = 0; | |
348 for (int i=0; i<offsets.length-1; i++) { | |
349 int offset = offsets [i]; | |
350 int length_ = offsets [i+1] - offsets [i]; | |
351 // The number of glyphs expected is <= length (segment length); | |
352 // the actual number returned may be less in case of Arabic ligatures. | |
353 result.nGlyphs = length_; | |
354 TCHAR[] textBuffer2 = StrToTCHARs(lpCs[1], text.substring(offset, offset + length_), false); | |
355 OS.GetCharacterPlacement(gc.handle, textBuffer2.ptr, textBuffer2.length, 0, &result, dwFlags); | |
356 | |
357 if (order !is null) { | |
358 int [] order2 = new int [length_]; | |
359 OS.MoveMemory(order2.ptr, result.lpOrder, order2.length * 4); | |
360 translateOrder(order2, glyphCount, isRightOriented); | |
361 System.arraycopy (order2, 0, order, offset, length_); | |
362 } | |
363 if (classBuffer !is null) { | |
364 byte [] classBuffer2 = new byte [length_]; | |
365 OS.MoveMemory(classBuffer2.ptr, result.lpClass, classBuffer2.length); | |
366 System.arraycopy (classBuffer2, 0, classBuffer, offset, length_); | |
367 } | |
368 glyphCount += result.nGlyphs; | |
369 | |
370 // We concatenate successive results of calls to GCP. | |
371 // For Arabic, it is the only good method since the number of output | |
372 // glyphs might be less than the number of input characters. | |
373 // This assumes that the whole line is built by successive adjacent | |
374 // segments without overlapping. | |
375 result.lpOrder += length_ * 4; | |
376 result.lpClass += length_; | |
377 } | |
378 | |
379 /* Free the memory that was allocated. */ | |
380 OS.HeapFree(hHeap, 0, lpClass); | |
381 OS.HeapFree(hHeap, 0, lpOrder); | |
382 } | |
383 /** | |
384 * Return bidi attribute information for the font in the specified gc. | |
385 * <p> | |
386 * | |
387 * @param gc the gc to query | |
388 * @return bitwise OR of the REORDER, LIGATE and GLYPHSHAPE flags | |
389 * defined by this class. | |
390 */ | |
391 public static int getFontBidiAttributes(GC gc) { | |
392 int fontStyle = 0; | |
393 int fontLanguageInfo = OS.GetFontLanguageInfo(gc.handle); | |
394 if (((fontLanguageInfo & GCP_REORDER) !is 0)) { | |
395 fontStyle |= REORDER; | |
396 } | |
397 if (((fontLanguageInfo & GCP_LIGATE) !is 0)) { | |
398 fontStyle |= LIGATE; | |
399 } | |
400 if (((fontLanguageInfo & GCP_GLYPHSHAPE) !is 0)) { | |
401 fontStyle |= GLYPHSHAPE; | |
402 } | |
403 return fontStyle; | |
404 } | |
405 /** | |
406 * Return the active keyboard language type. | |
407 * <p> | |
408 * | |
409 * @return an integer representing the active keyboard language (KEYBOARD_BIDI, | |
410 * KEYBOARD_NON_BIDI) | |
411 */ | |
412 public static int getKeyboardLanguage() { | |
413 int layout = cast(int) OS.GetKeyboardLayout(0); | |
213 | 414 int langID = OS.PRIMARYLANGID(OS.LOWORD(layout)); |
415 if (langID is LANG_HEBREW) return KEYBOARD_BIDI; | |
416 if (langID is LANG_ARABIC) return KEYBOARD_BIDI; | |
154 | 417 // return non-bidi for all other languages |
418 return KEYBOARD_NON_BIDI; | |
419 } | |
420 /** | |
421 * Return the languages that are installed for the keyboard. | |
422 * <p> | |
423 * | |
424 * @return integer array with an entry for each installed language | |
425 */ | |
426 static void*[] getKeyboardLanguageList() { | |
427 int maxSize = 10; | |
428 void*[] tempList = new void*[maxSize]; | |
429 int size = OS.GetKeyboardLayoutList(maxSize, tempList.ptr); | |
430 void*[] list = new void*[size]; | |
431 System.arraycopy(tempList, 0, list, 0, size); | |
432 return list; | |
433 } | |
434 /** | |
435 * Return whether or not the platform supports a bidi language. Determine this | |
436 * by looking at the languages that are installed. | |
437 * <p> | |
438 * | |
439 * @return true if bidi is supported, false otherwise. Always | |
440 * false on Windows CE. | |
441 */ | |
442 public static bool isBidiPlatform() { | |
443 if (OS.IsWinCE) return false; | |
444 if (isBidiPlatform_ !is -1) return isBidiPlatform_ is 1; // already set | |
445 | |
446 isBidiPlatform_ = 0; | |
447 | |
448 // The following test is a workaround for bug report 27629. On WinXP, | |
449 // both bidi and complex script (e.g., Thai) languages must be installed | |
450 // at the same time. Since the bidi platform calls do not support | |
451 // double byte characters, there is no way to run Eclipse using the | |
452 // complex script languages on XP, so constrain this test to answer true | |
453 // only if a bidi input language is defined. Doing so will allow complex | |
454 // script languages to work (e.g., one can install bidi and complex script | |
455 // languages, but only install the Thai keyboard). | |
456 if (!isKeyboardBidi()) return false; | |
457 | |
458 //Callback callback = null; | |
459 //try { | |
460 //callback = new Callback (Class.forName (CLASS_NAME), "EnumSystemLanguageGroupsProc", 5); //$NON-NLS-1$ | |
461 //int lpEnumSystemLanguageGroupsProc = callback.getAddress (); | |
462 //if (lpEnumSystemLanguageGroupsProc is 0) DWT.error(DWT.ERROR_NO_MORE_CALLBACKS); | |
463 OS.EnumSystemLanguageGroups(&EnumSystemLanguageGroupsProc, OS.LGRPID_INSTALLED, 0); | |
464 //callback.dispose (); | |
465 //} catch (ClassNotFoundException e) { | |
466 //if (callback !is null) callback.dispose(); | |
467 //} | |
468 if (isBidiPlatform_ is 1) return true; | |
469 // need to look at system code page for NT & 98 platforms since EnumSystemLanguageGroups is | |
470 // not supported for these platforms | |
212
ab60f3309436
reverted the char[] to String and use the an alias.
Frank Benoit <benoit@tionex.de>
parents:
197
diff
changeset
|
471 String codePage = to!(String)(OS.GetACP()); |
154 | 472 if (CD_PG_ARABIC==/*eq*/codePage || CD_PG_HEBREW==/*eq*/codePage) { |
473 isBidiPlatform_ = 1; | |
474 } | |
475 return isBidiPlatform_ is 1; | |
476 } | |
477 /** | |
478 * Return whether or not the keyboard supports input of a bidi language. Determine this | |
479 * by looking at the languages that are installed for the keyboard. | |
480 * <p> | |
481 * | |
482 * @return true if bidi is supported, false otherwise. | |
483 */ | |
484 public static bool isKeyboardBidi() { | |
485 void*[] list = getKeyboardLanguageList(); | |
486 for (int i=0; i<list.length; i++) { | |
213 | 487 int id = OS.PRIMARYLANGID(OS.LOWORD( cast(int) list[i])); |
154 | 488 if ((id is LANG_ARABIC) || (id is LANG_HEBREW)) { |
489 return true; | |
490 } | |
491 } | |
492 return false; | |
493 } | |
494 /** | |
495 * Removes the specified language listener. | |
496 * <p> | |
497 * | |
498 * @param hwnd the handle of the Control that is listening for keyboard language changes | |
499 */ | |
500 public static void removeLanguageListener (HWND hwnd) { | |
501 languageMap.remove(hwnd); | |
502 unsubclass(hwnd); | |
503 } | |
213 | 504 public static void removeLanguageListener (Control control) { |
505 removeLanguageListener(control.handle); | |
506 } | |
154 | 507 /** |
508 * Switch the keyboard language to the specified language type. We do | |
509 * not distinguish between multiple bidi or multiple non-bidi languages, so | |
510 * set the keyboard to the first language of the given type. | |
511 * <p> | |
512 * | |
513 * @param language integer representing language. One of | |
514 * KEYBOARD_BIDI, KEYBOARD_NON_BIDI. | |
515 */ | |
516 public static void setKeyboardLanguage(int language) { | |
517 // don't switch the keyboard if it doesn't need to be | |
518 if (language is getKeyboardLanguage()) return; | |
519 | |
520 if (language is KEYBOARD_BIDI) { | |
521 // get the list of active languages | |
522 void*[] list = getKeyboardLanguageList(); | |
523 // set to first bidi language | |
524 for (int i=0; i<list.length; i++) { | |
213 | 525 int id = OS.PRIMARYLANGID(OS.LOWORD( cast(int) list[i])); |
154 | 526 if ((id is LANG_ARABIC) || (id is LANG_HEBREW)) { |
527 OS.ActivateKeyboardLayout(list[i], 0); | |
528 return; | |
529 } | |
530 } | |
531 } else { | |
532 // get the list of active languages | |
533 void*[] list = getKeyboardLanguageList(); | |
534 // set to the first non-bidi language (anything not | |
535 // Hebrew or Arabic) | |
536 for (int i=0; i<list.length; i++) { | |
213 | 537 int id = OS.PRIMARYLANGID(OS.LOWORD( cast(int) list[i])); |
154 | 538 if ((id !is LANG_HEBREW) && (id !is LANG_ARABIC)) { |
539 OS.ActivateKeyboardLayout(list[i], 0); | |
540 return; | |
541 } | |
542 } | |
543 } | |
544 } | |
545 /** | |
546 * Sets the orientation (writing order) of the specified control. Text will | |
547 * be right aligned for right to left writing order. | |
548 * <p> | |
549 * | |
550 * @param hwnd the handle of the Control to change the orientation of | |
551 * @param orientation one of DWT.RIGHT_TO_LEFT or DWT.LEFT_TO_RIGHT | |
552 * @return true if the orientation was changed, false if the orientation | |
553 * could not be changed | |
554 */ | |
555 public static bool setOrientation (HWND hwnd, int orientation) { | |
556 if (OS.IsWinCE) return false; | |
557 if (OS.WIN32_VERSION < OS.VERSION(4, 10)) return false; | |
558 int bits = OS.GetWindowLong (hwnd, OS.GWL_EXSTYLE); | |
559 if ((orientation & DWT.RIGHT_TO_LEFT) !is 0) { | |
560 bits |= OS.WS_EX_LAYOUTRTL; | |
561 } else { | |
562 bits &= ~OS.WS_EX_LAYOUTRTL; | |
563 } | |
564 OS.SetWindowLong (hwnd, OS.GWL_EXSTYLE, bits); | |
565 return true; | |
566 } | |
213 | 567 public static bool setOrientation (Control control, int orientation) { |
568 return setOrientation(control.handle, orientation); | |
569 } | |
154 | 570 /** |
571 * Override the window proc. | |
572 * | |
573 * @param hwnd control to override the window proc of | |
574 */ | |
575 static void subclass(HWND hwnd) { | |
576 HWND key = hwnd; | |
577 if ( ( key in oldProcMap ) is null) { | |
213 | 578 int /*long*/ oldProc = OS.GetWindowLongPtr(hwnd, OS.GWLP_WNDPROC); |
154 | 579 oldProcMap[key] = cast(WNDPROC)oldProc; |
580 WNDPROC t = &windowProc; // test signature | |
213 | 581 OS.SetWindowLongPtr(hwnd, OS.GWLP_WNDPROC, cast(LONG_PTR)&windowProc); |
154 | 582 } |
583 } | |
584 /** | |
585 * Reverse the character array. Used for right orientation. | |
586 * | |
587 * @param charArray character array to reverse | |
588 */ | |
589 static void reverse(wchar[] charArray) { | |
590 int length_ = charArray.length; | |
591 for (int i = 0; i <= (length_ - 1) / 2; i++) { | |
592 wchar tmp = charArray[i]; | |
593 charArray[i] = charArray[length_ - 1 - i]; | |
594 charArray[length_ - 1 - i] = tmp; | |
595 } | |
596 } | |
597 /** | |
598 * Reverse the integer array. Used for right orientation. | |
599 * | |
600 * @param intArray integer array to reverse | |
601 */ | |
602 static void reverse(int[] intArray) { | |
603 int length_ = intArray.length; | |
604 for (int i = 0; i <= (length_ - 1) / 2; i++) { | |
605 int tmp = intArray[i]; | |
606 intArray[i] = intArray[length_ - 1 - i]; | |
607 intArray[length_ - 1 - i] = tmp; | |
608 } | |
609 } | |
610 /** | |
611 * Adjust the order array so that it is relative to the start of the line. Also reverse the order array if the orientation | |
612 * is to the right. | |
613 * | |
614 * @param orderArray integer array of order values to translate | |
615 * @param glyphCount number of glyphs that have been processed for the current line | |
616 * @param isRightOriented flag indicating whether or not current orientation is to the right | |
617 */ | |
618 static void translateOrder(int[] orderArray, int glyphCount, bool isRightOriented) { | |
619 int maxOrder = 0; | |
620 int length_ = orderArray.length; | |
621 if (isRightOriented) { | |
622 for (int i=0; i<length_; i++) { | |
623 maxOrder = Math.max(maxOrder, orderArray[i]); | |
624 } | |
625 } | |
626 for (int i=0; i<length_; i++) { | |
627 if (isRightOriented) orderArray[i] = maxOrder - orderArray[i]; | |
628 orderArray [i] += glyphCount; | |
629 } | |
630 } | |
631 /** | |
632 * Remove the overridden the window proc. | |
633 * | |
634 * @param hwnd control to remove the window proc override for | |
635 */ | |
636 static void unsubclass(HWND hwnd) { | |
637 HWND key = hwnd; | |
638 if (( key in languageMap ) is null && ( key in keyMap ) is null) { | |
639 WNDPROC proc; | |
640 if( auto p = key in oldProcMap ){ | |
641 proc = *p; | |
642 oldProcMap.remove( key ); | |
643 } | |
644 if (proc is null) return; | |
213 | 645 OS.SetWindowLongPtr(hwnd, OS.GWLP_WNDPROC, cast(LONG_PTR) proc ); |
154 | 646 } |
647 } | |
648 /** | |
649 * Window proc to intercept keyboard language switch event (WS_INPUTLANGCHANGE) | |
650 * and widget orientation changes. | |
651 * Run the Control's registered runnable when the keyboard language is switched. | |
652 * | |
653 * @param hwnd handle of the control that is listening for the keyboard language | |
654 * change event | |
655 * @param msg window message | |
656 */ | |
657 static extern(Windows) int windowProc (HWND hwnd, uint msg, uint wParam, int lParam) { | |
658 HWND key = hwnd; | |
659 switch (msg) { | |
660 case 0x51 /*OS.WM_INPUTLANGCHANGE*/: | |
661 Runnable runnable = languageMap[key]; | |
662 if (runnable !is null) runnable.run (); | |
663 break; | |
155 | 664 default: |
154 | 665 } |
666 auto oldProc = oldProcMap[key]; | |
213 | 667 return oldProc( hwnd, msg, wParam, lParam); |
154 | 668 } |
669 | |
670 } |