Procházet zdrojové kódy

* Fixes and start of keyboard API

Michaël Van Canneyt před 1 rokem
rodič
revize
89fcc44e4f

+ 1 - 3
demo/ButtonGenerator/WasmButtonGenerator.lpi

@@ -28,7 +28,6 @@
           <CodeGeneration>
             <TargetCPU Value="wasm32"/>
             <TargetOS Value="wasi"/>
-            <Subtarget Value="browser"/>
           </CodeGeneration>
           <Linking>
             <Debugging>
@@ -70,7 +69,7 @@
   <CompilerOptions>
     <Version Value="11"/>
     <Target>
-      <Filename Value="basic"/>
+      <Filename Value="ButtonGenerator.wasm" ApplyConventions="False"/>
     </Target>
     <SearchPaths>
       <IncludeFiles Value="$(ProjOutDir)"/>
@@ -80,7 +79,6 @@
     <CodeGeneration>
       <TargetCPU Value="wasm32"/>
       <TargetOS Value="wasi"/>
-      <Subtarget Value="browser"/>
     </CodeGeneration>
     <Linking>
       <Debugging>

+ 1133 - 0
src/base/fresnel.keys.pas

@@ -0,0 +1,1133 @@
+unit fresnel.keys;
+
+{$mode ObjFPC}{$H+}
+{$modeswitch advancedrecords}
+
+interface
+
+Type
+  TKeyNames = Record
+  Const
+    Alt = 'Alt';
+    AltGraph = 'AltGraph';
+    CapsLock = 'CapsLock';
+    Control = 'Control';
+    Fn = 'Fn';
+    FnLock = 'FnLock';
+    Hyper = 'Hyper';
+    Meta = 'Meta';
+    NumLock = 'NumLock';
+    ScrollLock = 'ScrollLock';
+    Shift = 'Shift';
+    Super = 'Super';
+    Symbol = 'Symbol';
+    SymbolLock = 'SymbolLock';
+    Enter = 'Enter';
+    Tab = 'Tab';
+    Space = 'Space';
+    ArrowDown = 'ArrowDown';
+    ArrowLeft = 'ArrowLeft';
+    ArrowRight = 'ArrowRight';
+    ArrowUp = 'ArrowUp';
+    End_ = 'End';
+    Home = 'Home';
+    PageDown = 'PageDown';
+    PageUp = 'PageUp';
+    BackSpace = 'Backspace';
+    Clear = 'Clear';
+    Copy = 'Copy';
+    CrSel = 'CrSel';
+    Cut = 'Cut';
+    Delete = 'Delete';
+    EraseEof = 'EraseEof';
+    ExSel = 'ExSel';
+    Insert = 'Insert';
+    Paste = 'Paste';
+    Redo = 'Redo';
+    Undo = 'Undo';
+    Accept = 'Accept';
+    Again = 'Again';
+    Attn = 'Attn';
+    Cancel = 'Cancel';
+    ContextMenu = 'Contextmenu';
+    Escape = 'Escape';
+    Execute = 'Execute';
+    Find = 'Find';
+    Finish = 'Finish';
+    Help = 'Help';
+    Pause = 'Pause';
+    Play = 'Play';
+    Props = 'Props';
+    Select = 'Select';
+    ZoomIn = 'ZoomIn';
+    ZoomOut = 'ZoomOut';
+    BrightnessDown = 'BrightnessDown';
+    BrightnessUp = 'BrightnessUp';
+    Eject = 'Eject';
+    LogOff = 'LogOff';
+    Power = 'Power';
+    PowerOff = 'PowerOff';
+    PrintScreen = 'PrintScreen';
+    Hibernate = 'Hibernate';
+    Standby = 'Standby';
+    WakeUp = 'WakeUp';
+    AllCandidates = 'AllCandidates';
+    Alphanumeric =  'Alphanumeric';
+    CodeInput = 'CodeInput';
+    Compose = 'Compose';
+    Convert = 'Convert';
+    Dead = 'Dead';
+    FinalMode = 'FinalMode';
+    GroupFirst = 'GroupFirst';
+    GroupLast = 'GroupLast';
+    GroupNext = 'GroupNext';
+    GroupPrevious = 'GroupPrevious';
+    ModeChange = 'ModeChange';
+    NextCandidate = 'NextCandidate';
+    NonConvert = 'NonConvert';
+    PreviousCandidate = 'PreviousCandidate';
+    Process = 'Process';
+    SingleCandidate = 'SingleCandidate';
+    HangulMode = 'HangulMode';
+    HanjaMode = 'HanjaMode';
+    JunjaMode = 'JunjaMode';
+    Eisu = 'Eisu';
+    Hankaku = 'Hankaku';
+    Hiranga = 'Hiranga';
+    HirangaKatakana = 'HirangaKatakana';
+    KanaMode = 'KanaMode';
+    Katakana = 'Katakana';
+    Romaji = 'Romaji';
+    Zenkaku = 'Zenkaku';
+    ZenkakuHanaku = 'ZenkakuHanaku';
+    F1 = 'F1';
+    F2 = 'F2';
+    F3 = 'F3';
+    F4 = 'F4';
+    F5 = 'F5';
+    F6 = 'F6';
+    F7 = 'F7';
+    F8 = 'F8';
+    F9 = 'F9';
+    F10 = 'F10';
+    F11 = 'F11';
+    F12 = 'F12';
+    F13 = 'F13';
+    F14 = 'F14';
+    F15 = 'F15';
+    F16 = 'F16';
+    F17 = 'F17';
+    F18 = 'F18';
+    F19 = 'F19';
+    F20 = 'F20';
+    Soft1 = 'Soft1';
+    Soft2 = 'Soft2';
+    Soft3 = 'Soft3';
+    Soft4 = 'Soft4';
+    Decimal = 'Decimal';
+    Key11 = 'Key11';
+    Key12 = 'Key12';
+    Multiply = 'Multiply';
+    Add = 'Add';
+    NumClear = 'Clear';
+    Divide = 'Divide';
+    Subtract = 'Subtract';
+    Separator = 'Separator';
+    AppSwitch = 'AppSwitch';
+    Call = 'Call';
+    Camera = 'Camera';
+    CameraFocus = 'CameraFocus';
+    EndCall = 'EndCall';
+    GoBack = 'GoBack';
+    GoHome = 'GoHome';
+    HeadsetHook = 'HeadsetHook';
+    LastNumberRedial = 'LastNumberRedial';
+    Notification = 'Notification';
+    MannerMode = 'MannerMode';
+    VoiceDial = 'VoiceDial';
+
+    // Multimedia keys
+    ChannelDown = 'ChannelDown';
+    ChannelUp = 'ChannelUp';
+    MediaFastForward = 'MediaFastForward';
+    MediaPause = 'MediaPause';
+    MediaPlay = 'MediaPlay';
+    MediaPlayPause = 'MediaPlayPause';
+    MediaRecord = 'MediaRecord';
+    MediaRewind = 'MediaRewind';
+    MediaStop = 'MediaStop';
+    MediaTrackNext = 'MediaTrackNext';
+    MediaTrackPrevious = 'MediaTrackPrevious';
+    // Audio control keys
+    AudioBalanceLeft = 'AudioBalanceLeft';
+    AudioBalanceRight = 'AudioBalanceRight';
+    AudioBassDown = 'AudioBassDown';
+    AudioBassBoostDown = 'AudioBassBoostDown';
+    AudioBassBoostToggle = 'AudioBassBoostToggle';
+    AudioBassBoostUp = 'AudioBassBoostUp';
+    AudioBassUp = 'AudioBassUp';
+    AudioFaderFront = 'AudioFaderFront';
+    AudioFaderRear = 'AudioFaderRear';
+    AudioSurroundModeNext = 'AudioSurroundModeNext';
+    AudioTrebleDown = 'AudioTrebleDown';
+    AudioTrebleUp = 'AudioTrebleUp';
+    AudioVolumeDown = 'AudioVolumeDown';
+    AudioVolumeMute = 'AudioVolumeMute';
+    AudioVolumeUp = 'AudioVolumeUp';
+    MicrophoneToggle = 'MicrophoneToggle';
+    MicrophoneVolumeDown = 'MicrophoneVolumeDown';
+    MicrophoneVolumeMute = 'MicrophoneVolumeMute';
+    MicrophoneVolumeUp = 'MicrophoneVolumeUp';
+    // TV Control keys
+    TV = 'TV';
+    TV3DMode = 'TV3DMode';
+    TVAntennaCable = 'TVAntennaCable';
+    TVAudioDescription = 'TVAudioDescription';
+    TVAudioDescriptionMixDown = 'TVAudioDescriptionMixDown';
+    TVAudioDescriptionMixUp = 'TVAudioDescriptionMixUp';
+    TVContentsMenu = 'TVContentsMenu';
+    TVDataService = 'TVDataService';
+    TVInput = 'TVInput';
+    TVInputComponent1 = 'TVInputComponent1';
+    TVInputComponent2 = 'TVInputComponent2';
+    TVInputComposite1 = 'TVInputComposite1';
+    TVInputComposite2 = 'TVInputComposite2';
+    TVInputHDMI1 = 'TVInputHDMI1';
+    TVInputHDMI2 = 'TVInputHDMI2';
+    TVInputHDMI3 = 'TVInputHDMI3';
+    TVInputHDMI4 = 'TVInputHDMI4';
+    TVInputVGA1 = 'TVInputVGA1';
+    TVMediaContext = 'TVMediaContext';
+    TVNetwork = 'TVNetwork';
+    TVNumberEntry = 'TVNumberEntry';
+    TVPower = 'TVPower';
+    TVRadioService = 'TVRadioService';
+    TVSatellite = 'TVSatellite';
+    TVSatelliteBS = 'TVSatelliteBS';
+    TVSatelliteCS = 'TVSatelliteCS';
+    TVSatelliteToggle = 'TVSatelliteToggle';
+    TVTerrestrialAnalog = 'TVTerrestrialAnalog';
+    TVTerrestrialDigital = 'TVTerrestrialDigital';
+    TVTimer = 'TVTimer';
+     // Media controller keys
+    AVRInput = 'AVRInput';
+    AVRPower = 'AVRPower';
+    ColorF0Red = 'ColorF0Red';
+    ColorF1Green = 'ColorF1Green';
+    ColorF2Yellow = 'ColorF2Yellow';
+    ColorF3Blue = 'ColorF3Blue';
+    ColorF4Grey = 'ColorF4Grey';
+    ColorF5Brown = 'ColorF5Brown';
+    ClosedCaptionToggle = 'ClosedCaptionToggle';
+    Dimmer = 'Dimmer';
+    DisplaySwap = 'DisplaySwap';
+    DVR = 'DVR';
+    Exit = 'Exit';
+    FavoriteClear0 = 'FavoriteClear0';
+    FavoriteClear1 = 'FavoriteClear1';
+    FavoriteClear2 = 'FavoriteClear2';
+    FavoriteClear3 = 'FavoriteClear3';
+    FavoriteRecall0 = 'FavoriteRecall0';
+    FavoriteRecall1 = 'FavoriteRecall1';
+    FavoriteRecall2 = 'FavoriteRecall2';
+    FavoriteRecall3 = 'FavoriteRecall3';
+    FavoriteStore0 = 'FavoriteStore0';
+    FavoriteStore1 = 'FavoriteStore1';
+    FavoriteStore2 = 'FavoriteStore2';
+    FavoriteStore3 = 'FavoriteStore3';
+    Guide = 'Guide';
+    GuideNextDay = 'GuideNextDay';
+    GuidePreviousDay = 'GuidePreviousDay';
+    Info = 'Info';
+    InstantReplay = 'InstantReplay';
+    Link = 'Link';
+    ListProgram = 'ListProgram';
+    LiveContent = 'LiveContent';
+    Lock = 'Lock';
+    MediaApps = 'MediaApps';
+    MediaAudioTrack = 'MediaAudioTrack';
+    MediaLast = 'MediaLast';
+    MediaSkipBackward = 'MediaSkipBackward';
+    MediaSkipForward = 'MediaSkipForward';
+    MediaStepBackward = 'MediaStepBackward';
+    MediaStepForward = 'MediaStepForward';
+    MediaTopMenu = 'MediaTopMenu';
+    NavigateIn = 'NavigateIn';
+    NavigateNext = 'NavigateNext';
+    NavigateOut = 'NavigateOut';
+    NavigatePrevious = 'NavigatePrevious';
+    NextFavoriteChannel = 'NextFavoriteChannel';
+    NextUserProfile = 'NextUserProfile';
+    OnDemand = 'OnDemand';
+    Pairing = 'Pairing';
+    PinPDown = 'PinPDown';
+    PinPMove = 'PinPMove';
+    PinPToggle = 'PinPToggle';
+    PinPUp = 'PinPUp';
+    PlaySpeedDown = 'PlaySpeedDown';
+    PlaySpeedReset = 'PlaySpeedReset';
+    PlaySpeedUp = 'PlaySpeedUp';
+    RandomToggle = 'RandomToggle';
+    RcLowBattery = 'RcLowBattery';
+    RecordSpeedNext = 'RecordSpeedNext';
+    RfBypass = 'RfBypass';
+    ScanChannelsToggle = 'ScanChannelsToggle';
+    ScreenModeNext = 'ScreenModeNext';
+    Settings = 'Settings';
+    SplitScreenToggle = 'SplitScreenToggle';
+    STBInput = 'STBInput';
+    STBPower = 'STBPower';
+    Subtitle = 'Subtitle';
+    Teletext = 'Teletext';
+    VideoModeNext = 'VideoModeNext';
+    Wink = 'Wink';
+    ZoomToggle = 'ZoomToggle';
+    // Speech recognition keys
+    SpeechCorrectionList = 'SpeechCorrectionList';
+    SpeechInputToggle = 'SpeechInputToggle';
+
+    // Document keys
+    Close = 'Close';
+    New = 'New';
+    Open = 'Open';
+    Print = 'Print';
+    Save = 'Save';
+    SpellCheck = 'SpellCheck';
+    MailForward = 'MailForward';
+    MailReply = 'MailReply';
+    MailSend = 'MailSend';
+    // Application selector keys
+    LaunchCalculator = 'LaunchCalculator';
+    LaunchCalendar = 'LaunchCalendar';
+    LaunchContacts = 'LaunchContacts';
+    LaunchMail = 'LaunchMail';
+    LaunchMediaPlayer = 'LaunchMediaPlayer';
+    LaunchMusicPlayer = 'LaunchMusicPlayer';
+    LaunchMyComputer = 'LaunchMyComputer';
+    LaunchPhone = 'LaunchPhone';
+    LaunchScreenSaver = 'LaunchScreenSaver';
+    LaunchSpreadsheet = 'LaunchSpreadsheet';
+    LaunchWebBrowser = 'LaunchWebBrowser';
+    LaunchWebCam = 'LaunchWebCam';
+    LaunchWordProcessor = 'LaunchWordProcessor';
+    LaunchApplication1 = 'LaunchApplication1';
+    LaunchApplication2 = 'LaunchApplication2';
+    LaunchApplication3 = 'LaunchApplication3';
+    LaunchApplication4 = 'LaunchApplication4';
+    LaunchApplication5 = 'LaunchApplication5';
+    LaunchApplication6 = 'LaunchApplication6';
+    LaunchApplication7 = 'LaunchApplication7';
+    LaunchApplication8 = 'LaunchApplication8';
+    LaunchApplication9 = 'LaunchApplication9';
+    LaunchApplication10 = 'LaunchApplication10';
+    LaunchApplication11 = 'LaunchApplication11';
+    LaunchApplication12 = 'LaunchApplication12';
+    LaunchApplication13 = 'LaunchApplication13';
+    LaunchApplication14 = 'LaunchApplication14';
+    LaunchApplication15 = 'LaunchApplication15';
+    LaunchApplication16 = 'LaunchApplication16';
+
+     // Browser Control keys
+    BrowserBack = 'BrowserBack';
+    BrowserFavorites = 'BrowserFavorites';
+    BrowserForward = 'BrowserForward';
+    BrowserHome = 'BrowserHome';
+    BrowserRefresh = 'BrowserRefresh';
+    BrowserSearch = 'BrowserSearch';
+    BrowserStop = 'BrowserStop';
+  end;
+
+  TKeyCodes = Record
+  Const
+    // Specials...
+    SpecialKeysOffset          = -1024;
+    // DoStart
+    Alt                        = SpecialKeysOffset - 0000;
+    AltGraph                   = SpecialKeysOffset - 0001;
+    CapsLock                   = SpecialKeysOffset - 0002;
+    Control                    = SpecialKeysOffset - 0003;
+    Fn                         = SpecialKeysOffset - 0004;
+    FnLock                     = SpecialKeysOffset - 0005;
+    Hyper                      = SpecialKeysOffset - 0006;
+    Meta                       = SpecialKeysOffset - 0007;
+    NumLock                    = SpecialKeysOffset - 0008;
+    ScrollLock                 = SpecialKeysOffset - 0009;
+    Shift                      = SpecialKeysOffset - 0010;
+    Super                      = SpecialKeysOffset - 0011;
+    Symbol                     = SpecialKeysOffset - 0012;
+    SymbolLock                 = SpecialKeysOffset - 0013;
+    Enter                      = SpecialKeysOffset - 0014;
+    Tab                        = SpecialKeysOffset - 0015;
+    Space                      = SpecialKeysOffset - 0016;
+    ArrowDown                  = SpecialKeysOffset - 0017;
+    ArrowLeft                  = SpecialKeysOffset - 0018;
+    ArrowRight                 = SpecialKeysOffset - 0019;
+    ArrowUp                    = SpecialKeysOffset - 0020;
+    End_                       = SpecialKeysOffset - 0021;
+    Home                       = SpecialKeysOffset - 0022;
+    PageDown                   = SpecialKeysOffset - 0023;
+    PageUp                     = SpecialKeysOffset - 0024;
+    BackSpace                  = SpecialKeysOffset - 0025;
+    Clear                      = SpecialKeysOffset - 0026;
+    Copy                       = SpecialKeysOffset - 0027;
+    CrSel                      = SpecialKeysOffset - 0028;
+    Cut                        = SpecialKeysOffset - 0029;
+    Delete                     = SpecialKeysOffset - 0030;
+    EraseEof                   = SpecialKeysOffset - 0031;
+    ExSel                      = SpecialKeysOffset - 0032;
+    Insert                     = SpecialKeysOffset - 0033;
+    Paste                      = SpecialKeysOffset - 0034;
+    Redo                       = SpecialKeysOffset - 0035;
+    Undo                       = SpecialKeysOffset - 0036;
+    Accept                     = SpecialKeysOffset - 0037;
+    Again                      = SpecialKeysOffset - 0038;
+    Attn                       = SpecialKeysOffset - 0039;
+    Cancel                     = SpecialKeysOffset - 0040;
+    ContextMenu                = SpecialKeysOffset - 0041;
+    Escape                     = SpecialKeysOffset - 0042;
+    Execute                    = SpecialKeysOffset - 0043;
+    Find                       = SpecialKeysOffset - 0044;
+    Finish                     = SpecialKeysOffset - 0045;
+    Help                       = SpecialKeysOffset - 0046;
+    Pause                      = SpecialKeysOffset - 0047;
+    Play                       = SpecialKeysOffset - 0048;
+    Props                      = SpecialKeysOffset - 0049;
+    Select                     = SpecialKeysOffset - 0050;
+    ZoomIn                     = SpecialKeysOffset - 0051;
+    ZoomOut                    = SpecialKeysOffset - 0052;
+    BrightnessDown             = SpecialKeysOffset - 0053;
+    BrightnessUp               = SpecialKeysOffset - 0054;
+    Eject                      = SpecialKeysOffset - 0055;
+    LogOff                     = SpecialKeysOffset - 0056;
+    Power                      = SpecialKeysOffset - 0057;
+    PowerOff                   = SpecialKeysOffset - 0058;
+    PrintScreen                = SpecialKeysOffset - 0059;
+    Hibernate                  = SpecialKeysOffset - 0060;
+    Standby                    = SpecialKeysOffset - 0061;
+    WakeUp                     = SpecialKeysOffset - 0062;
+    AllCandidates              = SpecialKeysOffset - 0063;
+    Alphanumeric               = SpecialKeysOffset - 0064;
+    CodeInput                  = SpecialKeysOffset - 0065;
+    Compose                    = SpecialKeysOffset - 0066;
+    Convert                    = SpecialKeysOffset - 0067;
+    Dead                       = SpecialKeysOffset - 0068;
+    FinalMode                  = SpecialKeysOffset - 0069;
+    GroupFirst                 = SpecialKeysOffset - 0070;
+    GroupLast                  = SpecialKeysOffset - 0071;
+    GroupNext                  = SpecialKeysOffset - 0072;
+    GroupPrevious              = SpecialKeysOffset - 0073;
+    ModeChange                 = SpecialKeysOffset - 0074;
+    NextCandidate              = SpecialKeysOffset - 0075;
+    NonConvert                 = SpecialKeysOffset - 0076;
+    PreviousCandidate          = SpecialKeysOffset - 0077;
+    Process                    = SpecialKeysOffset - 0078;
+    SingleCandidate            = SpecialKeysOffset - 0079;
+    HangulMode                 = SpecialKeysOffset - 0080;
+    HanjaMode                  = SpecialKeysOffset - 0081;
+    JunjaMode                  = SpecialKeysOffset - 0082;
+    Eisu                       = SpecialKeysOffset - 0083;
+    Hankaku                    = SpecialKeysOffset - 0084;
+    Hiranga                    = SpecialKeysOffset - 0085;
+    HirangaKatakana            = SpecialKeysOffset - 0086;
+    KanaMode                   = SpecialKeysOffset - 0087;
+    Katakana                   = SpecialKeysOffset - 0088;
+    Romaji                     = SpecialKeysOffset - 0089;
+    Zenkaku                    = SpecialKeysOffset - 0090;
+    ZenkakuHanaku              = SpecialKeysOffset - 0091;
+    F1                         = SpecialKeysOffset - 0092;
+    F2                         = SpecialKeysOffset - 0093;
+    F3                         = SpecialKeysOffset - 0094;
+    F4                         = SpecialKeysOffset - 0095;
+    F5                         = SpecialKeysOffset - 0096;
+    F6                         = SpecialKeysOffset - 0097;
+    F7                         = SpecialKeysOffset - 0098;
+    F8                         = SpecialKeysOffset - 0099;
+    F9                         = SpecialKeysOffset - 0100;
+    F10                        = SpecialKeysOffset - 0101;
+    F11                        = SpecialKeysOffset - 0102;
+    F12                        = SpecialKeysOffset - 0103;
+    F13                        = SpecialKeysOffset - 0104;
+    F14                        = SpecialKeysOffset - 0105;
+    F15                        = SpecialKeysOffset - 0106;
+    F16                        = SpecialKeysOffset - 0107;
+    F17                        = SpecialKeysOffset - 0108;
+    F18                        = SpecialKeysOffset - 0109;
+    F19                        = SpecialKeysOffset - 0110;
+    F20                        = SpecialKeysOffset - 0111;
+    Soft1                      = SpecialKeysOffset - 0112;
+    Soft2                      = SpecialKeysOffset - 0113;
+    Soft3                      = SpecialKeysOffset - 0114;
+    Soft4                      = SpecialKeysOffset - 0115;
+    Decimal                    = SpecialKeysOffset - 0116;
+    Key11                      = SpecialKeysOffset - 0117;
+    Key12                      = SpecialKeysOffset - 0118;
+    Multiply                   = SpecialKeysOffset - 0119;
+    Add                        = SpecialKeysOffset - 0120;
+    NumClear                   = SpecialKeysOffset - 0121;
+    Divide                     = SpecialKeysOffset - 0122;
+    Subtract                   = SpecialKeysOffset - 0123;
+    Separator                  = SpecialKeysOffset - 0124;
+    AppSwitch                  = SpecialKeysOffset - 0125;
+    Call                       = SpecialKeysOffset - 0126;
+    Camera                     = SpecialKeysOffset - 0127;
+    CameraFocus                = SpecialKeysOffset - 0128;
+    EndCall                    = SpecialKeysOffset - 0129;
+    GoBack                     = SpecialKeysOffset - 0130;
+    GoHome                     = SpecialKeysOffset - 0131;
+    HeadsetHook                = SpecialKeysOffset - 0132;
+    LastNumberRedial           = SpecialKeysOffset - 0133;
+    Notification               = SpecialKeysOffset - 0134;
+    MannerMode                 = SpecialKeysOffset - 0135;
+    VoiceDial                  = SpecialKeysOffset - 0136;
+
+    // Multimedia keys
+    ChannelDown                = SpecialKeysOffset - 0137;
+    ChannelUp                  = SpecialKeysOffset - 0138;
+    MediaFastForward           = SpecialKeysOffset - 0139;
+    MediaPause                 = SpecialKeysOffset - 0140;
+    MediaPlay                  = SpecialKeysOffset - 0141;
+    MediaPlayPause             = SpecialKeysOffset - 0142;
+    MediaRecord                = SpecialKeysOffset - 0143;
+    MediaRewind                = SpecialKeysOffset - 0144;
+    MediaStop                  = SpecialKeysOffset - 0145;
+    MediaTrackNext             = SpecialKeysOffset - 0146;
+    MediaTrackPrevious         = SpecialKeysOffset - 0147;
+    // Audio control keys
+    AudioBalanceLeft           = SpecialKeysOffset - 0148;
+    AudioBalanceRight          = SpecialKeysOffset - 0149;
+    AudioBassDown              = SpecialKeysOffset - 0150;
+    AudioBassBoostDown         = SpecialKeysOffset - 0151;
+    AudioBassBoostToggle       = SpecialKeysOffset - 0152;
+    AudioBassBoostUp           = SpecialKeysOffset - 0153;
+    AudioBassUp                = SpecialKeysOffset - 0154;
+    AudioFaderFront            = SpecialKeysOffset - 0155;
+    AudioFaderRear             = SpecialKeysOffset - 0156;
+    AudioSurroundModeNext      = SpecialKeysOffset - 0157;
+    AudioTrebleDown            = SpecialKeysOffset - 0158;
+    AudioTrebleUp              = SpecialKeysOffset - 0159;
+    AudioVolumeDown            = SpecialKeysOffset - 0160;
+    AudioVolumeMute            = SpecialKeysOffset - 0161;
+    AudioVolumeUp              = SpecialKeysOffset - 0162;
+    MicrophoneToggle           = SpecialKeysOffset - 0163;
+    MicrophoneVolumeDown       = SpecialKeysOffset - 0164;
+    MicrophoneVolumeMute       = SpecialKeysOffset - 0165;
+    MicrophoneVolumeUp         = SpecialKeysOffset - 0166;
+    // TV Control keys
+    TV                         = SpecialKeysOffset - 0167;
+    TV3DMode                   = SpecialKeysOffset - 0168;
+    TVAntennaCable             = SpecialKeysOffset - 0169;
+    TVAudioDescription         = SpecialKeysOffset - 0170;
+    TVAudioDescriptionMixDown  = SpecialKeysOffset - 0171;
+    TVAudioDescriptionMixUp    = SpecialKeysOffset - 0172;
+    TVContentsMenu             = SpecialKeysOffset - 0173;
+    TVDataService              = SpecialKeysOffset - 0174;
+    TVInput                    = SpecialKeysOffset - 0175;
+    TVInputComponent1          = SpecialKeysOffset - 0176;
+    TVInputComponent2          = SpecialKeysOffset - 0177;
+    TVInputComposite1          = SpecialKeysOffset - 0178;
+    TVInputComposite2          = SpecialKeysOffset - 0179;
+    TVInputHDMI1               = SpecialKeysOffset - 0180;
+    TVInputHDMI2               = SpecialKeysOffset - 0181;
+    TVInputHDMI3               = SpecialKeysOffset - 0182;
+    TVInputHDMI4               = SpecialKeysOffset - 0183;
+    TVInputVGA1                = SpecialKeysOffset - 0184;
+    TVMediaContext             = SpecialKeysOffset - 0185;
+    TVNetwork                  = SpecialKeysOffset - 0186;
+    TVNumberEntry              = SpecialKeysOffset - 0187;
+    TVPower                    = SpecialKeysOffset - 0188;
+    TVRadioService             = SpecialKeysOffset - 0189;
+    TVSatellite                = SpecialKeysOffset - 0190;
+    TVSatelliteBS              = SpecialKeysOffset - 0191;
+    TVSatelliteCS              = SpecialKeysOffset - 0192;
+    TVSatelliteToggle          = SpecialKeysOffset - 0193;
+    TVTerrestrialAnalog        = SpecialKeysOffset - 0194;
+    TVTerrestrialDigital       = SpecialKeysOffset - 0195;
+    TVTimer                    = SpecialKeysOffset - 0196;
+     // Media controller keys
+    AVRInput                   = SpecialKeysOffset - 0197;
+    AVRPower                   = SpecialKeysOffset - 0198;
+    ColorF0Red                 = SpecialKeysOffset - 0199;
+    ColorF1Green               = SpecialKeysOffset - 0200;
+    ColorF2Yellow              = SpecialKeysOffset - 0201;
+    ColorF3Blue                = SpecialKeysOffset - 0202;
+    ColorF4Grey                = SpecialKeysOffset - 0203;
+    ColorF5Brown               = SpecialKeysOffset - 0204;
+    ClosedCaptionToggle        = SpecialKeysOffset - 0205;
+    Dimmer                     = SpecialKeysOffset - 0206;
+    DisplaySwap                = SpecialKeysOffset - 0207;
+    DVR                        = SpecialKeysOffset - 0208;
+    Exit                       = SpecialKeysOffset - 0209;
+    FavoriteClear0             = SpecialKeysOffset - 0210;
+    FavoriteClear1             = SpecialKeysOffset - 0211;
+    FavoriteClear2             = SpecialKeysOffset - 0212;
+    FavoriteClear3             = SpecialKeysOffset - 0213;
+    FavoriteRecall0            = SpecialKeysOffset - 0214;
+    FavoriteRecall1            = SpecialKeysOffset - 0215;
+    FavoriteRecall2            = SpecialKeysOffset - 0216;
+    FavoriteRecall3            = SpecialKeysOffset - 0217;
+    FavoriteStore0             = SpecialKeysOffset - 0218;
+    FavoriteStore1             = SpecialKeysOffset - 0219;
+    FavoriteStore2             = SpecialKeysOffset - 0220;
+    FavoriteStore3             = SpecialKeysOffset - 0221;
+    Guide                      = SpecialKeysOffset - 0222;
+    GuideNextDay               = SpecialKeysOffset - 0223;
+    GuidePreviousDay           = SpecialKeysOffset - 0224;
+    Info                       = SpecialKeysOffset - 0225;
+    InstantReplay              = SpecialKeysOffset - 0226;
+    Link                       = SpecialKeysOffset - 0227;
+    ListProgram                = SpecialKeysOffset - 0228;
+    LiveContent                = SpecialKeysOffset - 0229;
+    Lock                       = SpecialKeysOffset - 0230;
+    MediaApps                  = SpecialKeysOffset - 0231;
+    MediaAudioTrack            = SpecialKeysOffset - 0232;
+    MediaLast                  = SpecialKeysOffset - 0233;
+    MediaSkipBackward          = SpecialKeysOffset - 0234;
+    MediaSkipForward           = SpecialKeysOffset - 0235;
+    MediaStepBackward          = SpecialKeysOffset - 0236;
+    MediaStepForward           = SpecialKeysOffset - 0237;
+    MediaTopMenu               = SpecialKeysOffset - 0238;
+    NavigateIn                 = SpecialKeysOffset - 0239;
+    NavigateNext               = SpecialKeysOffset - 0240;
+    NavigateOut                = SpecialKeysOffset - 0241;
+    NavigatePrevious           = SpecialKeysOffset - 0242;
+    NextFavoriteChannel        = SpecialKeysOffset - 0243;
+    NextUserProfile            = SpecialKeysOffset - 0244;
+    OnDemand                   = SpecialKeysOffset - 0245;
+    Pairing                    = SpecialKeysOffset - 0246;
+    PinPDown                   = SpecialKeysOffset - 0247;
+    PinPMove                   = SpecialKeysOffset - 0248;
+    PinPToggle                 = SpecialKeysOffset - 0249;
+    PinPUp                     = SpecialKeysOffset - 0250;
+    PlaySpeedDown              = SpecialKeysOffset - 0251;
+    PlaySpeedReset             = SpecialKeysOffset - 0252;
+    PlaySpeedUp                = SpecialKeysOffset - 0253;
+    RandomToggle               = SpecialKeysOffset - 0254;
+    RcLowBattery               = SpecialKeysOffset - 0255;
+    RecordSpeedNext            = SpecialKeysOffset - 0256;
+    RfBypass                   = SpecialKeysOffset - 0257;
+    ScanChannelsToggle         = SpecialKeysOffset - 0258;
+    ScreenModeNext             = SpecialKeysOffset - 0259;
+    Settings                   = SpecialKeysOffset - 0260;
+    SplitScreenToggle          = SpecialKeysOffset - 0261;
+    STBInput                   = SpecialKeysOffset - 0262;
+    STBPower                   = SpecialKeysOffset - 0263;
+    Subtitle                   = SpecialKeysOffset - 0264;
+    Teletext                   = SpecialKeysOffset - 0265;
+    VideoModeNext              = SpecialKeysOffset - 0266;
+    Wink                       = SpecialKeysOffset - 0267;
+    ZoomToggle                 = SpecialKeysOffset - 0268;
+    // Speech recognition keys
+    SpeechCorrectionList       = SpecialKeysOffset - 0269;
+    SpeechInputToggle          = SpecialKeysOffset - 0270;
+
+    // Document keys
+    Close                      = SpecialKeysOffset - 0271;
+    New                        = SpecialKeysOffset - 0272;
+    Open                       = SpecialKeysOffset - 0273;
+    Print                      = SpecialKeysOffset - 0274;
+    Save                       = SpecialKeysOffset - 0275;
+    SpellCheck                 = SpecialKeysOffset - 0276;
+    MailForward                = SpecialKeysOffset - 0277;
+    MailReply                  = SpecialKeysOffset - 0278;
+    MailSend                   = SpecialKeysOffset - 0279;
+    // Application selector keys
+    LaunchCalculator           = SpecialKeysOffset - 0280;
+    LaunchCalendar             = SpecialKeysOffset - 0281;
+    LaunchContacts             = SpecialKeysOffset - 0282;
+    LaunchMail                 = SpecialKeysOffset - 0283;
+    LaunchMediaPlayer          = SpecialKeysOffset - 0284;
+    LaunchMusicPlayer          = SpecialKeysOffset - 0285;
+    LaunchMyComputer           = SpecialKeysOffset - 0286;
+    LaunchPhone                = SpecialKeysOffset - 0287;
+    LaunchScreenSaver          = SpecialKeysOffset - 0288;
+    LaunchSpreadsheet          = SpecialKeysOffset - 0289;
+    LaunchWebBrowser           = SpecialKeysOffset - 0290;
+    LaunchWebCam               = SpecialKeysOffset - 0291;
+    LaunchWordProcessor        = SpecialKeysOffset - 0292;
+    LaunchApplication1         = SpecialKeysOffset - 0293;
+    LaunchApplication2         = SpecialKeysOffset - 0294;
+    LaunchApplication3         = SpecialKeysOffset - 0295;
+    LaunchApplication4         = SpecialKeysOffset - 0296;
+    LaunchApplication5         = SpecialKeysOffset - 0297;
+    LaunchApplication6         = SpecialKeysOffset - 0298;
+    LaunchApplication7         = SpecialKeysOffset - 0299;
+    LaunchApplication8         = SpecialKeysOffset - 0300;
+    LaunchApplication9         = SpecialKeysOffset - 0301;
+    LaunchApplication10        = SpecialKeysOffset - 0302;
+    LaunchApplication11        = SpecialKeysOffset - 0303;
+    LaunchApplication12        = SpecialKeysOffset - 0304;
+    LaunchApplication13        = SpecialKeysOffset - 0305;
+    LaunchApplication14        = SpecialKeysOffset - 0306;
+    LaunchApplication15        = SpecialKeysOffset - 0307;
+    LaunchApplication16        = SpecialKeysOffset - 0308;
+
+     // Browser Control keys
+    BrowserBack                = SpecialKeysOffset - 0309;
+    BrowserFavorites           = SpecialKeysOffset - 0310;
+    BrowserForward             = SpecialKeysOffset - 0311;
+    BrowserHome                = SpecialKeysOffset - 0312;
+    BrowserRefresh             = SpecialKeysOffset - 0313;
+    BrowserSearch              = SpecialKeysOffset - 0314;
+    BrowserStop                = SpecialKeysOffset - 0315;
+
+    // Numeric keypad
+    Numpad0                    = SpecialKeysOffset - 0316;
+    Numpad1                    = SpecialKeysOffset - 0317;
+    Numpad2                    = SpecialKeysOffset - 0318;
+    Numpad3                    = SpecialKeysOffset - 0319;
+    Numpad4                    = SpecialKeysOffset - 0320;
+    Numpad5                    = SpecialKeysOffset - 0321;
+    Numpad6                    = SpecialKeysOffset - 0322;
+    Numpad7                    = SpecialKeysOffset - 0323;
+    Numpad8                    = SpecialKeysOffset - 0324;
+    Numpad9                    = SpecialKeysOffset - 0325;
+    NumpadMultiply             = SpecialKeysOffset - 0326;
+    NumpadAdd                  = SpecialKeysOffset - 0327;
+    NumpadSeparator            = SpecialKeysOffset - 0328;
+    NumpadSubtract             = SpecialKeysOffset - 0329;
+    NumpadDecimal              = SpecialKeysOffset - 0330;
+    NumpadDivide               = SpecialKeysOffset - 0331;
+
+
+    // Left/Right
+    LeftMeta                   = Meta;
+    LeftAlta                   = Alt;
+    LeftShift                  = Shift;
+    LeftControl                = Control;
+    RightMeta                  = SpecialKeysOffset - 0332;
+    RightAlt                   = SpecialKeysOffset - 0333;
+    RightShift                 = SpecialKeysOffset - 0334;
+    RightControl               = SpecialKeysOffset - 0335;
+
+    F21                        = SpecialKeysOffset - 0336;
+    F22                        = SpecialKeysOffset - 0337;
+    F23                        = SpecialKeysOffset - 0338;
+    F24                        = SpecialKeysOffset - 0339;
+  end;
+  TKeyCodeName = record
+    Code : Integer;
+    Name : string;
+  end;
+  TKeyCodeNameArray = Array of TKeyCodeName;
+
+  TEnumKeysCallback = Procedure(aCode : Integer; aName : string) of object;
+
+  TSpecialKeyEnumerator = class(TObject)
+  Protected
+    Procedure EnumKey(aCode : Integer; aName : string); virtual; abstract;
+  end;
+
+  { TCountSpecialKeys }
+
+  TCountSpecialKeys = class(TSpecialKeyEnumerator)
+  private
+    class var _cached_count : Integer;
+  private
+    FCount : integer;
+  Protected
+    Procedure EnumKey(aCode : Integer; aName : string); override;
+  public
+    class function GetCount : integer;
+  end;
+
+
+  { TSpecialKeysArrayCreator }
+
+  TSpecialKeysArrayCreator = class(TSpecialKeyEnumerator)
+  private
+    class var _keyarray : TKeyCodeNameArray;
+  private
+    FIdx : integer;
+    FArray : TKeyCodeNameArray;
+  Protected
+    Procedure EnumKey(aCode : Integer; aName : string); override;
+  public
+    class function GetArray : TKeyCodeNameArray;
+  end;
+
+
+procedure EnumSpecialKeys(aCallback : TEnumKeysCallback);
+function GetSpecialKeyCount : Integer;
+function GetSpecialKeyArray : TKeyCodeNameArray;
+
+implementation
+
+function GetSpecialKeyCount : Integer;
+
+begin
+  Result:=TCountSpecialKeys.GetCount;
+end;
+
+function GetSpecialKeyArray : TKeyCodeNameArray;
+
+begin
+  Result:=TSpecialKeysArrayCreator.GetArray;
+end;
+
+procedure EnumSpecialKeys(aCallback : TEnumKeysCallback);
+
+begin
+  aCallBack(TKeyCodes.Alt ,TKeyNames.Alt );
+  aCallBack(TKeyCodes.AltGraph ,TKeyNames.AltGraph );
+  aCallBack(TKeyCodes.CapsLock ,TKeyNames.CapsLock );
+  aCallBack(TKeyCodes.Control ,TKeyNames.Control );
+  aCallBack(TKeyCodes.Fn ,TKeyNames.Fn );
+  aCallBack(TKeyCodes.FnLock ,TKeyNames.FnLock );
+  aCallBack(TKeyCodes.Hyper ,TKeyNames.Hyper );
+  aCallBack(TKeyCodes.Meta ,TKeyNames.Meta );
+  aCallBack(TKeyCodes.NumLock ,TKeyNames.NumLock );
+  aCallBack(TKeyCodes.ScrollLock ,TKeyNames.ScrollLock );
+  aCallBack(TKeyCodes.Shift ,TKeyNames.Shift );
+  aCallBack(TKeyCodes.Super ,TKeyNames.Super );
+  aCallBack(TKeyCodes.Symbol ,TKeyNames.Symbol );
+  aCallBack(TKeyCodes.SymbolLock ,TKeyNames.SymbolLock );
+  aCallBack(TKeyCodes.Enter ,TKeyNames.Enter );
+  aCallBack(TKeyCodes.Tab ,TKeyNames.Tab );
+  aCallBack(TKeyCodes.Space ,TKeyNames.Space );
+  aCallBack(TKeyCodes.ArrowDown ,TKeyNames.ArrowDown );
+  aCallBack(TKeyCodes.ArrowLeft ,TKeyNames.ArrowLeft );
+  aCallBack(TKeyCodes.ArrowRight ,TKeyNames.ArrowRight );
+  aCallBack(TKeyCodes.ArrowUp ,TKeyNames.ArrowUp );
+  aCallBack(TKeyCodes.End_ ,TKeyNames.End_ );
+  aCallBack(TKeyCodes.Home ,TKeyNames.Home );
+  aCallBack(TKeyCodes.PageDown ,TKeyNames.PageDown );
+  aCallBack(TKeyCodes.PageUp ,TKeyNames.PageUp );
+  aCallBack(TKeyCodes.BackSpace ,TKeyNames.BackSpace );
+  aCallBack(TKeyCodes.Clear ,TKeyNames.Clear );
+  aCallBack(TKeyCodes.Copy ,TKeyNames.Copy );
+  aCallBack(TKeyCodes.CrSel ,TKeyNames.CrSel );
+  aCallBack(TKeyCodes.Cut ,TKeyNames.Cut );
+  aCallBack(TKeyCodes.Delete ,TKeyNames.Delete );
+  aCallBack(TKeyCodes.EraseEof ,TKeyNames.EraseEof );
+  aCallBack(TKeyCodes.ExSel ,TKeyNames.ExSel );
+  aCallBack(TKeyCodes.Insert ,TKeyNames.Insert );
+  aCallBack(TKeyCodes.Paste ,TKeyNames.Paste );
+  aCallBack(TKeyCodes.Redo ,TKeyNames.Redo );
+  aCallBack(TKeyCodes.Undo ,TKeyNames.Undo );
+  aCallBack(TKeyCodes.Accept ,TKeyNames.Accept );
+  aCallBack(TKeyCodes.Again ,TKeyNames.Again );
+  aCallBack(TKeyCodes.Attn ,TKeyNames.Attn );
+  aCallBack(TKeyCodes.Cancel ,TKeyNames.Cancel );
+  aCallBack(TKeyCodes.ContextMenu ,TKeyNames.ContextMenu );
+  aCallBack(TKeyCodes.Escape ,TKeyNames.Escape );
+  aCallBack(TKeyCodes.Execute ,TKeyNames.Execute );
+  aCallBack(TKeyCodes.Find ,TKeyNames.Find );
+  aCallBack(TKeyCodes.Finish ,TKeyNames.Finish );
+  aCallBack(TKeyCodes.Help ,TKeyNames.Help );
+  aCallBack(TKeyCodes.Pause ,TKeyNames.Pause );
+  aCallBack(TKeyCodes.Play ,TKeyNames.Play );
+  aCallBack(TKeyCodes.Props ,TKeyNames.Props );
+  aCallBack(TKeyCodes.Select ,TKeyNames.Select );
+  aCallBack(TKeyCodes.ZoomIn ,TKeyNames.ZoomIn );
+  aCallBack(TKeyCodes.ZoomOut ,TKeyNames.ZoomOut );
+  aCallBack(TKeyCodes.BrightnessDown ,TKeyNames.BrightnessDown );
+  aCallBack(TKeyCodes.BrightnessUp ,TKeyNames.BrightnessUp );
+  aCallBack(TKeyCodes.Eject ,TKeyNames.Eject );
+  aCallBack(TKeyCodes.LogOff ,TKeyNames.LogOff );
+  aCallBack(TKeyCodes.Power ,TKeyNames.Power );
+  aCallBack(TKeyCodes.PowerOff ,TKeyNames.PowerOff );
+  aCallBack(TKeyCodes.PrintScreen ,TKeyNames.PrintScreen );
+  aCallBack(TKeyCodes.Hibernate ,TKeyNames.Hibernate );
+  aCallBack(TKeyCodes.Standby ,TKeyNames.Standby );
+  aCallBack(TKeyCodes.WakeUp ,TKeyNames.WakeUp );
+  aCallBack(TKeyCodes.AllCandidates ,TKeyNames.AllCandidates );
+  aCallBack(TKeyCodes.Alphanumeric ,TKeyNames.Alphanumeric );
+  aCallBack(TKeyCodes.CodeInput ,TKeyNames.CodeInput );
+  aCallBack(TKeyCodes.Compose ,TKeyNames.Compose );
+  aCallBack(TKeyCodes.Convert ,TKeyNames.Convert );
+  aCallBack(TKeyCodes.Dead ,TKeyNames.Dead );
+  aCallBack(TKeyCodes.FinalMode ,TKeyNames.FinalMode );
+  aCallBack(TKeyCodes.GroupFirst ,TKeyNames.GroupFirst );
+  aCallBack(TKeyCodes.GroupLast ,TKeyNames.GroupLast );
+  aCallBack(TKeyCodes.GroupNext ,TKeyNames.GroupNext );
+  aCallBack(TKeyCodes.GroupPrevious ,TKeyNames.GroupPrevious );
+  aCallBack(TKeyCodes.ModeChange ,TKeyNames.ModeChange );
+  aCallBack(TKeyCodes.NextCandidate ,TKeyNames.NextCandidate );
+  aCallBack(TKeyCodes.NonConvert ,TKeyNames.NonConvert );
+  aCallBack(TKeyCodes.PreviousCandidate ,TKeyNames.PreviousCandidate );
+  aCallBack(TKeyCodes.Process ,TKeyNames.Process );
+  aCallBack(TKeyCodes.SingleCandidate ,TKeyNames.SingleCandidate );
+  aCallBack(TKeyCodes.HangulMode ,TKeyNames.HangulMode );
+  aCallBack(TKeyCodes.HanjaMode ,TKeyNames.HanjaMode );
+  aCallBack(TKeyCodes.JunjaMode ,TKeyNames.JunjaMode );
+  aCallBack(TKeyCodes.Eisu ,TKeyNames.Eisu );
+  aCallBack(TKeyCodes.Hankaku ,TKeyNames.Hankaku );
+  aCallBack(TKeyCodes.Hiranga ,TKeyNames.Hiranga );
+  aCallBack(TKeyCodes.HirangaKatakana ,TKeyNames.HirangaKatakana );
+  aCallBack(TKeyCodes.KanaMode ,TKeyNames.KanaMode );
+  aCallBack(TKeyCodes.Katakana ,TKeyNames.Katakana );
+  aCallBack(TKeyCodes.Romaji ,TKeyNames.Romaji );
+  aCallBack(TKeyCodes.Zenkaku ,TKeyNames.Zenkaku );
+  aCallBack(TKeyCodes.ZenkakuHanaku ,TKeyNames.ZenkakuHanaku );
+  aCallBack(TKeyCodes.F1 ,TKeyNames.F1 );
+  aCallBack(TKeyCodes.F2 ,TKeyNames.F2 );
+  aCallBack(TKeyCodes.F3 ,TKeyNames.F3 );
+  aCallBack(TKeyCodes.F4 ,TKeyNames.F4 );
+  aCallBack(TKeyCodes.F5 ,TKeyNames.F5 );
+  aCallBack(TKeyCodes.F6 ,TKeyNames.F6 );
+  aCallBack(TKeyCodes.F7 ,TKeyNames.F7 );
+  aCallBack(TKeyCodes.F8 ,TKeyNames.F8 );
+  aCallBack(TKeyCodes.F9 ,TKeyNames.F9 );
+  aCallBack(TKeyCodes.F10 ,TKeyNames.F10 );
+  aCallBack(TKeyCodes.F11 ,TKeyNames.F11 );
+  aCallBack(TKeyCodes.F12 ,TKeyNames.F12 );
+  aCallBack(TKeyCodes.F13 ,TKeyNames.F13 );
+  aCallBack(TKeyCodes.F14 ,TKeyNames.F14 );
+  aCallBack(TKeyCodes.F15 ,TKeyNames.F15 );
+  aCallBack(TKeyCodes.F16 ,TKeyNames.F16 );
+  aCallBack(TKeyCodes.F17 ,TKeyNames.F17 );
+  aCallBack(TKeyCodes.F18 ,TKeyNames.F18 );
+  aCallBack(TKeyCodes.F19 ,TKeyNames.F19 );
+  aCallBack(TKeyCodes.F20 ,TKeyNames.F20 );
+  aCallBack(TKeyCodes.Soft1 ,TKeyNames.Soft1 );
+  aCallBack(TKeyCodes.Soft2 ,TKeyNames.Soft2 );
+  aCallBack(TKeyCodes.Soft3 ,TKeyNames.Soft3 );
+  aCallBack(TKeyCodes.Soft4 ,TKeyNames.Soft4 );
+  aCallBack(TKeyCodes.Decimal ,TKeyNames.Decimal );
+  aCallBack(TKeyCodes.Key11 ,TKeyNames.Key11 );
+  aCallBack(TKeyCodes.Key12 ,TKeyNames.Key12 );
+  aCallBack(TKeyCodes.Multiply ,TKeyNames.Multiply );
+  aCallBack(TKeyCodes.Add ,TKeyNames.Add );
+  aCallBack(TKeyCodes.NumClear ,TKeyNames.NumClear );
+  aCallBack(TKeyCodes.Divide ,TKeyNames.Divide );
+  aCallBack(TKeyCodes.Subtract ,TKeyNames.Subtract );
+  aCallBack(TKeyCodes.Separator ,TKeyNames.Separator );
+  aCallBack(TKeyCodes.AppSwitch ,TKeyNames.AppSwitch );
+  aCallBack(TKeyCodes.Call ,TKeyNames.Call );
+  aCallBack(TKeyCodes.Camera ,TKeyNames.Camera );
+  aCallBack(TKeyCodes.CameraFocus ,TKeyNames.CameraFocus );
+  aCallBack(TKeyCodes.EndCall ,TKeyNames.EndCall );
+  aCallBack(TKeyCodes.GoBack ,TKeyNames.GoBack );
+  aCallBack(TKeyCodes.GoHome ,TKeyNames.GoHome );
+  aCallBack(TKeyCodes.HeadsetHook ,TKeyNames.HeadsetHook );
+  aCallBack(TKeyCodes.LastNumberRedial ,TKeyNames.LastNumberRedial );
+  aCallBack(TKeyCodes.Notification ,TKeyNames.Notification );
+  aCallBack(TKeyCodes.MannerMode ,TKeyNames.MannerMode );
+  aCallBack(TKeyCodes.VoiceDial ,TKeyNames.VoiceDial );
+  aCallBack(TKeyCodes.ChannelDown ,TKeyNames.ChannelDown );
+  aCallBack(TKeyCodes.ChannelUp ,TKeyNames.ChannelUp );
+  aCallBack(TKeyCodes.MediaFastForward ,TKeyNames.MediaFastForward );
+  aCallBack(TKeyCodes.MediaPause ,TKeyNames.MediaPause );
+  aCallBack(TKeyCodes.MediaPlay ,TKeyNames.MediaPlay );
+  aCallBack(TKeyCodes.MediaPlayPause ,TKeyNames.MediaPlayPause );
+  aCallBack(TKeyCodes.MediaRecord ,TKeyNames.MediaRecord );
+  aCallBack(TKeyCodes.MediaRewind ,TKeyNames.MediaRewind );
+  aCallBack(TKeyCodes.MediaStop ,TKeyNames.MediaStop );
+  aCallBack(TKeyCodes.MediaTrackNext ,TKeyNames.MediaTrackNext );
+  aCallBack(TKeyCodes.MediaTrackPrevious ,TKeyNames.MediaTrackPrevious );
+  aCallBack(TKeyCodes.AudioBalanceLeft ,TKeyNames.AudioBalanceLeft );
+  aCallBack(TKeyCodes.AudioBalanceRight ,TKeyNames.AudioBalanceRight );
+  aCallBack(TKeyCodes.AudioBassDown ,TKeyNames.AudioBassDown );
+  aCallBack(TKeyCodes.AudioBassBoostDown ,TKeyNames.AudioBassBoostDown );
+  aCallBack(TKeyCodes.AudioBassBoostToggle ,TKeyNames.AudioBassBoostToggle );
+  aCallBack(TKeyCodes.AudioBassBoostUp ,TKeyNames.AudioBassBoostUp );
+  aCallBack(TKeyCodes.AudioBassUp ,TKeyNames.AudioBassUp );
+  aCallBack(TKeyCodes.AudioFaderFront ,TKeyNames.AudioFaderFront );
+  aCallBack(TKeyCodes.AudioFaderRear ,TKeyNames.AudioFaderRear );
+  aCallBack(TKeyCodes.AudioSurroundModeNext ,TKeyNames.AudioSurroundModeNext );
+  aCallBack(TKeyCodes.AudioTrebleDown ,TKeyNames.AudioTrebleDown );
+  aCallBack(TKeyCodes.AudioTrebleUp ,TKeyNames.AudioTrebleUp );
+  aCallBack(TKeyCodes.AudioVolumeDown ,TKeyNames.AudioVolumeDown );
+  aCallBack(TKeyCodes.AudioVolumeMute ,TKeyNames.AudioVolumeMute );
+  aCallBack(TKeyCodes.AudioVolumeUp ,TKeyNames.AudioVolumeUp );
+  aCallBack(TKeyCodes.MicrophoneToggle ,TKeyNames.MicrophoneToggle );
+  aCallBack(TKeyCodes.MicrophoneVolumeDown ,TKeyNames.MicrophoneVolumeDown );
+  aCallBack(TKeyCodes.MicrophoneVolumeMute ,TKeyNames.MicrophoneVolumeMute );
+  aCallBack(TKeyCodes.MicrophoneVolumeUp ,TKeyNames.MicrophoneVolumeUp );
+  aCallBack(TKeyCodes.TV ,TKeyNames.TV );
+  aCallBack(TKeyCodes.TV3DMode ,TKeyNames.TV3DMode );
+  aCallBack(TKeyCodes.TVAntennaCable ,TKeyNames.TVAntennaCable );
+  aCallBack(TKeyCodes.TVAudioDescription ,TKeyNames.TVAudioDescription );
+  aCallBack(TKeyCodes.TVAudioDescriptionMixDown ,TKeyNames.TVAudioDescriptionMixDown );
+  aCallBack(TKeyCodes.TVAudioDescriptionMixUp ,TKeyNames.TVAudioDescriptionMixUp );
+  aCallBack(TKeyCodes.TVContentsMenu ,TKeyNames.TVContentsMenu );
+  aCallBack(TKeyCodes.TVDataService ,TKeyNames.TVDataService );
+  aCallBack(TKeyCodes.TVInput ,TKeyNames.TVInput );
+  aCallBack(TKeyCodes.TVInputComponent1 ,TKeyNames.TVInputComponent1 );
+  aCallBack(TKeyCodes.TVInputComponent2 ,TKeyNames.TVInputComponent2 );
+  aCallBack(TKeyCodes.TVInputComposite1 ,TKeyNames.TVInputComposite1 );
+  aCallBack(TKeyCodes.TVInputComposite2 ,TKeyNames.TVInputComposite2 );
+  aCallBack(TKeyCodes.TVInputHDMI1 ,TKeyNames.TVInputHDMI1 );
+  aCallBack(TKeyCodes.TVInputHDMI2 ,TKeyNames.TVInputHDMI2 );
+  aCallBack(TKeyCodes.TVInputHDMI3 ,TKeyNames.TVInputHDMI3 );
+  aCallBack(TKeyCodes.TVInputHDMI4 ,TKeyNames.TVInputHDMI4 );
+  aCallBack(TKeyCodes.TVInputVGA1 ,TKeyNames.TVInputVGA1 );
+  aCallBack(TKeyCodes.TVMediaContext ,TKeyNames.TVMediaContext );
+  aCallBack(TKeyCodes.TVNetwork ,TKeyNames.TVNetwork );
+  aCallBack(TKeyCodes.TVNumberEntry ,TKeyNames.TVNumberEntry );
+  aCallBack(TKeyCodes.TVPower ,TKeyNames.TVPower );
+  aCallBack(TKeyCodes.TVRadioService ,TKeyNames.TVRadioService );
+  aCallBack(TKeyCodes.TVSatellite ,TKeyNames.TVSatellite );
+  aCallBack(TKeyCodes.TVSatelliteBS ,TKeyNames.TVSatelliteBS );
+  aCallBack(TKeyCodes.TVSatelliteCS ,TKeyNames.TVSatelliteCS );
+  aCallBack(TKeyCodes.TVSatelliteToggle ,TKeyNames.TVSatelliteToggle );
+  aCallBack(TKeyCodes.TVTerrestrialAnalog ,TKeyNames.TVTerrestrialAnalog );
+  aCallBack(TKeyCodes.TVTerrestrialDigital ,TKeyNames.TVTerrestrialDigital );
+  aCallBack(TKeyCodes.TVTimer ,TKeyNames.TVTimer );
+  aCallBack(TKeyCodes.AVRInput ,TKeyNames.AVRInput );
+  aCallBack(TKeyCodes.AVRPower ,TKeyNames.AVRPower );
+  aCallBack(TKeyCodes.ColorF0Red ,TKeyNames.ColorF0Red );
+  aCallBack(TKeyCodes.ColorF1Green ,TKeyNames.ColorF1Green );
+  aCallBack(TKeyCodes.ColorF2Yellow ,TKeyNames.ColorF2Yellow );
+  aCallBack(TKeyCodes.ColorF3Blue ,TKeyNames.ColorF3Blue );
+  aCallBack(TKeyCodes.ColorF4Grey ,TKeyNames.ColorF4Grey );
+  aCallBack(TKeyCodes.ColorF5Brown ,TKeyNames.ColorF5Brown );
+  aCallBack(TKeyCodes.ClosedCaptionToggle ,TKeyNames.ClosedCaptionToggle );
+  aCallBack(TKeyCodes.Dimmer ,TKeyNames.Dimmer );
+  aCallBack(TKeyCodes.DisplaySwap ,TKeyNames.DisplaySwap );
+  aCallBack(TKeyCodes.DVR ,TKeyNames.DVR );
+  aCallBack(TKeyCodes.Exit ,TKeyNames.Exit );
+  aCallBack(TKeyCodes.FavoriteClear0 ,TKeyNames.FavoriteClear0 );
+  aCallBack(TKeyCodes.FavoriteClear1 ,TKeyNames.FavoriteClear1 );
+  aCallBack(TKeyCodes.FavoriteClear2 ,TKeyNames.FavoriteClear2 );
+  aCallBack(TKeyCodes.FavoriteClear3 ,TKeyNames.FavoriteClear3 );
+  aCallBack(TKeyCodes.FavoriteRecall0 ,TKeyNames.FavoriteRecall0 );
+  aCallBack(TKeyCodes.FavoriteRecall1 ,TKeyNames.FavoriteRecall1 );
+  aCallBack(TKeyCodes.FavoriteRecall2 ,TKeyNames.FavoriteRecall2 );
+  aCallBack(TKeyCodes.FavoriteRecall3 ,TKeyNames.FavoriteRecall3 );
+  aCallBack(TKeyCodes.FavoriteStore0 ,TKeyNames.FavoriteStore0 );
+  aCallBack(TKeyCodes.FavoriteStore1 ,TKeyNames.FavoriteStore1 );
+  aCallBack(TKeyCodes.FavoriteStore2 ,TKeyNames.FavoriteStore2 );
+  aCallBack(TKeyCodes.FavoriteStore3 ,TKeyNames.FavoriteStore3 );
+  aCallBack(TKeyCodes.Guide ,TKeyNames.Guide );
+  aCallBack(TKeyCodes.GuideNextDay ,TKeyNames.GuideNextDay );
+  aCallBack(TKeyCodes.GuidePreviousDay ,TKeyNames.GuidePreviousDay );
+  aCallBack(TKeyCodes.Info ,TKeyNames.Info );
+  aCallBack(TKeyCodes.InstantReplay ,TKeyNames.InstantReplay );
+  aCallBack(TKeyCodes.Link ,TKeyNames.Link );
+  aCallBack(TKeyCodes.ListProgram ,TKeyNames.ListProgram );
+  aCallBack(TKeyCodes.LiveContent ,TKeyNames.LiveContent );
+  aCallBack(TKeyCodes.Lock ,TKeyNames.Lock );
+  aCallBack(TKeyCodes.MediaApps ,TKeyNames.MediaApps );
+  aCallBack(TKeyCodes.MediaAudioTrack ,TKeyNames.MediaAudioTrack );
+  aCallBack(TKeyCodes.MediaLast ,TKeyNames.MediaLast );
+  aCallBack(TKeyCodes.MediaSkipBackward ,TKeyNames.MediaSkipBackward );
+  aCallBack(TKeyCodes.MediaSkipForward ,TKeyNames.MediaSkipForward );
+  aCallBack(TKeyCodes.MediaStepBackward ,TKeyNames.MediaStepBackward );
+  aCallBack(TKeyCodes.MediaStepForward ,TKeyNames.MediaStepForward );
+  aCallBack(TKeyCodes.MediaTopMenu ,TKeyNames.MediaTopMenu );
+  aCallBack(TKeyCodes.NavigateIn ,TKeyNames.NavigateIn );
+  aCallBack(TKeyCodes.NavigateNext ,TKeyNames.NavigateNext );
+  aCallBack(TKeyCodes.NavigateOut ,TKeyNames.NavigateOut );
+  aCallBack(TKeyCodes.NavigatePrevious ,TKeyNames.NavigatePrevious );
+  aCallBack(TKeyCodes.NextFavoriteChannel ,TKeyNames.NextFavoriteChannel );
+  aCallBack(TKeyCodes.NextUserProfile ,TKeyNames.NextUserProfile );
+  aCallBack(TKeyCodes.OnDemand ,TKeyNames.OnDemand );
+  aCallBack(TKeyCodes.Pairing ,TKeyNames.Pairing );
+  aCallBack(TKeyCodes.PinPDown ,TKeyNames.PinPDown );
+  aCallBack(TKeyCodes.PinPMove ,TKeyNames.PinPMove );
+  aCallBack(TKeyCodes.PinPToggle ,TKeyNames.PinPToggle );
+  aCallBack(TKeyCodes.PinPUp ,TKeyNames.PinPUp );
+  aCallBack(TKeyCodes.PlaySpeedDown ,TKeyNames.PlaySpeedDown );
+  aCallBack(TKeyCodes.PlaySpeedReset ,TKeyNames.PlaySpeedReset );
+  aCallBack(TKeyCodes.PlaySpeedUp ,TKeyNames.PlaySpeedUp );
+  aCallBack(TKeyCodes.RandomToggle ,TKeyNames.RandomToggle );
+  aCallBack(TKeyCodes.RcLowBattery ,TKeyNames.RcLowBattery );
+  aCallBack(TKeyCodes.RecordSpeedNext ,TKeyNames.RecordSpeedNext );
+  aCallBack(TKeyCodes.RfBypass ,TKeyNames.RfBypass );
+  aCallBack(TKeyCodes.ScanChannelsToggle ,TKeyNames.ScanChannelsToggle );
+  aCallBack(TKeyCodes.ScreenModeNext ,TKeyNames.ScreenModeNext );
+  aCallBack(TKeyCodes.Settings ,TKeyNames.Settings );
+  aCallBack(TKeyCodes.SplitScreenToggle ,TKeyNames.SplitScreenToggle );
+  aCallBack(TKeyCodes.STBInput ,TKeyNames.STBInput );
+  aCallBack(TKeyCodes.STBPower ,TKeyNames.STBPower );
+  aCallBack(TKeyCodes.Subtitle ,TKeyNames.Subtitle );
+  aCallBack(TKeyCodes.Teletext ,TKeyNames.Teletext );
+  aCallBack(TKeyCodes.VideoModeNext ,TKeyNames.VideoModeNext );
+  aCallBack(TKeyCodes.Wink ,TKeyNames.Wink );
+  aCallBack(TKeyCodes.ZoomToggle ,TKeyNames.ZoomToggle );
+  aCallBack(TKeyCodes.SpeechCorrectionList ,TKeyNames.SpeechCorrectionList );
+  aCallBack(TKeyCodes.SpeechInputToggle ,TKeyNames.SpeechInputToggle );
+  aCallBack(TKeyCodes.Close ,TKeyNames.Close );
+  aCallBack(TKeyCodes.New ,TKeyNames.New );
+  aCallBack(TKeyCodes.Open ,TKeyNames.Open );
+  aCallBack(TKeyCodes.Print ,TKeyNames.Print );
+  aCallBack(TKeyCodes.Save ,TKeyNames.Save );
+  aCallBack(TKeyCodes.SpellCheck ,TKeyNames.SpellCheck );
+  aCallBack(TKeyCodes.MailForward ,TKeyNames.MailForward );
+  aCallBack(TKeyCodes.MailReply ,TKeyNames.MailReply );
+  aCallBack(TKeyCodes.MailSend ,TKeyNames.MailSend );
+  aCallBack(TKeyCodes.LaunchCalculator ,TKeyNames.LaunchCalculator );
+  aCallBack(TKeyCodes.LaunchCalendar ,TKeyNames.LaunchCalendar );
+  aCallBack(TKeyCodes.LaunchContacts ,TKeyNames.LaunchContacts );
+  aCallBack(TKeyCodes.LaunchMail ,TKeyNames.LaunchMail );
+  aCallBack(TKeyCodes.LaunchMediaPlayer ,TKeyNames.LaunchMediaPlayer );
+  aCallBack(TKeyCodes.LaunchMusicPlayer ,TKeyNames.LaunchMusicPlayer );
+  aCallBack(TKeyCodes.LaunchMyComputer ,TKeyNames.LaunchMyComputer );
+  aCallBack(TKeyCodes.LaunchPhone ,TKeyNames.LaunchPhone );
+  aCallBack(TKeyCodes.LaunchScreenSaver ,TKeyNames.LaunchScreenSaver );
+  aCallBack(TKeyCodes.LaunchSpreadsheet ,TKeyNames.LaunchSpreadsheet );
+  aCallBack(TKeyCodes.LaunchWebBrowser ,TKeyNames.LaunchWebBrowser );
+  aCallBack(TKeyCodes.LaunchWebCam ,TKeyNames.LaunchWebCam );
+  aCallBack(TKeyCodes.LaunchWordProcessor ,TKeyNames.LaunchWordProcessor );
+  aCallBack(TKeyCodes.LaunchApplication1 ,TKeyNames.LaunchApplication1 );
+  aCallBack(TKeyCodes.LaunchApplication2 ,TKeyNames.LaunchApplication2 );
+  aCallBack(TKeyCodes.LaunchApplication3 ,TKeyNames.LaunchApplication3 );
+  aCallBack(TKeyCodes.LaunchApplication4 ,TKeyNames.LaunchApplication4 );
+  aCallBack(TKeyCodes.LaunchApplication5 ,TKeyNames.LaunchApplication5 );
+  aCallBack(TKeyCodes.LaunchApplication6 ,TKeyNames.LaunchApplication6 );
+  aCallBack(TKeyCodes.LaunchApplication7 ,TKeyNames.LaunchApplication7 );
+  aCallBack(TKeyCodes.LaunchApplication8 ,TKeyNames.LaunchApplication8 );
+  aCallBack(TKeyCodes.LaunchApplication9 ,TKeyNames.LaunchApplication9 );
+  aCallBack(TKeyCodes.LaunchApplication10 ,TKeyNames.LaunchApplication10 );
+  aCallBack(TKeyCodes.LaunchApplication11 ,TKeyNames.LaunchApplication11 );
+  aCallBack(TKeyCodes.LaunchApplication12 ,TKeyNames.LaunchApplication12 );
+  aCallBack(TKeyCodes.LaunchApplication13 ,TKeyNames.LaunchApplication13 );
+  aCallBack(TKeyCodes.LaunchApplication14 ,TKeyNames.LaunchApplication14 );
+  aCallBack(TKeyCodes.LaunchApplication15 ,TKeyNames.LaunchApplication15 );
+  aCallBack(TKeyCodes.LaunchApplication16 ,TKeyNames.LaunchApplication16 );
+  aCallBack(TKeyCodes.BrowserBack ,TKeyNames.BrowserBack );
+  aCallBack(TKeyCodes.BrowserFavorites ,TKeyNames.BrowserFavorites );
+  aCallBack(TKeyCodes.BrowserForward ,TKeyNames.BrowserForward );
+  aCallBack(TKeyCodes.BrowserHome ,TKeyNames.BrowserHome );
+  aCallBack(TKeyCodes.BrowserRefresh ,TKeyNames.BrowserRefresh );
+  aCallBack(TKeyCodes.BrowserSearch ,TKeyNames.BrowserSearch );
+  aCallBack(TKeyCodes.BrowserStop ,TKeyNames.BrowserStop );
+end;
+
+{ TCountSpecialKeys }
+
+procedure TCountSpecialKeys.EnumKey(aCode: Integer; aName: string);
+begin
+  inc(FCount);
+end;
+
+class function TCountSpecialKeys.GetCount: integer;
+begin
+  if (_cached_count=0) then
+    With TCountSpecialKeys.Create do
+      try
+        EnumSpecialKeys(@EnumKey);
+        _cached_count:=FCount;
+      finally
+        Free;
+      end;
+  Result:=_cached_count;
+end;
+
+{ TSpecialKeysArrayCreator }
+
+procedure TSpecialKeysArrayCreator.EnumKey(aCode: Integer; aName: string);
+begin
+  FArray[FIdx].Code:=ACode;
+  FArray[FIdx].Name:=AName;
+  Inc(FIdx);
+end;
+
+class function TSpecialKeysArrayCreator.GetArray: TKeyCodeNameArray;
+begin
+  if _keyarray=Nil then
+    With TSpecialKeysArrayCreator.Create do
+      try
+        EnumSpecialKeys(@EnumKey);
+        SetLength(FArray,GetSpecialKeyCount);
+        _KeyArray:=FArray;
+      finally
+        Free;
+      end;
+  Result:=_keyArray;
+end;
+
+
+end.
+

+ 25 - 9
src/base/fresnel.textlayouter.pas

@@ -18,8 +18,10 @@ Const
 Type
   {$IF SIZEOF(CHAR)=1}
   TTextString = UTF8String;
+  TFontNameString = AnsiString;
   {$ELSE}
   TTextString = UnicodeString;
+  TFontNameString = UnicodeString;
   {$ENDIF}
 
   ETextLayout = Class(Exception);
@@ -72,7 +74,7 @@ Type
 
   TTextMeasures = record
     Width, Height : TTextUnits;
-    Descender : TTextUnits;
+    Ascender, Descender : TTextUnits;
   end;
   TTextPoint = {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}Types.TPointF;
 
@@ -146,7 +148,7 @@ Type
   public
     Constructor Create(aLayouter : TTextLayouter); virtual;
     // Font size in points.
-    Procedure SetFont(const aFontName : String; aSize : SmallInt; Attrs : TFontAttributes); virtual; abstract;
+    Procedure SetFont(const aFontName : TFontNameString; aSize : SmallInt; Attrs : TFontAttributes); virtual; abstract;
     Procedure SetFont(const aFont: TTextFont);
     Function MeasureText(aText : TTextString) : TTextMeasures; virtual; abstract;
     Function WhitespaceWidth : TTextUnits;
@@ -166,7 +168,7 @@ Type
     FFontName : String;
   Public
     Constructor Create(aLayouter : TTextLayouter); override;
-    Procedure SetFont(const aFontName : String; aSize : SmallInt; aAttrs : TFontAttributes); override;
+    Procedure SetFont(const aFontName : TFontNameString; aSize : SmallInt; aAttrs : TFontAttributes); override;
     Function MeasureText(aText : TTextString) : TTextMeasures; override;
     Property CharHeight : TTextUnits Read FHeight Write FHeight;
     Property CharWidth : TTextUnits Read FWidth Write FWidth;
@@ -200,10 +202,17 @@ Type
     procedure Assign(aBlock : TTextBlock); virtual;
     function ToString : RTLString; override;
     Procedure TrimTrailingWhiteSpace;
+    // Text for this block. Calculated from offset/len
     Property Text : TTextString Read GetText;
+    // Layouter
     Property Layouter : TTextLayouter Read FLayouter;
+    // Width of this block
     Property Width : TTextUnits Read Size.Width;
+    // Total height of this block
     Property Height : TTextUnits Read Size.Height;
+    // Ascender for this block
+    Property Ascender : TTextUnits Read Size.Ascender;
+    // Descender for this block
     Property Descender : TTextUnits Read Size.Descender;
   end;
   TTextBlockClass = Class of TTextBlock;
@@ -277,6 +286,7 @@ Type
     procedure Assign(Source: TPersistent); override;
     Constructor Create(aLayouter : TTextLayouter);
     Property AsPoint : TTextPoint Read GetAsPoint Write SetAsPoint;
+    Function ToString : RTLString; override;
   Published
     Property Width : TTextUnits Read FWidth Write SetWidth;
     Property Height : TTextUnits Read FHeight Write SetHeight;
@@ -670,6 +680,11 @@ begin
   FLayouter:=aLayouter;
 end;
 
+function TTextLayoutBounds.ToString: RTLString;
+begin
+  Result:=ClassName+': '+AsPoint.ToString
+end;
+
 { TTextSplitter }
 
 Function SplitPoint(aOffset, aSpaces : SizeInt) : TTextSplitPoint;
@@ -806,7 +821,7 @@ begin
   CharHeight:=12;
 end;
 
-procedure TFixedSizeTextMeasurer.SetFont(const aFontName: String; aSize: SmallInt; aAttrs: TFontAttributes);
+procedure TFixedSizeTextMeasurer.SetFont(const aFontName: TFontNameString; aSize: SmallInt; aAttrs: TFontAttributes);
 begin
   FSize:=aSize;
   FFontName:=aFontName;
@@ -1247,7 +1262,6 @@ begin
     CurrPart:=Copy(S,aPos,lSplit.offset-aPos+1);
     if UseHyphen then
       CurrPart:=CurrPart+HyphenationChar;
-    Writeln('Curr : >',CurrPart,'<');
     lSize:=Measurer.MeasureText(CurrPart);
     Result:=CurrPos.X+lSize.Width>=Bounds.Width;
     if not Result then
@@ -1443,14 +1457,13 @@ begin
   ApplyVertTextAlignment;
   ApplyHorzTextAlignment;
   Result:=TextBlockCount;
-  Writeln('Result : ',ToString);
 end;
 
 function TTextLayouter.Execute(const aText: String): Integer;
 
 begin
   Text:=aText;
-  Result:=Execute;
+  Result:=Execute();
 end;
 
 function TTextLayouter.GetTotalWidth: TTextUnits;
@@ -1956,14 +1969,15 @@ begin
       for i := 0 to FBlocks.Count-1 do
         begin
         tb := FBlocks[i];
+        // Writeln('AlignV: block ',i,' h:',tb.Height,' desc :',tb.Descender);
         if i = 0 then  // do this only for the first block
-          lTotalHeight := tb.Height + tb.Descender;
+          lTotalHeight := tb.Height; // + tb.Descender;
         if tb.LayoutPos.Y = lLastYPos then // still on the same text line
           Continue
         else
           begin
           { a new line has started - process what we have collected in lList }
-          lTotalHeight := lTotalHeight + LineSpacing + tb.Height + tb.Descender;
+          lTotalHeight := lTotalHeight + LineSpacing + tb.Height // + tb.Descender;
           end; { if..else }
         lLastYPos := tb.LayoutPos.Y;
         end; { for i }
@@ -1971,6 +1985,8 @@ begin
       { Now process them line-by-line }
       lList.Clear;
       lYOffset := (Bounds.Height - lTotalHeight) / 2;
+      // Writeln('AlignV: Bounds.Height : ',Bounds.Height:8:2,' total : ',lTotalHeight :8:2,',offset: ',lYOffset:8:2);
+
       lLastYPos := 0;
       for i := 0 to FBlocks.Count-1 do
         begin

Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 622 - 44
src/pas2js/fresnel.pas2js.wasmapi.pp


+ 6 - 2
src/pas2js/p2jsfresnelapi.lpk

@@ -6,7 +6,7 @@
     <CompilerOptions>
       <Version Value="11"/>
       <SearchPaths>
-        <OtherUnitFiles Value="../wasm"/>
+        <OtherUnitFiles Value="../wasm;../base"/>
         <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
       </SearchPaths>
       <Linking>
@@ -25,9 +25,13 @@
         <Filename Value="../wasm/fresnel.wasm.shared.pp"/>
         <UnitName Value="fresnel.wasm.shared"/>
       </Item>
+      <Item>
+        <Filename Value="../base/fresnel.keys.pas"/>
+        <UnitName Value="fresnel.keys"/>
+      </Item>
     </Files>
     <UsageOptions>
-      <UnitPath Value="$(PkgDir);$(PkgDir)/../wasm"/>
+      <UnitPath Value="$(PkgDir);$(PkgDir)/../wasm;$(PkgDir)/../base"/>
     </UsageOptions>
     <PublishOptions>
       <Version Value="2"/>

+ 1 - 1
src/pas2js/p2jsfresnelapi.pas

@@ -8,7 +8,7 @@ unit p2jsfresnelapi;
 interface
 
 uses
-  fresnel.pas2js.wasmapi, fresnel.wasm.shared;
+  fresnel.pas2js.wasmapi, fresnel.wasm.shared, fresnel.keys;
 
 implementation
 

+ 150 - 11
src/wasm/fresnel.wasm.api.pp

@@ -18,6 +18,9 @@ unit fresnel.wasm.api;
 
 {$mode objfpc}{$H+}
 
+// Define this if you want to remove logging code.
+{ $DEFINE NOFRESNELLOG}
+
 interface
 
 uses fresnel.wasm.shared;
@@ -32,6 +35,15 @@ function __fresnel_canvas_allocate(
   aID: PCanvasID
 ): TCanvasError; external 'fresnel_api' name 'canvas_allocate';
 
+function __fresnel_canvas_allocate_offscreen(
+  SizeX : Longint;
+  SizeY : Longint;
+  aImageData : PByte;
+  aID: PCanvasID
+): TCanvasError; external 'fresnel_api' name 'canvas_allocate_offscreen';
+
+
+
 function __fresnel_canvas_deallocate(
   aID: TCanvasID
 ): TCanvasError; external 'fresnel_api' name 'canvas_deallocate';
@@ -50,6 +62,12 @@ function __fresnel_canvas_getsizes(
   aHeight: PLongint
 ): TCanvasError; external 'fresnel_api' name 'canvas_getsizes';
 
+function __fresnel_canvas_setsizes(
+  aID : TCanvasID;
+  aWidth: Longint;
+  aHeight: Longint
+): TCanvasError; external 'fresnel_api' name 'canvas_setsizes';
+
 
 function __fresnel_canvas_moveto(
   aID : TCanvasID;
@@ -175,6 +193,11 @@ function __fresnel_canvas_set_linemiterlimit(
   aWidth : TCanvasLineMiterLimit
 ):  TCanvasError; external 'fresnel_api' name 'canvas_set_linemiterlimit';
 
+function __fresnel_canvas_set_textbaseline(
+  aID : TCanvasID;
+  aWidth : TCanvasTextBaseLine
+):  TCanvasError; external 'fresnel_api' name 'canvas_set_textbaseline';
+
 
 function __fresnel_canvas_set_linedash(  aID : TCanvasID;
   aOffset : Longint;
@@ -194,8 +217,24 @@ function __fresnel_canvas_measure_text(
   aTextLen : Longint;
   aWidth : PLongint;
   aHeight : PLongint
+):  TCanvasError; deprecated 'use float versions instead';
+
+function __fresnel_canvas_measure_text(
+  aID : TCanvasID;
+  aText : PByte;
+  aTextLen : Longint;
+  Out aWidth,aHeight,aAscender,aDescender : Single
+):  TCanvasError;
+
+
+function __fresnel_canvas_measure_text(
+  aID : TCanvasID;
+  aText : PByte;
+  aTextLen : Longint;
+  aData : PCanvasMeasureTextData
 ):  TCanvasError; external 'fresnel_api' name 'canvas_measure_text';
 
+
 function __fresnel_canvas_set_textshadow_params (aID : TCanvasID;
     aOffsetX,aOffsetY,aRadius : Longint;
     aRed,aGreen,aBlue,aAlpha : Longint
@@ -234,7 +273,7 @@ function __fresnel_canvas_point_in_path(
   aID : TCanvasID;
   aX : Longint;
   aY : Longint;
-  aPointCount : Integer;
+  aPointCount : Longint;
   aPointData : PByte;
   aRes : PByte
 ):  TCanvasError; external 'fresnel_api' name 'canvas_point_in_path';
@@ -252,6 +291,35 @@ function __fresnel_canvas_set_transform(
  Flags : Longint;
  m11,m12,m21,m22,m31,m32 : Longint) : TCanvasError; external 'fresnel_api' name 'canvas_set_transform';
 
+function __fresnel_canvas_get_viewport_sizes(
+ aFlags : Longint;
+ aWidth,aHeight : PLongint) : TCanvasError; external 'fresnel_api' name 'canvas_get_viewport_sizes';
+
+function __fresnel_canvas_set_title(
+  aID : TCanvasID;
+  aTitle : PByte;
+  aTitleLen : Longint
+):  TCanvasError; external 'fresnel_api' name 'canvas_set_title';
+
+function __fresnel_canvas_save_state(
+  aID : TCanvasID;
+  Flags : Longint
+):  TCanvasError; external 'fresnel_api' name 'canvas_save_state';
+
+function __fresnel_canvas_restore_state(
+  aID : TCanvasID;
+  Flags : Longint
+):  TCanvasError; external 'fresnel_api' name 'canvas_restore_state';
+
+function __fresnel_canvas_clip_add_rect(
+  aID : TCanvasID;
+  X : Longint;
+  Y : Longint;
+  Width : Longint;
+  Height : Longint
+):  TCanvasError; external 'fresnel_api' name 'canvas_clip_add_rect';
+
+
 
 { ---------------------------------------------------------------------
   Timer API
@@ -277,17 +345,28 @@ function __fresnel_event_count(
   aCount : PLongint
 ):  TCanvasError; external 'fresnel_api' name 'event_count';
 
+function __fresnel_event_set_special_keymap(
+  aMap : PKeyMap;
+  aCount : Longint
+):  TCanvasError; external 'fresnel_api' name 'event_set_special_keymap';
+
 Type
+
+  TFresnelLogLevel = (fllTrace, fllDebug, fllInfo, fllWarning, fllError, fllCritical);
+  TFresnelLogLevels = set of TFresnelLogLevel;
+
   TFresnelTickEvent = Procedure(aCurrent,aPrevious : Double) of Object;
   TFresnelProcessMessageEvent = TFresnelTickEvent;
   TFresnelTimerTickEvent = Procedure (aTimerID : TTimerID; userdata : pointer; var aContinue : Boolean);
   TFresnelLogHook = procedure (const Msg : string) of object;
+  TFresnelLogLevelHook = procedure (Level : TFresnelLogLevel; const Msg : string) of object;
 
 var
   OnFresnelWasmTick : TFresnelTickEvent;
   OnFresnelProcessMessage : TFresnelProcessMessageEvent;
   OnFresnelTimerTick : TFresnelTimerTickEvent;
-  OnFresnelLog : TFresnelLogHook;
+  OnFresnelLog : TFresnelLogHook deprecated 'Use OnFresnelLogLevel';
+  OnFresnelLogLevel : TFresnelLogLevelHook;
 
 { Exported functions }
 
@@ -295,23 +374,65 @@ procedure __fresnel_tick (aCurrent,aPrevious : double);
 procedure __fresnel_process_message (aCurrent,aPrevious : double);
 function __fresnel_timer_tick(timerid: TTimerID; userdata : pointer) : boolean;
 
-procedure __fresnel_log(Const Msg : string);
-procedure __fresnel_log(Const Fmt : string; args : Array of const);
+
+procedure __fresnel_log(aLevel : TFresnelLogLevel; Const Msg : string);
+procedure __fresnel_log(aLevel : TFresnelLogLevel; Const Fmt : string; args : Array of const);
+// These use fllInfo:
+procedure __fresnel_log(Const Msg : string); inline;
+procedure __fresnel_log(Const Fmt : string; args : Array of const); inline;
 
 function __fresnel_scale(len : single) : longint;
 
 implementation
 
+{$IFDEF FPC_DOTTEDUNITS}
+uses System.SysUtils;
+{$ELSE}
+uses SysUtils;
+{$ENDIF}
+
 function __fresnel_scale(len : single) : longint;
 
 begin
   Result:=Round(len*FresnelScaleFactor);
 end;
 
+function __fresnel_canvas_measure_text(aID: TCanvasID; aText: PByte; aTextLen: Longint; aWidth: PLongint; aHeight: PLongint
+  ): TCanvasError;
+
+var
+  Data : TCanvasMeasureTextData;
+
+begin
+  Data:=Default(TCanvasMeasureTextData);
+  Result:=__fresnel_canvas_measure_text(aID,aText,aTextLen,@Data);
+  if Result=ECANVAS_SUCCESS then
+    begin
+    aWidth^:=Round(FresnelUnScale(Data[WASMMEASURE_WIDTH]));
+    aHeight^:=Round(FresnelUnScale(Data[WASMMEASURE_HEIGHT]));
+    end;
+end;
+
+function __fresnel_canvas_measure_text(aID: TCanvasID; aText: PByte; aTextLen: Longint; out aWidth, aHeight, aAscender,
+  aDescender: Single): TCanvasError;
+var
+  Data : TCanvasMeasureTextData;
+
+begin
+  Data:=Default(TCanvasMeasureTextData);
+  Result:=__fresnel_canvas_measure_text(aID,aText,aTextLen,@Data);
+  if Result=ECANVAS_SUCCESS then
+    begin
+    aWidth:=FresnelUnScale(Data[WASMMEASURE_WIDTH]);
+    aHeight:=FresnelUnScale(Data[WASMMEASURE_HEIGHT]);
+    aAscender:=FresnelUnScale(Data[WASMMEASURE_ASCENDER]);
+    aDescender:=FresnelUnScale(Data[WASMMEASURE_DESCENDER]);
+    end;
+end;
+
 procedure __fresnel_tick (aCurrent,aPrevious : double);
 
 begin
-  Writeln('Tick');
   if assigned(OnFresnelWasmTick) then
     OnFresnelWasmTick(aCurrent,aPrevious);
 end;
@@ -323,26 +444,44 @@ begin
     OnFresnelProcessMessage(aCurrent,aPrevious);
 end;
 
+procedure __fresnel_log(aLevel : TFresnelLogLevel; Const Msg : string);
+
+begin
+  {$IFNDEF NOFRESNELLOG}
+  if Assigned(OnFresnelLoglevel) then
+    OnFresnelLogLevel(aLevel,Msg)
+  else if Assigned(OnFresnelLog) then
+    OnFresnelLog(Msg)
+  {$ENDIF}
+end;
+
 procedure __fresnel_log(Const Msg : string);
 
 begin
-  {$IFDEF FASMXLOG}
-  Writeln(Msg);
-  if Assigned(OnFresnelLog) then
-    OnFresnelLog(Msg);
+  {$IFNDEF NOFRESNELLOG}
+  __fresnel_log(fllInfo,Msg);
+  {$ENDIF}
+end;
+
+procedure __fresnel_log(aLevel : TFresnelLogLevel; Const Fmt : string; args : Array of const);
+
+begin
+  {$IFNDEF NOFRESNELLOG}
+  __fresnel_log(aLevel,SafeFormat(Fmt,Args));
   {$ENDIF}
 end;
 
 procedure __fresnel_log(Const Fmt : string; args : Array of const);
 begin
-  {$IFDEF FASMXLOG}
-  Writeln(SafeFormat(Fmt,Args));
+  {$IFNDEF NOFRESNELLOG}
+  __fresnel_log(fllInfo,Fmt,Args);
   {$ENDIF}
 end;
 
 function __fresnel_timer_tick(timerid: TTimerID; userdata : pointer) : boolean;
 
 begin
+  Result:=True;
   if assigned(OnFresnelTimerTick) then
     OnFresnelTimerTick(timerid,userdata,Result)
   else

+ 70 - 6
src/wasm/fresnel.wasm.shared.pp

@@ -30,6 +30,7 @@ uses
 
 const
   CanvasMsgSize = 4;
+  CanvasMeasureTextSize = 4;
   FresnelScaleFactor = 100;
 
 Type
@@ -46,11 +47,16 @@ Type
   TCanvasLineWidth = longint; // Width * 100
   TCanvasLineCap = byte;
   TCanvasLineJoin = byte;
+  TCanvasTextBaseLine = Byte;
   TCanvasLineMiterLimit = longint;
 
   TCanvasMessageID = longint;
   TCanvasMessageParam = longint;
   TCanvasMessageData = Array[0..CanvasMsgSize-1] of TCanvasMessageParam;
+
+  TCanvasMeasureTextParam = longint;
+  TCanvasMeasureTextData = Array[0..CanvasMeasureTextSize] of TCanvasMeasureTextParam;
+
   TLineDashPattern = longint; // Scaled 100
   TLineDashPatternData = Array of TLineDashPattern;
 
@@ -81,16 +87,29 @@ Type
   PCanvasColor = ^TCanvasColor;
   PCanvasMessageID = ^TCanvasMessageID;
   PCanvasMessageData = ^TCanvasMessageData;
+  PCanvasMeasureTextData = ^TCanvasMeasureTextData;
   PCanvasRoundRectData = ^TCanvasRoundRectData;
   PGradientColorPoints = ^TGradientColorPoint;
   PLineDashPatternData = ^TLineDashPattern;
+  PKeyMap = PLongint;
+  {$ELSE}
+  PCanvasID = Longint;
+  PCanvasColor = Longint;
+  PCanvasMessageID = Longint;
+  PCanvasMessageData = Longint;
+  PCanvasMeasureTextData = Longint;
+  PCanvasRoundRectData = Longint;
+  PGradientColorPoints = Longint;
+  PLineDashPatternData = Longint;
+  PKeyMap = Longint;
   {$ENDIF}
 
 Const
-  ECANVAS_SUCCESS     = 0;
-  ECANVAS_NOCANVAS    = 1;
-  ECANVAS_INVALIDPATH = 2;
-  ECANVAS_UNSPECIFIED = -1;
+  ECANVAS_SUCCESS      = 0;
+  ECANVAS_NOCANVAS     = 1;
+  ECANVAS_INVALIDPATH  = 2;
+  ECANVAS_INVALIDPARAM = 3;
+  ECANVAS_UNSPECIFIED  = -1;
 
   CANVAS_LINECAP_BUTT   = 0;
   CANVAS_LINECAP_ROUND  = 1;
@@ -117,13 +136,27 @@ Const
   WASM_KEYSTATE_HYPER   = 1 shl Ord(ssHyper);
   WASM_KEYSTATE_ALTGR   = 1 shl Ord(ssAltGr);
 
-  // Location of data in parameters array
+  // Location of mouse state data in parameters array
   WASMSG_MOUSESTATE_X        = 0;
   WASMSG_MOUSESTATE_Y        = 1;
   WASMSG_MOUSESTATE_STATE    = 2;
   WASMSG_MOUSESTATE_BUTTON   = 3;
   WASMSG_MOUSESTATE_DISTANCE = 3;
 
+  // location of key state data in parameters array
+  WASMSG_KEYSTATE_KEYCODE    = 0;
+  WASMSG_KEYSTATE_KIND       = 1;
+  WASMSG_KEYSTATE_SHIFTSTATE = 2;
+
+  WASMSG_KEYKIND_CHAR    = 0;
+  WASMSG_KEYKIND_SPECIAL = 1;
+
+  // Location of data in measuretext array
+  WASMMEASURE_WIDTH     = 0;
+  WASMMEASURE_HEIGHT    = 1;
+  WASMMEASURE_ASCENDER  = 2;
+  WASMMEASURE_DESCENDER = 3;
+
 Const
   WASMSG_NONE        = 0;
   WASMSG_MOVE        = 1; // Params[0]= X, [1]=Y, [2]=State
@@ -135,7 +168,8 @@ Const
   WASMSG_DBLCLICK    = 7;
   WASMSG_ENTER       = 8;
   WASMSG_LEAVE       = 9;
-  WASMSG_KEY      = 10;
+  WASMSG_KEYDOWN     = 10;
+  WASMSG_KEYUP       = 11;
 
   // Roundrect flags
   ROUNDRECT_FLAG_FILL         = 1;
@@ -190,9 +224,24 @@ Const
   DRAWPATH_TYPECURVETO = 2;
   DRAWPATH_TYPECLOSE   = 3;
 
+  // Which window size ?
+  GETVIEWPORTSIZE_CLIENT = 0;
+  GETVIEWPORTSIZE_WINDOW = 1;
+
+  // Baseline for text
+  TEXTBASELINE_TOP         = 0;
+  TEXTBASELINE_HANGING     = 1;
+  TEXTBASELINE_MIDDLE      = 2;
+  TEXTBASELINE_ALPHABETIC  = 3;
+  TEXTBASELINE_IDEOGRAPHIC = 4;
+  TEXTBASELINE_BOTTOM      = 5;
+
+  // Save/Restore
+  STATE_FLAGS_RESTORE_PROPS = 1;
 
 Function LineCapToString(aCap: TCanvasLineCap) : String;
 Function LineJoinToString(aJoin: TCanvasLineJoin) : String;
+Function TextBaseLineToString(aBaseLine : TCanvasTextBaseLine) : String;
 
 Function FresnelUnScale(aLen : Longint) : TFresnelFloat;
 Function FresnelScale(aLen : TFresnelFloat) : Longint;
@@ -237,6 +286,21 @@ begin
   end;
 end;
 
+Function TextBaseLineToString(aBaseLine : TCanvasTextBaseLine) : String;
+
+begin
+  Case aBaseLine of
+    TEXTBASELINE_TOP : Result:='top';
+    TEXTBASELINE_HANGING : Result:='hanging';
+    TEXTBASELINE_MIDDLE : Result:='middle';
+    TEXTBASELINE_ALPHABETIC : Result:='alphabetic';
+    TEXTBASELINE_IDEOGRAPHIC : Result:='ideographic';
+    TEXTBASELINE_BOTTOM : Result:='bottom';
+  else
+    Result:='alphabetic';
+  end;
+end;
+
 { TGradientColorPoint }
 
 function TGradientColorPoint.ToString: string;

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů