mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-15 05:14:46 +00:00
winemac: Generate KEY_PRESS/RELEASE events from Cocoa key events.
This commit is contained in:
parent
d0e1a02515
commit
77de57683f
|
@ -42,9 +42,11 @@ @interface WineApplication : NSApplication <NSApplicationDelegate>
|
|||
unsigned long windowFocusSerial;
|
||||
|
||||
CGEventSourceKeyboardType keyboardType;
|
||||
NSEvent* lastFlagsChanged;
|
||||
}
|
||||
|
||||
@property (nonatomic) CGEventSourceKeyboardType keyboardType;
|
||||
@property (readonly, copy, nonatomic) NSEvent* lastFlagsChanged;
|
||||
|
||||
- (void) transformProcessToForeground;
|
||||
|
||||
|
@ -56,6 +58,8 @@ - (double) ticksForEventTime:(NSTimeInterval)eventTime;
|
|||
|
||||
- (void) windowGotFocus:(WineWindow*)window;
|
||||
|
||||
- (void) keyboardSelectionDidChange;
|
||||
|
||||
@end
|
||||
|
||||
void OnMainThread(dispatch_block_t block);
|
||||
|
|
|
@ -28,9 +28,16 @@
|
|||
int macdrv_err_on;
|
||||
|
||||
|
||||
@interface WineApplication ()
|
||||
|
||||
@property (readwrite, copy, nonatomic) NSEvent* lastFlagsChanged;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation WineApplication
|
||||
|
||||
@synthesize keyboardType;
|
||||
@synthesize keyboardType, lastFlagsChanged;
|
||||
|
||||
- (id) init
|
||||
{
|
||||
|
@ -219,6 +226,18 @@ - (void) keyboardSelectionDidChange
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* ---------- NSApplication method overrides ----------
|
||||
*/
|
||||
- (void) sendEvent:(NSEvent*)anEvent
|
||||
{
|
||||
if ([anEvent type] == NSFlagsChanged)
|
||||
self.lastFlagsChanged = anEvent;
|
||||
|
||||
[super sendEvent:anEvent];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ---------- NSApplicationDelegate methods ----------
|
||||
*/
|
||||
|
|
|
@ -46,6 +46,8 @@ @interface WineWindow : NSPanel <NSWindowDelegate>
|
|||
|
||||
BOOL usePerPixelAlpha;
|
||||
|
||||
NSUInteger lastModifierFlags;
|
||||
|
||||
BOOL causing_becomeKeyWindow;
|
||||
BOOL ignore_windowMiniaturize;
|
||||
BOOL ignore_windowDeminiaturize;
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
*/
|
||||
|
||||
#import <Carbon/Carbon.h>
|
||||
|
||||
#import "cocoa_window.h"
|
||||
|
||||
#include "macdrv_cocoa.h"
|
||||
|
@ -25,6 +27,12 @@
|
|||
#import "cocoa_event.h"
|
||||
|
||||
|
||||
/* Additional Mac virtual keycode, to complement those in Carbon's <HIToolbox/Events.h>. */
|
||||
enum {
|
||||
kVK_RightCommand = 0x36, /* Invented for Wine; was unused */
|
||||
};
|
||||
|
||||
|
||||
static NSUInteger style_mask_for_features(const struct macdrv_window_features* wf)
|
||||
{
|
||||
NSUInteger style_mask;
|
||||
|
@ -55,6 +63,49 @@ static BOOL frame_intersects_screens(NSRect frame, NSArray* screens)
|
|||
}
|
||||
|
||||
|
||||
/* We rely on the supposedly device-dependent modifier flags to distinguish the
|
||||
keys on the left side of the keyboard from those on the right. Some event
|
||||
sources don't set those device-depdendent flags. If we see a device-independent
|
||||
flag for a modifier without either corresponding device-dependent flag, assume
|
||||
the left one. */
|
||||
static inline void fix_device_modifiers_by_generic(NSUInteger* modifiers)
|
||||
{
|
||||
if ((*modifiers & (NX_COMMANDMASK | NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK)) == NX_COMMANDMASK)
|
||||
*modifiers |= NX_DEVICELCMDKEYMASK;
|
||||
if ((*modifiers & (NX_SHIFTMASK | NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK)) == NX_SHIFTMASK)
|
||||
*modifiers |= NX_DEVICELSHIFTKEYMASK;
|
||||
if ((*modifiers & (NX_CONTROLMASK | NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK)) == NX_CONTROLMASK)
|
||||
*modifiers |= NX_DEVICELCTLKEYMASK;
|
||||
if ((*modifiers & (NX_ALTERNATEMASK | NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK)) == NX_ALTERNATEMASK)
|
||||
*modifiers |= NX_DEVICELALTKEYMASK;
|
||||
}
|
||||
|
||||
/* As we manipulate individual bits of a modifier mask, we can end up with
|
||||
inconsistent sets of flags. In particular, we might set or clear one of the
|
||||
left/right-specific bits, but not the corresponding non-side-specific bit.
|
||||
Fix that. If either side-specific bit is set, set the non-side-specific bit,
|
||||
otherwise clear it. */
|
||||
static inline void fix_generic_modifiers_by_device(NSUInteger* modifiers)
|
||||
{
|
||||
if (*modifiers & (NX_DEVICELCMDKEYMASK | NX_DEVICERCMDKEYMASK))
|
||||
*modifiers |= NX_COMMANDMASK;
|
||||
else
|
||||
*modifiers &= ~NX_COMMANDMASK;
|
||||
if (*modifiers & (NX_DEVICELSHIFTKEYMASK | NX_DEVICERSHIFTKEYMASK))
|
||||
*modifiers |= NX_SHIFTMASK;
|
||||
else
|
||||
*modifiers &= ~NX_SHIFTMASK;
|
||||
if (*modifiers & (NX_DEVICELCTLKEYMASK | NX_DEVICERCTLKEYMASK))
|
||||
*modifiers |= NX_CONTROLMASK;
|
||||
else
|
||||
*modifiers &= ~NX_CONTROLMASK;
|
||||
if (*modifiers & (NX_DEVICELALTKEYMASK | NX_DEVICERALTKEYMASK))
|
||||
*modifiers |= NX_ALTERNATEMASK;
|
||||
else
|
||||
*modifiers &= ~NX_ALTERNATEMASK;
|
||||
}
|
||||
|
||||
|
||||
@interface WineContentView : NSView
|
||||
@end
|
||||
|
||||
|
@ -493,6 +544,44 @@ - (void) makeFocused
|
|||
[self windowDidResize:nil];
|
||||
}
|
||||
|
||||
- (void) postKey:(uint16_t)keyCode
|
||||
pressed:(BOOL)pressed
|
||||
modifiers:(NSUInteger)modifiers
|
||||
event:(NSEvent*)theEvent
|
||||
{
|
||||
macdrv_event event;
|
||||
CGEventRef cgevent;
|
||||
WineApplication* app = (WineApplication*)NSApp;
|
||||
|
||||
event.type = pressed ? KEY_PRESS : KEY_RELEASE;
|
||||
event.window = (macdrv_window)[self retain];
|
||||
event.key.keycode = keyCode;
|
||||
event.key.modifiers = modifiers;
|
||||
event.key.time_ms = [app ticksForEventTime:[theEvent timestamp]];
|
||||
|
||||
if ((cgevent = [theEvent CGEvent]))
|
||||
{
|
||||
CGEventSourceKeyboardType keyboardType = CGEventGetIntegerValueField(cgevent,
|
||||
kCGKeyboardEventKeyboardType);
|
||||
if (keyboardType != app.keyboardType)
|
||||
{
|
||||
app.keyboardType = keyboardType;
|
||||
[app keyboardSelectionDidChange];
|
||||
}
|
||||
}
|
||||
|
||||
[queue postEvent:&event];
|
||||
}
|
||||
|
||||
- (void) postKeyEvent:(NSEvent *)theEvent
|
||||
{
|
||||
[self flagsChanged:theEvent];
|
||||
[self postKey:[theEvent keyCode]
|
||||
pressed:[theEvent type] == NSKeyDown
|
||||
modifiers:[theEvent modifierFlags]
|
||||
event:theEvent];
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ---------- NSWindow method overrides ----------
|
||||
|
@ -556,12 +645,81 @@ - (void) mouseUp:(NSEvent *)theEvent { [self postMouseButtonEvent:theEvent press
|
|||
- (void) rightMouseUp:(NSEvent *)theEvent { [self mouseUp:theEvent]; }
|
||||
- (void) otherMouseUp:(NSEvent *)theEvent { [self mouseUp:theEvent]; }
|
||||
|
||||
- (void) keyDown:(NSEvent *)theEvent { [self postKeyEvent:theEvent]; }
|
||||
- (void) keyUp:(NSEvent *)theEvent { [self postKeyEvent:theEvent]; }
|
||||
|
||||
- (void) flagsChanged:(NSEvent *)theEvent
|
||||
{
|
||||
static const struct {
|
||||
NSUInteger mask;
|
||||
uint16_t keycode;
|
||||
} modifiers[] = {
|
||||
{ NX_ALPHASHIFTMASK, kVK_CapsLock },
|
||||
{ NX_DEVICELSHIFTKEYMASK, kVK_Shift },
|
||||
{ NX_DEVICERSHIFTKEYMASK, kVK_RightShift },
|
||||
{ NX_DEVICELCTLKEYMASK, kVK_Control },
|
||||
{ NX_DEVICERCTLKEYMASK, kVK_RightControl },
|
||||
{ NX_DEVICELALTKEYMASK, kVK_Option },
|
||||
{ NX_DEVICERALTKEYMASK, kVK_RightOption },
|
||||
{ NX_DEVICELCMDKEYMASK, kVK_Command },
|
||||
{ NX_DEVICERCMDKEYMASK, kVK_RightCommand },
|
||||
};
|
||||
|
||||
NSUInteger modifierFlags = [theEvent modifierFlags];
|
||||
NSUInteger changed;
|
||||
int i, last_changed;
|
||||
|
||||
fix_device_modifiers_by_generic(&modifierFlags);
|
||||
changed = modifierFlags ^ lastModifierFlags;
|
||||
|
||||
last_changed = -1;
|
||||
for (i = 0; i < sizeof(modifiers)/sizeof(modifiers[0]); i++)
|
||||
if (changed & modifiers[i].mask)
|
||||
last_changed = i;
|
||||
|
||||
for (i = 0; i <= last_changed; i++)
|
||||
{
|
||||
if (changed & modifiers[i].mask)
|
||||
{
|
||||
BOOL pressed = (modifierFlags & modifiers[i].mask) != 0;
|
||||
|
||||
if (i == last_changed)
|
||||
lastModifierFlags = modifierFlags;
|
||||
else
|
||||
{
|
||||
lastModifierFlags ^= modifiers[i].mask;
|
||||
fix_generic_modifiers_by_device(&lastModifierFlags);
|
||||
}
|
||||
|
||||
// Caps lock generates one event for each press-release action.
|
||||
// We need to simulate a pair of events for each actual event.
|
||||
if (modifiers[i].mask == NX_ALPHASHIFTMASK)
|
||||
{
|
||||
[self postKey:modifiers[i].keycode
|
||||
pressed:TRUE
|
||||
modifiers:lastModifierFlags
|
||||
event:(NSEvent*)theEvent];
|
||||
pressed = FALSE;
|
||||
}
|
||||
|
||||
[self postKey:modifiers[i].keycode
|
||||
pressed:pressed
|
||||
modifiers:lastModifierFlags
|
||||
event:(NSEvent*)theEvent];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ---------- NSWindowDelegate methods ----------
|
||||
*/
|
||||
- (void)windowDidBecomeKey:(NSNotification *)notification
|
||||
{
|
||||
NSEvent* event = [NSApp lastFlagsChanged];
|
||||
if (event)
|
||||
[self flagsChanged:event];
|
||||
|
||||
if (causing_becomeKeyWindow) return;
|
||||
|
||||
[NSApp windowGotFocus:self];
|
||||
|
|
|
@ -33,6 +33,8 @@ static const char *dbgstr_event(int type)
|
|||
{
|
||||
static const char * const event_names[] = {
|
||||
"APP_DEACTIVATED",
|
||||
"KEY_PRESS",
|
||||
"KEY_RELEASE",
|
||||
"KEYBOARD_CHANGED",
|
||||
"MOUSE_BUTTON",
|
||||
"WINDOW_CLOSE_REQUESTED",
|
||||
|
@ -58,7 +60,11 @@ static macdrv_event_mask get_event_mask(DWORD mask)
|
|||
if ((mask & QS_ALLINPUT) == QS_ALLINPUT) return -1;
|
||||
|
||||
if (mask & QS_KEY)
|
||||
{
|
||||
event_mask |= event_mask_for_type(KEY_PRESS);
|
||||
event_mask |= event_mask_for_type(KEY_RELEASE);
|
||||
event_mask |= event_mask_for_type(KEYBOARD_CHANGED);
|
||||
}
|
||||
|
||||
if (mask & QS_MOUSEBUTTON)
|
||||
event_mask |= event_mask_for_type(MOUSE_BUTTON);
|
||||
|
@ -98,6 +104,10 @@ void macdrv_handle_event(macdrv_event *event)
|
|||
case APP_DEACTIVATED:
|
||||
macdrv_app_deactivated();
|
||||
break;
|
||||
case KEY_PRESS:
|
||||
case KEY_RELEASE:
|
||||
macdrv_key_event(hwnd, event);
|
||||
break;
|
||||
case KEYBOARD_CHANGED:
|
||||
macdrv_keyboard_changed(event);
|
||||
break;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "wine/unicode.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(keyboard);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(key);
|
||||
|
||||
|
||||
/* Carbon-style modifier mask definitions from <Carbon/HIToolbox/Events.h>. */
|
||||
|
@ -663,6 +664,62 @@ void macdrv_compute_keyboard_layout(struct macdrv_thread_data *thread_data)
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* macdrv_send_keyboard_input
|
||||
*/
|
||||
static void macdrv_send_keyboard_input(HWND hwnd, WORD vkey, WORD scan, DWORD flags, DWORD time)
|
||||
{
|
||||
INPUT input;
|
||||
|
||||
TRACE_(key)("hwnd %p vkey=%04x scan=%04x flags=%04x\n", hwnd, vkey, scan, flags);
|
||||
|
||||
input.type = INPUT_KEYBOARD;
|
||||
input.ki.wVk = vkey;
|
||||
input.ki.wScan = scan;
|
||||
input.ki.dwFlags = flags;
|
||||
input.ki.time = time;
|
||||
input.ki.dwExtraInfo = 0;
|
||||
|
||||
__wine_send_input(hwnd, &input);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* macdrv_key_event
|
||||
*
|
||||
* Handler for KEY_PRESS and KEY_RELEASE events.
|
||||
*/
|
||||
void macdrv_key_event(HWND hwnd, const macdrv_event *event)
|
||||
{
|
||||
struct macdrv_thread_data *thread_data = macdrv_thread_data();
|
||||
WORD vkey, scan;
|
||||
DWORD flags;
|
||||
|
||||
TRACE_(key)("win %p/%p key %s keycode %hu modifiers 0x%08llx\n",
|
||||
hwnd, event->window, (event->type == KEY_PRESS ? "press" : "release"),
|
||||
event->key.keycode, event->key.modifiers);
|
||||
|
||||
if (event->key.keycode < sizeof(thread_data->keyc2vkey)/sizeof(thread_data->keyc2vkey[0]))
|
||||
{
|
||||
vkey = thread_data->keyc2vkey[event->key.keycode];
|
||||
scan = thread_data->keyc2scan[event->key.keycode];
|
||||
}
|
||||
else
|
||||
vkey = scan = 0;
|
||||
|
||||
TRACE_(key)("keycode %hu converted to vkey 0x%X scan 0x%02x\n",
|
||||
event->key.keycode, vkey, scan);
|
||||
|
||||
if (!vkey) return;
|
||||
|
||||
flags = 0;
|
||||
if (event->type == KEY_RELEASE) flags |= KEYEVENTF_KEYUP;
|
||||
if (scan & 0x100) flags |= KEYEVENTF_EXTENDEDKEY;
|
||||
|
||||
macdrv_send_keyboard_input(hwnd, vkey, scan & 0xff, flags, event->key.time_ms);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* macdrv_keyboard_changed
|
||||
*
|
||||
|
|
|
@ -135,5 +135,6 @@ static inline RECT rect_from_cgrect(CGRect cgrect)
|
|||
|
||||
extern void macdrv_compute_keyboard_layout(struct macdrv_thread_data *thread_data) DECLSPEC_HIDDEN;
|
||||
extern void macdrv_keyboard_changed(const macdrv_event *event) DECLSPEC_HIDDEN;
|
||||
extern void macdrv_key_event(HWND hwnd, const macdrv_event *event) DECLSPEC_HIDDEN;
|
||||
|
||||
#endif /* __WINE_MACDRV_H */
|
||||
|
|
|
@ -125,6 +125,8 @@
|
|||
/* event */
|
||||
enum {
|
||||
APP_DEACTIVATED,
|
||||
KEY_PRESS,
|
||||
KEY_RELEASE,
|
||||
KEYBOARD_CHANGED,
|
||||
MOUSE_BUTTON,
|
||||
WINDOW_CLOSE_REQUESTED,
|
||||
|
@ -142,6 +144,11 @@
|
|||
int type;
|
||||
macdrv_window window;
|
||||
union {
|
||||
struct {
|
||||
CGKeyCode keycode;
|
||||
CGEventFlags modifiers;
|
||||
unsigned long time_ms;
|
||||
} key;
|
||||
struct {
|
||||
CFDataRef uchr;
|
||||
CGEventSourceKeyboardType keyboard_type;
|
||||
|
|
Loading…
Reference in a new issue