This commit is contained in:
Pavel 2022-10-17 16:27:24 +03:00
parent 144fedd550
commit b2c3bfb565
2 changed files with 853 additions and 9 deletions

200
rtl/mpmc_queue.pas Normal file
View File

@ -0,0 +1,200 @@
{ Implimentation of Dmitry Vyukov Bounded MPMC queue on free pascal
Copyright (C) 2022 Red_prig
This library is free software; you can redistribute it and/or modify it
under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2 of the License, or (at your
option) any later version with the following modification:
As a special exception, the copyright holders of this library give you
permission to link this library with independent modules to produce an
executable, regardless of the license terms of these independent modules,and
to copy and distribute the resulting executable under terms of your choice,
provided that you also meet, for each linked independent module, the terms
and conditions of the license of that module. An independent module is a
module which is not derived from or based on this library. If you modify
this library, you may extend this exception to your version of the library,
but you are not obligated to do so. If you do not wish to do so, delete this
exception statement from your version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
for more details.
}
unit mpmc_queue;
{$mode objfpc}{$H+}
interface
Const
cacheline_size=64;
Type
cacheline_pad_t=array[0..cacheline_size-1] of Byte;
generic mpmc_bounded_queue<TItem>=object
type
p_cell_t=^cell_t;
cell_t=record
sequence_:PtrUInt;
data_:TItem;
end;
var
pad0_:cacheline_pad_t;
buffer_:p_cell_t;
buffer_mask_:PtrUInt;
pad1_:cacheline_pad_t;
enqueue_pos_:PtrUInt;
pad2_:cacheline_pad_t;
dequeue_pos_:PtrUInt;
pad3_:cacheline_pad_t;
Procedure Create(buffer_size:PtrUInt);
Procedure Free;
function enqueue(var data:TItem):Boolean;
function dequeue(var data:TItem):Boolean;
end;
function load_consume(Var addr:PtrUInt):PtrUInt; inline;
function load_acquire(Var addr:PtrUInt):PtrUInt; inline;
Procedure store_release(Var addr:PtrUInt;v:PtrUInt); inline;
function CAS(Var addr:PtrUInt;Comp,New:PtrUInt):Boolean; inline;
implementation
function load_consume(Var addr:PtrUInt):PtrUInt; inline;
begin
ReadDependencyBarrier;
Result:=addr;
end;
function load_acquire(Var addr:PtrUInt):PtrUInt; inline;
begin
ReadBarrier;
Result:=addr;
end;
Procedure store_release(Var addr:PtrUInt;v:PtrUInt); inline;
begin
WriteBarrier;
addr:=v;
end;
function CAS(Var addr:PtrUInt;Comp,New:PtrUInt):Boolean; inline;
begin
Result:=system.InterlockedCompareExchange(Pointer(addr),Pointer(New),Pointer(Comp))=Pointer(Comp);
end;
//
Procedure mpmc_bounded_queue.Create(buffer_size:PtrUInt);
var
i:PtrUInt;
begin
Assert((buffer_size >= 2) and ((buffer_size and (buffer_size-1))=0));
buffer_:=AllocMem(buffer_size*SizeOf(cell_t));
buffer_mask_:=buffer_size-1;
For i:=0 to buffer_mask_ do
begin
buffer_[i].sequence_:=i;
end;
enqueue_pos_:=0;
dequeue_pos_:=0;
end;
Procedure mpmc_bounded_queue.Free;
begin
FreeMem(buffer_);
end;
function mpmc_bounded_queue.enqueue(var data:TItem):Boolean;
var
cell:p_cell_t;
pos:PtrUInt;
seq:PtrUInt;
dif:PtrInt;
begin
pos:=load_consume(enqueue_pos_);
repeat
cell:=@buffer_[pos and buffer_mask_];
seq:=load_acquire(cell^.sequence_);
dif:=PtrInt(seq)-PtrInt(pos);
if (dif=0) then
begin
if CAS(enqueue_pos_,pos,pos+1) then
begin
Break;
end;
end else
if (dif<0) then
begin
Exit(False);
end else
begin
pos:=load_consume(enqueue_pos_);
end;
until false;
cell^.data_:=data;
store_release(cell^.sequence_,pos+1);
Result:=True;
end;
function mpmc_bounded_queue.dequeue(var data:TItem):Boolean;
var
cell:p_cell_t;
pos:PtrUInt;
seq:PtrUInt;
dif:PtrInt;
begin
pos:=load_consume(dequeue_pos_);
repeat
cell:=@buffer_[pos and buffer_mask_];
seq:=load_acquire(cell^.sequence_);
dif:=PtrInt(seq)-PtrInt(pos+1);
if (dif=0) then
begin
if CAS(dequeue_pos_,pos,pos+1) then
begin
Break;
end;
end else
if (dif<0) then
begin
Exit(False);
end else
begin
pos:=load_consume(dequeue_pos_);
end;
until false;
data:=cell^.data_;
store_release(cell^.sequence_,pos+buffer_mask_+1);
Result:=True;
end;
end.

View File

@ -5,20 +5,456 @@ unit ps4_libSceIme;
interface
uses
windows,
sys_types,
ps4_time,
ps4_program,
atomic,
mpmc_queue,
Classes,
SysUtils;
implementation
const
SCE_IME_ERROR_BUSY =-2135162879; // 0x80BC0001
SCE_IME_ERROR_NOT_OPENED =-2135162878; // 0x80BC0002
SCE_IME_ERROR_NO_MEMORY =-2135162877; // 0x80BC0003
SCE_IME_ERROR_CONNECTION_FAILED =-2135162876; // 0x80BC0004
SCE_IME_ERROR_TOO_MANY_REQUESTS =-2135162875; // 0x80BC0005
SCE_IME_ERROR_INVALID_TEXT =-2135162874; // 0x80BC0006
SCE_IME_ERROR_EVENT_OVERFLOW =-2135162873; // 0x80BC0007
SCE_IME_ERROR_NOT_ACTIVE =-2135162872; // 0x80BC0008
SCE_IME_ERROR_IME_SUSPENDING =-2135162871; // 0x80BC0009
SCE_IME_ERROR_DEVICE_IN_USE =-2135162870; // 0x80BC000A
SCE_IME_ERROR_INVALID_USER_ID =-2135162864; // 0x80BC0010
SCE_IME_ERROR_INVALID_TYPE =-2135162863; // 0x80BC0011
SCE_IME_ERROR_INVALID_SUPPORTED_LANGUAGES =-2135162862; // 0x80BC0012
SCE_IME_ERROR_INVALID_ENTER_LABEL =-2135162861; // 0x80BC0013
SCE_IME_ERROR_INVALID_INPUT_METHOD =-2135162860; // 0x80BC0014
SCE_IME_ERROR_INVALID_OPTION =-2135162859; // 0x80BC0015
SCE_IME_ERROR_INVALID_MAX_TEXT_LENGTH =-2135162858; // 0x80BC0016
SCE_IME_ERROR_INVALID_INPUT_TEXT_BUFFER =-2135162857; // 0x80BC0017
SCE_IME_ERROR_INVALID_POSX =-2135162856; // 0x80BC0018
SCE_IME_ERROR_INVALID_POSY =-2135162855; // 0x80BC0019
SCE_IME_ERROR_INVALID_HORIZONTAL_ALIGNMENT=-2135162854; // 0x80BC001A
SCE_IME_ERROR_INVALID_VERTICAL_ALIGNMENT =-2135162853; // 0x80BC001B
SCE_IME_ERROR_INVALID_EXTENDED =-2135162852; // 0x80BC001C
SCE_IME_ERROR_INVALID_KEYBOARD_TYPE =-2135162851; // 0x80BC001D
SCE_IME_ERROR_INVALID_WORK =-2135162848; // 0x80BC0020
SCE_IME_ERROR_INVALID_ARG =-2135162847; // 0x80BC0021
SCE_IME_ERROR_INVALID_HANDLER =-2135162846; // 0x80BC0022
SCE_IME_ERROR_NO_RESOURCE_ID =-2135162845; // 0x80BC0023
SCE_IME_ERROR_INVALID_MODE =-2135162844; // 0x80BC0024
SCE_IME_ERROR_INVALID_PARAM =-2135162832; // 0x80BC0030
SCE_IME_ERROR_INVALID_ADDRESS =-2135162831; // 0x80BC0031
SCE_IME_ERROR_INVALID_RESERVED =-2135162830; // 0x80BC0032
SCE_IME_ERROR_INVALID_TIMING =-2135162829; // 0x80BC0033
SCE_IME_ERROR_INTERNAL =-2135162625; // 0x80BC00FF
SCE_IME_WORK_BUFFER_SIZE=(20*1024);
//Various maximum sizes for the IME
SCE_IME_MAX_PREEDIT_LENGTH =30;
SCE_IME_MAX_EXPANDED_PREEDIT_LENGTH=120;
SCE_IME_MAX_TEXT_LENGTH =2048;
SCE_IME_MAX_TEXT_AREA =4;
SCE_IME_MAX_CANDIDATE_WORD_LENGTH =55;
SCE_IME_MAX_CANDIDATE_LIST_SIZE =100;
//OSK display area standard values
SCE_IME_OSK_DISPLAY_SIZE_WIDTH =1920;
SCE_IME_OSK_DISPLAY_SIZE_HEIGHT=1080;
SCE_IME_OSK_OVER_2K_DISPLAY_SIZE_WIDTH =3840;
SCE_IME_OSK_OVER_2K_DISPLAY_SIZE_HEIGHT=2160;
//Languages supported by the IME
SCE_IME_LANGUAGE_DANISH =$0000000000000001;
SCE_IME_LANGUAGE_GERMAN =$0000000000000002;
SCE_IME_LANGUAGE_ENGLISH_US =$0000000000000004;
SCE_IME_LANGUAGE_SPANISH =$0000000000000008;
SCE_IME_LANGUAGE_FRENCH =$0000000000000010;
SCE_IME_LANGUAGE_ITALIAN =$0000000000000020;
SCE_IME_LANGUAGE_DUTCH =$0000000000000040;
SCE_IME_LANGUAGE_NORWEGIAN =$0000000000000080;
SCE_IME_LANGUAGE_POLISH =$0000000000000100;
SCE_IME_LANGUAGE_PORTUGUESE_PT =$0000000000000200;
SCE_IME_LANGUAGE_RUSSIAN =$0000000000000400;
SCE_IME_LANGUAGE_FINNISH =$0000000000000800;
SCE_IME_LANGUAGE_SWEDISH =$0000000000001000;
SCE_IME_LANGUAGE_JAPANESE =$0000000000002000;
SCE_IME_LANGUAGE_KOREAN =$0000000000004000;
SCE_IME_LANGUAGE_SIMPLIFIED_CHINESE =$0000000000008000;
SCE_IME_LANGUAGE_TRADITIONAL_CHINESE=$0000000000010000;
SCE_IME_LANGUAGE_PORTUGUESE_BR =$0000000000020000;
SCE_IME_LANGUAGE_ENGLISH_GB =$0000000000040000;
SCE_IME_LANGUAGE_TURKISH =$0000000000080000;
SCE_IME_LANGUAGE_SPANISH_LA =$0000000000100000;
SCE_IME_LANGUAGE_ARABIC =$0000000001000000;
SCE_IME_LANGUAGE_FRENCH_CA =$0000000002000000;
SCE_IME_LANGUAGE_THAI =$0000000004000000;
SCE_IME_LANGUAGE_CZECH =$0000000008000000;
SCE_IME_LANGUAGE_GREEK =$0000000010000000;
SCE_IME_LANGUAGE_INDONESIAN =$0000000020000000;
SCE_IME_LANGUAGE_VIETNAMESE =$0000000040000000;
SCE_IME_LANGUAGE_ROMANIAN =$0000000080000000;
SCE_IME_LANGUAGE_HUNGARIAN =$0000000100000000;
//IME options
SCE_IME_OPTION_DEFAULT =$00000000;
SCE_IME_OPTION_MULTILINE =$00000001;
SCE_IME_OPTION_NO_AUTO_CAPITALIZATION =$00000002;
SCE_IME_OPTION_PASSWORD =$00000004;
SCE_IME_OPTION_LANGUAGES_FORCED =$00000008;
SCE_IME_OPTION_EXT_KEYBOARD =$00000010;
SCE_IME_OPTION_NO_LEARNING =$00000020;
SCE_IME_OPTION_FIXED_POSITION =$00000040;
SCE_IME_OPTION_DISABLE_COPY_PASTE =$00000080;
SCE_IME_OPTION_DISABLE_RESUME =$00000100;
SCE_IME_OPTION_DISABLE_AUTO_SPACE =$00000200;
SCE_IME_OPTION_DISABLE_POSITION_ADJUSTMENT =$00000800;
SCE_IME_OPTION_EXPANDED_PREEDIT_BUFFER =$00001000;
SCE_IME_OPTION_USE_JAPANESE_EISUU_KEY_AS_CAPSLOCK=$00002000;
SCE_IME_OPTION_USE_OVER_2K_COORDINATES =$00004000;
//IME extended options
SCE_IME_EXT_OPTION_DEFAULT =$00000000;
SCE_IME_EXT_OPTION_SET_COLOR =$00000001;
SCE_IME_EXT_OPTION_SET_PRIORITY =$00000002;
SCE_IME_EXT_OPTION_PRIORITY_SHIFT =$00000004;
SCE_IME_EXT_OPTION_PRIORITY_FULL_WIDTH =$00000008;
SCE_IME_EXT_OPTION_PRIORITY_FIXED_PANEL =$00000010;
SCE_IME_EXT_OPTION_DISABLE_POINTER =$00000040;
SCE_IME_EXT_OPTION_ENABLE_ADDITIONAL_DICTIONARY =$00000080;
SCE_IME_EXT_OPTION_DISABLE_STARTUP_SE =$00000100;
SCE_IME_EXT_OPTION_DISABLE_LIST_FOR_EXT_KEYBOARD=$00000200;
SCE_IME_EXT_OPTION_HIDE_KEYPANEL_IF_EXT_KEYBOARD=$00000400;
SCE_IME_EXT_OPTION_INIT_EXT_KEYBOARD_MODE =$00000800;
SCE_IME_DIALOG_EXT_OPTION_ENABLE_ACCESSIBILITY =$00001000;
SCE_IME_DIALOG_EXT_OPTION_ACCESSIBILITY_PANEL_FORCED =$00002000;
SCE_IME_EXT_OPTION_ADDITIONAL_DICTIONARY_PRIORITY_MODE=$00004000;
//Device not used with the IME
SCE_IME_DISABLE_DEVICE_DEFAULT =$00000000;
SCE_IME_DISABLE_DEVICE_CONTROLLER =$00000001;
SCE_IME_DISABLE_DEVICE_EXT_KEYBOARD=$00000002;
SCE_IME_DISABLE_DEVICE_REMOTE_OSK =$00000004;
// States of edited strings
SCE_IME_INPUT_METHOD_STATE_PREEDIT =$01000000;
SCE_IME_INPUT_METHOD_STATE_SELECTED =$02000000;
SCE_IME_INPUT_METHOD_STATE_NATIVE =$04000000;
SCE_IME_INPUT_METHOD_STATE_NATIVE2 =$08000000;
SCE_IME_INPUT_METHOD_STATE_FULL_WIDTH=$10000000;
//External keyboard initial mode
SCE_IME_INIT_EXT_KEYBOARD_MODE_DISABLE_ARABIC_INDIC_NUMERALS=$00000001;
SCE_IME_INIT_EXT_KEYBOARD_MODE_ENABLE_FORMAT_CHARACTERS =$00000002;
SCE_IME_INIT_EXT_KEYBOARD_MODE_INPUT_METHOD_STATE_NATIVE =SCE_IME_INPUT_METHOD_STATE_NATIVE;
SCE_IME_INIT_EXT_KEYBOARD_MODE_INPUT_METHOD_STATE_NATIVE2 =SCE_IME_INPUT_METHOD_STATE_NATIVE2;
SCE_IME_INIT_EXT_KEYBOARD_MODE_INPUT_METHOD_STATE_FULL_WIDTH=SCE_IME_INPUT_METHOD_STATE_FULL_WIDTH ;
//Event IDs of IME event/keyboard event
//SceImeEventId
SCE_IME_EVENT_OPEN = 0;
SCE_IME_EVENT_UPDATE_TEXT = 1;
SCE_IME_EVENT_UPDATE_CARET = 2;
SCE_IME_EVENT_CHANGE_SIZE = 3;
SCE_IME_EVENT_PRESS_CLOSE = 4;
SCE_IME_EVENT_PRESS_ENTER = 5;
SCE_IME_EVENT_ABORT = 6;
SCE_IME_EVENT_CANDIDATE_LIST_START = 7;
SCE_IME_EVENT_CANDIDATE_LIST_END = 8;
SCE_IME_EVENT_CANDIDATE_WORD = 9;
SCE_IME_EVENT_CANDIDATE_INDEX = 10;
SCE_IME_EVENT_CANDIDATE_DONE = 11;
SCE_IME_EVENT_CANDIDATE_CANCEL = 12;
SCE_IME_EVENT_CHANGE_DEVICE = 14;
SCE_IME_EVENT_JUMP_TO_NEXT_OBJECT = 15;
SCE_IME_EVENT_JUMP_TO_BEFORE_OBJECT = 16;
SCE_IME_EVENT_CHANGE_WINDOW_TYPE = 17;
SCE_IME_EVENT_CHANGE_INPUT_METHOD_STATE = 18;
SCE_IME_KEYBOARD_EVENT_OPEN = 256;
SCE_IME_KEYBOARD_EVENT_KEYCODE_DOWN = 257;
SCE_IME_KEYBOARD_EVENT_KEYCODE_UP = 258;
SCE_IME_KEYBOARD_EVENT_KEYCODE_REPEAT = 259;
SCE_IME_KEYBOARD_EVENT_CONNECTION = 260;
SCE_IME_KEYBOARD_EVENT_DISCONNECTION = 261;
SCE_IME_KEYBOARD_EVENT_ABORT = 262;
//IME horizontal display origins
//SceImeHorizontalAlignment
SCE_IME_HALIGN_LEFT = 0;
SCE_IME_HALIGN_CENTER = 1;
SCE_IME_HALIGN_RIGHT = 2;
//IME vertical display origins
//SceImeVerticalAlignment
SCE_IME_VALIGN_TOP = 0;
SCE_IME_VALIGN_CENTER = 1;
SCE_IME_VALIGN_BOTTOM = 2;
//IME Enter key labels
//SceImeEnterLabel
SCE_IME_ENTER_LABEL_DEFAULT = 0;
SCE_IME_ENTER_LABEL_SEND = 1;
SCE_IME_ENTER_LABEL_SEARCH = 2;
SCE_IME_ENTER_LABEL_GO = 3;
//IME input UI types
//SceImeType
SCE_IME_TYPE_DEFAULT = 0;
SCE_IME_TYPE_BASIC_LATIN = 1;
SCE_IME_TYPE_URL = 2;
SCE_IME_TYPE_MAIL = 3;
SCE_IME_TYPE_NUMBER = 4;
//IME prioritized input panel
//SceImePanelPriority
SCE_IME_PANEL_PRIORITY_DEFAULT = 0;
SCE_IME_PANEL_PRIORITY_ALPHABET = 1;
SCE_IME_PANEL_PRIORITY_SYMBOL = 2;
SCE_IME_PANEL_PRIORITY_ACCENT = 3;
//IME input method
//SceImeInputMethod
SCE_IME_INPUT_METHOD_DEFAULT = 0;
//Caret movement position information
//SceImeCaretMovementDirection
SCE_IME_CARET_MOVE_STILL = 0;
SCE_IME_CARET_MOVE_LEFT = 1;
SCE_IME_CARET_MOVE_RIGHT = 2;
SCE_IME_CARET_MOVE_UP = 3;
SCE_IME_CARET_MOVE_DOWN = 4;
SCE_IME_CARET_MOVE_HOME = 5;
SCE_IME_CARET_MOVE_END = 6;
SCE_IME_CARET_MOVE_PAGE_UP = 7;
SCE_IME_CARET_MOVE_PAGE_DOWN = 8;
SCE_IME_CARET_MOVE_TOP = 9;
SCE_IME_CARET_MOVE_BOTTOM = 10;
//Text area type
//SceImeTextAreaMode
SCE_IME_TEXT_AREA_MODE_DISABLE = 0;
SCE_IME_TEXT_AREA_MODE_EDIT = 1;
SCE_IME_TEXT_AREA_MODE_PREEDIT = 2;
SCE_IME_TEXT_AREA_MODE_SELECT = 3;
//Definitions for keyboard
SCE_IME_KEYBOARD_MAX_NUMBER = 5;
//Keyboard states
SCE_IME_KEYCODE_STATE_KEYCODE_VALID =$00000001;
SCE_IME_KEYCODE_STATE_CHARACTER_VALID =$00000002;
SCE_IME_KEYCODE_STATE_WITH_IME =$00000004;
SCE_IME_KEYCODE_STATE_FROM_OSK =$00000008;
SCE_IME_KEYCODE_STATE_FROM_OSK_SHORTCUT =$00000010;
SCE_IME_KEYCODE_STATE_FROM_IME_OPERATION=$00000020;
SCE_IME_KEYCODE_STATE_REPLACE_CHARACTER =$00000040;
SCE_IME_KEYCODE_STATE_CONTINUOUS_EVENT =$00000080;
SCE_IME_KEYCODE_STATE_MODIFIER_L_CTRL =$00000100;
SCE_IME_KEYCODE_STATE_MODIFIER_L_SHIFT =$00000200;
SCE_IME_KEYCODE_STATE_MODIFIER_L_ALT =$00000400;
SCE_IME_KEYCODE_STATE_MODIFIER_L_GUI =$00000800;
SCE_IME_KEYCODE_STATE_MODIFIER_R_CTRL =$00001000;
SCE_IME_KEYCODE_STATE_MODIFIER_R_SHIFT =$00002000;
SCE_IME_KEYCODE_STATE_MODIFIER_R_ALT =$00004000;
SCE_IME_KEYCODE_STATE_MODIFIER_R_GUI =$00008000;
SCE_IME_KEYCODE_STATE_LED_NUM_LOCK =$00010000;
SCE_IME_KEYCODE_STATE_LED_CAPS_LOCK =$00020000;
SCE_IME_KEYCODE_STATE_LED_SCROLL_LOCK =$00040000;
SCE_IME_KEYCODE_STATE_RESERVED1 =$00080000;
SCE_IME_KEYCODE_STATE_RESERVED2 =$00100000;
SCE_IME_KEYCODE_STATE_FROM_IME_INPUT =$00200000;
//Keyboard reception options
SCE_IME_KEYBOARD_OPTION_DEFAULT =$00000000;
SCE_IME_KEYBOARD_OPTION_REPEAT =$00000001;
SCE_IME_KEYBOARD_OPTION_REPEAT_EACH_KEY =$00000002;
SCE_IME_KEYBOARD_OPTION_ADD_OSK =$00000004;
SCE_IME_KEYBOARD_OPTION_EFFECTIVE_WITH_IME=$00000008;
SCE_IME_KEYBOARD_OPTION_DISABLE_RESUME =$00000010;
SCE_IME_KEYBOARD_OPTION_DISABLE_CAPSLOCK_WITHOUT_SHIFT=$00000020;
//Keyboard output modes
SCE_IME_KEYBOARD_MODE_AUTO =$00000000;
SCE_IME_KEYBOARD_MODE_MANUAL =$00000001;
SCE_IME_KEYBOARD_MODE_ALPHABET =$00000000;
SCE_IME_KEYBOARD_MODE_NATIVE =$00000002;
SCE_IME_KEYBOARD_MODE_PART =$00000004;
SCE_IME_KEYBOARD_MODE_KATAKANA =$00000008;
SCE_IME_KEYBOARD_MODE_HKANA =$00000010;
SCE_IME_KEYBOARD_MODE_ARABIC_INDIC_NUMERALS =$00000020;
SCE_IME_KEYBOARD_MODE_DISABLE_FORMAT_CHARACTERS=$00000040;
//Defined keyboard resource ID
SCE_IME_KEYBOARD_RESOURCE_ID_INVALID=$00000000;
SCE_IME_KEYBOARD_RESOURCE_ID_OSK =$00000001;
//Keyboard device statuses
//SceImeKeyboardStatus
CE_IME_KEYBOARD_STATE_DISCONNECTED = 0;
CE_IME_KEYBOARD_STATE_CONNECTED = 1;
//Keyboard layout types for keyboard devices
//SceImeKeyboardType
SCE_IME_KEYBOARD_TYPE_NONE = 0;
SCE_IME_KEYBOARD_TYPE_DANISH = 1;
SCE_IME_KEYBOARD_TYPE_GERMAN = 2;
SCE_IME_KEYBOARD_TYPE_GERMAN_SW = 3;
SCE_IME_KEYBOARD_TYPE_ENGLISH_US = 4;
SCE_IME_KEYBOARD_TYPE_ENGLISH_GB = 5;
SCE_IME_KEYBOARD_TYPE_SPANISH = 6;
SCE_IME_KEYBOARD_TYPE_SPANISH_LA = 7;
SCE_IME_KEYBOARD_TYPE_FINNISH = 8;
SCE_IME_KEYBOARD_TYPE_FRENCH = 9;
SCE_IME_KEYBOARD_TYPE_FRENCH_BR = 10;
SCE_IME_KEYBOARD_TYPE_FRENCH_CA = 11;
SCE_IME_KEYBOARD_TYPE_FRENCH_SW = 12;
SCE_IME_KEYBOARD_TYPE_ITALIAN = 13;
SCE_IME_KEYBOARD_TYPE_DUTCH = 14;
SCE_IME_KEYBOARD_TYPE_NORWEGIAN = 15;
SCE_IME_KEYBOARD_TYPE_POLISH = 16;
SCE_IME_KEYBOARD_TYPE_PORTUGUESE_BR = 17;
SCE_IME_KEYBOARD_TYPE_PORTUGUESE_PT = 18;
SCE_IME_KEYBOARD_TYPE_RUSSIAN = 19;
SCE_IME_KEYBOARD_TYPE_SWEDISH = 20;
SCE_IME_KEYBOARD_TYPE_TURKISH = 21;
SCE_IME_KEYBOARD_TYPE_JAPANESE_ROMAN = 22;
SCE_IME_KEYBOARD_TYPE_JAPANESE_KANA = 23;
SCE_IME_KEYBOARD_TYPE_KOREAN = 24;
SCE_IME_KEYBOARD_TYPE_SM_CHINESE = 25;
SCE_IME_KEYBOARD_TYPE_TR_CHINESE_ZY = 26;
SCE_IME_KEYBOARD_TYPE_TR_CHINESE_PY_HK = 27;
SCE_IME_KEYBOARD_TYPE_TR_CHINESE_PY_TW = 28;
SCE_IME_KEYBOARD_TYPE_TR_CHINESE_CG = 29;
SCE_IME_KEYBOARD_TYPE_ARABIC_AR = 30;
SCE_IME_KEYBOARD_TYPE_THAI = 31;
SCE_IME_KEYBOARD_TYPE_CZECH = 32;
SCE_IME_KEYBOARD_TYPE_GREEK = 33;
SCE_IME_KEYBOARD_TYPE_INDONESIAN = 34;
SCE_IME_KEYBOARD_TYPE_VIETNAMESE = 35;
SCE_IME_KEYBOARD_TYPE_ROMANIAN = 36;
SCE_IME_KEYBOARD_TYPE_HUNGARIAN = 37;
//Keyboard device types
//SceImeKeyboardDeviceType
SCE_IME_KEYBOARD_DEVICE_TYPE_KEYBOARD = 0;
SCE_IME_KEYBOARD_DEVICE_TYPE_OSK = 1;
//IME panel type
//SceImePanelType
SCE_IME_PANEL_TYPE_HIDE = 0;
SCE_IME_PANEL_TYPE_OSK = 1;
SCE_IME_PANEL_TYPE_DIALOG = 2;
SCE_IME_PANEL_TYPE_CANDIDATE = 3;
SCE_IME_PANEL_TYPE_EDIT = 4;
SCE_IME_PANEL_TYPE_EDIT_AND_CANDIDATE = 5;
SCE_IME_PANEL_TYPE_ACCESSIBILITY = 6;
//Types of input devices that use the IME
//SceImeDeviceType
SCE_IME_DEVICE_TYPE_NONE = 0;
SCE_IME_DEVICE_TYPE_CONTROLLER = 1;
SCE_IME_DEVICE_TYPE_EXT_KEYBOARD = 2;
SCE_IME_DEVICE_TYPE_REMOTE_OSK = 3;
type
SceImeTextAreaProperty=packed record
mode:Integer; //SceImeTextAreaMode
index:DWORD;
length:Integer;
end;
SceImeEditText=packed record
str:pWideChar;
caretIndex:DWORD;
areaNum:DWORD;
textArea:array[0..SCE_IME_MAX_TEXT_AREA-1] of SceImeTextAreaProperty;
end;
SceImePositionAndForm=packed record
_type:Integer; //SceImePanelType
posx,posy:Single;
horizontalAlignment:Integer; //SceImeHorizontalAlignment
verticalAlignment :Integer; //SceImeVerticalAlignment
width,height:DWORD;
end;
SceImeRect=packed record
x,y:Single;
width,height:DWORD;
end;
SceImeTextGeometry=packed record
x,y:Single;
width,height:DWORD;
end;
SceImeCaret=packed record
x,y:Single;
height:DWORD;
index:DWORD;
end;
SceImeColor=packed record
r,g,b,a:Byte;
end;
SceImeKeyboardInfo=packed record
userId:Integer;
device:Integer; //SceImeKeyboardDeviceType
_type:Integer; //SceImeKeyboardType
repeatDelay:DWORD;
repeatRate :DWORD;
status:Integer; //SceImeKeyboardStatus
reserved:array[0..11] of Byte;
end;
SceImeKeyboardResourceIdArray=packed record
userId:Integer;
resourceId:array[0..SCE_IME_KEYBOARD_MAX_NUMBER-1] of DWORD;
end;
SceImeKeycode=packed record
keycode:Word;
character:WideChar;
status:DWORD;
_type:Integer; //SceImeKeyboardType
userId:Integer;
resourceId:DWORD;
timestamp:QWORD; //SceRtcTick
end;
pSceImeEventParam=^SceImeEventParam;
SceImeEventParam=packed record
Case Byte of
0:(rect:SceImeRect);
1:(text:SceImeEditText);
2:(caretMove:Integer); //SceImeCaretMovementDirection
3:(keycode:SceImeKeycode);
4:(resourceIdArray:SceImeKeyboardResourceIdArray);
5:(candidateWord:PWideChar);
6:(candidateIndex:Integer);
7:(deviceType:Integer); //SceImeDeviceType
8:(panelType:Integer); //SceImePanelType
9:(inputMethodState:DWORD);
10:(reserved:array[0..63] of Byte);
end;
pSceImeEvent=^SceImeEvent;
SceImeEvent=packed record
id:Integer; //SceImeEventId
//param:SceImeEventParam;
param:SceImeEventParam;
end;
SceImeEventHandler=procedure(arg:Pointer;e:pSceImeEvent);
SceImeEventHandler=procedure(arg:Pointer;e:pSceImeEvent); SysV_ABI_CDecl;
pSceImeKeyboardParam=^SceImeKeyboardParam;
SceImeKeyboardParam=packed record
@ -29,21 +465,227 @@ type
reserved2:QWORD;
end;
implementation
type
t_ime_event_queue=specialize mpmc_bounded_queue<SceImeEvent>;
var
g_ime_event_queue:t_ime_event_queue;
keyboard_init:QWORD=0;
keyboard_fini:QWORD=0;
g_hook:HHOOK;
g_handler:SceImeEventHandler=nil;
g_cb_arg:Pointer=nil;
Procedure push_keyboard_open(userId:Integer);
var
event:SceImeEvent;
begin
event:=Default(SceImeEvent);
event.id:=SCE_IME_KEYBOARD_EVENT_OPEN;
event.param.resourceIdArray.userId:=userId;
event.param.resourceIdArray.resourceId[0]:=1;
g_ime_event_queue.enqueue(event);
end;
Procedure push_keyboard_code(id:Integer;var keycode:SceImeKeycode);
var
event:SceImeEvent;
begin
event:=Default(SceImeEvent);
event.id:=id;
event.param.keycode:=keycode;
g_ime_event_queue.enqueue(event);
end;
function ToUnicodeEx(wVirtKey,wScanCode:UINT;lpKeyState:PByte;pwszBuff:PWideChar;cchBuff:Integer;
wFlags:UINT;dwhkl:HKL):Integer; stdcall; external 'user32.dll';
function GetCurrentTick(pTick:PQWORD):Integer;
var
time:timespec;
begin
if (pTick=nil) then Exit(-1);
Result:=ps4_sceKernelClockGettime(0,@time);
if (Result>=0) then
begin
pTick^:=(time.tv_nsec div 1000) + (time.tv_sec*1000000) + $dcbffeff2bc000;
end
end;
function KeyboardHookCallback(nCode:longint;wParam:WPARAM;lParam:LPARAM):LRESULT; stdcall;
var
KeyBoardState:TKeyboardState;
ActiveThreadID:DWORD;
KeyBoardLayOut:HKL;
ScanCode:DWORD;
status:DWORD;
AChr:array[0..1] of WideChar;
keycode:SceImeKeycode;
begin
if (nCode=HC_ACTION) then
begin
KeyBoardState:=Default(TKeyboardState);
GetKeyboardState(KeyBoardState);
ActiveThreadID:=GetWindowThreadProcessId(GetForegroundWindow, nil);
KeyBoardLayOut:=GetKeyboardLayout(ActiveThreadID);
ScanCode:=MapVirtualKeyEx(wParam,0,KeyBoardLayOut);
status:=0;
if (ScanCode<>0) then
begin
status:=status or SCE_IME_KEYCODE_STATE_KEYCODE_VALID;
AChr[0]:=#0;
AChr[1]:=#0;
ToUnicodeEx(wParam,ScanCode,@KeyBoardState,@AChr,SizeOf(Achr),0,KeyBoardLayOut);
if (AChr[0]<>#0) then
begin
status:=status or SCE_IME_KEYCODE_STATE_CHARACTER_VALID;
end;
end;
if ((lParam and (KF_ALTDOWN shl 16))<>0) then
begin
if ((lParam and (KF_EXTENDED shl 16))=0) then
begin
status:=status or SCE_IME_KEYCODE_STATE_MODIFIER_L_ALT;
end else
begin
status:=status or SCE_IME_KEYCODE_STATE_MODIFIER_R_ALT;
end;
end;
if ((GetKeyState(VK_CONTROL) and $8000)<>0) then
begin
if ((lParam and (KF_EXTENDED shl 16))=0) then
begin
status:=status or SCE_IME_KEYCODE_STATE_MODIFIER_L_CTRL;
end else
begin
status:=status or SCE_IME_KEYCODE_STATE_MODIFIER_R_CTRL;
end;
end;
if ((GetKeyState(VK_SHIFT) and $8000)<>0) then
begin
if ((lParam and (KF_EXTENDED shl 16))=0) then
begin
status:=status or SCE_IME_KEYCODE_STATE_MODIFIER_L_SHIFT;
end else
begin
status:=status or SCE_IME_KEYCODE_STATE_MODIFIER_R_SHIFT;
end;
end;
if ((GetKeyState(VK_LWIN) and $8000)<>0) then
begin
status:=status or SCE_IME_KEYCODE_STATE_MODIFIER_L_GUI;
end;
if ((GetKeyState(VK_RWIN) and $8000)<>0) then
begin
status:=status or SCE_IME_KEYCODE_STATE_MODIFIER_R_GUI;
end;
if ((GetKeyState(VK_NUMLOCK) and 1)<>0) then
begin
status:=status or SCE_IME_KEYCODE_STATE_LED_NUM_LOCK;
end;
if ((GetKeyState(VK_CAPITAL) and 1)<>0) then
begin
status:=status or SCE_IME_KEYCODE_STATE_LED_CAPS_LOCK;
end;
if ((GetKeyState(VK_SCROLL) and 1)<>0) then
begin
status:=status or SCE_IME_KEYCODE_STATE_LED_SCROLL_LOCK;
end;
keycode:=Default(SceImeKeycode);
keycode.keycode :=ScanCode;
keycode.character :=AChr[0];
keycode.status :=status;
keycode._type :=SCE_IME_KEYBOARD_TYPE_ENGLISH_US;
keycode.userId :=-1;
keycode.resourceId:=1;
GetCurrentTick(@keycode.timestamp);
if ((lParam and (KF_UP shl 16))=0) then
begin
push_keyboard_code(SCE_IME_KEYBOARD_EVENT_KEYCODE_DOWN,keycode);
end else
begin
push_keyboard_code(SCE_IME_KEYBOARD_EVENT_KEYCODE_UP,keycode);
end;
end;
Result:=CallNextHookEx(g_hook,nCode,wParam,lParam);
end;
function ps4_sceImeKeyboardOpen(
userId:Integer;
param:pSceImeKeyboardParam
):Integer; SysV_ABI_CDecl;
begin
Writeln('sceImeKeyboardOpen:',userId,' ',HexStr(param));
Result:=Integer($80BC0004);
if (param=nil) then Exit(SCE_IME_ERROR_INVALID_ADDRESS);
if ((param^.option and (not $1F))<>0) then Exit(SCE_IME_ERROR_INVALID_OPTION);
if (param^.handler=nil) then Exit(SCE_IME_ERROR_INVALID_HANDLER);
if not CAS(keyboard_init,0,1) then Exit(SCE_IME_ERROR_BUSY);
g_hook:=SetWindowsHookExW(WH_KEYBOARD,@KeyboardHookCallback,GetModuleHandle(nil),MainThreadID);
if (g_hook=0) then
begin
store_release(keyboard_init,0);
Exit(SCE_IME_ERROR_INTERNAL);
end;
g_handler:=param^.handler;
g_cb_arg :=param^.arg;
push_keyboard_open(userId);
store_release(keyboard_fini,1);
Result:=0;
end;
function ps4_sceImeUpdate(
handler:Pointer //SceImeEventHandler
):Integer; SysV_ABI_CDecl;
function ps4_sceImeUpdate(handler:SceImeEventHandler):Integer; SysV_ABI_CDecl;
var
i:Integer;
event:SceImeEvent;
begin
Writeln('sceImeUpdate:',HexStr(handler));
Result:=Integer($80BC0004);
if (handler=nil) then Exit(SCE_IME_ERROR_INTERNAL);
event:=Default(SceImeEvent);
For i:=0 to 255 do
begin
if not g_ime_event_queue.dequeue(event) then Break;
handler(g_cb_arg,@event);
end;
Result:=0;
end;
procedure init_ime;
begin
g_ime_event_queue.Create(256);
end;
function Load_libSceIme(Const name:RawByteString):TElf_node;
@ -56,6 +698,8 @@ begin
lib:=Result._add_lib('libSceIme');
lib^.set_proc($79A1578DF26FDF1B,@ps4_sceImeKeyboardOpen);
lib^.set_proc($FF81827D874D175B,@ps4_sceImeUpdate);
init_ime;
end;
initialization