{%MainUnit customdrawnwsforms.pp}

{ TCDWSCustomForm }

class procedure TCDWSCustomForm.UpdateMotifWMHints(const AWinControl: TWinControl; CanMaximize: Boolean);
type
  PMotifWmHints = ^TMotifWmHints;
  TMotifWmHints = packed record
    Flags, Functions, Decorations: LongWord;
    InputMode: LongInt;
    Status: LongWord;
  end;
const
  MWM_HINTS_FUNCTIONS = 1;
  MWM_HINTS_DECORATIONS = 2;
  FuncAll = 1;
  FuncResize = 2;
  FuncMove = 4;
  FuncMinimize = 8;
  FuncMaximize = 16;
  FuncClose = 32;
  DecorAll = 1;
  DecorBorder = 2;
  DecorResizeH = 4;
  DecorTitle = 8;
  DecorMenu = 16;
  DecorMinimize = 32;
  DecorMaximize = 64;
var
  PropType: TAtom;
  PropFormat: LongInt;
  PropItemCount, PropBytesAfter: LongWord;
  Hints: PMotifWmHints;
  NewHints: TMotifWmHints;
  lWindow: TWindow;
  lWindowInfo: TX11WindowInfo;
begin
  lWindowInfo := TX11WindowInfo(AWinControl.Handle);
  lWindow := lWindowInfo.Window;

  if CDWidgetSet.FWMHints = 0 then
    CDWidgetSet.FWMHints :=
      XInternAtom(CDWidgetSet.FDisplay, '_MOTIF_WM_HINTS', False);

  XGetWindowProperty(CDWidgetSet.FDisplay, lWindow,
    CDWidgetSet.FWMHints, 0, 5, False, AnyPropertyType, @PropType,
    @PropFormat, @PropItemCount, @PropBytesAfter, @Hints);

  NewHints.Flags := MWM_HINTS_FUNCTIONS or MWM_HINTS_DECORATIONS;
  NewHints.Functions := FuncResize or FuncMove or FuncMinimize or FuncClose;

  if {(woToolWindow in WindowOptions) or (woWindow in WindowOptions) or
   (woPopup in WindowOptions)}True then
    NewHints.Decorations := DecorBorder or DecorTitle or DecorMenu or DecorMinimize
  else
    NewHints.Decorations := 0;
  if CanMaximize then
  begin
    NewHints.Functions := NewHints.Functions or FuncMaximize;
    NewHints.Decorations := NewHints.Decorations or DecorMaximize;
  end;

  if Assigned(Hints) then
  begin
    Hints^.Flags := Hints^.Flags or NewHints.Flags;
    Hints^.Decorations := NewHints.Decorations;
    Hints^.Functions := NewHints.Functions;
  end else
    Hints := @NewHints;

  XChangeProperty(CDWidgetSet.FDisplay, lWindow,
    CDWidgetSet.FWMHints, CDWidgetSet.FWMHints,
    32, PropModeReplace, Pointer(Hints), 5);
  if Hints <> @NewHints then
    XFree(Hints);
end;

class procedure TCDWSCustomForm.SetPosition(const AWinControl: TWinControl; const APosition: TPoint);
var
  Supplied: PtrInt;
  SizeHints: PXSizeHints;

  dx, dy: integer;
  lx, ly: integer;
  cw : PWindow;
  lWindow: TWindow;
  lWindowInfo: TX11WindowInfo;
begin
  lWindowInfo := TX11WindowInfo(AWinControl.Handle);
  lWindow := lWindowInfo.Window;

  if AWinControl.Parent = nil then
  begin
    {$Note This doesn't work yet. I want to position a new window relative to
      another window. Used for popup windows, like the TComboBox dropdown. }
    {$IFDEF DEBUG} writeln('SetPosition with no Parent'); {$ENDIF}
    lx := APosition.x;
    ly := APosition.y;

    {---------------------------------------------------------------------------
    We must not call XTranslate:
    if applied to the root window, this makes X crazy, because it attempts
    to translate the coordinates to themselves.
    If applied to another window, it's wrong, because window position has already
    been determined by LCL
    ---------------------------------------------------------------------------}
    {XTranslateCoordinates(CDWidgetSet.FDisplay, lWindow,
        XDefaultRootWindow(CDWidgetSet.FDisplay),
        lx, ly, @dx, @dy, @cw);
    lx := dx;
    ly := dy;}
  end
  else
  begin
    {$IFDEF DEBUG} writeln('SetPosition inside parent'); {$ENDIF}
    lx := APosition.x;
    ly := APosition.y;
  end;
  {$IFDEF DEBUG} Writeln(Format('was (%d,%d) and is now (%d,%d)', [APosition.x, APosition.y, lx, ly])); {$ENDIF}

  SizeHints := XAllocSizeHints;
  XGetWMNormalHints(CDWidgetSet.FDisplay, lWindow, SizeHints, @Supplied);
  SizeHints^.flags := SizeHints^.flags or PPosition;
  SizeHints^.x := lx;
  SizeHints^.y := ly;
  XSetWMNormalHints(CDWidgetSet.FDisplay, lWindow, SizeHints);
  XFree(SizeHints);
  XMoveWindow(CDWidgetSet.FDisplay, lWindow, lx, ly);
end;

class procedure TCDWSCustomForm.SetSize(const AWinControl: TWinControl; const ASize: TSize);
var
  ChangeMask: Cardinal;
  Changes: TXWindowChanges;
  lWindow: TWindow;
  lWindowInfo: TX11WindowInfo;
begin
  lWindowInfo := TX11WindowInfo(AWinControl.Handle);
  lWindow := lWindowInfo.Window;

  ChangeMask := CWWidth or CWHeight;
  Changes.Width := ASize.cx;
  Changes.Height := ASize.cy;

  if ChangeMask <> 0 then
    XConfigureWindow(CDWidgetSet.FDisplay, lWindow, ChangeMask, @Changes);
end;

class procedure TCDWSCustomForm.SetMinMaxSize(const AWinControl: TWinControl; const AMinSize, AMaxSize: TSize);
var
  Supplied: PtrInt;
  SizeHints: PXSizeHints;
  CanMaximize: Boolean;
  lWindow: TWindow;
  lWindowInfo: TX11WindowInfo;
begin
  lWindowInfo := TX11WindowInfo(AWinControl.Handle);
  lWindow := lWindowInfo.Window;

  CanMaximize := (AMaxSize.cx = 0) or (AMaxSize.cy = 0) or
    (AMaxSize.cx > AMinSize.cx) or (AMaxSize.cy > AMinSize.cy);
  UpdateMotifWMHints(AWinControl, CanMaximize);

  SizeHints := XAllocSizeHints;
  XGetWMNormalHints(CDWidgetSet.FDisplay, lWindow, SizeHints, @Supplied);
  with SizeHints^ do
  begin
    if (AMinSize.cx > 0) or (AMinSize.cy > 0) then
    begin
      flags := flags or PMinSize;
      min_width := AMinSize.cx;
      min_height := AMinSize.cy;
    end else
      flags := flags and not PMinSize;

    if (AMaxSize.cx > 0) or (AMaxSize.cy > 0) then
    begin
      flags := flags or PMaxSize;
      if AMaxSize.cx > 0 then
        max_width := AMaxSize.cx
      else
        max_width := 32767;
      if AMaxSize.cy > 0 then
        max_height := AMaxSize.cy
      else
        max_height := 32767;
    end else
      flags := flags and not PMaxSize;
  end;

  XSetWMNormalHints(CDWidgetSet.FDisplay, lWindow, SizeHints);
  XFree(SizeHints);
end;

class procedure TCDWSCustomForm.CreateX11Canvas(AWindowInfo: TX11WindowInfo);
var
  DummyWnd: PWindow;
  DummyInt: LongInt;
  GCValues: XLib.TXGCValues;
  FWidth, FHeight: Integer;
begin
  XGetGeometry(CDWidgetSet.FDisplay, AWindowInfo.Window, @DummyWnd, @DummyInt, @DummyInt,
    @FWidth, @FHeight, @DummyInt, @DummyInt);

  GCValues.graphics_exposures := 0;
  AWindowInfo.GC := XCreateGC(CDWidgetSet.FDisplay, AWindowInfo.Window, GCGraphicsExposures, @GCValues);
  {$ifdef CD_X11_SmartPaint}
  AWindowInfo.Valid:= False; // Need Paint
  AWindowInfo.Moved:= False; // And not move
  {$endif}
//  if not Assigned(GC) then
//    raise EX11Error.Create(SGCCreationFailed);

//  XSetLineAttributes(GFApplication.Handle, GC, 0,
//    LineSolid, CapNotLast, JoinMiter);

//  FFont := AFont;
//  FXftDraw := XftDrawCreate(CDWidgetSet.FDisplay, AWindowInfo.Window,
//    XDefaultVisual(CDWidgetSet.FDisplay, XDefaultScreen(CDWidgetSet.FDisplay)),
//    XDefaultColormap(CDWidgetSet.FDisplay, XDefaultScreen(CDWidgetSet.FDisplay)));

//  FRegion := XCreateRegion;
//  Resized(Width, Height);	// Set up a proper clipping region

  //

{  XGetWindowAttributes(CDWidgetSet.FDisplay, AWindowInfo.Window, @Attr);
  FVisual := Attr.Visual;

  case Attr.Depth of
    1: PixelFormat.FormatType := ftMono;
    4: PixelFormat.FormatType := ftPal4;
    8: PixelFormat.FormatType := ftPal8;
    16: PixelFormat.FormatType := ftRGB16;
    24: PixelFormat.FormatType := ftRGB24;
    32: PixelFormat.FormatType := ftRGB32;
    else
      raise EX11Error.CreateFmt(SWindowUnsupportedPixelFormat, [Attr.Depth]);
  end;

  if Attr.Depth >= 16 then
  begin
    PixelFormat.RedMask   := Visual^.red_mask;
    PixelFormat.GreenMask := Visual^.green_mask;
    PixelFormat.BlueMask  := Visual^.blue_mask;
  end;}
end;

(*
 * Error handling.
 */
static int ErrorFlag = 0;
  static int HandleXError( Display *dpy, XErrorEvent *event )
  {
      ErrorFlag = 1;
      return 0;
  *)

{
 There are 2 ways to put an image into a X11 Window which everyone uses, even OpenGL:

 XPutImage and XShmPutImage

 Because XPutImage is so slow as to be unusable, we will always try to use XShmPutImage
}
class procedure TCDWSCustomForm.DrawRawImageToGC(ARawImage: TRawImage;
  ADestWindowInfo: TX11WindowInfo; ADestX, ADestY, ADestWidth, ADestHeight: Integer);
var
  UsePutImage: Boolean = False;
  major, minor, ignore: cint;
  {$IFDEF VerboseCDPaintProfiler}
  lTimeStart: TDateTime;
  {$ENDIF}
  pixmaps: cint;
begin
  {$IFDEF VerboseCDPaintProfiler}
  lTimeStart := NowUTC();
  {$ENDIF}

  // First check if XShm is available
  UsePutImage := True;
{  if not XQueryExtension(CDWidgetSet.FDisplay, 'MIT-SHM', @ignore, @ignore, @ignore) then UsePutImage := True
  else if not XShmQueryVersion(CDWidgetSet.FDisplay, @major, @minor, @pixmaps) then UsePutImage := True;
  if pixmaps <> 2 then UsePutImage := True;}

  if UsePutImage then DrawRawImageToGC_XPutImage(ARawImage, ADestWindowInfo, ADestX, ADestY, ADestWidth, ADestHeight)
  else DrawRawImageToGC_XShmPutImage(ARawImage, ADestWindowInfo, ADestX, ADestY, ADestWidth, ADestHeight);

  {$IFDEF VerboseCDPaintProfiler}
  DebugLn(Format('[TCDWSCustomForm.DrawRawImageToGC] Paint duration: %d ms', [DateTimeToMilliseconds(NowUTC() - lTimeStart)]));
  {$ENDIF}
end;

// XShm tutorial:
// http://personales.mundivia.es/jap/xshm.htm
class function TCDWSCustomForm.alloc_xshm_image(dpy: PDisplay; vis: PVisual;
  width, height, depth: Integer; out shminfo: TXShmSegmentInfo): PXImage;
var
  img: XLib.PXImage;
  ctx: TGC;
begin
  Result := nil;

  {
  * We have to do a _lot_ of error checking here to be sure we can
  * really use the XSHM extension.  It seems different servers trigger
  * errors at different points if the extension won't work.  Therefore
  * we have to be very careful...
  }

  img := XShmCreateImage(dpy, vis, depth,
                        ZPixmap, nil, @shminfo,
                        width, height );
  if (img = nil) then
  begin
   DebugLn('XShmCreateImage failed!');
   Exit;
  end;

(*  shminfo.shmid := shmget( IPC_PRIVATE, img^.bytes_per_line
  		       * img->height, IPC_CREAT or 0777 );
  if (shminfo.shmid < 0) then
  begin
   DebugLn('error in shmget. alloc_back_buffer: Shared memory error (shmget), disabling.');
   XDestroyImage( img );
   //c->shm = 0;
   Exit;
  end;

  img^.data := shmat( shminfo.shmid, 0, 0 );
  shminfo.shmaddr := img^.data;
  (*   if (shminfo.shmaddr == (char * ) -1) {
    perror("alloc_back_buffer");
    XDestroyImage( img );
    img = NULL;
    printf("shmat failed\n");
    return NULL;
  }

  shminfo.readOnly = False;
  ErrorFlag = 0;
  XSetErrorHandler( HandleXError );
  // This may trigger the X protocol error we're ready to catch: */
  XShmAttach( dpy, &shminfo );
  XSync( dpy, False );

  if (ErrorFlag) {
    /* we are on a remote display, this error is normal, don't print it */
    XFlush( dpy );
    ErrorFlag = 0;
    XDestroyImage( img );
    shmdt( shminfo.shmaddr );
    shmctl( shminfo.shmid, IPC_RMID, 0 );
    return NULL;
  }

  shmctl( shminfo.shmid, IPC_RMID, 0 ); // nobody else needs it*)*)

(*#ifdef OPTIONAL_PART
   /* An error may still occur upon the first XShmPutImage.  So it's a */
   /* good idea to test it here.  However, we need a window to put the */
   /* image into, etc.... */
   gc = XCreateGC( dpy, window, 0, NULL );
   XShmPutImage( dpy, window, gc,
  	       img, 0, 0, 0, 0, 1, 1 /*one pixel*/, False );
   XSync( dpy, False );
   XFreeGC( dpy, gc );
   XSetErrorHandler( NULL );
   if (ErrorFlag) {
      XFlush( dpy );
      ErrorFlag = 0;
      XDestroyImage( img );
      shmdt( shminfo.shmaddr );
      shmctl( shminfo.shmid, IPC_RMID, 0 );
      return NULL;
   }
#endif*)

  Result := img;
end;

class procedure TCDWSCustomForm.destroy_xshm_image(img: PXImage; var shminfo: TXShmSegmentInfo);
begin
   XShmDetach(CDWidgetSet.FDisplay, @shminfo );
   XDestroyImage( img );
//   shmdt( shminfo.shmaddr );
end;

class procedure TCDWSCustomForm.DrawRawImageToGC_XShmPutImage(ARawImage: TRawImage;
  ADestWindowInfo: TX11WindowInfo; ADestX, ADestY, ADestWidth, ADestHeight: Integer);
var
  img: XLib.PXImage;
  shminfo: TXShmSegmentInfo;
begin
  // make shared XImage
  img := alloc_xshm_image(CDWidgetSet.FDisplay, ADestWindowInfo.Attr.visual, ADestWidth, ADestHeight, ADestWindowInfo.ColorDepth, shminfo);
  if (img = nil) then
  begin
    DebugLn('[TCDWSCustomForm.DrawRawImageToGC_XShmPutImage] couldn''t allocate shared XImage');
    Exit;
  end;

  // Now you can render into the img->data buffer
  // ???

  // Draw the image in the window
  XShmPutImage(CDWidgetSet.FDisplay, ADestWindowInfo.Window, ADestWindowInfo.GC,
    img, 0, 0, ADestX, ADestY, ADestWidth, ADestHeight, False);

  // Destroy image
  destroy_xshm_image(img, shminfo);
end;

class procedure TCDWSCustomForm.DrawRawImageToGC_XPutImage(ARawImage: TRawImage;
  ADestWindowInfo: TX11WindowInfo; ADestX, ADestY, ADestWidth, ADestHeight: Integer);
var
  Image: XLib.PXImage;
  XImage: XLib.TXImage;
  lScanlineSize: cint;
  lScreen: cint;
  lVisual: PVisual;
  lDepth: cint;
begin
  lScanlineSize := (ADestWindowInfo.Canvas.Width*ADestWindowInfo.ColorDepth) div 8;
  lScreen := DefaultScreen(CDWidgetSet.FDisplay);
  lVisual := {DefaultVisual(CDWidgetSet.FDisplay, lScreen); //} ADestWindowInfo.Attr.Visual;
  lDepth := ADestWindowInfo.ColorDepth;

  XImage.Width := ADestWidth;
  XImage.Height := ADestHeight;
  XImage.xoffset        := 0;
  XImage.obdata         := #0;
  XImage.byte_order     := LSBFirst;
  XImage.bitmap_bit_order := MSBFirst;
  XImage.bitmap_pad     := 32;
  XImage.bytes_per_line := 0;

  {     if acolordepth = 1 then
       begin
         format         := XYBitmap;
         bitmap_unit    := 8;
         depth          := 1;
         bits_per_pixel := 1;
         red_mask       := 1;
         green_mask     := 0;
         blue_mask      := 0;
       end
      else
    begin}
  XImage.format      := ZPixmap;
  XImage.bitmap_unit := 32;

  // only truecolor 24/32 displays supported now, otherwise color conversion required!
  // this must be match for the display !!!
  XImage.depth := ADestWindowInfo.ColorDepth;
  XImage.bits_per_pixel := 24;

  // Pixel mask
  XImage.red_mask   := lVisual^.red_mask;
  XImage.green_mask := lVisual^.green_mask;
  XImage.blue_mask  := lVisual^.blue_mask;

  XImage.Data := PChar(ARawImage.Data);

  XInitImage(@XImage);

// Create a native Image
// No idea why but using XCreateImage it ends up using a format which I have no idea which is,
// and the missmatch criples the image, XInitImage works fine
//  Image := XCreateImage(CDWidgetSet.FDisplay, lVisual,
//    lDepth, ZPixmap, 0, PChar(ARawImage.Data),
//    ADestWidth, ADestHeight, 8, 0);

  {$IFDEF VerboseCDForms}
    DebugLn(Format('[TCDWSCustomForm.DrawRawImageToGC_XPutImage] XImage=%x Data=%x'
      + ' ColorDepth:%d Width=%d Height=%d ScanlineSize=%d'
      + ' red_mask=%x green_mask=%x blue_mask=%x',
      [PtrInt(Image), PtrInt(ARawImage.Data), lDepth,
       ADestWidth, ADestHeight, lScanlineSize,
       XImage.red_mask, XImage.green_mask, XImage.blue_mask]));
  {$ENDIF}

  // Note that XPutImage is slow
  XPutImage(CDWidgetSet.FDisplay, ADestWindowInfo.Window, ADestWindowInfo.GC,
    @XImage, 0, 0, ADestX, ADestY, ADestWidth, ADestHeight);

  // Free the native image -> Used only together with XCreateImage
//  Image.data := nil;
//  XDestroyImage(Image);
end;

class procedure TCDWSCustomForm.EvKeyPressed(const AWinControl: TWinControl;
  AWindowInfo: TX11WindowInfo; var Event: TXKeyEvent);
var
  lKey: Word;
  lForm: TCDForm;
  KeySym: TKeySym;
  lCurString: String;
  lCurChar: TUTF8Char;
  i: Integer;
  lEndComposing: Boolean;
begin
  lForm := TCDForm(AWinControl.Handle);
  KeySym := StartComposing(Event);
  lKey := X11KeyToLCLKey(KeySym);
  CDWidgetset.LastKeySym := KeySym;
  CDWidgetset.LastKey := lKey;
  CDWidgetSet.ShiftState := CDWidgetSet.XStateToLCLState(Event.state);

  CallbackKeyDown(lForm, lKey);

  // EndComposing embedded here
  lEndComposing := CDWidgetset.ComposeStatus <> XLookupNone;
  lEndComposing := lEndComposing and ((Event.state and (ControlMask or Mod1Mask)) = 0);
  if lEndComposing then
  begin
    for i := 1 to UTF8Length(CDWidgetset.ComposeBuffer) do
    begin
      lCurString := CDWidgetset.ComposeBuffer;
      lCurString := UTF8Copy(lCurString, i, 1);
      lCurChar := lCurString;
      CallbackKeyChar(lForm, 0, lCurChar);
    end;
  end;
end;

class procedure TCDWSCustomForm.EvKeyReleased(const AWinControl: TWinControl;
  AWindowInfo: TX11WindowInfo; var Event: TXKeyEvent);
var
  lKey: Word;
  lForm: TCDForm;
begin
  // Send back the last pressed key as a KeyUp event
  lForm := TCDForm(AWinControl.Handle);

  lKey := CDWidgetset.LastKey;
  CDWidgetSet.ShiftState := CDWidgetSet.XStateToLCLState(Event.state);
  CallbackKeyUp(lForm, lKey);

  // Do not call EndComposing, as this would generate duplicate KeyChar events!}
end;

class procedure TCDWSCustomForm.EvMousePressed(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo;
  var Event: TXButtonEvent);
var
  lForm: TCDForm;
  MouseButton: TMouseButton;
begin
  lForm := TCDForm(AWinControl.Handle);
  if XButtonToMouseButton(Event.button, MouseButton) then
  begin
    CallbackMouseDown(lForm, Event.x, Event.y, MouseButton, []);
  end
  else
  begin
{   if Event.button = 4 then Sum := -1
   else Sum := 1;

   // Check for other mouse wheel messages in the queue
   while XCheckTypedWindowEvent(GFApplication.Handle,
    WindowEntry.Handle, X.ButtonPress, @NewEvent) do
   begin
   if NewEvent.xbutton.Button = 4 then Dec(Sum)
     else if NewEvent.xbutton.Button = 5 then Inc(Sum)
     else
     begin
       XPutBackEvent(GFApplication.Handle, @NewEvent);
       break;
     end;
   end;

   WindowEntry.EvMouseWheel(
    Sum, Point(XEvent.xbutton.x, XEvent.xbutton.y));}
  end;
end;

class procedure TCDWSCustomForm.EvMouseReleased(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo;
  var Event: TXButtonEvent);
var
  lForm: TCDForm;
  MouseButton: TMouseButton;
begin
  lForm := TCDForm(AWinControl.Handle);
  XButtonToMouseButton(Event.button, MouseButton);

  { Release events are only for mouse buttons, and not mouse wheel moviments }
  if (Event.button >= 1) and (Event.button <= 3) then
  begin
    CallbackMouseUp(lForm, Event.x, Event.y, MouseButton, []);
  end;
end;

class procedure TCDWSCustomForm.EvMouseEnter(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo);
begin
end;

class procedure TCDWSCustomForm.EvMouseLeave(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo);
begin
end;

class procedure TCDWSCustomForm.EvMouseMove(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo;
  var Event: TXMotionEvent);
var
  lForm: TCDForm;
{  lTarget: TWinControl;
  lEventPos: TPoint;}
begin
  lForm := TCDForm(AWinControl.Handle);
  CallbackMouseMove(lForm, Event.x, Event.y, []);
{  lTarget := FindControlWhichReceivedEvent(TCustomForm(AWinControl), AWindowInfo.Children, Event.x, Event.y);

  lEventPos := FormPosToControlPos(lTarget, Event.x, Event.y);

  LCLSendMouseMoveMsg(lTarget, lEventPos.x, lEventPos.y, []);}
end;

// Top-level windows receive LM_ACTIVATE while constrols receive LM_SETFOCUS
// See http://blogs.msdn.com/b/jfoscoding/archive/2006/08/02/686141.aspx
// Here we have 1 handle per window, so the X11 backend should only send LM_ACTIVATE
class procedure TCDWSCustomForm.EvFocusIn(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo);
begin
  LCLSendActivateMsg(AWinControl, WA_ACTIVE, false);
end;

class procedure TCDWSCustomForm.EvFocusOut(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo);
begin
  LCLSendActivateMsg(AWinControl, WA_INACTIVE, false);
end;

class procedure TCDWSCustomForm.EvPaint(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo);
var
  lWidth, lHeight: Integer;
  lBitmap, lMask: HBITMAP;
  lRawImage: TRawImage;
  Event: TXClientMessageEvent;
  reslt: Integer;
  {$IFDEF VerboseCDPaintProfiler}
  lTimeStart, lCDTimeEnd, lNativeTimeStart: TDateTime;
  lTimeSend: Integer;
  {$ENDIF}
begin
  {$IFDEF VerboseCDPaintProfiler}
  lTimeStart := NowUTC();
  {$ENDIF}
  {$IFDEF VerboseCDForms}
    DebugLn(Format('[TCDWSCustomForm.EvPaint] AWindowInfo: %x', [PtrInt(AWindowInfo)]));
  {$ENDIF}
  if (AWinControl = nil) or (AWindowInfo = nil) then Exit;

  lWidth := Round(AWinControl.width);
  lHeight := Round(AWinControl.height);

  // Prepare the non-native image and canvas
  {$IFDEF VerboseCDForms}
    DebugLn(Format('[TCDWSCustomForm.EvPaint] Visual: Red-Mask: %x Green-Mask: %x Blue-Mask: %x'
      + ' bits_per_rgb=%d c_class=%d',
      [AWindowInfo.Attr.visual^.red_mask, AWindowInfo.Attr.visual^.green_mask, AWindowInfo.Attr.visual^.blue_mask,
       AWindowInfo.Attr.Visual^.bits_per_rgb, AWindowInfo.Attr.Visual^.c_class]));
   { c_class values:
   StaticGray = 0;
   GrayScale = 1;
   StaticColor = 2;
   PseudoColor = 3;
   TrueColor = 4;
   DirectColor = 5;}
  {$ENDIF}

  {$ifdef CD_X11_SmartPaint}
  if AWindowInfo.InvalidateRequestedInAnyControl then AWindowInfo.Valid:= False;
  if (not AWindowInfo.Moved) or (not AWindowInfo.Valid) then begin // we're here just because a Move. We don't need to repaint
    UpdateControlLazImageAndCanvas(AWindowInfo.Image, AWindowInfo.Canvas, lWidth, lHeight, clfBGR24);
    RenderForm(AWindowInfo.Image, AWindowInfo.Canvas, TCustomForm(AWinControl));
  end;
  {$else}
  UpdateControlLazImageAndCanvas(AWindowInfo.Image, AWindowInfo.Canvas, lWidth, lHeight, clfBGR24);

  RenderForm(AWindowInfo.Image, AWindowInfo.Canvas, TCustomForm(AWinControl));
  {$endif}

  {$IFDEF VerboseCDPaintProfiler}
  lCDTimeEnd := NowUTC();
  lNativeTimeStart := NowUTC();
  {$ENDIF}

  {$ifdef CD_X11_NewNativePaint}
  // if not already done, send a message to X
  if CDWidgetSet.CheckInvalidateWindowForX(AWindowInfo.Window) then
  begin
    FillChar(Event,sizeof(Event),0);
    Event._type:= ClientMessage;
    Event.display:=CDWidgetSet.FDisplay;
    Event.window:=AWindowInfo.Window;
    Event.message_type:= CDWidgetSet.FWMPaint;
    Event.format:= 32; // Must hold a culong for TXID
    Event.data.l[0]:= AWindowInfo.Window;
    {$IFDEF VerboseCDPaintProfiler}
    Event.data.l[1]:= DateTimeToMilliseconds(Now());
    {$ENDIF}
    reslt := XSendEvent(CDWidgetSet.FDisplay,AWindowInfo.Window,{Propagate=}True,0,@Event);
    // Painting will carried out from main event loop
  end;
  {$else}
  // Now render it into the control
  AWindowInfo.Image.GetRawImage(lRawImage);
  DrawRawImageToGC(lRawImage, AWindowInfo, 0, 0, lWidth, lHeight);
  {$endif}

  {$IFDEF VerboseCDPaintProfiler}
  DebugLn(Format('[TCDWSCustomForm.EvPaint] Total Paint duration: %d ms of this CustomDrawn: %d ms Native: %d',
    [DateTimeToMilliseconds(NowUTC() - lTimeStart),
     DateTimeToMilliseconds(lCDTimeEnd - lTimeStart),
     DateTimeToMilliseconds(NowUTC() - lNativeTimeStart)
    ]));
  {$ENDIF}
end;

class procedure TCDWSCustomForm.EvPaintEx(const AWinControl: TWinControl;
  AWindowInfo: TX11WindowInfo);
var
  lWidth, lHeight: Integer;
  lRawImage: TRawImage;
  reslt: integer;
begin
  lWidth := Round(AWinControl.width);
  lHeight := Round(AWinControl.height);
  AWindowInfo.Image.GetRawImage(lRawImage);
  DrawRawImageToGC(lRawImage, AWindowInfo, 0, 0, lWidth, lHeight);
end;

class procedure TCDWSCustomForm.EvConfigureNotify(const AWinControl: TWinControl; AWindowInfo: TX11WindowInfo;
  var Event: TXConfigureEvent);
begin
  // Without this while, it will get stuck in a loop resizing endlessly
  while XCheckTypedWindowEvent(CDWidgetset.FDisplay, AWindowInfo.Window, X.ConfigureNotify, @Event) do;

  {$ifdef VerboseCDEvents}
  DebugLn(Format('LCL-CustomDrawn-X11: X11 event received: %s X=%d Y=%d', [GetXEventName(Event._type), Event.x, Event.y]));
  {$endif}

  // Move event
  if (Event.x <> AWinControl.Left) or (Event.y <> AWinControl.Top) then
  begin
    {$ifdef CD_X11_SmartPaint}
    AWindowInfo.Moved:= True; // doesn't need full painting
    {$endif}
    LCLSendMoveMsg(AWinControl, Event.x, Event.y);
  end;
  // Size event
  if (Event.Width <> AWinControl.Width) or (Event.Height <> AWinControl.Height) then
  begin
    {$ifdef CD_X11_SmartPaint}
    AWindowInfo.Valid:= False; // Needs full Painting
    {$endif}
    //SIZENORMAL, SIZEICONIC, SIZEFULLSCREEN, SIZEZOOMSHOW, SIZEZOOMHIDE.
    LCLSendSizeMsg(AWinControl, Event.Width, Event.Height, SIZENORMAL);

    //    TX11Canvas(Canvas).Resized(ClientWidth, ClientHeight); seams unnecessary here
  end;
end;

class procedure TCDWSCustomForm.EvClientMessage(const AWinControl: TWinControl;
  AWindowInfo: TX11WindowInfo; var Event: TXClientMessageEvent);
begin
  if Event.message_type = CDWidgetset.FWMProtocols then
  begin
    if Event.Data.l[0] = CDWidgetset.FWMDeleteWindow then
    begin
      // Message results : 0 - do nothing, 1 - destroy window (felipe: is this comment correct? taken from lcl-cocoa)
      {--------------------------------------------------------
      LCLSendCloseQueryMsg sends the message to TCustomForm.WMCloseQuery which
      performs the close actions (query included) and always returns 0
      No way to know here if the close action will actually be performed.
      -----------------------------------------------------------------------}
      LCLSendCloseQueryMsg(AWinControl);
      {----------------------------------------------------------------------
      No need to call LCLSendCloseUpMsg, because the form has already been closed,
      if allowed by CanClose.
      We can't ask X to destroy the window, because we don't know if CanClose was
      true or false. Here we're just told by X that someone tried to close the
      window, using WM functions. Moreover there are still hanging X events
      to process. Either we implement AppTerminate, or we take yhe lazy
      path and let the window be destroyed by the WM when the application terminates.
      --------------------------------------------------------------------------}
      (*if {CanClose} True then // CanClose is returning false -> ToDo: find out why
      begin
        LCLSendCloseUpMsg(AWinControl);
        XDestroyWindow(CDWidgetset.FDisplay, AWinControl.Handle);
      end;*)
    end
    else
      DebugLn(Format('LCL-CustomDrawn-X11: Unknown client protocol message: %d', [Event.Data.l[0]]));
  end
  else
    DebugLn(Format('LCL-CustomDrawn-X11: Unknown client message: %d', [Event.message_type]));
end;

class function TCDWSCustomForm.StartComposing(const Event: TXKeyEvent): TKeySym;
var
  len: integer;
begin
  SetLength(CDWidgetset.ComposeBuffer, 20);
  // Xutf8LookupString returns the size of FComposeBuffer in bytes.
  len := Xutf8LookupString(CDWidgetset.InputContext, @Event, @CDWidgetset.ComposeBuffer[1],
      Length(CDWidgetset.ComposeBuffer), @Result, @CDWidgetset.ComposeStatus);
  SetLength(CDWidgetset.ComposeBuffer, len);

  {$ifdef VerboseCDText}
  case CDWidgetset.ComposeStatus of
    XBufferOverflow: DebugLn('[TCDWSCustomForm.StartComposing] Status=XBufferOverflow');
    XLookupNone: DebugLn('[TCDWSCustomForm.StartComposing] Status=XLookupNone');
    XLookupChars: DebugLn('[TCDWSCustomForm.StartComposing] Status=XLookupChars');
    XLookupKeySymVal: DebugLn('[TCDWSCustomForm.StartComposing] Status=XLookupKeySym');
    XLookupBoth: DebugLn('[TCDWSCustomForm.StartComposing] Status=XLookupBoth');
  end;
  {$endif}

  // if overflow occurred, then previous SetLength() would have fixed the buffer
  // size, so run Xutf8LookupString again to read correct value.
  if CDWidgetset.ComposeStatus = XBufferOverflow then
    Xutf8LookupString(CDWidgetset.InputContext, @Event, @CDWidgetset.ComposeBuffer[1],
      Length(CDWidgetset.ComposeBuffer), @Result, @CDWidgetset.ComposeStatus);
end;

// The Key table is in http://www.cl.cam.ac.uk/~mgk25/ucs/keysyms.txt
class function TCDWSCustomForm.X11KeyToLCLKey(AX11Key: TKeySym): Word;
begin
  case AX11Key of
    $20: Result := VK_SPACE;
{ 0x0021   U0021   .   # exclam
 0x0022   U0022   .   # quotedbl
 0x0023   U0023   .   # numbersign
 0x0024   U0024   .   # dollar
 0x0025   U0025   .   # percent
 0x0026   U0026   .   # ampersand
 0x0027   U0027   .   # apostrophe
 0x0027   U0027   .   # quoteright	/* deprecated */
 0x0028   U0028   .   # parenleft
 0x0029   U0029   .   # parenright
 0x002a   U002a   .   # asterisk
 0x002b   U002b   .   # plus
 0x002c   U002c   .   # comma
 0x002d   U002d   .   # minus
 0x002e   U002e   .   # period
 0x002f   U002f   .   # slash}
    $0030: Result := VK_0;
    $0031: Result := VK_1;
    $0032: Result := VK_2;
    $0033: Result := VK_3;
    $0034: Result := VK_4;
    $0035: Result := VK_5;
    $0036: Result := VK_6;
    $0037: Result := VK_7;
    $0038: Result := VK_8;
    $0039: Result := VK_9;
{ 0x003a   U003a   .   # colon
 0x003b   U003b   .   # semicolon
 0x003c   U003c   .   # less
 0x003d   U003d   .   # equal
 0x003e   U003e   .   # greater
 0x003f   U003f   .   # question
 0x0040   U0040   .   # at      }
    $41: Result := VK_A;
    $42: Result := VK_B;
    $43: Result := VK_C;
    $44: Result := VK_D;
    $45: Result := VK_E;
    $46: Result := VK_F;
    $47: Result := VK_G;
    $48: Result := VK_H;
    $49: Result := VK_I;
    $4A: Result := VK_J;
    $4B: Result := VK_K;
    $4C: Result := VK_L;
    $4D: Result := VK_M;
    $4E: Result := VK_N;
    $4F: Result := VK_O;
    $50: Result := VK_P;
    $51: Result := VK_Q;
    $52: Result := VK_R;
    $53: Result := VK_S;
    $54: Result := VK_T;
    $55: Result := VK_U;
    $56: Result := VK_V;
    $57: Result := VK_W;
    $58: Result := VK_X;
    $59: Result := VK_Y;
    $5A: Result := VK_Z;
{ 0x005b   U005b   .   # bracketleft
 0x005c   U005c   .   # backslash
 0x005d   U005d   .   # bracketright
 0x005e   U005e   .   # asciicircum
 0x005f   U005f   .   # underscore
 0x0060   U0060   .   # grave
 0x0060   U0060   .   # quoteleft	/* deprecated */ }
    $61: Result := VK_A;
    $62: Result := VK_B;
    $63: Result := VK_C;
    $64: Result := VK_D;
    $65: Result := VK_E;
    $66: Result := VK_F;
    $67: Result := VK_G;
    $68: Result := VK_H;
    $69: Result := VK_I;
    $6A: Result := VK_J;
    $6B: Result := VK_K;
    $6C: Result := VK_L;
    $6D: Result := VK_M;
    $6E: Result := VK_N;
    $6F: Result := VK_O;
    $70: Result := VK_P;
    $71: Result := VK_Q;
    $72: Result := VK_R;
    $73: Result := VK_S;
    $74: Result := VK_T;
    $75: Result := VK_U;
    $76: Result := VK_V;
    $77: Result := VK_W;
    $78: Result := VK_X;
    $79: Result := VK_Y;
    $7A: Result := VK_Z;
{    0x007b   U007b   .   # braceleft
    0x007c   U007c   .   # bar
    0x007d   U007d   .   # braceright
    0x007e   U007e   .   # asciitilde
    0x00a0   U00a0   .   # nobreakspace
    0x00a1   U00a1   .   # exclamdown
    0x00a2   U00a2   .   # cent
    0x00a3   U00a3   .   # sterling
    0x00a4   U00a4   .   # currency
    0x00a5   U00a5   .   # yen
    0x00a6   U00a6   .   # brokenbar
    0x00a7   U00a7   .   # section
    0x00a8   U00a8   .   # diaeresis
    0x00a9   U00a9   .   # copyright
    0x00aa   U00aa   .   # ordfeminine
    0x00ab   U00ab   .   # guillemotleft	/* left angle quotation mark */
    0x00ac   U00ac   .   # notsign
    0x00ad   U00ad   .   # hyphen
    0x00ae   U00ae   .   # registered
    0x00af   U00af   .   # macron
    0x00b0   U00b0   .   # degree
    0x00b1   U00b1   .   # plusminus
    0x00b2   U00b2   .   # twosuperior
    0x00b3   U00b3   .   # threesuperior
    0x00b4   U00b4   .   # acute
    0x00b5   U00b5   .   # mu
    0x00b6   U00b6   .   # paragraph
    0x00b7   U00b7   .   # periodcentered
    0x00b8   U00b8   .   # cedilla
    0x00b9   U00b9   .   # onesuperior
    0x00ba   U00ba   .   # masculine
    0x00bb   U00bb   .   # guillemotright	/* right angle quotation mark */
    0x00bc   U00bc   .   # onequarter
    0x00bd   U00bd   .   # onehalf
    0x00be   U00be   .   # threequarters
    0x00bf   U00bf   .   # questiondown
    0x00c0   U00c0   .   # Agrave
    0x00c1   U00c1   .   # Aacute
    0x00c2   U00c2   .   # Acircumflex
    0x00c3   U00c3   .   # Atilde
    0x00c4   U00c4   .   # Adiaeresis
    0x00c5   U00c5   .   # Aring
    0x00c6   U00c6   .   # AE
    0x00c7   U00c7   .   # Ccedilla
    0x00c8   U00c8   .   # Egrave
    0x00c9   U00c9   .   # Eacute
    0x00ca   U00ca   .   # Ecircumflex
    0x00cb   U00cb   .   # Ediaeresis
    0x00cc   U00cc   .   # Igrave
    0x00cd   U00cd   .   # Iacute
    0x00ce   U00ce   .   # Icircumflex
    0x00cf   U00cf   .   # Idiaeresis
    0x00d0   U00d0   .   # ETH
    0x00d0   U00d0   .   # Eth	/* deprecated */
    0x00d1   U00d1   .   # Ntilde
    0x00d2   U00d2   .   # Ograve
    0x00d3   U00d3   .   # Oacute
    0x00d4   U00d4   .   # Ocircumflex
    0x00d5   U00d5   .   # Otilde
    0x00d6   U00d6   .   # Odiaeresis
    0x00d7   U00d7   .   # multiply
    0x00d8   U00d8   .   # Ooblique
    0x00d9   U00d9   .   # Ugrave
    0x00da   U00da   .   # Uacute
    0x00db   U00db   .   # Ucircumflex
    0x00dc   U00dc   .   # Udiaeresis
    0x00dd   U00dd   .   # Yacute
    0x00de   U00de   .   # THORN
    0x00de   U00de   .   # Thorn	/* deprecated */
    0x00df   U00df   .   # ssharp
    0x00e0   U00e0   .   # agrave
    0x00e1   U00e1   .   # aacute
    0x00e2   U00e2   .   # acircumflex
    0x00e3   U00e3   .   # atilde
    0x00e4   U00e4   .   # adiaeresis
    0x00e5   U00e5   .   # aring
    0x00e6   U00e6   .   # ae
    0x00e7   U00e7   .   # ccedilla
    0x00e8   U00e8   .   # egrave
    0x00e9   U00e9   .   # eacute
    0x00ea   U00ea   .   # ecircumflex
    0x00eb   U00eb   .   # ediaeresis
    0x00ec   U00ec   .   # igrave
    0x00ed   U00ed   .   # iacute
    0x00ee   U00ee   .   # icircumflex
    0x00ef   U00ef   .   # idiaeresis
    0x00f0   U00f0   .   # eth
    0x00f1   U00f1   .   # ntilde
    0x00f2   U00f2   .   # ograve
    0x00f3   U00f3   .   # oacute
    0x00f4   U00f4   .   # ocircumflex
    0x00f5   U00f5   .   # otilde
    0x00f6   U00f6   .   # odiaeresis
    0x00f7   U00f7   .   # division
    0x00f8   U00f8   .   # oslash
    0x00f9   U00f9   .   # ugrave
    0x00fa   U00fa   .   # uacute
    0x00fb   U00fb   .   # ucircumflex
    0x00fc   U00fc   .   # udiaeresis
    0x00fd   U00fd   .   # yacute
    0x00fe   U00fe   .   # thorn
    0x00ff   U00ff   .   # ydiaeresis
    0x01a1   U0104   .   # Aogonek
    0x01a2   U02d8   .   # breve
    0x01a3   U0141   .   # Lstroke
    0x01a5   U013d   .   # Lcaron
    0x01a6   U015a   .   # Sacute
    0x01a9   U0160   .   # Scaron
    0x01aa   U015e   .   # Scedilla
    0x01ab   U0164   .   # Tcaron
    0x01ac   U0179   .   # Zacute
    0x01ae   U017d   .   # Zcaron
    0x01af   U017b   .   # Zabovedot
    0x01b1   U0105   .   # aogonek
    0x01b2   U02db   .   # ogonek
    0x01b3   U0142   .   # lstroke
    0x01b5   U013e   .   # lcaron
    0x01b6   U015b   .   # sacute
    0x01b7   U02c7   .   # caron
    0x01b9   U0161   .   # scaron
    0x01ba   U015f   .   # scedilla
    0x01bb   U0165   .   # tcaron
    0x01bc   U017a   .   # zacute
    0x01bd   U02dd   .   # doubleacute
    0x01be   U017e   .   # zcaron
    0x01bf   U017c   .   # zabovedot
    0x01c0   U0154   .   # Racute
    0x01c3   U0102   .   # Abreve
    0x01c5   U0139   .   # Lacute
    0x01c6   U0106   .   # Cacute
    0x01c8   U010c   .   # Ccaron
    0x01ca   U0118   .   # Eogonek
    0x01cc   U011a   .   # Ecaron
    0x01cf   U010e   .   # Dcaron
    0x01d0   U0110   .   # Dstroke
    0x01d1   U0143   .   # Nacute
    0x01d2   U0147   .   # Ncaron
    0x01d5   U0150   .   # Odoubleacute
    0x01d8   U0158   .   # Rcaron
    0x01d9   U016e   .   # Uring
    0x01db   U0170   .   # Udoubleacute
    0x01de   U0162   .   # Tcedilla
    0x01e0   U0155   .   # racute
    0x01e3   U0103   .   # abreve
    0x01e5   U013a   .   # lacute
    0x01e6   U0107   .   # cacute
    0x01e8   U010d   .   # ccaron
    0x01ea   U0119   .   # eogonek
    0x01ec   U011b   .   # ecaron
    0x01ef   U010f   .   # dcaron
    0x01f0   U0111   .   # dstroke
    0x01f1   U0144   .   # nacute
    0x01f2   U0148   .   # ncaron
    0x01f5   U0151   .   # odoubleacute
    0x01f8   U0159   .   # rcaron
    0x01f9   U016f   .   # uring
    0x01fb   U0171   .   # udoubleacute
    0x01fe   U0163   .   # tcedilla
    0x01ff   U02d9   .   # abovedot
    0x02a1   U0126   .   # Hstroke
    0x02a6   U0124   .   # Hcircumflex
    0x02a9   U0130   .   # Iabovedot
    0x02ab   U011e   .   # Gbreve
    0x02ac   U0134   .   # Jcircumflex
    0x02b1   U0127   .   # hstroke
    0x02b6   U0125   .   # hcircumflex
    0x02b9   U0131   .   # idotless
    0x02bb   U011f   .   # gbreve
    0x02bc   U0135   .   # jcircumflex
    0x02c5   U010a   .   # Cabovedot
    0x02c6   U0108   .   # Ccircumflex
    0x02d5   U0120   .   # Gabovedot
    0x02d8   U011c   .   # Gcircumflex
    0x02dd   U016c   .   # Ubreve
    0x02de   U015c   .   # Scircumflex
    0x02e5   U010b   .   # cabovedot
    0x02e6   U0109   .   # ccircumflex
    0x02f5   U0121   .   # gabovedot
    0x02f8   U011d   .   # gcircumflex
    0x02fd   U016d   .   # ubreve
    0x02fe   U015d   .   # scircumflex
    0x03a2   U0138   .   # kra
    0x03a3   U0156   .   # Rcedilla
    0x03a5   U0128   .   # Itilde
    0x03a6   U013b   .   # Lcedilla
    0x03aa   U0112   .   # Emacron
    0x03ab   U0122   .   # Gcedilla
    0x03ac   U0166   .   # Tslash
    0x03b3   U0157   .   # rcedilla
    0x03b5   U0129   .   # itilde
    0x03b6   U013c   .   # lcedilla
    0x03ba   U0113   .   # emacron
    0x03bb   U0123   .   # gcedilla
    0x03bc   U0167   .   # tslash
    0x03bd   U014a   .   # ENG
    0x03bf   U014b   .   # eng
    0x03c0   U0100   .   # Amacron
    0x03c7   U012e   .   # Iogonek
    0x03cc   U0116   .   # Eabovedot
    0x03cf   U012a   .   # Imacron
    0x03d1   U0145   .   # Ncedilla
    0x03d2   U014c   .   # Omacron
    0x03d3   U0136   .   # Kcedilla
    0x03d9   U0172   .   # Uogonek
    0x03dd   U0168   .   # Utilde
    0x03de   U016a   .   # Umacron
    0x03e0   U0101   .   # amacron
    0x03e7   U012f   .   # iogonek
    0x03ec   U0117   .   # eabovedot
    0x03ef   U012b   .   # imacron
    0x03f1   U0146   .   # ncedilla
    0x03f2   U014d   .   # omacron
    0x03f3   U0137   .   # kcedilla
    0x03f9   U0173   .   # uogonek
    0x03fd   U0169   .   # utilde
    0x03fe   U016b   .   # umacron
    0x047e   U203e   .   # overline
    0x04a1   U3002   .   # kana_fullstop
    0x04a2   U300c   .   # kana_openingbracket
    0x04a3   U300d   .   # kana_closingbracket
    0x04a4   U3001   .   # kana_comma
    0x04a5   U30fb   .   # kana_conjunctive
    0x04a6   U30f2   .   # kana_WO
    0x04a7   U30a1   .   # kana_a
    0x04a8   U30a3   .   # kana_i
    0x04a9   U30a5   .   # kana_u
    0x04aa   U30a7   .   # kana_e
    0x04ab   U30a9   .   # kana_o
    0x04ac   U30e3   .   # kana_ya
    0x04ad   U30e5   .   # kana_yu
    0x04ae   U30e7   .   # kana_yo
    0x04af   U30c3   .   # kana_tsu
    0x04b0   U30fc   .   # prolongedsound
    0x04b1   U30a2   .   # kana_A
    0x04b2   U30a4   .   # kana_I
    0x04b3   U30a6   .   # kana_U
    0x04b4   U30a8   .   # kana_E
    0x04b5   U30aa   .   # kana_O
    0x04b6   U30ab   .   # kana_KA
    0x04b7   U30ad   .   # kana_KI
    0x04b8   U30af   .   # kana_KU
    0x04b9   U30b1   .   # kana_KE
    0x04ba   U30b3   .   # kana_KO
    0x04bb   U30b5   .   # kana_SA
    0x04bc   U30b7   .   # kana_SHI
    0x04bd   U30b9   .   # kana_SU
    0x04be   U30bb   .   # kana_SE
    0x04bf   U30bd   .   # kana_SO
    0x04c0   U30bf   .   # kana_TA
    0x04c1   U30c1   .   # kana_CHI
    0x04c2   U30c4   .   # kana_TSU
    0x04c3   U30c6   .   # kana_TE
    0x04c4   U30c8   .   # kana_TO
    0x04c5   U30ca   .   # kana_NA
    0x04c6   U30cb   .   # kana_NI
    0x04c7   U30cc   .   # kana_NU
    0x04c8   U30cd   .   # kana_NE
    0x04c9   U30ce   .   # kana_NO
    0x04ca   U30cf   .   # kana_HA
    0x04cb   U30d2   .   # kana_HI
    0x04cc   U30d5   .   # kana_FU
    0x04cd   U30d8   .   # kana_HE
    0x04ce   U30db   .   # kana_HO
    0x04cf   U30de   .   # kana_MA
    0x04d0   U30df   .   # kana_MI
    0x04d1   U30e0   .   # kana_MU
    0x04d2   U30e1   .   # kana_ME
    0x04d3   U30e2   .   # kana_MO
    0x04d4   U30e4   .   # kana_YA
    0x04d5   U30e6   .   # kana_YU
    0x04d6   U30e8   .   # kana_YO
    0x04d7   U30e9   .   # kana_RA
    0x04d8   U30ea   .   # kana_RI
    0x04d9   U30eb   .   # kana_RU
    0x04da   U30ec   .   # kana_RE
    0x04db   U30ed   .   # kana_RO
    0x04dc   U30ef   .   # kana_WA
    0x04dd   U30f3   .   # kana_N
    0x04de   U309b   .   # voicedsound
    0x04df   U309c   .   # semivoicedsound
    0x05ac   U060c   .   # Arabic_comma
    0x05bb   U061b   .   # Arabic_semicolon
    0x05bf   U061f   .   # Arabic_question_mark
    0x05c1   U0621   .   # Arabic_hamza
    0x05c2   U0622   .   # Arabic_maddaonalef
    0x05c3   U0623   .   # Arabic_hamzaonalef
    0x05c4   U0624   .   # Arabic_hamzaonwaw
    0x05c5   U0625   .   # Arabic_hamzaunderalef
    0x05c6   U0626   .   # Arabic_hamzaonyeh
    0x05c7   U0627   .   # Arabic_alef
    0x05c8   U0628   .   # Arabic_beh
    0x05c9   U0629   .   # Arabic_tehmarbuta
    0x05ca   U062a   .   # Arabic_teh
    0x05cb   U062b   .   # Arabic_theh
    0x05cc   U062c   .   # Arabic_jeem
    0x05cd   U062d   .   # Arabic_hah
    0x05ce   U062e   .   # Arabic_khah
    0x05cf   U062f   .   # Arabic_dal
    0x05d0   U0630   .   # Arabic_thal
    0x05d1   U0631   .   # Arabic_ra
    0x05d2   U0632   .   # Arabic_zain
    0x05d3   U0633   .   # Arabic_seen
    0x05d4   U0634   .   # Arabic_sheen
    0x05d5   U0635   .   # Arabic_sad
    0x05d6   U0636   .   # Arabic_dad
    0x05d7   U0637   .   # Arabic_tah
    0x05d8   U0638   .   # Arabic_zah
    0x05d9   U0639   .   # Arabic_ain
    0x05da   U063a   .   # Arabic_ghain
    0x05e0   U0640   .   # Arabic_tatweel
    0x05e1   U0641   .   # Arabic_feh
    0x05e2   U0642   .   # Arabic_qaf
    0x05e3   U0643   .   # Arabic_kaf
    0x05e4   U0644   .   # Arabic_lam
    0x05e5   U0645   .   # Arabic_meem
    0x05e6   U0646   .   # Arabic_noon
    0x05e7   U0647   .   # Arabic_ha
    0x05e8   U0648   .   # Arabic_waw
    0x05e9   U0649   .   # Arabic_alefmaksura
    0x05ea   U064a   .   # Arabic_yeh
    0x05eb   U064b   .   # Arabic_fathatan
    0x05ec   U064c   .   # Arabic_dammatan
    0x05ed   U064d   .   # Arabic_kasratan
    0x05ee   U064e   .   # Arabic_fatha
    0x05ef   U064f   .   # Arabic_damma
    0x05f0   U0650   .   # Arabic_kasra
    0x05f1   U0651   .   # Arabic_shadda
    0x05f2   U0652   .   # Arabic_sukun
    0x06a1   U0452   .   # Serbian_dje
    0x06a2   U0453   .   # Macedonia_gje
    0x06a3   U0451   .   # Cyrillic_io
    0x06a4   U0454   .   # Ukrainian_ie
    0x06a5   U0455   .   # Macedonia_dse
    0x06a6   U0456   .   # Ukrainian_i
    0x06a7   U0457   .   # Ukrainian_yi
    0x06a8   U0458   .   # Cyrillic_je
    0x06a9   U0459   .   # Cyrillic_lje
    0x06aa   U045a   .   # Cyrillic_nje
    0x06ab   U045b   .   # Serbian_tshe
    0x06ac   U045c   .   # Macedonia_kje
    0x06ae   U045e   .   # Byelorussian_shortu
    0x06af   U045f   .   # Cyrillic_dzhe
    0x06b0   U2116   .   # numerosign
    0x06b1   U0402   .   # Serbian_DJE
    0x06b2   U0403   .   # Macedonia_GJE
    0x06b3   U0401   .   # Cyrillic_IO
    0x06b4   U0404   .   # Ukrainian_IE
    0x06b5   U0405   .   # Macedonia_DSE
    0x06b6   U0406   .   # Ukrainian_I
    0x06b7   U0407   .   # Ukrainian_YI
    0x06b8   U0408   .   # Cyrillic_JE
    0x06b9   U0409   .   # Cyrillic_LJE
    0x06ba   U040a   .   # Cyrillic_NJE
    0x06bb   U040b   .   # Serbian_TSHE
    0x06bc   U040c   .   # Macedonia_KJE
    0x06be   U040e   .   # Byelorussian_SHORTU
    0x06bf   U040f   .   # Cyrillic_DZHE
    0x06c0   U044e   .   # Cyrillic_yu
    0x06c1   U0430   .   # Cyrillic_a
    0x06c2   U0431   .   # Cyrillic_be
    0x06c3   U0446   .   # Cyrillic_tse
    0x06c4   U0434   .   # Cyrillic_de
    0x06c5   U0435   .   # Cyrillic_ie
    0x06c6   U0444   .   # Cyrillic_ef
    0x06c7   U0433   .   # Cyrillic_ghe
    0x06c8   U0445   .   # Cyrillic_ha
    0x06c9   U0438   .   # Cyrillic_i
    0x06ca   U0439   .   # Cyrillic_shorti
    0x06cb   U043a   .   # Cyrillic_ka
    0x06cc   U043b   .   # Cyrillic_el
    0x06cd   U043c   .   # Cyrillic_em
    0x06ce   U043d   .   # Cyrillic_en
    0x06cf   U043e   .   # Cyrillic_o
    0x06d0   U043f   .   # Cyrillic_pe
    0x06d1   U044f   .   # Cyrillic_ya
    0x06d2   U0440   .   # Cyrillic_er
    0x06d3   U0441   .   # Cyrillic_es
    0x06d4   U0442   .   # Cyrillic_te
    0x06d5   U0443   .   # Cyrillic_u
    0x06d6   U0436   .   # Cyrillic_zhe
    0x06d7   U0432   .   # Cyrillic_ve
    0x06d8   U044c   .   # Cyrillic_softsign
    0x06d9   U044b   .   # Cyrillic_yeru
    0x06da   U0437   .   # Cyrillic_ze
    0x06db   U0448   .   # Cyrillic_sha
    0x06dc   U044d   .   # Cyrillic_e
    0x06dd   U0449   .   # Cyrillic_shcha
    0x06de   U0447   .   # Cyrillic_che
    0x06df   U044a   .   # Cyrillic_hardsign
    0x06e0   U042e   .   # Cyrillic_YU
    0x06e1   U0410   .   # Cyrillic_A
    0x06e2   U0411   .   # Cyrillic_BE
    0x06e3   U0426   .   # Cyrillic_TSE
    0x06e4   U0414   .   # Cyrillic_DE
    0x06e5   U0415   .   # Cyrillic_IE
    0x06e6   U0424   .   # Cyrillic_EF
    0x06e7   U0413   .   # Cyrillic_GHE
    0x06e8   U0425   .   # Cyrillic_HA
    0x06e9   U0418   .   # Cyrillic_I
    0x06ea   U0419   .   # Cyrillic_SHORTI
    0x06eb   U041a   .   # Cyrillic_KA
    0x06ec   U041b   .   # Cyrillic_EL
    0x06ed   U041c   .   # Cyrillic_EM
    0x06ee   U041d   .   # Cyrillic_EN
    0x06ef   U041e   .   # Cyrillic_O
    0x06f0   U041f   .   # Cyrillic_PE
    0x06f1   U042f   .   # Cyrillic_YA
    0x06f2   U0420   .   # Cyrillic_ER
    0x06f3   U0421   .   # Cyrillic_ES
    0x06f4   U0422   .   # Cyrillic_TE
    0x06f5   U0423   .   # Cyrillic_U
    0x06f6   U0416   .   # Cyrillic_ZHE
    0x06f7   U0412   .   # Cyrillic_VE
    0x06f8   U042c   .   # Cyrillic_SOFTSIGN
    0x06f9   U042b   .   # Cyrillic_YERU
    0x06fa   U0417   .   # Cyrillic_ZE
    0x06fb   U0428   .   # Cyrillic_SHA
    0x06fc   U042d   .   # Cyrillic_E
    0x06fd   U0429   .   # Cyrillic_SHCHA
    0x06fe   U0427   .   # Cyrillic_CHE
    0x06ff   U042a   .   # Cyrillic_HARDSIGN
    0x07a1   U0386   .   # Greek_ALPHAaccent
    0x07a2   U0388   .   # Greek_EPSILONaccent
    0x07a3   U0389   .   # Greek_ETAaccent
    0x07a4   U038a   .   # Greek_IOTAaccent
    0x07a5   U03aa   .   # Greek_IOTAdiaeresis
    0x07a7   U038c   .   # Greek_OMICRONaccent
    0x07a8   U038e   .   # Greek_UPSILONaccent
    0x07a9   U03ab   .   # Greek_UPSILONdieresis
    0x07ab   U038f   .   # Greek_OMEGAaccent
    0x07ae   U0385   .   # Greek_accentdieresis
    0x07af   U2015   .   # Greek_horizbar
    0x07b1   U03ac   .   # Greek_alphaaccent
    0x07b2   U03ad   .   # Greek_epsilonaccent
    0x07b3   U03ae   .   # Greek_etaaccent
    0x07b4   U03af   .   # Greek_iotaaccent
    0x07b5   U03ca   .   # Greek_iotadieresis
    0x07b6   U0390   .   # Greek_iotaaccentdieresis
    0x07b7   U03cc   .   # Greek_omicronaccent
    0x07b8   U03cd   .   # Greek_upsilonaccent
    0x07b9   U03cb   .   # Greek_upsilondieresis
    0x07ba   U03b0   .   # Greek_upsilonaccentdieresis
    0x07bb   U03ce   .   # Greek_omegaaccent
    0x07c1   U0391   .   # Greek_ALPHA
    0x07c2   U0392   .   # Greek_BETA
    0x07c3   U0393   .   # Greek_GAMMA
    0x07c4   U0394   .   # Greek_DELTA
    0x07c5   U0395   .   # Greek_EPSILON
    0x07c6   U0396   .   # Greek_ZETA
    0x07c7   U0397   .   # Greek_ETA
    0x07c8   U0398   .   # Greek_THETA
    0x07c9   U0399   .   # Greek_IOTA
    0x07ca   U039a   .   # Greek_KAPPA
    0x07cb   U039b   .   # Greek_LAMBDA
    0x07cb   U039b   .   # Greek_LAMDA
    0x07cc   U039c   .   # Greek_MU
    0x07cd   U039d   .   # Greek_NU
    0x07ce   U039e   .   # Greek_XI
    0x07cf   U039f   .   # Greek_OMICRON
    0x07d0   U03a0   .   # Greek_PI
    0x07d1   U03a1   .   # Greek_RHO
    0x07d2   U03a3   .   # Greek_SIGMA
    0x07d4   U03a4   .   # Greek_TAU
    0x07d5   U03a5   .   # Greek_UPSILON
    0x07d6   U03a6   .   # Greek_PHI
    0x07d7   U03a7   .   # Greek_CHI
    0x07d8   U03a8   .   # Greek_PSI
    0x07d9   U03a9   .   # Greek_OMEGA
    0x07e1   U03b1   .   # Greek_alpha
    0x07e2   U03b2   .   # Greek_beta
    0x07e3   U03b3   .   # Greek_gamma
    0x07e4   U03b4   .   # Greek_delta
    0x07e5   U03b5   .   # Greek_epsilon
    0x07e6   U03b6   .   # Greek_zeta
    0x07e7   U03b7   .   # Greek_eta
    0x07e8   U03b8   .   # Greek_theta
    0x07e9   U03b9   .   # Greek_iota
    0x07ea   U03ba   .   # Greek_kappa
    0x07eb   U03bb   .   # Greek_lambda
    0x07ec   U03bc   .   # Greek_mu
    0x07ed   U03bd   .   # Greek_nu
    0x07ee   U03be   .   # Greek_xi
    0x07ef   U03bf   .   # Greek_omicron
    0x07f0   U03c0   .   # Greek_pi
    0x07f1   U03c1   .   # Greek_rho
    0x07f2   U03c3   .   # Greek_sigma
    0x07f3   U03c2   .   # Greek_finalsmallsigma
    0x07f4   U03c4   .   # Greek_tau
    0x07f5   U03c5   .   # Greek_upsilon
    0x07f6   U03c6   .   # Greek_phi
    0x07f7   U03c7   .   # Greek_chi
    0x07f8   U03c8   .   # Greek_psi
    0x07f9   U03c9   .   # Greek_omega
    0x08a1   U23b7   .   # leftradical
    0x08a2   U250c   d   # topleftradical
    0x08a3   U2500   d   # horizconnector
    0x08a4   U2320   .   # topintegral
    0x08a5   U2321   .   # botintegral
    0x08a6   U2502   d   # vertconnector
    0x08a7   U23a1   .   # topleftsqbracket
    0x08a8   U23a3   .   # botleftsqbracket
    0x08a9   U23a4   .   # toprightsqbracket
    0x08aa   U23a6   .   # botrightsqbracket
    0x08ab   U239b   .   # topleftparens
    0x08ac   U239d   .   # botleftparens
    0x08ad   U239e   .   # toprightparens
    0x08ae   U23a0   .   # botrightparens
    0x08af   U23a8   .   # leftmiddlecurlybrace
    0x08b0   U23ac   .   # rightmiddlecurlybrace
    0x08b1   U0000   o   # topleftsummation
    0x08b2   U0000   o   # botleftsummation
    0x08b3   U0000   o   # topvertsummationconnector
    0x08b4   U0000   o   # botvertsummationconnector
    0x08b5   U0000   o   # toprightsummation
    0x08b6   U0000   o   # botrightsummation
    0x08b7   U0000   o   # rightmiddlesummation
    0x08bc   U2264   .   # lessthanequal
    0x08bd   U2260   .   # notequal
    0x08be   U2265   .   # greaterthanequal
    0x08bf   U222b   .   # integral
    0x08c0   U2234   .   # therefore
    0x08c1   U221d   .   # variation
    0x08c2   U221e   .   # infinity
    0x08c5   U2207   .   # nabla
    0x08c8   U223c   .   # approximate
    0x08c9   U2243   .   # similarequal
    0x08cd   U21d4   .   # ifonlyif
    0x08ce   U21d2   .   # implies
    0x08cf   U2261   .   # identical
    0x08d6   U221a   .   # radical
    0x08da   U2282   .   # includedin
    0x08db   U2283   .   # includes
    0x08dc   U2229   .   # intersection
    0x08dd   U222a   .   # union
    0x08de   U2227   .   # logicaland
    0x08df   U2228   .   # logicalor
    0x08ef   U2202   .   # partialderivative
    0x08f6   U0192   .   # function
    0x08fb   U2190   .   # leftarrow
    0x08fc   U2191   .   # uparrow
    0x08fd   U2192   .   # rightarrow
    0x08fe   U2193   .   # downarrow
    0x09df   U0000   o   # blank
    0x09e0   U25c6   .   # soliddiamond
    0x09e1   U2592   .   # checkerboard
    0x09e2   U2409   .   # ht
    0x09e3   U240c   .   # ff
    0x09e4   U240d   .   # cr
    0x09e5   U240a   .   # lf
    0x09e8   U2424   .   # nl
    0x09e9   U240b   .   # vt
    0x09ea   U2518   .   # lowrightcorner
    0x09eb   U2510   .   # uprightcorner
    0x09ec   U250c   .   # upleftcorner
    0x09ed   U2514   .   # lowleftcorner
    0x09ee   U253c   .   # crossinglines
    0x09ef   U23ba   .   # horizlinescan1
    0x09f0   U23bb   .   # horizlinescan3
    0x09f1   U2500   .   # horizlinescan5
    0x09f2   U23bc   .   # horizlinescan7
    0x09f3   U23bd   .   # horizlinescan9
    0x09f4   U251c   .   # leftt
    0x09f5   U2524   .   # rightt
    0x09f6   U2534   .   # bott
    0x09f7   U252c   .   # topt
    0x09f8   U2502   .   # vertbar
    0x0aa1   U2003   .   # emspace
    0x0aa2   U2002   .   # enspace
    0x0aa3   U2004   .   # em3space
    0x0aa4   U2005   .   # em4space
    0x0aa5   U2007   .   # digitspace
    0x0aa6   U2008   .   # punctspace
    0x0aa7   U2009   .   # thinspace
    0x0aa8   U200a   .   # hairspace
    0x0aa9   U2014   .   # emdash
    0x0aaa   U2013   .   # endash
    0x0aac   U2423   o   # signifblank
    0x0aae   U2026   .   # ellipsis
    0x0aaf   U2025   .   # doubbaselinedot
    0x0ab0   U2153   .   # onethird
    0x0ab1   U2154   .   # twothirds
    0x0ab2   U2155   .   # onefifth
    0x0ab3   U2156   .   # twofifths
    0x0ab4   U2157   .   # threefifths
    0x0ab5   U2158   .   # fourfifths
    0x0ab6   U2159   .   # onesixth
    0x0ab7   U215a   .   # fivesixths
    0x0ab8   U2105   .   # careof
    0x0abb   U2012   .   # figdash
    0x0abc   U27e8   o   # leftanglebracket
    0x0abd   U002e   o   # decimalpoint
    0x0abe   U27e9   o   # rightanglebracket
    0x0abf   U0000   o   # marker
    0x0ac3   U215b   .   # oneeighth
    0x0ac4   U215c   .   # threeeighths
    0x0ac5   U215d   .   # fiveeighths
    0x0ac6   U215e   .   # seveneighths
    0x0ac9   U2122   .   # trademark
    0x0aca   U2613   o   # signaturemark
    0x0acb   U0000   o   # trademarkincircle
    0x0acc   U25c1   o   # leftopentriangle
    0x0acd   U25b7   o   # rightopentriangle
    0x0ace   U25cb   o   # emopencircle
    0x0acf   U25af   o   # emopenrectangle
    0x0ad0   U2018   .   # leftsinglequotemark
    0x0ad1   U2019   .   # rightsinglequotemark
    0x0ad2   U201c   .   # leftdoublequotemark
    0x0ad3   U201d   .   # rightdoublequotemark
    0x0ad4   U211e   .   # prescription
    0x0ad6   U2032   .   # minutes
    0x0ad7   U2033   .   # seconds
    0x0ad9   U271d   .   # latincross
    0x0ada   U0000   o   # hexagram
    0x0adb   U25ac   o   # filledrectbullet
    0x0adc   U25c0   o   # filledlefttribullet
    0x0add   U25b6   o   # filledrighttribullet
    0x0ade   U25cf   o   # emfilledcircle
    0x0adf   U25ae   o   # emfilledrect
    0x0ae0   U25e6   o   # enopencircbullet
    0x0ae1   U25ab   o   # enopensquarebullet
    0x0ae2   U25ad   o   # openrectbullet
    0x0ae3   U25b3   o   # opentribulletup
    0x0ae4   U25bd   o   # opentribulletdown
    0x0ae5   U2606   o   # openstar
    0x0ae6   U2022   o   # enfilledcircbullet
    0x0ae7   U25aa   o   # enfilledsqbullet
    0x0ae8   U25b2   o   # filledtribulletup
    0x0ae9   U25bc   o   # filledtribulletdown
    0x0aea   U261c   o   # leftpointer
    0x0aeb   U261e   o   # rightpointer
    0x0aec   U2663   .   # club
    0x0aed   U2666   .   # diamond
    0x0aee   U2665   .   # heart
    0x0af0   U2720   .   # maltesecross
    0x0af1   U2020   .   # dagger
    0x0af2   U2021   .   # doubledagger
    0x0af3   U2713   .   # checkmark
    0x0af4   U2717   .   # ballotcross
    0x0af5   U266f   .   # musicalsharp
    0x0af6   U266d   .   # musicalflat
    0x0af7   U2642   .   # malesymbol
    0x0af8   U2640   .   # femalesymbol
    0x0af9   U260e   .   # telephone
    0x0afa   U2315   .   # telephonerecorder
    0x0afb   U2117   .   # phonographcopyright
    0x0afc   U2038   .   # caret
    0x0afd   U201a   .   # singlelowquotemark
    0x0afe   U201e   .   # doublelowquotemark
    0x0aff   U0000   o   # cursor
    0x0ba3   U003c   d   # leftcaret
    0x0ba6   U003e   d   # rightcaret
    0x0ba8   U2228   d   # downcaret
    0x0ba9   U2227   d   # upcaret
    0x0bc0   U00af   d   # overbar
    0x0bc2   U22a5   .   # downtack
    0x0bc3   U2229   d   # upshoe
    0x0bc4   U230a   .   # downstile
    0x0bc6   U005f   d   # underbar
    0x0bca   U2218   .   # jot
    0x0bcc   U2395   .   # quad
    0x0bce   U22a4   .   # uptack
    0x0bcf   U25cb   .   # circle
    0x0bd3   U2308   .   # upstile
    0x0bd6   U222a   d   # downshoe
    0x0bd8   U2283   d   # rightshoe
    0x0bda   U2282   d   # leftshoe
    0x0bdc   U22a2   .   # lefttack
    0x0bfc   U22a3   .   # righttack
    0x0cdf   U2017   .   # hebrew_doublelowline
    0x0ce0   U05d0   .   # hebrew_aleph
    0x0ce1   U05d1   .   # hebrew_bet
    0x0ce1   U05d1   .   # hebrew_beth  /* deprecated */
    0x0ce2   U05d2   .   # hebrew_gimel
    0x0ce2   U05d2   .   # hebrew_gimmel  /* deprecated */
    0x0ce3   U05d3   .   # hebrew_dalet
    0x0ce3   U05d3   .   # hebrew_daleth  /* deprecated */
    0x0ce4   U05d4   .   # hebrew_he
    0x0ce5   U05d5   .   # hebrew_waw
    0x0ce6   U05d6   .   # hebrew_zain
    0x0ce6   U05d6   .   # hebrew_zayin  /* deprecated */
    0x0ce7   U05d7   .   # hebrew_chet
    0x0ce7   U05d7   .   # hebrew_het  /* deprecated */
    0x0ce8   U05d8   .   # hebrew_tet
    0x0ce8   U05d8   .   # hebrew_teth  /* deprecated */
    0x0ce9   U05d9   .   # hebrew_yod
    0x0cea   U05da   .   # hebrew_finalkaph
    0x0ceb   U05db   .   # hebrew_kaph
    0x0cec   U05dc   .   # hebrew_lamed
    0x0ced   U05dd   .   # hebrew_finalmem
    0x0cee   U05de   .   # hebrew_mem
    0x0cef   U05df   .   # hebrew_finalnun
    0x0cf0   U05e0   .   # hebrew_nun
    0x0cf1   U05e1   .   # hebrew_samech
    0x0cf1   U05e1   .   # hebrew_samekh  /* deprecated */
    0x0cf2   U05e2   .   # hebrew_ayin
    0x0cf3   U05e3   .   # hebrew_finalpe
    0x0cf4   U05e4   .   # hebrew_pe
    0x0cf5   U05e5   .   # hebrew_finalzade
    0x0cf5   U05e5   .   # hebrew_finalzadi  /* deprecated */
    0x0cf6   U05e6   .   # hebrew_zade
    0x0cf6   U05e6   .   # hebrew_zadi  /* deprecated */
    0x0cf7   U05e7   .   # hebrew_kuf  /* deprecated */
    0x0cf7   U05e7   .   # hebrew_qoph
    0x0cf8   U05e8   .   # hebrew_resh
    0x0cf9   U05e9   .   # hebrew_shin
    0x0cfa   U05ea   .   # hebrew_taf  /* deprecated */
    0x0cfa   U05ea   .   # hebrew_taw
    0x0da1   U0e01   .   # Thai_kokai
    0x0da2   U0e02   .   # Thai_khokhai
    0x0da3   U0e03   .   # Thai_khokhuat
    0x0da4   U0e04   .   # Thai_khokhwai
    0x0da5   U0e05   .   # Thai_khokhon
    0x0da6   U0e06   .   # Thai_khorakhang
    0x0da7   U0e07   .   # Thai_ngongu
    0x0da8   U0e08   .   # Thai_chochan
    0x0da9   U0e09   .   # Thai_choching
    0x0daa   U0e0a   .   # Thai_chochang
    0x0dab   U0e0b   .   # Thai_soso
    0x0dac   U0e0c   .   # Thai_chochoe
    0x0dad   U0e0d   .   # Thai_yoying
    0x0dae   U0e0e   .   # Thai_dochada
    0x0daf   U0e0f   .   # Thai_topatak
    0x0db0   U0e10   .   # Thai_thothan
    0x0db1   U0e11   .   # Thai_thonangmontho
    0x0db2   U0e12   .   # Thai_thophuthao
    0x0db3   U0e13   .   # Thai_nonen
    0x0db4   U0e14   .   # Thai_dodek
    0x0db5   U0e15   .   # Thai_totao
    0x0db6   U0e16   .   # Thai_thothung
    0x0db7   U0e17   .   # Thai_thothahan
    0x0db8   U0e18   .   # Thai_thothong
    0x0db9   U0e19   .   # Thai_nonu
    0x0dba   U0e1a   .   # Thai_bobaimai
    0x0dbb   U0e1b   .   # Thai_popla
    0x0dbc   U0e1c   .   # Thai_phophung
    0x0dbd   U0e1d   .   # Thai_fofa
    0x0dbe   U0e1e   .   # Thai_phophan
    0x0dbf   U0e1f   .   # Thai_fofan
    0x0dc0   U0e20   .   # Thai_phosamphao
    0x0dc1   U0e21   .   # Thai_moma
    0x0dc2   U0e22   .   # Thai_yoyak
    0x0dc3   U0e23   .   # Thai_rorua
    0x0dc4   U0e24   .   # Thai_ru
    0x0dc5   U0e25   .   # Thai_loling
    0x0dc6   U0e26   .   # Thai_lu
    0x0dc7   U0e27   .   # Thai_wowaen
    0x0dc8   U0e28   .   # Thai_sosala
    0x0dc9   U0e29   .   # Thai_sorusi
    0x0dca   U0e2a   .   # Thai_sosua
    0x0dcb   U0e2b   .   # Thai_hohip
    0x0dcc   U0e2c   .   # Thai_lochula
    0x0dcd   U0e2d   .   # Thai_oang
    0x0dce   U0e2e   .   # Thai_honokhuk
    0x0dcf   U0e2f   .   # Thai_paiyannoi
    0x0dd0   U0e30   .   # Thai_saraa
    0x0dd1   U0e31   .   # Thai_maihanakat
    0x0dd2   U0e32   .   # Thai_saraaa
    0x0dd3   U0e33   .   # Thai_saraam
    0x0dd4   U0e34   .   # Thai_sarai
    0x0dd5   U0e35   .   # Thai_saraii
    0x0dd6   U0e36   .   # Thai_saraue
    0x0dd7   U0e37   .   # Thai_sarauee
    0x0dd8   U0e38   .   # Thai_sarau
    0x0dd9   U0e39   .   # Thai_sarauu
    0x0dda   U0e3a   .   # Thai_phinthu
    0x0dde   U0000   o   # Thai_maihanakat_maitho
    0x0ddf   U0e3f   .   # Thai_baht
    0x0de0   U0e40   .   # Thai_sarae
    0x0de1   U0e41   .   # Thai_saraae
    0x0de2   U0e42   .   # Thai_sarao
    0x0de3   U0e43   .   # Thai_saraaimaimuan
    0x0de4   U0e44   .   # Thai_saraaimaimalai
    0x0de5   U0e45   .   # Thai_lakkhangyao
    0x0de6   U0e46   .   # Thai_maiyamok
    0x0de7   U0e47   .   # Thai_maitaikhu
    0x0de8   U0e48   .   # Thai_maiek
    0x0de9   U0e49   .   # Thai_maitho
    0x0dea   U0e4a   .   # Thai_maitri
    0x0deb   U0e4b   .   # Thai_maichattawa
    0x0dec   U0e4c   .   # Thai_thanthakhat
    0x0ded   U0e4d   .   # Thai_nikhahit
    0x0df0   U0e50   .   # Thai_leksun
    0x0df1   U0e51   .   # Thai_leknung
    0x0df2   U0e52   .   # Thai_leksong
    0x0df3   U0e53   .   # Thai_leksam
    0x0df4   U0e54   .   # Thai_leksi
    0x0df5   U0e55   .   # Thai_lekha
    0x0df6   U0e56   .   # Thai_lekhok
    0x0df7   U0e57   .   # Thai_lekchet
    0x0df8   U0e58   .   # Thai_lekpaet
    0x0df9   U0e59   .   # Thai_lekkao
    0x0ea1   U3131   f   # Hangul_Kiyeog
    0x0ea2   U3132   f   # Hangul_SsangKiyeog
    0x0ea3   U3133   f   # Hangul_KiyeogSios
    0x0ea4   U3134   f   # Hangul_Nieun
    0x0ea5   U3135   f   # Hangul_NieunJieuj
    0x0ea6   U3136   f   # Hangul_NieunHieuh
    0x0ea7   U3137   f   # Hangul_Dikeud
    0x0ea8   U3138   f   # Hangul_SsangDikeud
    0x0ea9   U3139   f   # Hangul_Rieul
    0x0eaa   U313a   f   # Hangul_RieulKiyeog
    0x0eab   U313b   f   # Hangul_RieulMieum
    0x0eac   U313c   f   # Hangul_RieulPieub
    0x0ead   U313d   f   # Hangul_RieulSios
    0x0eae   U313e   f   # Hangul_RieulTieut
    0x0eaf   U313f   f   # Hangul_RieulPhieuf
    0x0eb0   U3140   f   # Hangul_RieulHieuh
    0x0eb1   U3141   f   # Hangul_Mieum
    0x0eb2   U3142   f   # Hangul_Pieub
    0x0eb3   U3143   f   # Hangul_SsangPieub
    0x0eb4   U3144   f   # Hangul_PieubSios
    0x0eb5   U3145   f   # Hangul_Sios
    0x0eb6   U3146   f   # Hangul_SsangSios
    0x0eb7   U3147   f   # Hangul_Ieung
    0x0eb8   U3148   f   # Hangul_Jieuj
    0x0eb9   U3149   f   # Hangul_SsangJieuj
    0x0eba   U314a   f   # Hangul_Cieuc
    0x0ebb   U314b   f   # Hangul_Khieuq
    0x0ebc   U314c   f   # Hangul_Tieut
    0x0ebd   U314d   f   # Hangul_Phieuf
    0x0ebe   U314e   f   # Hangul_Hieuh
    0x0ebf   U314f   f   # Hangul_A
    0x0ec0   U3150   f   # Hangul_AE
    0x0ec1   U3151   f   # Hangul_YA
    0x0ec2   U3152   f   # Hangul_YAE
    0x0ec3   U3153   f   # Hangul_EO
    0x0ec4   U3154   f   # Hangul_E
    0x0ec5   U3155   f   # Hangul_YEO
    0x0ec6   U3156   f   # Hangul_YE
    0x0ec7   U3157   f   # Hangul_O
    0x0ec8   U3158   f   # Hangul_WA
    0x0ec9   U3159   f   # Hangul_WAE
    0x0eca   U315a   f   # Hangul_OE
    0x0ecb   U315b   f   # Hangul_YO
    0x0ecc   U315c   f   # Hangul_U
    0x0ecd   U315d   f   # Hangul_WEO
    0x0ece   U315e   f   # Hangul_WE
    0x0ecf   U315f   f   # Hangul_WI
    0x0ed0   U3160   f   # Hangul_YU
    0x0ed1   U3161   f   # Hangul_EU
    0x0ed2   U3162   f   # Hangul_YI
    0x0ed3   U3163   f   # Hangul_I
    0x0ed4   U11a8   f   # Hangul_J_Kiyeog
    0x0ed5   U11a9   f   # Hangul_J_SsangKiyeog
    0x0ed6   U11aa   f   # Hangul_J_KiyeogSios
    0x0ed7   U11ab   f   # Hangul_J_Nieun
    0x0ed8   U11ac   f   # Hangul_J_NieunJieuj
    0x0ed9   U11ad   f   # Hangul_J_NieunHieuh
    0x0eda   U11ae   f   # Hangul_J_Dikeud
    0x0edb   U11af   f   # Hangul_J_Rieul
    0x0edc   U11b0   f   # Hangul_J_RieulKiyeog
    0x0edd   U11b1   f   # Hangul_J_RieulMieum
    0x0ede   U11b2   f   # Hangul_J_RieulPieub
    0x0edf   U11b3   f   # Hangul_J_RieulSios
    0x0ee0   U11b4   f   # Hangul_J_RieulTieut
    0x0ee1   U11b5   f   # Hangul_J_RieulPhieuf
    0x0ee2   U11b6   f   # Hangul_J_RieulHieuh
    0x0ee3   U11b7   f   # Hangul_J_Mieum
    0x0ee4   U11b8   f   # Hangul_J_Pieub
    0x0ee5   U11b9   f   # Hangul_J_PieubSios
    0x0ee6   U11ba   f   # Hangul_J_Sios
    0x0ee7   U11bb   f   # Hangul_J_SsangSios
    0x0ee8   U11bc   f   # Hangul_J_Ieung
    0x0ee9   U11bd   f   # Hangul_J_Jieuj
    0x0eea   U11be   f   # Hangul_J_Cieuc
    0x0eeb   U11bf   f   # Hangul_J_Khieuq
    0x0eec   U11c0   f   # Hangul_J_Tieut
    0x0eed   U11c1   f   # Hangul_J_Phieuf
    0x0eee   U11c2   f   # Hangul_J_Hieuh
    0x0eef   U316d   f   # Hangul_RieulYeorinHieuh
    0x0ef0   U3171   f   # Hangul_SunkyeongeumMieum
    0x0ef1   U3178   f   # Hangul_SunkyeongeumPieub
    0x0ef2   U317f   f   # Hangul_PanSios
    0x0ef3   U3181   f   # Hangul_KkogjiDalrinIeung
    0x0ef4   U3184   f   # Hangul_SunkyeongeumPhieuf
    0x0ef5   U3186   f   # Hangul_YeorinHieuh
    0x0ef6   U318d   f   # Hangul_AraeA
    0x0ef7   U318e   f   # Hangul_AraeAE
    0x0ef8   U11eb   f   # Hangul_J_PanSios
    0x0ef9   U11f0   f   # Hangul_J_KkogjiDalrinIeung
    0x0efa   U11f9   f   # Hangul_J_YeorinHieuh
    0x0eff   U20a9   o   # Korean_Won
    0x13bc   U0152   .   # OE
    0x13bd   U0153   .   # oe
    0x13be   U0178   .   # Ydiaeresis
    0x20a0   U20a0   u   # EcuSign
    0x20a1   U20a1   u   # ColonSign
    0x20a2   U20a2   u   # CruzeiroSign
    0x20a3   U20a3   u   # FFrancSign
    0x20a4   U20a4   u   # LiraSign
    0x20a5   U20a5   u   # MillSign
    0x20a6   U20a6   u   # NairaSign
    0x20a7   U20a7   u   # PesetaSign
    0x20a8   U20a8   u   # RupeeSign
    0x20a9   U20a9   u   # WonSign
    0x20aa   U20aa   u   # NewSheqelSign
    0x20ab   U20ab   u   # DongSign
    0x20ac   U20ac   .   # EuroSign
    0xfd01   U0000   f   # 3270_Duplicate
    0xfd02   U0000   f   # 3270_FieldMark
    0xfd03   U0000   f   # 3270_Right2
    0xfd04   U0000   f   # 3270_Left2
    0xfd05   U0000   f   # 3270_BackTab
    0xfd06   U0000   f   # 3270_EraseEOF
    0xfd07   U0000   f   # 3270_EraseInput
    0xfd08   U0000   f   # 3270_Reset
    0xfd09   U0000   f   # 3270_Quit
    0xfd0a   U0000   f   # 3270_PA1
    0xfd0b   U0000   f   # 3270_PA2
    0xfd0c   U0000   f   # 3270_PA3
    0xfd0d   U0000   f   # 3270_Test
    0xfd0e   U0000   f   # 3270_Attn
    0xfd0f   U0000   f   # 3270_CursorBlink
    0xfd10   U0000   f   # 3270_AltCursor
    0xfd11   U0000   f   # 3270_KeyClick
    0xfd12   U0000   f   # 3270_Jump
    0xfd13   U0000   f   # 3270_Ident
    0xfd14   U0000   f   # 3270_Rule
    0xfd15   U0000   f   # 3270_Copy
    0xfd16   U0000   f   # 3270_Play
    0xfd17   U0000   f   # 3270_Setup
    0xfd18   U0000   f   # 3270_Record
    0xfd19   U0000   f   # 3270_ChangeScreen
    0xfd1a   U0000   f   # 3270_DeleteWord
    0xfd1b   U0000   f   # 3270_ExSelect
    0xfd1c   U0000   f   # 3270_CursorSelect
    0xfd1d   U0000   f   # 3270_PrintScreen
    0xfd1e   U0000   f   # 3270_Enter
    0xfe01   U0000   f   # ISO_Lock
    0xfe02   U0000   f   # ISO_Level2_Latch}
    $FE03: Result := VK_RMENU; // ISO_Level3_Shift
    {0xfe04   U0000   f   # ISO_Level3_Latch
    0xfe05   U0000   f   # ISO_Level3_Lock
    0xfe06   U0000   f   # ISO_Group_Latch
    0xfe07   U0000   f   # ISO_Group_Lock
    0xfe08   U0000   f   # ISO_Next_Group
    0xfe09   U0000   f   # ISO_Next_Group_Lock
    0xfe0a   U0000   f   # ISO_Prev_Group
    0xfe0b   U0000   f   # ISO_Prev_Group_Lock
    0xfe0c   U0000   f   # ISO_First_Group
    0xfe0d   U0000   f   # ISO_First_Group_Lock
    0xfe0e   U0000   f   # ISO_Last_Group
    0xfe0f   U0000   f   # ISO_Last_Group_Lock
    0xfe20   U0000   f   # ISO_Left_Tab
    0xfe21   U0000   f   # ISO_Move_Line_Up
    0xfe22   U0000   f   # ISO_Move_Line_Down
    0xfe23   U0000   f   # ISO_Partial_Line_Up
    0xfe24   U0000   f   # ISO_Partial_Line_Down
    0xfe25   U0000   f   # ISO_Partial_Space_Left
    0xfe26   U0000   f   # ISO_Partial_Space_Right
    0xfe27   U0000   f   # ISO_Set_Margin_Left
    0xfe28   U0000   f   # ISO_Set_Margin_Right
    0xfe29   U0000   f   # ISO_Release_Margin_Left
    0xfe2a   U0000   f   # ISO_Release_Margin_Right
    0xfe2b   U0000   f   # ISO_Release_Both_Margins
    0xfe2c   U0000   f   # ISO_Fast_Cursor_Left
    0xfe2d   U0000   f   # ISO_Fast_Cursor_Right
    0xfe2e   U0000   f   # ISO_Fast_Cursor_Up
    0xfe2f   U0000   f   # ISO_Fast_Cursor_Down
    0xfe30   U0000   f   # ISO_Continuous_Underline
    0xfe31   U0000   f   # ISO_Discontinuous_Underline
    0xfe32   U0000   f   # ISO_Emphasize
    0xfe33   U0000   f   # ISO_Center_Object
    0xfe34   U0000   f   # ISO_Enter
    0xfe50   U0300   f   # dead_grave
    0xfe51   U0301   f   # dead_acute
    0xfe52   U0302   f   # dead_circumflex
    0xfe53   U0303   f   # dead_tilde
    0xfe54   U0304   f   # dead_macron
    0xfe55   U0306   f   # dead_breve
    0xfe56   U0307   f   # dead_abovedot
    0xfe57   U0308   f   # dead_diaeresis
    0xfe58   U030a   f   # dead_abovering
    0xfe59   U030b   f   # dead_doubleacute
    0xfe5a   U030c   f   # dead_caron
    0xfe5b   U0327   f   # dead_cedilla
    0xfe5c   U0328   f   # dead_ogonek
    0xfe5d   U0345   f   # dead_iota
    0xfe5e   U3099   f   # dead_voiced_sound
    0xfe5f   U309a   f   # dead_semivoiced_sound
    0xfe70   U0000   f   # AccessX_Enable
    0xfe71   U0000   f   # AccessX_Feedback_Enable
    0xfe72   U0000   f   # RepeatKeys_Enable
    0xfe73   U0000   f   # SlowKeys_Enable
    0xfe74   U0000   f   # BounceKeys_Enable
    0xfe75   U0000   f   # StickyKeys_Enable
    0xfe76   U0000   f   # MouseKeys_Enable
    0xfe77   U0000   f   # MouseKeys_Accel_Enable
    0xfe78   U0000   f   # Overlay1_Enable
    0xfe79   U0000   f   # Overlay2_Enable
    0xfe7a   U0000   f   # AudibleBell_Enable
    0xfed0   U0000   f   # First_Virtual_Screen
    0xfed1   U0000   f   # Prev_Virtual_Screen
    0xfed2   U0000   f   # Next_Virtual_Screen
    0xfed4   U0000   f   # Last_Virtual_Screen
    0xfed5   U0000   f   # Terminate_Server
    0xfee0   U0000   f   # Pointer_Left
    0xfee1   U0000   f   # Pointer_Right
    0xfee2   U0000   f   # Pointer_Up
    0xfee3   U0000   f   # Pointer_Down
    0xfee4   U0000   f   # Pointer_UpLeft
    0xfee5   U0000   f   # Pointer_UpRight
    0xfee6   U0000   f   # Pointer_DownLeft
    0xfee7   U0000   f   # Pointer_DownRight
    0xfee8   U0000   f   # Pointer_Button_Dflt
    0xfee9   U0000   f   # Pointer_Button1
    0xfeea   U0000   f   # Pointer_Button2
    0xfeeb   U0000   f   # Pointer_Button3
    0xfeec   U0000   f   # Pointer_Button4
    0xfeed   U0000   f   # Pointer_Button5
    0xfeee   U0000   f   # Pointer_DblClick_Dflt
    0xfeef   U0000   f   # Pointer_DblClick1
    0xfef0   U0000   f   # Pointer_DblClick2
    0xfef1   U0000   f   # Pointer_DblClick3
    0xfef2   U0000   f   # Pointer_DblClick4
    0xfef3   U0000   f   # Pointer_DblClick5
    0xfef4   U0000   f   # Pointer_Drag_Dflt
    0xfef5   U0000   f   # Pointer_Drag1
    0xfef6   U0000   f   # Pointer_Drag2
    0xfef7   U0000   f   # Pointer_Drag3
    0xfef8   U0000   f   # Pointer_Drag4
    0xfef9   U0000   f   # Pointer_EnableKeys
    0xfefa   U0000   f   # Pointer_Accelerate
    0xfefb   U0000   f   # Pointer_DfltBtnNext
    0xfefc   U0000   f   # Pointer_DfltBtnPrev
    0xfefd   U0000   f   # Pointer_Drag5}
    $FF08: Result := VK_BACK; // BackSpace	/* back space, back char */
    $FF09: Result := VK_TAB;
//    0xff0a   U000a   f   # Linefeed	/* Linefeed, LF */
    $FF0B: Result := VK_CLEAR;
    $FF0D: Result := VK_RETURN; // Return, enter */
{    0xff13   U0013   f   # Pause	/* Pause, hold */
    0xff14   U0014   f   # Scroll_Lock
    0xff15   U0015   f   # Sys_Req}
    $FF1B: Result := VK_ESCAPE;
{    0xff20   U0000   f   # Multi_key
    0xff21   U0000   f   # Kanji
    0xff22   U0000   f   # Muhenkan
    0xff23   U0000   f   # Henkan_Mode
    0xff24   U0000   f   # Romaji
    0xff25   U0000   f   # Hiragana
    0xff26   U0000   f   # Katakana
    0xff27   U0000   f   # Hiragana_Katakana
    0xff28   U0000   f   # Zenkaku
    0xff29   U0000   f   # Hankaku
    0xff2a   U0000   f   # Zenkaku_Hankaku
    0xff2b   U0000   f   # Touroku
    0xff2c   U0000   f   # Massyo
    0xff2d   U0000   f   # Kana_Lock
    0xff2e   U0000   f   # Kana_Shift
    0xff2f   U0000   f   # Eisu_Shift
    0xff30   U0000   f   # Eisu_toggle
    0xff31   U0000   f   # Hangul
    0xff32   U0000   f   # Hangul_Start
    0xff33   U0000   f   # Hangul_End
    0xff34   U0000   f   # Hangul_Hanja
    0xff35   U0000   f   # Hangul_Jamo
    0xff36   U0000   f   # Hangul_Romaja
    0xff37   U0000   f   # Codeinput
    0xff38   U0000   f   # Hangul_Jeonja
    0xff39   U0000   f   # Hangul_Banja
    0xff3a   U0000   f   # Hangul_PreHanja
    0xff3b   U0000   f   # Hangul_PostHanja
    0xff3c   U0000   f   # SingleCandidate
    0xff3d   U0000   f   # MultipleCandidate
    0xff3e   U0000   f   # PreviousCandidate
    0xff3f   U0000   f   # Hangul_Special}
    $FF50: Result := VK_HOME;
    $FF51: Result := VK_LEFT;
    $FF52: Result := VK_UP;
    $FF53: Result := VK_RIGHT;
    $FF54: Result := VK_DOWN;
    $FF55: Result := VK_PRIOR;
    $FF56: Result := VK_NEXT;
    $ff57: Result := VK_END;
{    0xff58   U0000   f   # Begin
    0xff60   U0000   f   # Select
    0xff61   U0000   f   # Print
    0xff62   U0000   f   # Execute
    0xff63   U0000   f   # Insert
    0xff65   U0000   f   # Undo
    0xff66   U0000   f   # Redo
    0xff67   U0000   f   # Menu
    0xff68   U0000   f   # Find
    0xff69   U0000   f   # Cancel
    0xff6a   U0000   f   # Help
    0xff6b   U0000   f   # Break
    0xff7e   U0000   f   # Mode_switch}
    $FF7F: Result := VK_NUMLOCK;
//    0xff7f   U0000   f   # Num_Lock
    $FF80: Result := VK_SPACE;
    $FF89: Result := VK_TAB;
    $FF8D: Result := VK_RETURN; // KP_Enter	/* enter */
{    0xff91   U0000   f   # KP_F1
    0xff92   U0000   f   # KP_F2
    0xff93   U0000   f   # KP_F3
    0xff94   U0000   f   # KP_F4
    0xff95   U0000   f   # KP_Home
    0xff96   U0000   f   # KP_Left
    0xff97   U0000   f   # KP_Up
    0xff98   U0000   f   # KP_Right
    0xff99   U0000   f   # KP_Down
    0xff9a   U0000   f   # KP_Prior
    0xff9b   U0000   f   # KP_Next
    0xff9c   U0000   f   # KP_End
    0xff9d   U0000   f   # KP_Begin
    0xff9e   U0000   f   # KP_Insert
    0xff9f   U0000   f   # KP_Delete
    0xffaa   U002a   f   # KP_Multiply
    0xffab   U002b   f   # KP_Add
    0xffac   U002c   f   # KP_Separator	/* separator, often comma */
    0xffad   U002d   f   # KP_Subtract
    0xffae   U002e   f   # KP_Decimal
    0xffaf   U002f   f   # KP_Divide
    0xffb0   U0030   f   # KP_0
    0xffb1   U0031   f   # KP_1
    0xffb2   U0032   f   # KP_2
    0xffb3   U0033   f   # KP_3
    0xffb4   U0034   f   # KP_4
    0xffb5   U0035   f   # KP_5
    0xffb6   U0036   f   # KP_6
    0xffb7   U0037   f   # KP_7
    0xffb8   U0038   f   # KP_8
    0xffb9   U0039   f   # KP_9
    0xffbd   U003d   f   # KP_Equal	/* equals */}
    $FFBE: Result := VK_F1;
    $FFBF: Result := VK_F2;
    $FFC0: Result := VK_F3;
    $FFC1: Result := VK_F4;
    $FFC2: Result := VK_F5;
    $FFC3: Result := VK_F6;
    $FFC4: Result := VK_F7;
    $FFC5: Result := VK_F8;
    $FFC6: Result := VK_F9;
    $FFC7: Result := VK_F10;
    $FFC8: Result := VK_F11;
    $FFC9: Result := VK_F12;
{    0xffca   U0000   f   # F13
    0xffcb   U0000   f   # F14
    0xffcc   U0000   f   # F15
    0xffcd   U0000   f   # F16
    0xffce   U0000   f   # F17
    0xffcf   U0000   f   # F18
    0xffd0   U0000   f   # F19
    0xffd1   U0000   f   # F20
    0xffd2   U0000   f   # F21
    0xffd3   U0000   f   # F22
    0xffd4   U0000   f   # F23
    0xffd5   U0000   f   # F24
    0xffd6   U0000   f   # F25
    0xffd7   U0000   f   # F26
    0xffd8   U0000   f   # F27
    0xffd9   U0000   f   # F28
    0xffda   U0000   f   # F29
    0xffdb   U0000   f   # F30
    0xffdc   U0000   f   # F31
    0xffdd   U0000   f   # F32
    0xffde   U0000   f   # F33
    0xffdf   U0000   f   # F34
    0xffe0   U0000   f   # F35}
    $FFE1: Result := VK_LSHIFT;
    $FFE2: Result := VK_RSHIFT;
    $FFE3: Result := VK_LCONTROL;
    $FFE4: Result := VK_RCONTROL;
{    0xffe5   U0000   f   # Caps_Lock
    0xffe6   U0000   f   # Shift_Lock
    0xffe7   U0000   f   # Meta_L
    0xffe8   U0000   f   # Meta_R}
    $FFE9: Result := VK_LMENU;
    {0xffea   U0000   f   # Alt_R
    0xffeb   U0000   f   # Super_L
    0xffec   U0000   f   # Super_R
    0xffed   U0000   f   # Hyper_L
    0xffee   U0000   f   # Hyper_R
    0xffff   U0000   f   # Delete }
    $FFFF: Result := VK_DELETE;
{    0xffffff U0000   f   # VoidSymbol

    # Various XFree86 extensions since X11R6.4
    # http://cvsweb.xfree86.org/cvsweb/xc/include/keysymdef.h

    # KOI8-U support (Aleksey Novodvorsky, 1999-05-30)
    # http://cvsweb.xfree86.org/cvsweb/xc/include/keysymdef.h.diff?r1=1.4&r2=1.5
    # Used in XFree86's /usr/lib/X11/xkb/symbols/ua mappings

    0x06ad   U0491   .   # Ukrainian_ghe_with_upturn
    0x06bd   U0490   .   # Ukrainian_GHE_WITH_UPTURN

    # Support for armscii-8, ibm-cp1133, mulelao-1, viscii1.1-1,
    # tcvn-5712, georgian-academy, georgian-ps
    # (#2843, Pablo Saratxaga <pablo@mandrakesoft.com>, 1999-06-06)
    # http://cvsweb.xfree86.org/cvsweb/xc/include/keysymdef.h.diff?r1=1.6&r2=1.7

    # Armenian
    # (not used in any XFree86 4.4 kbd layouts, where /usr/lib/X11/xkb/symbols/am
    # uses directly Unicode-mapped hexadecimal values instead)
    0x14a1   U0000   r   # Armenian_eternity
    0x14a2   U0587   u   # Armenian_ligature_ew
    0x14a3   U0589   u   # Armenian_verjaket
    0x14a4   U0029   r   # Armenian_parenright
    0x14a5   U0028   r   # Armenian_parenleft
    0x14a6   U00bb   r   # Armenian_guillemotright
    0x14a7   U00ab   r   # Armenian_guillemotleft
    0x14a8   U2014   r   # Armenian_em_dash
    0x14a9   U002e   r   # Armenian_mijaket
    0x14aa   U055d   u   # Armenian_but
    0x14ab   U002c   r   # Armenian_comma
    0x14ac   U2013   r   # Armenian_en_dash
    0x14ad   U058a   u   # Armenian_yentamna
    0x14ae   U2026   r   # Armenian_ellipsis
    0x14af   U055c   u   # Armenian_amanak
    0x14b0   U055b   u   # Armenian_shesht
    0x14b1   U055e   u   # Armenian_paruyk
    0x14b2   U0531   u   # Armenian_AYB
    0x14b3   U0561   u   # Armenian_ayb
    0x14b4   U0532   u   # Armenian_BEN
    0x14b5   U0562   u   # Armenian_ben
    0x14b6   U0533   u   # Armenian_GIM
    0x14b7   U0563   u   # Armenian_gim
    0x14b8   U0534   u   # Armenian_DA
    0x14b9   U0564   u   # Armenian_da
    0x14ba   U0535   u   # Armenian_YECH
    0x14bb   U0565   u   # Armenian_yech
    0x14bc   U0536   u   # Armenian_ZA
    0x14bd   U0566   u   # Armenian_za
    0x14be   U0537   u   # Armenian_E
    0x14bf   U0567   u   # Armenian_e
    0x14c0   U0538   u   # Armenian_AT
    0x14c1   U0568   u   # Armenian_at
    0x14c2   U0539   u   # Armenian_TO
    0x14c3   U0569   u   # Armenian_to
    0x14c4   U053a   u   # Armenian_ZHE
    0x14c5   U056a   u   # Armenian_zhe
    0x14c6   U053b   u   # Armenian_INI
    0x14c7   U056b   u   # Armenian_ini
    0x14c8   U053c   u   # Armenian_LYUN
    0x14c9   U056c   u   # Armenian_lyun
    0x14ca   U053d   u   # Armenian_KHE
    0x14cb   U056d   u   # Armenian_khe
    0x14cc   U053e   u   # Armenian_TSA
    0x14cd   U056e   u   # Armenian_tsa
    0x14ce   U053f   u   # Armenian_KEN
    0x14cf   U056f   u   # Armenian_ken
    0x14d0   U0540   u   # Armenian_HO
    0x14d1   U0570   u   # Armenian_ho
    0x14d2   U0541   u   # Armenian_DZA
    0x14d3   U0571   u   # Armenian_dza
    0x14d4   U0542   u   # Armenian_GHAT
    0x14d5   U0572   u   # Armenian_ghat
    0x14d6   U0543   u   # Armenian_TCHE
    0x14d7   U0573   u   # Armenian_tche
    0x14d8   U0544   u   # Armenian_MEN
    0x14d9   U0574   u   # Armenian_men
    0x14da   U0545   u   # Armenian_HI
    0x14db   U0575   u   # Armenian_hi
    0x14dc   U0546   u   # Armenian_NU
    0x14dd   U0576   u   # Armenian_nu
    0x14de   U0547   u   # Armenian_SHA
    0x14df   U0577   u   # Armenian_sha
    0x14e0   U0548   u   # Armenian_VO
    0x14e1   U0578   u   # Armenian_vo
    0x14e2   U0549   u   # Armenian_CHA
    0x14e3   U0579   u   # Armenian_cha
    0x14e4   U054a   u   # Armenian_PE
    0x14e5   U057a   u   # Armenian_pe
    0x14e6   U054b   u   # Armenian_JE
    0x14e7   U057b   u   # Armenian_je
    0x14e8   U054c   u   # Armenian_RA
    0x14e9   U057c   u   # Armenian_ra
    0x14ea   U054d   u   # Armenian_SE
    0x14eb   U057d   u   # Armenian_se
    0x14ec   U054e   u   # Armenian_VEV
    0x14ed   U057e   u   # Armenian_vev
    0x14ee   U054f   u   # Armenian_TYUN
    0x14ef   U057f   u   # Armenian_tyun
    0x14f0   U0550   u   # Armenian_RE
    0x14f1   U0580   u   # Armenian_re
    0x14f2   U0551   u   # Armenian_TSO
    0x14f3   U0581   u   # Armenian_tso
    0x14f4   U0552   u   # Armenian_VYUN
    0x14f5   U0582   u   # Armenian_vyun
    0x14f6   U0553   u   # Armenian_PYUR
    0x14f7   U0583   u   # Armenian_pyur
    0x14f8   U0554   u   # Armenian_KE
    0x14f9   U0584   u   # Armenian_ke
    0x14fa   U0555   u   # Armenian_O
    0x14fb   U0585   u   # Armenian_o
    0x14fc   U0556   u   # Armenian_FE
    0x14fd   U0586   u   # Armenian_fe
    0x14fe   U055a   u   # Armenian_apostrophe
    0x14ff   U00a7   r   # Armenian_section_sign

    # Gregorian
    # (not used in any XFree86 4.4 kbd layouts, were /usr/lib/X11/xkb/symbols/ge_*
    # uses directly Unicode-mapped hexadecimal values instead)
    0x15d0   U10d0   u   # Georgian_an
    0x15d1   U10d1   u   # Georgian_ban
    0x15d2   U10d2   u   # Georgian_gan
    0x15d3   U10d3   u   # Georgian_don
    0x15d4   U10d4   u   # Georgian_en
    0x15d5   U10d5   u   # Georgian_vin
    0x15d6   U10d6   u   # Georgian_zen
    0x15d7   U10d7   u   # Georgian_tan
    0x15d8   U10d8   u   # Georgian_in
    0x15d9   U10d9   u   # Georgian_kan
    0x15da   U10da   u   # Georgian_las
    0x15db   U10db   u   # Georgian_man
    0x15dc   U10dc   u   # Georgian_nar
    0x15dd   U10dd   u   # Georgian_on
    0x15de   U10de   u   # Georgian_par
    0x15df   U10df   u   # Georgian_zhar
    0x15e0   U10e0   u   # Georgian_rae
    0x15e1   U10e1   u   # Georgian_san
    0x15e2   U10e2   u   # Georgian_tar
    0x15e3   U10e3   u   # Georgian_un
    0x15e4   U10e4   u   # Georgian_phar
    0x15e5   U10e5   u   # Georgian_khar
    0x15e6   U10e6   u   # Georgian_ghan
    0x15e7   U10e7   u   # Georgian_qar
    0x15e8   U10e8   u   # Georgian_shin
    0x15e9   U10e9   u   # Georgian_chin
    0x15ea   U10ea   u   # Georgian_can
    0x15eb   U10eb   u   # Georgian_jil
    0x15ec   U10ec   u   # Georgian_cil
    0x15ed   U10ed   u   # Georgian_char
    0x15ee   U10ee   u   # Georgian_xan
    0x15ef   U10ef   u   # Georgian_jhan
    0x15f0   U10f0   u   # Georgian_hae
    0x15f1   U10f1   u   # Georgian_he
    0x15f2   U10f2   u   # Georgian_hie
    0x15f3   U10f3   u   # Georgian_we
    0x15f4   U10f4   u   # Georgian_har
    0x15f5   U10f5   u   # Georgian_hoe
    0x15f6   U10f6   u   # Georgian_fi

    # Pablo Saratxaga's i18n updates for XFree86 that are used in Mandrake 7.2.
    # (#4195, Pablo Saratxaga <pablo@mandrakesoft.com>, 2000-10-27)
    # http://cvsweb.xfree86.org/cvsweb/xc/include/keysymdef.h.diff?r1=1.9&r2=1.10

    # Latin-8
    # (the *abovedot keysyms are used in /usr/lib/X11/xkb/symbols/ie)
    0x12a1   U1e02   u   # Babovedot
    0x12a2   U1e03   u   # babovedot
    0x12a6   U1e0a   u   # Dabovedot
    0x12a8   U1e80   u   # Wgrave
    0x12aa   U1e82   u   # Wacute
    0x12ab   U1e0b   u   # dabovedot
    0x12ac   U1ef2   u   # Ygrave
    0x12b0   U1e1e   u   # Fabovedot
    0x12b1   U1e1f   u   # fabovedot
    0x12b4   U1e40   u   # Mabovedot
    0x12b5   U1e41   u   # mabovedot
    0x12b7   U1e56   u   # Pabovedot
    0x12b8   U1e81   u   # wgrave
    0x12b9   U1e57   u   # pabovedot
    0x12ba   U1e83   u   # wacute
    0x12bb   U1e60   u   # Sabovedot
    0x12bc   U1ef3   u   # ygrave
    0x12bd   U1e84   u   # Wdiaeresis
    0x12be   U1e85   u   # wdiaeresis
    0x12bf   U1e61   u   # sabovedot
    0x12d0   U0174   u   # Wcircumflex
    0x12d7   U1e6a   u   # Tabovedot
    0x12de   U0176   u   # Ycircumflex
    0x12f0   U0175   u   # wcircumflex
    0x12f7   U1e6b   u   # tabovedot
    0x12fe   U0177   u   # ycircumflex

    # Arabic
    # (of these, in XFree86 4.4 only Arabic_superscript_alef, Arabic_madda_above,
    # Arabic_hamza_* are actually used, e.g. in /usr/lib/X11/xkb/symbols/syr)
    0x0590   U06f0   u   # Farsi_0
    0x0591   U06f1   u   # Farsi_1
    0x0592   U06f2   u   # Farsi_2
    0x0593   U06f3   u   # Farsi_3
    0x0594   U06f4   u   # Farsi_4
    0x0595   U06f5   u   # Farsi_5
    0x0596   U06f6   u   # Farsi_6
    0x0597   U06f7   u   # Farsi_7
    0x0598   U06f8   u   # Farsi_8
    0x0599   U06f9   u   # Farsi_9
    0x05a5   U066a   u   # Arabic_percent
    0x05a6   U0670   u   # Arabic_superscript_alef
    0x05a7   U0679   u   # Arabic_tteh
    0x05a8   U067e   u   # Arabic_peh
    0x05a9   U0686   u   # Arabic_tcheh
    0x05aa   U0688   u   # Arabic_ddal
    0x05ab   U0691   u   # Arabic_rreh
    0x05ae   U06d4   u   # Arabic_fullstop
    0x05b0   U0660   u   # Arabic_0
    0x05b1   U0661   u   # Arabic_1
    0x05b2   U0662   u   # Arabic_2
    0x05b3   U0663   u   # Arabic_3
    0x05b4   U0664   u   # Arabic_4
    0x05b5   U0665   u   # Arabic_5
    0x05b6   U0666   u   # Arabic_6
    0x05b7   U0667   u   # Arabic_7
    0x05b8   U0668   u   # Arabic_8
    0x05b9   U0669   u   # Arabic_9
    0x05f3   U0653   u   # Arabic_madda_above
    0x05f4   U0654   u   # Arabic_hamza_above
    0x05f5   U0655   u   # Arabic_hamza_below
    0x05f6   U0698   u   # Arabic_jeh
    0x05f7   U06a4   u   # Arabic_veh
    0x05f8   U06a9   u   # Arabic_keheh
    0x05f9   U06af   u   # Arabic_gaf
    0x05fa   U06ba   u   # Arabic_noon_ghunna
    0x05fb   U06be   u   # Arabic_heh_doachashmee
    0x05fc   U06cc   u   # Farsi_yeh
    0x05fd   U06d2   u   # Arabic_yeh_baree
    0x05fe   U06c1   u   # Arabic_heh_goal

    # Cyrillic
    # (none of these are actually used in any XFree86 4.4 kbd layouts)
    0x0680   U0492   u   # Cyrillic_GHE_bar
    0x0681   U0496   u   # Cyrillic_ZHE_descender
    0x0682   U049a   u   # Cyrillic_KA_descender
    0x0683   U049c   u   # Cyrillic_KA_vertstroke
    0x0684   U04a2   u   # Cyrillic_EN_descender
    0x0685   U04ae   u   # Cyrillic_U_straight
    0x0686   U04b0   u   # Cyrillic_U_straight_bar
    0x0687   U04b2   u   # Cyrillic_HA_descender
    0x0688   U04b6   u   # Cyrillic_CHE_descender
    0x0689   U04b8   u   # Cyrillic_CHE_vertstroke
    0x068a   U04ba   u   # Cyrillic_SHHA
    0x068c   U04d8   u   # Cyrillic_SCHWA
    0x068d   U04e2   u   # Cyrillic_I_macron
    0x068e   U04e8   u   # Cyrillic_O_bar
    0x068f   U04ee   u   # Cyrillic_U_macron
    0x0690   U0493   u   # Cyrillic_ghe_bar
    0x0691   U0497   u   # Cyrillic_zhe_descender
    0x0692   U049b   u   # Cyrillic_ka_descender
    0x0693   U049d   u   # Cyrillic_ka_vertstroke
    0x0694   U04a3   u   # Cyrillic_en_descender
    0x0695   U04af   u   # Cyrillic_u_straight
    0x0696   U04b1   u   # Cyrillic_u_straight_bar
    0x0697   U04b3   u   # Cyrillic_ha_descender
    0x0698   U04b7   u   # Cyrillic_che_descender
    0x0699   U04b9   u   # Cyrillic_che_vertstroke
    0x069a   U04bb   u   # Cyrillic_shha
    0x069c   U04d9   u   # Cyrillic_schwa
    0x069d   U04e3   u   # Cyrillic_i_macron
    0x069e   U04e9   u   # Cyrillic_o_bar
    0x069f   U04ef   u   # Cyrillic_u_macron

    # Caucasus
    # (of these, in XFree86 4.4 only Gcaron, gcaron are actually used,
    # e.g. in /usr/lib/X11/xkb/symbols/sapmi; the lack of Unicode
    # equivalents for the others suggests that they are bogus)
    0x16a2   U0000   r   # Ccedillaabovedot
    0x16a3   U1e8a   u   # Xabovedot
    0x16a5   U0000   r   # Qabovedot
    0x16a6   U012c   u   # Ibreve
    0x16a7   U0000   r   # IE
    0x16a8   U0000   r   # UO
    0x16a9   U01b5   u   # Zstroke
    0x16aa   U01e6   u   # Gcaron
    0x16af   U019f   u   # Obarred
    0x16b2   U0000   r   # ccedillaabovedot
    0x16b3   U1e8b   u   # xabovedot
    0x16b4   U0000   r   # Ocaron
    0x16b5   U0000   r   # qabovedot
    0x16b6   U012d   u   # ibreve
    0x16b7   U0000   r   # ie
    0x16b8   U0000   r   # uo
    0x16b9   U01b6   u   # zstroke
    0x16ba   U01e7   u   # gcaron
    0x16bd   U01d2   u   # ocaron
    0x16bf   U0275   u   # obarred
    0x16c6   U018f   u   # SCHWA
    0x16f6   U0259   u   # schwa

    # Inupiak, Guarani
    # (none of these are actually used in any XFree86 4.4 kbd layouts,
    # and the lack of Unicode equivalents suggests that they are bogus)
    0x16d1   U1e36   u   # Lbelowdot
    0x16d2   U0000   r   # Lstrokebelowdot
    0x16d3   U0000   r   # Gtilde
    0x16e1   U1e37   u   # lbelowdot
    0x16e2   U0000   r   # lstrokebelowdot
    0x16e3   U0000   r   # gtilde

    # Vietnamese
    # (none of these are actually used in any XFree86 4.4 kbd layouts; they are
    # also pointless, as Vietnamese input methods use dead accent keys + ASCII keys)
    0x1ea0   U1ea0   u   # Abelowdot
    0x1ea1   U1ea1   u   # abelowdot
    0x1ea2   U1ea2   u   # Ahook
    0x1ea3   U1ea3   u   # ahook
    0x1ea4   U1ea4   u   # Acircumflexacute
    0x1ea5   U1ea5   u   # acircumflexacute
    0x1ea6   U1ea6   u   # Acircumflexgrave
    0x1ea7   U1ea7   u   # acircumflexgrave
    0x1ea8   U1ea8   u   # Acircumflexhook
    0x1ea9   U1ea9   u   # acircumflexhook
    0x1eaa   U1eaa   u   # Acircumflextilde
    0x1eab   U1eab   u   # acircumflextilde
    0x1eac   U1eac   u   # Acircumflexbelowdot
    0x1ead   U1ead   u   # acircumflexbelowdot
    0x1eae   U1eae   u   # Abreveacute
    0x1eaf   U1eaf   u   # abreveacute
    0x1eb0   U1eb0   u   # Abrevegrave
    0x1eb1   U1eb1   u   # abrevegrave
    0x1eb2   U1eb2   u   # Abrevehook
    0x1eb3   U1eb3   u   # abrevehook
    0x1eb4   U1eb4   u   # Abrevetilde
    0x1eb5   U1eb5   u   # abrevetilde
    0x1eb6   U1eb6   u   # Abrevebelowdot
    0x1eb7   U1eb7   u   # abrevebelowdot
    0x1eb8   U1eb8   u   # Ebelowdot
    0x1eb9   U1eb9   u   # ebelowdot
    0x1eba   U1eba   u   # Ehook
    0x1ebb   U1ebb   u   # ehook
    0x1ebc   U1ebc   u   # Etilde
    0x1ebd   U1ebd   u   # etilde
    0x1ebe   U1ebe   u   # Ecircumflexacute
    0x1ebf   U1ebf   u   # ecircumflexacute
    0x1ec0   U1ec0   u   # Ecircumflexgrave
    0x1ec1   U1ec1   u   # ecircumflexgrave
    0x1ec2   U1ec2   u   # Ecircumflexhook
    0x1ec3   U1ec3   u   # ecircumflexhook
    0x1ec4   U1ec4   u   # Ecircumflextilde
    0x1ec5   U1ec5   u   # ecircumflextilde
    0x1ec6   U1ec6   u   # Ecircumflexbelowdot
    0x1ec7   U1ec7   u   # ecircumflexbelowdot
    0x1ec8   U1ec8   u   # Ihook
    0x1ec9   U1ec9   u   # ihook
    0x1eca   U1eca   u   # Ibelowdot
    0x1ecb   U1ecb   u   # ibelowdot
    0x1ecc   U1ecc   u   # Obelowdot
    0x1ecd   U1ecd   u   # obelowdot
    0x1ece   U1ece   u   # Ohook
    0x1ecf   U1ecf   u   # ohook
    0x1ed0   U1ed0   u   # Ocircumflexacute
    0x1ed1   U1ed1   u   # ocircumflexacute
    0x1ed2   U1ed2   u   # Ocircumflexgrave
    0x1ed3   U1ed3   u   # ocircumflexgrave
    0x1ed4   U1ed4   u   # Ocircumflexhook
    0x1ed5   U1ed5   u   # ocircumflexhook
    0x1ed6   U1ed6   u   # Ocircumflextilde
    0x1ed7   U1ed7   u   # ocircumflextilde
    0x1ed8   U1ed8   u   # Ocircumflexbelowdot
    0x1ed9   U1ed9   u   # ocircumflexbelowdot
    0x1eda   U1eda   u   # Ohornacute
    0x1edb   U1edb   u   # ohornacute
    0x1edc   U1edc   u   # Ohorngrave
    0x1edd   U1edd   u   # ohorngrave
    0x1ede   U1ede   u   # Ohornhook
    0x1edf   U1edf   u   # ohornhook
    0x1ee0   U1ee0   u   # Ohorntilde
    0x1ee1   U1ee1   u   # ohorntilde
    0x1ee2   U1ee2   u   # Ohornbelowdot
    0x1ee3   U1ee3   u   # ohornbelowdot
    0x1ee4   U1ee4   u   # Ubelowdot
    0x1ee5   U1ee5   u   # ubelowdot
    0x1ee6   U1ee6   u   # Uhook
    0x1ee7   U1ee7   u   # uhook
    0x1ee8   U1ee8   u   # Uhornacute
    0x1ee9   U1ee9   u   # uhornacute
    0x1eea   U1eea   u   # Uhorngrave
    0x1eeb   U1eeb   u   # uhorngrave
    0x1eec   U1eec   u   # Uhornhook
    0x1eed   U1eed   u   # uhornhook
    0x1eee   U1eee   u   # Uhorntilde
    0x1eef   U1eef   u   # uhorntilde
    0x1ef0   U1ef0   u   # Uhornbelowdot
    0x1ef1   U1ef1   u   # uhornbelowdot
    0x1ef4   U1ef4   u   # Ybelowdot
    0x1ef5   U1ef5   u   # ybelowdot
    0x1ef6   U1ef6   u   # Yhook
    0x1ef7   U1ef7   u   # yhook
    0x1ef8   U1ef8   u   # Ytilde
    0x1ef9   U1ef9   u   # ytilde

    0x1efa   U01a0   u   # Ohorn
    0x1efb   U01a1   u   # ohorn
    0x1efc   U01af   u   # Uhorn
    0x1efd   U01b0   u   # uhorn

    # (Unicode combining characters have no direct equivalence with
    # keysyms, where dead keys are defined instead)
    0x1e9f   U0303   r   # combining_tilde
    0x1ef2   U0300   r   # combining_grave
    0x1ef3   U0301   r   # combining_acute
    0x1efe   U0309   r   # combining_hook
    0x1eff   U0323   r   # combining_belowdot

    # These probably should be added to the X11 standard properly,
    # as they could be of use for Vietnamese input methods.
    0xfe60   U0323   f   # dead_belowdot
    0xfe61   U0309   f   # dead_hook
    0xfe62   U031b   f   # dead_horn}
  else
    Result := 0;
  end;
  if Result = 0 then DebugLn('[X11KeyToLCLKey] Unknown KeySym: $' + IntToHex(AX11Key, 4));
end;

class function TCDWSCustomForm.DoCreateHandle(const AWinControl: TWinControl;
  const AParams: TCreateParams): TLCLHandle;
begin
end;

class procedure TCDWSCustomForm.DoShowHide(const AWinControl: TWinControl);
begin
end;

{------------------------------------------------------------------------------
  Method: TCDWSCustomForm.CreateHandle
  Params:  None
  Returns: Nothing

  Creates a Windows CE Form, initializes it according to it´s properties and shows it
 ------------------------------------------------------------------------------}
class function TCDWSCustomForm.CreateHandle(const AWinControl: TWinControl;
  const AParams: TCreateParams): TLCLHandle;
const
  WindowHints: TXWMHints = (
    flags: InputHint or StateHint or WindowGroupHint;
    input: 1;
    initial_state: NormalState;
    icon_pixmap: 0;
    icon_window: 0;
    icon_x: 0;
    icon_y: 0;
    icon_mask: 0;
    window_group: 0;
  );
var
  Colormap: TColormap;
  Attr: TXSetWindowAttributes;
  SizeHints: TXSizeHints;
  ClassHint: PXClassHint;
  lParentHandle: X.TWindow;
  mask: longword;
  lWindowInfo: TX11WindowInfo;
  lWindow: TWindow;
  AForm: TCustomForm absolute AWinControl;
begin
  {$ifdef VerboseCDForms}
  DebugLn(Format(':>[TCDWSCustomForm.CreateHandle] AWinControl=%x Name=%s: %s',
    [PtrInt(AWinControl), AWinControl.Name, AWinControl.ClassName]));
  {$endif}
  Colormap := XDefaultColormap(CDWidgetSet.FDisplay, XDefaultScreen(CDWidgetSet.FDisplay));
  Attr.Colormap := Colormap;

  SizeHints.flags     := XUtil.PSize;
  SizeHints.x         := 0; // If it doesnt start with zero, setting bounds later on fails, no idea why
  SizeHints.y         := 0;
  SizeHints.width     := 200;
  SizeHints.height    := 200;

  { Make sure we use the correct parent handle }
{  if FParent <> nil then
    lParentHandle := TX11Window(FParent).Handle
  else}
    lParentHandle := XDefaultRootWindow(CDWidgetSet.FDisplay);

  { setup attributes and masks }
  if (AForm.BorderStyle in [bsNone, bsToolWindow]) then
  begin
    Attr.Override_Redirect := 1;    // this removes window borders
    mask := CWOverrideRedirect;// or CWColormap;
  end
{  else if (woPopup in WindowOptions) then
  begin
    Attr.Override_Redirect := True;    // this removes window borders
    Attr.save_under := True;
    mask := CWOverrideRedirect or CWSaveUnder;
  end}
  else
  begin
    Attr.Override_Redirect := 0;
    mask := CWColormap;
  end;

  lWindow := XCreateWindow(
    CDWidgetSet.FDisplay,
    lParentHandle,                      // parent
    SizeHints.x, SizeHints.x,           // position (top, left)
    SizeHints.width, SizeHints.height,  // default size (width, height)
    0,                                  // border size
    CopyFromParent,                     // depth
    InputOutput,                        // class
    XDefaultVisual(CDWidgetSet.FDisplay, XDefaultScreen(CDWidgetSet.FDisplay)),  // visual
    mask,
    @Attr);

  if lWindow = 0 then
    raise Exception.Create('[TCDWSCustomForm.CreateHandle] Window creation failed');

  XSelectInput(CDWidgetSet.FDisplay, lWindow, KeyPressMask or KeyReleaseMask
    or ButtonPressMask or ButtonReleaseMask
    or EnterWindowMask or LeaveWindowMask
    or ButtonMotionMask or PointerMotionMask
    or ExposureMask
    or FocusChangeMask
    or StructureNotifyMask
//    or PropertyChangeMask
    );

//  if (not (woX11SkipWMHints in WindowOptions)) and (woWindow in WindowOptions) then
//  begin
    XSetStandardProperties(CDWidgetSet.FDisplay, lWindow, nil, nil, 0,
     argv, argc, @SizeHints);

    XSetWMNormalHints(CDWidgetSet.FDisplay, lWindow, @SizeHints);

    WindowHints.flags := WindowGroupHint;
    WindowHints.window_group := CDWidgetSet.LeaderWindow;
    XSetWMHints(CDWidgetSet.FDisplay, lWindow, @WindowHints);

    XChangeProperty(CDWidgetSet.FDisplay, lWindow, CDWidgetSet.ClientLeaderAtom, 33, 32,
     PropModeReplace, @CDWidgetSet.LeaderWindow, 1);

     // We want to get a Client Message when the user tries to close this window
    if CDWidgetSet.FWMProtocols = 0 then
     CDWidgetSet.FWMProtocols := XInternAtom(CDWidgetSet.FDisplay, 'WM_PROTOCOLS', False);
    if CDWidgetSet.FWMDeleteWindow = 0 then
     CDWidgetSet.FWMDeleteWindow := XInternAtom(CDWidgetSet.FDisplay, 'WM_DELETE_WINDOW', False);
    {$ifdef CD_X11_NewNativePaint}
    // Client Message for Paint Event
    if CDWidgetSet.FWMPaint = 0 then
      CDWidgetSet.FWMPaint := XInternAtom(CDWidgetSet.FDisplay, 'WM_PAINT', False);
    {$endif}

     // send close event instead of quitting the whole application...
     XSetWMProtocols(CDWidgetSet.FDisplay, lWindow, @CDWidgetSet.FWMDeleteWindow, 1);
//   end;

  { Child windows do not appear until parent (lParentHandle) is mapped }
//  if FParent <> nil then
//    XMapSubwindows(CDWidgetSet.FDisplay, lParentHandle);

  // for modal windows, this is necessary
//  if (woModal in WindowOptions) then
//    XSetTransientForHint(GFApplication.Handle, Handle, Handle);

  // Add the window to the list of windows
  lWindowInfo := TX11WindowInfo.Create;
  lWindowInfo.Window := lWindow;
  lWindowInfo.LCLForm := TCustomForm(AWinControl);
  XGetWindowAttributes(CDWidgetSet.FDisplay, lWindow, @lWindowInfo.Attr);
  lWindowInfo.Colormap := XDefaultColormap(CDWidgetSet.FDisplay, XDefaultScreen(CDWidgetSet.FDisplay));
  lWindowInfo.ColorDepth := lWindowInfo.Attr.depth;
  CreateX11Canvas(lWindowInfo);
  Result := TLCLHandle(lWindowInfo);

  {$ifdef CD_X11_NewNativePaint}
  CDWidgetSet.XWindowList.AddObject('New',TObject(lWindowInfo));
  {$endif}

  {$ifdef VerboseCDForms}
  DebugLn(Format(':<[TCDWSCustomForm.CreateHandle] Result=%x',
    [Result]));
  {$endif}
end;

class procedure TCDWSCustomForm.DestroyHandle(const AWinControl: TWinControl);
begin

end;

class procedure TCDWSCustomForm.SetBorderIcons(const AForm: TCustomForm;
 const ABorderIcons: TBorderIcons);
begin
end;

class procedure TCDWSCustomForm.SetFormBorderStyle(const AForm: TCustomForm;
          const AFormBorderStyle: TFormBorderStyle);
begin
  RecreateWnd(AForm);
end;

class procedure TCDWSCustomForm.SetBounds(const AWinControl: TWinControl;
    const ALeft, ATop, AWidth, AHeight: Integer);
begin
  {$ifdef VerboseCDForms}
  DebugLn(Format('[TCDWSCustomForm.SetBounds] AWinControl=%x ALeft=%d ATop=%d AWidth=%d AHeight=%d',
    [PtrInt(AWinControl), ALeft, ATop, AWidth, AHeight]));
  {$endif}
  SetPosition(AWinControl, Point(ALeft, ATop));
  SetSize(AWinControl, Size(AWidth, AHeight));
end;

class procedure TCDWSCustomForm.SetIcon(const AForm: TCustomForm; const Small, Big: HICON);
begin
end;

class procedure TCDWSCustomForm.SetShowInTaskbar(const AForm: TCustomForm;
  const AValue: TShowInTaskbar);
begin
end;

class procedure TCDWSCustomForm.ShowModal(const ACustomForm: TCustomForm);
begin
end;

class procedure TCDWSCustomForm.ShowHide(const AWinControl: TWinControl);
var
  lIndex: Integer;
  lWindow: TWindow;
  lWindowInfo: TX11WindowInfo;
begin
  lWindowInfo := TX11WindowInfo(AWinControl.Handle);
  lWindow := lWindowInfo.Window;

  if AWinControl.Visible then
  begin
    {$ifdef VerboseCDForms}
    DebugLn(Format('[TCDWSCustomForm.ShowHide] Visible=True AWinControl=%x Handle=%x',
      [PtrInt(AWinControl), PtrInt(AWinControl.Handle)]));
    {$endif}
    XMapRaised(CDWidgetSet.FDisplay, lWindow);
  end
  else
  begin
    {$ifdef VerboseCDForms}
    DebugLn(Format('[TCDWSCustomForm.ShowHide] Visible=False AWinControl=%x', [PtrInt(AWinControl)]));
    {$endif}
    XUnmapWindow(CDWidgetSet.FDisplay, lWindow);
    // Don't remove it here, wait for a X11 Destroy event
    {---------------------------------------------------------------------------
    We will never get an X11 event, if we don't tell X11 to unmap the window!
    Even if the WM attempts to close the window, it's the application which
    triggers the actual operation. If CanClose is false, it doesn't do it.
    ---------------------------------------------------------------------------}
  end;
end;

class function TCDWSCustomForm.GetText(const AWinControl: TWinControl; var AText: String): Boolean;
var
  s: PChar;
  lWindow: TWindow;
  lWindowInfo: TX11WindowInfo;
begin
  lWindowInfo := TX11WindowInfo(AWinControl.Handle);
  lWindow := lWindowInfo.Window;

  XFetchName(CDWidgetSet.FDisplay, lWindow, @s);
  AText := s;
  XFree(s);
end;

class function TCDWSCustomForm.GetTextLen(const AWinControl: TWinControl; var ALength: Integer): Boolean;
var
  lText: string;
begin
  Result := GetText(AWinControl, lText);
  ALength := Length(lText);
end;

class procedure TCDWSCustomForm.SetText(const AWinControl: TWinControl; const AText: String);
var
  tp: TXTextProperty;
  lWindow: TWindow;
  lWindowInfo: TX11WindowInfo;
begin
  lWindowInfo := TX11WindowInfo(AWinControl.Handle);
  lWindow := lWindowInfo.Window;

  tp.value    := PCUChar(AText);
  tp.encoding := XA_WM_NAME;
  tp.format   := 8;
  tp.nitems   := UTF8Length(AText);

  XSetWMName(CDWidgetSet.FDisplay, lWindow, @tp);
  XStoreName(CDWidgetSet.FDisplay, lWindow, PChar(AText));
  XSetIconName(CDWidgetSet.FDisplay, lWindow, PChar(AText));
  XSetWMIconName(CDWidgetSet.FDisplay, lWindow, @tp);
end;

class function TCDWSCustomForm.GetClientBounds(const AWincontrol: TWinControl; var ARect: TRect): Boolean;
begin
end;

class function TCDWSCustomForm.GetClientRect(const AWincontrol: TWinControl; var ARect: TRect): Boolean;
begin
end;


