如何发送自定义SWT键事件,以便在不进行任何转换的情况下输入该确切的文字字符?
我们正在制作一个自定义的屏幕图形键盘,允许多种可能的布局 - QWERTY是主要的布局,但其他几个计划,包括可视化模拟iPhone键盘布局或其他相对于非键盘布局的其他布局PC。
我希望能够将我选择的任意字符作为事件发送,这样就会导致输入该字符。但是,每当我发送一个具有给定角色的事件时, SWT似乎会根据系统的键盘设置和状态自动解释和转换它,将其更改为大写/小写或使用移位的符号取决于是否按下了shift键(例如实际键盘上的真实键)。例如,通过键事件传递字符'T'将导致't'或'T',具体取决于shift键。它与“4”字符的表现相似,根据班次做“4”或“$”。
这是有问题的,因为我希望手动执行字符移位,并且实际上可能不希望在任何给定情况下使用与标准QWERTY键盘相同的移位字符(例如,我想要'$'来是一个较小的手机式键盘上的'R'的移位(或“功能”键)版本。我怎样才能使用这些事件,以免它假设使用QWERTY键?
SWT事件中“字符”字段的文档说明如下:
键入的键所代表的字符。这是决赛 应用所有修改器后得到的字符。对于 例如,当用户键入Ctrl + A时,字符值为0x01。它 重要的是应用程序不会尝试修改字符 基于stateMask(例如SWT.CTRL)或结果的值 字符不正确。
这让我相信它不应该像我一样转换我的角色,因为我命令它使用我的“最终”结果。
我创建了一个简单的独立示例来演示我的问题(请注意,这不是我在做实际键盘的方式,而只是为了突出显示关键事件问题):
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Button;
public class KeyboardIssueExample extends Shell {
private Text txtTextArea;
private Composite cmpButtons;
private Button btnBigA;
private Button btnBigS;
private Button btnLittleD;
private Button btnSix;
private Button btnSeven;
private Button btnDollah;
private Button btnStar;
private SelectionListener mainListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent selE) {
Button b = (Button)selE.widget;
char c = b.getText().charAt(0);
sendKey(c);
}
};
/**
* Launch the application.
* @param args
*/
public static void main(String args[]) {
try {
Display display = Display.getDefault();
KeyboardIssueExample shell = new KeyboardIssueExample(display);
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Create the shell.
* @param display
*/
public KeyboardIssueExample(Display display) {
super(display, SWT.SHELL_TRIM);
createContents();
}
/**
* Create contents of the shell.
*/
protected void createContents() {
setText("SWT Application");
setSize(450, 300);
setLayout(new GridLayout());
txtTextArea = new Text(this, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CANCEL | SWT.MULTI);
txtTextArea.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
cmpButtons = new Composite(this, SWT.NONE);
cmpButtons.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
GridLayout gl_cmpButtons = new GridLayout(7, false);
gl_cmpButtons.marginWidth = 0;
gl_cmpButtons.marginHeight = 0;
cmpButtons.setLayout(gl_cmpButtons);
btnBigA = new Button(cmpButtons, SWT.NONE);
btnBigA.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
btnBigA.setText("A");
btnBigS = new Button(cmpButtons, SWT.NONE);
btnBigS.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
btnBigS.setText("S");
btnLittleD = new Button(cmpButtons, SWT.NONE);
btnLittleD.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
btnLittleD.setText("d");
btnSix = new Button(cmpButtons, SWT.NONE);
btnSix.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
btnSix.setText("6");
btnSeven = new Button(cmpButtons, SWT.NONE);
btnSeven.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
btnSeven.setText("7");
btnDollah = new Button(cmpButtons, SWT.NONE);
btnDollah.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
btnDollah.setText("$");
btnStar = new Button(cmpButtons, SWT.NONE);
btnStar.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1));
btnStar.setText("*");
init();
}
private void init() {
btnBigA.addSelectionListener(mainListener);
btnBigS.addSelectionListener(mainListener);
btnLittleD.addSelectionListener(mainListener);
btnSix.addSelectionListener(mainListener);
btnSeven.addSelectionListener(mainListener);
btnDollah.addSelectionListener(mainListener);
btnStar.addSelectionListener(mainListener);
}
@Override
protected void checkSubclass() {
// Disable the check that prevents subclassing of SWT components
}
private void sendKey(char c) {
sendKeyEvent(c, SWT.KeyDown);
sendKeyEvent(c, SWT.KeyUp);
}
private void sendKeyEvent(char c, int eventType) {
txtTextArea.forceFocus();
Event event = new Event();
event.type = eventType;
event.character = c;
getDisplay().post(event);
}
}
正如您将发现的那样,关键事件不尊重我自己的大写自定义用法,而是使用它自己的。多么麻烦。
答案 0 :(得分:4)
查看Mac和Windows的Display.post
来源,有很多特定于密钥上/下事件的代码。这包括调用OS特定的API,将您指定的字符和键代码转换为用于生成键击事件的OS特定方法所需的参数。
对于Windows,此代码调用VkKeyScan
,根据Microsoft文档,它会查看当前的键盘状态。
Display
确实有postEvent(Event)
方法,可以在不更改任何内容的情况下添加到事件队列中,但这不是公开的,因此您必须使用反射访问它。由于它不是官方API的一部分,因此可能会发生变化。
编辑: 实际上有一个Eclipse错误报告here。它已经开放了10年,所以可能不会被修复!
更新:
还有一个Widget.notifyListeners(eventType, Event)
方法可用于将键事件发送到特定控件。您必须创建Event
并设置必填字段。