How to capture combination key event? - windows

In C#, it was written like this:
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control && e.Shift && e.KeyCode == Keys.P)
{
MessageBox.Show("Hello");
}
}
Capturing Ctrl + Shift + P key stroke in a C# Windows Forms application [duplicate]
I tried to emulate the way they wrote it in C# to Delphi XE8 but it doesn't seemed to work:
procedure TForm12.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if (GetKeyState(VK_CONTROL) < 0) and (Key = 53) then
ShowMessage('You pressed "ctrl + s"');
end;
Note: The TForm.KeyPreview Troperty is set to true
How can I capture that combination key event?

The key you are looking for, S, has code $53. The key you specified has code 53 and is the number 5. The difference is the $ which signifies hexadecimal.
You'd avoid such silly mistakes, and make the code much clearer, if you let the compiler do the work:
Key = ord('S')
You really don't want to use magic constants in your program. That is very important.
Note that Key is a virtual key code and the convention is that for the 26 keys of the Latin alphabet, they are represented by the ordinal value of the uppercase letter.
The message already passes the state of the modifier keys in the Shift argument, so it is idiomatic to write the test as follows:
if (ssCtrl in Shift) and (Key = ord('S')) then
Your test using GetKeyState does work well, but it's just not idiomatic.
Note that this test, which matches that in the question will, ignores the state of the other modifier keys. Indeed, the C# code in the question also ignores the state of the ALT modifier.
So you may want a true test for CTRL + S you must also check that the other modifiers are up:
if ([ssCtrl] = Shift*[ssCtrl, ssShift, ssAlt]) and (Key = ord('S')) then
All this said, it's usually much easier to manage your shortcuts using actions. This will allow you to specify shortcuts directly, and let the framework detect the low level key events that make up a shortcut. What's more actions allow you to centralise handling of the actions behind buttons and menus without you repeating yourself.

You can use actions to automate shortcuts. Drop in a TActionManager and add a TAction to it. On that action, assign a Name, Caption, and an OnExecute event handler, and most importantly a value for ShortCut. This can be a string representing the keystrokes, in your case Ctrl+Shift+P. Then, you can either assign that action to various controls, or call it like MyAction.Execute.

In Delphi you use the Shift: TShiftState to check which 'shift'-keys are pressed.
As pointed out in comments your error is that the key value for letter s is not decimal 53, but hexadecimal 53, iow $53in Delphi syntax.
I first thought you also wanted to check for the shift key as in the referenced source of your inspiration, in which case you can test for the exclusive combination as follows:
procedure TForm15.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (Key = $53) and ([ssCtrl, ssShift] = Shift) then
begin
ShowMessage('You pressed "ctrl + shift + s"');
Key := 0; // optional
end;
end;
You may or may not want to clear the Key parameter to prevent further action by the control with focus.
Rereading your question after another comment, you seem to want to detect only the Ctrl + s combination, in which case the exclusive condition test becomes
if (Key = $53) and ([ssCtrl] = Shift) then
I recommed to be precise (exclusive) in the shift state test, because the shift state includes not only the Shift, Ctrland Alt keys but also mouse buttons and some gestures.
The documentation on TShiftState provides other possible values of Shift to check for.
Finally, as #David Heffernan points out in his answer, instead of a magic constant ($53) for the key test, use Ord('S').

Related

Pascal readkey command issue

I use readkey command twice.
It works fine on the first time but refuses to work in the second one.
I'd like that program waits for my key press but the program ends itself.
code:
program window1;
uses crt;
var x,y:integer;
begin
clrscr;
window(1,1,80,25);
readkey;
//writting just window borders
for x:=1 to 80 do
for y:=1 to 25 do
begin
if (x >= 2) and (x <= 79) and
(y >= 2) and (y <= 24) then
continue
else
begin
gotoxy(x,y);
write('*');
end;
end;
gotoxy(2,23);
write('inside window press any key to exit...');
readkey;
//readln;
end.
I've pressed the up arrow key.
I've pressed the up arrow key
Some keys on a keyboard generates what is called extended keys. The arrow keys (among others) are such keys. They return two characters, not one. The first character is ASCII 0 and the second is the scan code of the pressed key.
For ReadKey it is documented:
ReadKey reads 1 key from the keyboard buffer, and returns this. If an extended or function key has been pressed, then the zero ASCII code is returned. You can then read the scan code of the key with a second ReadKey call.
I could add to that, that ReadKey waits for input if the keyboard buffer is empty (but only if it is empty).
Therefore, when your program calls ReadKey for the first time, and you hit the "up arrow key", two bytes are put into the buffer, $00 and $48. The first one ($00) is returned to your code, and the scan code for the up arrow remains in the input buffer. When you then later call ReadKey a second time it receives the scan code from the buffer and continues immediately without stopping for input.
You can deal with this in one of two ways:
1.Write a procedure, say WaitForAnyKey that deals with the extended keys:
procedure WaitForAnyKey;
var
c: char;
begin
c:=ReadKey;
if c=#0 then
c:=ReadKey;
end;
and you call it instead of calling ReadKey directly.
2.Write a procedure that waits for, and accepts a specific key only:
procedure WaitForCR; // wait for CR, Carriage Return (Enter)
const
CR=#13;
var
c: Char;
begin
repeat
c:=ReadKey;
until c=CR;
end
and you call it instead of calling ReadKey directly.

visual basic calculator without using decision structures or loops

1st year coding student and have a project in my visual basics class.
Create a simple calculator that will multiply, divide, subtract and add. Thing is we are not allowed to use any decision structures or loops, only sequential style coding structure.
I am struggling with storing, passing, and utilizing the selected mathematical operator later in the program.
When coding equations, what data type are operators considered?
For example in 4-1=3 is - considered a string?
How would one go about storing this value and passing it to another section of the program then converting that to a form you could plug into a formula, all without using a decision structure or loop?
for example:
1) User clicks on "1" button a string value of 1 is stored in a label as a string.
2) The user clicks the the "+" button and a + is stored (not sure what data type to use here for later needs) in a label.
3) Then user clicks "1" button a 1 is stored in a label as a string.
4) User clicks the "=" button.
5) The = button event handler executes code converting both the "1" strings to integer variables and the formula should represent IntResult= IntvariableOne + intVariableTwo. but since the operator may not always be + and no decision structure can be used. how can this be coded in a way that uses a variable to store the operator and complete the processing correctly in a formula?
In the most simple terms it would be equivalent to something like:
intResult= intvariableOne, Operatorvarible, intVariableTwo
Like I said I am new to coding so I apologize if this is a dumb question or completely wrong approach.
any info is appreciated.
thanks
It's a cheat, but try using Eval:
Eval("4-1") ' returns 3
Reading your post I was thinking about using the "CallByName" function.
But you can also try something more elegant with some kind of "oop" (reaching some of the limits offered by the old VB6) :
Create a file "ICalculator.cls" :
'
' Defines the "ICalculator" interface.
'
Option Explicit
Public Function CalcProcess(value1 As Integer, value2 As Integer)
End Function
Create a file named "CalculatorAdd.cls" that will take "additions" in charge:
'
' This "class" will implement "ICalculator" inteface to manage additions.
'
Option Explicit
Implements ICalculator
Private Function ICalculator_CalcProcess(value1 As Integer, value2 As Integer)
ICalculator_CalcProcess = value1 + value2
End Function
An then, an example of how it works :
Sub Test()
Dim value1 As Integer
Dim value2 As Integer
value1 = 1
value2 = 2
' Global object :
Dim objCalculator As ICalculator
...
' The object is set to "Addition" in the onclick event of the "add" button :
Set objCalculator = New CalculatorAdd
...
' The process is done in the onclick event of the "equal" button
value1 = objCalculator.CalcProcess(value1, value2)
...
' You can also have :
'Set objCalculator = New CalculatorSub
'value1 = objCalculator.CalcProcess(value1, value2)
'etc...
End Sub
You can create classes for each operation "add, sub, divide, multiply" and set your global variable objCalculator according to the button pressed by the user.
That's just a beginning, you'll have to put the whole logic of a calculator in place...

Sending KeyPress events in X11

I have a program where for various reasons i need to send keypress events to various windows. What I am using at the moment
XEvent event;
/* set some other stuff*/
event.type = KeyPress;
event.xkey.keycode = XKeysymToKeycode(display,XStringToKeysym(curr_key));
works for lower case letters and numbers, but I need to modify this so that it is capable of sending the enter key and upper case letters.
From the XStringToKeysym man page:
void XConvertCase(KeySym keysym, KeySym *lower_return, KeySym *upper_return);
The XConvertCase function returns the uppercase and lowercase forms of the specified Keysym, if the KeySym is subject to case conversion; otherwise, the specified KeySym is returned to both lower_return and upper_return. Support for conversion of other than Latin and Cyrillic KeySyms is implementation-dependent.
All the keysyms are in /usr/include/X11/keysymdef.h e.g. the enter key is XK_Return. The letters are there too e.g. XK_a and XK_A.

Obtaining modifier key pressed in CGEvent tap

Having setup an event tap, I'm not able to identify what modifier key was pressed given a CGEvent.
CGEventFlags flagsP;
flagsP=CGEventGetFlags(event);
NSLog(#"flags: 0x%llX",flagsP);
NSLog(#"stored: 0x%llX",kCGEventFlagMaskCommand);
if (flagsP==kCGEventFlagMaskCommand) {
NSLog(#"command pressed");
}
Given the above snippet, the first NSLog returns a different value from the second NSLog. No surprise that the conditional is never triggered when the command modifier key is pressed.
I need to identify whether command, alternate, option, control or shift are pressed for a given CGEvent. First though, I need help to understand why the above isn't working.
Thanks!
These are bit masks, which will be bitwise-ORed together into the value you receive from CGEventGetFlags (or pass when creating an event yourself).
You can't test equality here because no single bit mask will be equal to a combination of multiple bit masks. You need to test equality of a single bit.
To extract a single bit mask's value from a combined bit mask, use the bitwise-AND (&) operator. Then, compare that to the single bit mask you're interested in:
BOOL commandKeyIsPressed = (flagsP & kCGEventFlagMaskCommand) == kCGEventFlagMaskCommand;
Why both?
The & expression evaluates to the same type as its operands, which is CGEventFlags in this case, which may not fit in the size of a BOOL, which is a signed char. The == expression resolves that to 1 or 0, which is all that will fit in a BOOL.
Other solutions to that problem include negating the value twice (!!) and declaring the variable as bool or _Bool rather than Boolean or BOOL. C99's _Bool type (synonymized to bool when you include stdbool.h) forces its value to be either 1 or 0, just as the == and !! solutions do.

How do I use CGEventKeyboardSetUnicodeString with multiple characters?

I'm trying to use event taps to create an OS X program that will listen for Yiddish typed in transliteration and post the result in Hebrew characters. I made a very short program to test one things I'd have to do: http://pastie.org/791398
As is, the program successfully replaces every typed 'q' with 'w':
if(inputString[0] == 'q') { inputString[0] = 'w'; }
But how does one post a string of more than one character? For instance, if someone types 'sh' you'd presumably have to post a backspace (to delete the character that was posted for 's' alone) and then post the character that corresponds to 'sh'. However, this code results in only a backspace being posted:
else if(inputString[0] == 'm') { inputString[0] = '\b'; inputString[1] = 'n'; }
I apologize if these are basic questions; I have read all the documentation I could find, but I might not have understood it all. It's also possible that I'm going about this entirely the wrong way.
Ideally you should be using an input method instead of a program with event taps, most likely using Input Method Kit if you don't need to support pre-10.5. Using event taps for this purpose is inherently a bad idea because the user can change where he/she is typing with the mouse as well as the keyboard. So if the user typed a "s" in one text field followed by a "h" in another, you wouldn't be able to tell the difference.
That said, here's a direct answer to your question.
The string is length-counted, so you can't just provide the incoming length (1); the second character will be ignored. However, most applications also don't like to get more than a single character per event, so they'll just discard the remaining characters. (Terminal is a notable exception.)
So what you can do is simply post a second event with the second character in it.
else if(inputString[0] == 'm') {
inputString[0] = 'n';
CGEventKeyboardSetUnicodeString(event, 1, inputString);
CGEventPost(kCGSessionEventTap, event);
inputString[0] = '\b';
}
In the general case (simulating > 2 keypresses) you'll need to create an event for each character you want to insert. This mailing list post includes a simple example.
This is how I send a string to the first responder ( foreground application )
// 1 - Get the string length in bytes.
NSUInteger l = [string lengthOfBytesUsingEncoding:NSUTF16StringEncoding];
// 2 - Get bytes for unicode characters
UniChar *uc = malloc(l);
[string getBytes:uc maxLength:l usedLength:NULL encoding:NSUTF16StringEncoding options:0 range:NSMakeRange(0, l) remainingRange:NULL];
// 3 - create an empty tap event, and set unicode string
CGEventRef tap = CGEventCreateKeyboardEvent(NULL,0, YES);
CGEventKeyboardSetUnicodeString(tap, string.length, uc);
// 4 - Send event and tear down
CGEventPost(kCGSessionEventTap, tap);
CFRelease(tap);
free(uc);

Resources