How to use windows IME in delphi? - windows

I have several keyboards and they type in different TMemos. In english, everything works fine, but in Korean the keystrokes get sent to the IME before it sends it to my onKeypress (which handles/identifies the different keyboards), so I can't exactly tell which keyboard it came from before that.
I don't exactly know how to use WinApi, but I need to learn to use the part that deals with the IME. There is a lot of information HERE, but I need to know how to apply it in delphi. I need to store each users keystrokes and send them to the IME.
Perhaps someone can help me learn to use IMM.PAS

Got it to work. Using ImmGetContext, ImmSetCompositon, ImmGetComposition and NormalizeString.
procedure TForm1.IMEFUNCTION(var msg: TMsg);
var
buf: array [0..20] of char;
hHimc: HIMC;
i, j: integer;
str: string;
temporary: PWideChar;
begin
hHimc:= ImmGetContext (msg.hwnd);
if hHimc = 0 then
Exit;
fillchar (buf, 20, 0);
ImmSetCompositionStringW (hHimc, SCS_SETSTR, PChar (''), Length(''), nil, 0);
ImmGetCompositionString (hHimc, GCS_COMPSTR, #buf, 20);
temporary:= PWideChar(Edit1.Text+buf[0]);
NormalizeString(5 , temporary, -1, buf, 20);
Edit1.Text:=buf;
end;//end if
end;//end for
ImmReleaseContext (handle, hHimc);
end;
Side note: I didn't really use TEdit, I used a StringGrid and a for-loop. (but the general idea is there)

I doubt that Windows supports what you want to do, and I doubt that you can make Windows work differently. It sounds like you are trying to use two physical keyboards on a single computer.
IMM.PAS is a wrapper for the Windows IME API, and does not appear to have been written to help you do exactly what you want to do.
Why aren't you using two computers, with two keyboards?

Related

How can I read and set the paper style (aka papername) in Firemonkey MacOS

Working in Delphi Firemonkey for Mac OS64.
Trying to read and then set the variable Apple calls the "paperName", which is the paper type (letter, legal, envelope, etc.) I know that it is accessed through NSPrinter.PaperName? but I do not understand how to code FMX to access it.
I'm using cookbooked code to get the paper rectangle:
FPrintInfo := TNSPrintInfo.Wrap(TNSPrintInfo.OCClass.sharedPrintInfo);
FPrintInfo.retain;
PMGetAdjustedPaperRect(FPrintInfo.PMPageFormat, #PaperRect);
FPrintInfo.release;
but I'm not experienced at all with Mac code so my attempts to plug-and-play off of this code to get papername have not been successful.
Thanks for your help.
Dave,
Thanks. Sorry, I didn't really give you enough info. The code I provided does work, to get the paper rectangle.
What I am trying to get, in addition, is the paper name, and I can't figure out what function will get me that.
I'm trying to use PMGetPageFormatPaper(FPrintInfo.PMPageFormat, #PaperTypeS); but I think I may not be declaring PaperTypeS correctly.
What I'm trying is:
function getPaperShape: string;
var
FPrintInfo: NSPrintInfo;
PaperRect: PMRect;
paperwidth,paperheight:double;
paperTypeS:string;
begin
FPrintInfo := TNSPrintInfo.Wrap(TNSPrintInfo.OCClass.sharedPrintInfo);
FPrintInfo.retain;
PMGetAdjustedPaperRect(FPrintInfo.PMPageFormat, #PaperRect);
PMGetPageFormatPaper(FPrintInfo.PMPageFormat, #PaperTypeS);
FPrintInfo.release;
paperwidth:= PaperRect.right-PaperRect.left;
paperheight:= PaperRect.bottom-PaperRect.top;
end;
That clearly is not correct, since I get nothing returned in paperTypeS. I've tried declaring paperTypeS as NSPrinter.PaperName, or just as PaperName, or as PMPaperName, but clearly I'm just guessing here and none of those are recognized by FMX as valid types.
Does that make more sense?
Again, thanks.
Scott

AHK: Using RandomBezier Function

I'm trying to use RandomBezier.ahk (https://github.com/MasterFocus/AutoHotkey/tree/master/Functions/RandomBezier) to randomize the mouse path to click on things in game.
The Example.ahk in that github works for me, but when trying to use it in my own program, it doesn't work when calling the RandomBezier function.
I have the files in the same local directory.
Any help on getting this function to work?
Thanks
#SingleInstance force
#Include RandomBezier.ahk
^j::
screenWidth := A_ScreenWidth
screenHeight := A_ScreenHeight
//I'm using ratios so that I'm not hardcoding based on a given display resolution
Play_X := floor(0.02604*A_ScreenWidth)
Play_Y := floor(0.37037*A_ScreenHeight)
RandomBezier(0, 0, %Play_X%, %Play_Y%, "T1200 RO RD OT100 OB-100 OL0 OR0 P4-3") //<-- this line doesn't do anything. the mouse doesn't move.
;MouseMove, %Play_X%, %Play_Y%, 10 <--this line works, so I know that the variables Play_X, Play_Y works
Sleep 50
Click
This is a classic mistake of trying to use legacy syntax in a place where it doesn't belong (though I'd argue it no longer belongs anywhere whatsoever).
Function parameters are passed in as expressions, not as legacy text parameters.
So instead of legacy way of referencing a variable
RandomBezier(0, 0, %Play_X%, %Play_Y%,,
you do
RandomBezier(0, 0, Play_X, Play_Y,.
Overall I'd recommend you to try to to get rid of legacy syntax. It's not 2008 anymore.
Reading this page on the documentation is a good start to learning the difference
https://www.autohotkey.com/docs/Language.htm

How to fill "waveInGetDevCaps" function parameters in Delphi?

I'm using the Window's API, in particular the 'WaveIn' functions. I want to know the format that my laptop's input audio device supports.
Therefore, I used the function "waveInGetDevCaps." This function call , once called, fills in a WAVEINCAPS structure with the information about the audio device.
This is my code so far:
procedure TForm1.Button4Click(Sender: TObject);
var
wc : WAVEINCAPS; // structure to be filled with audio device info
begin
waveInGetDevCaps(WAVE_MAPPER, &wc, sizeof(WAVEINCAPS));
Showmessage (wc.dwFormats);
end;
However I keep getting an error:
"E2010 Incompatible types: 'PWaveInCapsA' and 'tagWAVEINCAPSA2"
I would appreciate any help please.
Information on "waveInGetDevCaps" and "WAVEINCAPS" can be found:
https://msdn.microsoft.com/en-us/library/dd743841%28v=vs.85%29.aspx
https://msdn.microsoft.com/en-us/library/dd743839%28v=vs.85%29.aspx
You are using the wrong operator to take the address. You use & in C and C++. In Delphi the operator is #. This operator is documented here: http://docwiki.embarcadero.com/RADStudio/en/Expressions_(Delphi)#The_.40_Operator
In Delphi, & is used to escape keywords. It has no effect here, because wc is not a keyword, and is essentially ignored, treated as whitespace.
Replace & with # and your code will compile. Don't forget to check the return value of the function call for errors, as described in the function documentation.
The Delphi header translations introduce Pascal-case type names so instead of the WAVEINCAPS type it would be idiomatic to use the TWaveInCaps type.

how to internationalize a delphi application [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Translate application
What is the best way to internationalize my application written in delphi xe2 ?
I've seen the stringtable resource but I'm worried because I've got the feeling that the implementation could be time consuming and laborious.
Are there other equally valid methods to do this?
Maybe not the best tool for translations, but I'm using GNU Gettext for many years.
The process is quite simple:
You run dxgettext to extract strings
You translate or give for translation the files
I personally love poEdit tool to translate and manage translation repository
Optional : You merge your translation files into the final EXE
OR you put the translation files in subdirectories and that's it !
http://dxgettext.po.dk/
Update:
1/ GNU Gettext is included in JCL/JVCL library, you just need to activate this option at startup.
2/ Gnu Gettext can translate everything in the library, as VCL, JCL/JVCL also ! It's not just limited to your code !
One option is to use the Integrated Translation Environment in Delphi:
http://docwiki.embarcadero.com/RADStudio/XE3/en/Localizing_Applications_by_Using_Translation_Manager_Overview
Here you can find two articles about this theme:
Multilingua application with GNU gettext
Multilingua application with standard method (IDE)
You can find other methods and commencial components (i have used TsiLang components -excellent library-)
A Greeting.
I don't know is this the best way of internationalize an application, but for me it worked. It's a kind of home made.
I created an xml file, which is the dictionary containing the translations, but you can use any other format, from json, to xls (maybe this is the best). Than implemented a class which read the translations from this file, and a way to register procedures in case of the language is changed runtime, which is I think a good feature.
TDictionary = class
private
fOnChanged: TSignal;
fLanguage: String;
procedure setLanguage( const Value: String );
public
procedure loadFromFile( filename: string );
function getTranslation( id: string; lang: string = '' ): string;
property language: String read fLanguage write setLanguage;
property onChanged: TSignal read fonChanged;
end;
...
function TDictionary.getTranslation( id: string; lang: string = '' ): string;
begin
if lang = '' then
lang := Language; // use the default lang.
// read the translation from the file.
end;
procedure TDictionary.setLanguage( const Value: String );
begin
fLanguage := Value;
onChanged.Execute;
end;
TSignal is a class which register methods, and if you call Execute executes all the registered methods, Maybe in xe2 you have something built in for this, in delphi7 I had to create this class myself, but it's fun to implement.
in a form's createForm:
procedure TMyClass.doTranslate( dictionary: TObject );
begin
with dictionary as TDictionary do
begin
caption := dictionary.getTranslation( 'myclass.caption' );
button.caption := dictionary.getTranslation( 'some id' );
end;
// or you can go through Controls array, and automate the assignment.
end;
procedure TMyClass.FormCreate(Sender: TObject);
begin
Dictionary.onChanged.register( doTranslate );
doTranslate( dictionary );
end;
procedure TMyClass.FormDestroy(Sender: TObject);
begin
Dictionary.onChanged.deregister( doTranslate );
end;
As you can see, this is not a working example what you can copy and paste, I just wanted to show you the idea behind. if something is not clear, comment it, and I can extend my answer.
Some notes:
I think it's important to have the translations in utf8 format.
using xls makes the localizers live easier, and your too, if they ruin your xml file (If the translator is not prof., It can happen that you get back your xml file in microsoft word format)
you can put your dictionary file into resource, and load from there.
Pros
This way you can change the language runtime
if you need another language, you just need to edit the dictionary file.
Cons
If you have many forms, it's a nightmare to connect all the labels, buttons, etc, but you can automate it in smart ways.
It slows down your app a little, but not much, if changing your app language is not happening so often.
There is a product called sisulizer, it works after you have build the executable fies I think. Haven't tried it but I've read a lot about it.
Have a look at this

How to get the sort order in Delphi as in Windows Explorer?

Summarization:
The terminology that I have been
looking for seems to be "natural
sort".
For behaviors in operating systems:
For Windows (version >= XP), Windows Explorer utilizes natural
sort.
For Linux terminals: use "ls -v" instead of plain "ls" to get natural
sort.
For programing in Delphi, use StrCmpLogicalW Windows API to get natural sort.
For programing in Delphi & Kylix & Lazarus, use hand-crafted functions to get
natural sort:
(1) Delphi wrapper for Natural Order String Comparison by Martin Pool.
http://irsoft.de/web/strnatcmp-and-natsort-for-delphi
(2) Codes of alphanum sorting algorithm in other languages from davekeolle site.
http://www.davekoelle.com/alphanum.html
(3) Other knowledgable pages:
http://www.codinghorror.com/blog/2007/12/sorting-for-humans-natural-sort-order.html
http://objectmix.com/delphi/722211-natural-sorting-optimizing-working-solution.html
http://groups.google.com/group/borland.public.delphi.language.delphi.general/browse_thread/thread/1141d49f8bbba577
http://objectmix.com/delphi/401713-alphanumeric-sort-routine-delphi.html
==========================
The following file names will be ordered in the Windows Explorer as shown below:
test_1_test.txt
test_2_test.txt
test_11_test.txt
test_12_test.txt
test_21_test.txt
test_22_test.txt
If, for example, I put them in a TStringList instance and call Sort, the sorted order is as below:
test_1_test.txt
test_11_test.txt
test_12_test.txt
test_2_test.txt
test_21_test.txt
test_22_test.txt
And for record, the above file names will be ordered in the rxvt terminal of Cygwin or xterm terminal of Linux distributions such as CentOS as shown below:
test_11_test.txt
test_12_test.txt
test_1_test.txt
test_21_test.txt
test_22_test.txt
test_2_test.txt
Could you help to comment on how to understand this difference of sorting behaviors? Furthermore, is it possible to get the same order as in Windows Explorer? Any suggestion is appreciated!
PS: My Windows locale is set to Chinese but I would think the same for English locale.
StrCmpLogicalW is able to handle numbers, the other alternative is CompareString
Thanks to Anders - the answer is StrCmpLogicalW; I have not found it's declaration in Delphi 2009 sources, so I declared it myself in the test below:
type
TMyStringList = class(TStringList)
protected
function CompareStrings(const S1, S2: string): Integer; override;
end;
function StrCmpLogicalW(P1, P2: PWideChar): Integer; stdcall; external 'Shlwapi.dll';
function TMyStringList.CompareStrings(const S1, S2: string): Integer;
begin
Result:= StrCmpLogicalW(PChar(S1), PChar(S2));
end;
procedure TForm11.Button2Click(Sender: TObject);
var
SL: TMyStringList;
begin
SL:= TMyStringList.Create;
try
SL.Add('test_1_test.txt');
SL.Add('test_11_test.txt');
SL.Add('test_12_test.txt');
SL.Add('test_2_test.txt');
SL.Add('test_21_test.txt');
SL.Add('test_22_test.txt');
SL.Sort;
Memo1.Lines:= SL;
finally
SL.Free;
end;
end;

Resources