File:  [Apple Darwin 0.x] / driverkit / libDriver / Kernel / EventInput.m
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:37:51 2018 UTC (8 years, 3 months ago) by root
Branches: MAIN, Apple
CVS tags: HEAD, Darwin03, Darwin02
Darwin 0.2 Driver Kit

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.1 (the "License").  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON- INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/* 	Copyright (c) 1992 NeXT Computer, Inc.  All rights reserved. 
 *
 * EventInput.m -	Event System periodic operations module,
 *			ObjC implementation.
 *
 *			This module is the kernel version.  It will need
 *			to be re-implemented to run in user space.
 *
 *			Periodic services driven out ot this module are almost
 *			entirely cursor related.
 *
 * HISTORY
 * 31-Mar-92    Mike Paquette at NeXT 
 *      Created. 
 * 5  Aug 1993	  Erik Kay at NeXT
 *	minor API cleanup
 */
 
#import <driverkit/generalFuncs.h>
#import <machkit/NXLock.h>
#import <driverkit/kernelDriver.h>
#import <mach/notify.h>
#if	__nrw__
#import	<bsd/sys/reboot.h>	// For disgusting hard poweroff hack...
#endif
#import <bsd/dev/ev_keymap.h>
#import <bsd/dev/evio.h>
#import <kern/queue.h>
#import <bsd/dev/machine/ev_private.h>	/* Per-machine configuration info */
#import <driverkit/EventInput.h>
#if	m88k
#import <machdep/m88k/xpr.h>
#else
#define xpr_ev_cursor(x, a, b, c, d, e)
#endif

#if	DEBUG && __nrw__
/*  
 * Avoid compiler headbutts with mon/types.h..
 *
 * Is this machine dependent?  If so, wrap it and put the 
 * cover function in machine/ev.c
 */
#define _MON_TYPES_BOOLEAN_
#define _MON_TYPES_CPUTYPES_
#define _MON_TYPES_SIZE_
#define	_MON_BIT_MACROS_
#import <mon/mon_service.h>

static void 
break_to_parent()
{
	mon_command_mode();
}
#endif /* DEBUG && __nrw__ */


#define PtInRect(ptp,rp) \
	((ptp)->x >= (rp)->minx && (ptp)->x <  (rp)->maxx && \
	(ptp)->y >= (rp)->miny && (ptp)->y <  (rp)->maxy)

@implementation EventDriver(Input)

//
// Kernel versions of nanosecond callouts.
//
static void EvPeriodicCallout( void *data )
{
	EventDriver *inst = (EventDriver *)data;
	inst->periodicRunPending = NO;
	[inst periodicEvents];
}

//
// Schedule periodicEvents to be run nst nanoseconds.
//
- runPeriodicEvent:(ns_time_t)nst
{

	if ( periodicRunPending == YES )
	    ns_untimeout((func)EvPeriodicCallout,(void *)self);
	ns_abstimeout(	(func)EvPeriodicCallout,
			(void *)self,
			nst,
			CALLOUT_PRI_THREAD );
	periodicRunPending = YES;
	return self;
}

//
// Schedule the next periodic event to be run, based on the current state of
// the event system.  We have to consider things here such as when the last
// periodic event pass ran, if there is currently any mouse delta accumulated,
// and how long it has been since the last event was consumed by an app (for
// driving the wait cursor).
//
// This code should only be run from the periodicEvents method or
// _setCursorPosition.
//
- scheduleNextPeriodicEvent
{
	ns_time_t time_for_next_run;
	ns_time_t current_time;

	IOGetTimestamp(&current_time);
	time_for_next_run = current_time + EV_TICK_TO_NS(10);

	// figure in wait cursor delay periods here
	if (waitFrameTime > current_time && waitFrameTime < time_for_next_run)
		time_for_next_run = waitFrameTime;

	if (	periodicRunPending == NO		// need to schedule
	    ||	nextPeriodicRun > time_for_next_run	// need to reschedule
	    ||	nextPeriodicRun <= thisPeriodicRun )	// clock wrapped around
	{
		nextPeriodicRun = time_for_next_run;
		[self runPeriodicEvent:time_for_next_run];
	}
	
	return self;
}

// Periodic events are driven from this method.
// After taking care of all pending work, the method
// calls scheduleNextPeriodicEvent to compute and set the
// next callout.
//
- (void)periodicEvents
{
	unsigned int	tick;
	EvGlobals	*glob;

	// If eventsOpen is false, then the driver shmem is
	// no longer valid, and it is in the process of shutting down.
	// We should give up without rescheduling.
	[driverLock lock];
	if ( eventsOpen == NO )
	{
		[driverLock unlock];
		return;
	}
	glob = (EvGlobals *)evg;
	// Increment event time stamp last
	IOGetTimestamp(&thisPeriodicRun);

	// Temporary hack til we wean PS off of VertRetraceClock
	tick = EV_NS_TO_TICK(thisPeriodicRun);
	if ( tick == 0 )
		tick = 1;
	glob->VertRetraceClock = tick;

	// Update cursor position if needed
	if ( needSetCursorPosition == YES )
		[self _setCursorPosition:&pointerLoc atTime:tick];

	// WAITCURSOR ACTION
	if ( ev_try_lock(&glob->waitCursorSema) )
	{
	    if ( ev_try_lock(&glob->cursorSema) )
	    {
		// See if the current context has timed out
		if (   (glob->AALastEventSent != glob->AALastEventConsumed)
		    && ((glob->VertRetraceClock - glob->AALastEventSent >
					glob->waitThreshold)))
		    glob->ctxtTimedOut = TRUE;
		// If wait cursor enabled and context timed out, do waitcursor
		if (glob->waitCursorEnabled && glob->globalWaitCursorEnabled &&
		glob->ctxtTimedOut)
		{
		    /* WAIT CURSOR SHOULD BE ON */
		    if (!glob->waitCursorUp)
			[self showWaitCursor];
		} else
		{
		    /* WAIT CURSOR SHOULD BE OFF */
		    if (glob->waitCursorUp && waitSusTime <= thisPeriodicRun)
			[self hideWaitCursor];
		}
		/* Animate cursor */
		if (glob->waitCursorUp && waitFrameTime <= thisPeriodicRun)
			[self animateWaitCursor];
		ev_unlock(&glob->cursorSema);
		if ((glob->VertRetraceClock > autoDimTime) && (!autoDimmed))
		    [self doAutoDim];
	    }
	    ev_unlock(&glob->waitCursorSema);
	}
	[self scheduleNextPeriodicEvent];
	[driverLock unlock];

	return;
}

//
// Start the cursor system running.  Invoked via setParameterInt:EVIOST from
// the Window Server.
//
// At this point, the WindowServer is up, running, and ready to process events.
// We will attach the keyboard and mouse, if none are available yet.
//
- (void)startCursor
{
    Point p;

    if (screens)	// Should be at least 1!
    {
	[driverLock lock];
	if ( eventsOpen == NO )
	{
	    [driverLock unlock];
	    return;
	}
        p = ((EvGlobals*)evg)->cursorLoc;
	if ( (currentScreen = [self pointToScreen:&p]) < 0 )
	{
	    [driverLock unlock];
	    return;
	}
	cursorPin = ((EvScreen*)evScreen)[currentScreen].bounds;
	cursorPin.maxx--;	// Set the range the cursor is pinned
	cursorPin.maxy--;	// to for this display [closed range]
	[self setBrightness];
	[self showCursor];
	[driverLock unlock];	// We may get events in the attach process
	[self attachDefaultEventSources];
    }
}

//
// Wait Cursor machinery.  The driverLock should be held on entry to
// these methods, and the shared memory area must be set up.
//
- (void)showWaitCursor
{
	xpr_ev_cursor("showWaitCursor\n",1,2,3,4,5);
	((EvGlobals*)evg)->waitCursorUp = YES;
	[self changeCursor:EV_WAITCURSOR];
	// Set animation and sustain absolute times.
	waitFrameTime = waitFrameRate + thisPeriodicRun;
	waitSusTime = waitSustain + thisPeriodicRun;
}

- (void)hideWaitCursor
{
	xpr_ev_cursor("hideWaitCursor\n",1,2,3,4,5);
	((EvGlobals*)evg)->waitCursorUp = NO;
	[self changeCursor:EV_STD_CURSOR];
	waitFrameTime = 0ULL;
	waitSusTime = 0ULL;
}

- (void)animateWaitCursor
{
	xpr_ev_cursor("animateWaitCursor\n",1,2,3,4,5);
	[self changeCursor:((EvGlobals*)evg)->frame + 1];
	// Set the next animation time.
	waitFrameTime = waitFrameRate + thisPeriodicRun;
}

- (void)changeCursor:(int)frame
{
	((EvGlobals*)evg)->frame = (frame > EV_MAXCURSOR) ? EV_WAITCURSOR : frame;
	xpr_ev_cursor("changeCursor %d\n",((EvGlobals*)evg)->frame,2,3,4,5);
	[self moveCursor];
}

//
// Return the screen number in which point p lies.  Return -1 if the point
// lies outside of all registered screens.
//
- (int) pointToScreen:(Point *) p
{
    int i;
    EvScreen *screen = (EvScreen *)evScreen;
    for (i=screens; --i != -1; ) {
	if (screen[i].instance != nil
	&& (p->x >= screen[i].bounds.minx)
	&& (p->x < screen[i].bounds.maxx)
	&& (p->y >= screen[i].bounds.miny)
	&& (p->y < screen[i].bounds.maxy))
	    return i;
    }
    return(-1);	/* Cursor outside of known screen boundary */
}

//
// API used to manipulate screen brightness
//
// On entry to each of these, the driverLock should be set.
//
// Set the current brightness
- setBrightness:(int)b
{
	if ( b < EV_SCREEN_MIN_BRIGHTNESS )
		b = EV_SCREEN_MIN_BRIGHTNESS;
	else if ( b > EV_SCREEN_MAX_BRIGHTNESS )
		b = EV_SCREEN_MAX_BRIGHTNESS;
	if ( b != curBright )
	{
	    curBright = b;
	    if ( autoDimmed == NO )
		return [self setBrightness];
	}
	return self;
}

- (int)brightness
{
	return curBright;
}

// Set the current brightness
- setAutoDimBrightness:(int)b
{
	if ( b < EV_SCREEN_MIN_BRIGHTNESS )
		b = EV_SCREEN_MIN_BRIGHTNESS;
	else if ( b > EV_SCREEN_MAX_BRIGHTNESS )
		b = EV_SCREEN_MAX_BRIGHTNESS;
	if ( b != dimmedBrightness )
	{
	    dimmedBrightness = b;
	    if ( autoDimmed == YES )
		return [self setBrightness];
	}
	return self;
}

- (int)autoDimBrightness
{
	return dimmedBrightness;
}


- (int)currentBrightness;		// Return the current brightness
{
	if ( autoDimmed == YES && dimmedBrightness < curBright )
		return dimmedBrightness;
	else
		return curBright;
}

- doAutoDim
{
	autoDimmed = YES;
	[self setBrightness];
	return self;
}

// Return display brightness to normal
- undoAutoDim
{
	autoDimmed = NO;
	[self setBrightness];
	return self;
}

- forceAutoDimState:(BOOL)dim
{
    	if ( dim == YES )
	{
	    if ( autoDimmed == NO )
	    {
		if ( eventsOpen == YES )
		    autoDimTime = ((EvGlobals*)evg)->VertRetraceClock;
		[self doAutoDim];
	    }
	}
	else
	{
	    if ( autoDimmed == YES )
	    {
		if ( eventsOpen == YES )
		    autoDimTime = ((EvGlobals*)evg)->VertRetraceClock
		    			+ autoDimPeriod;
		[self undoAutoDim];
	    }
	}
	return self;
}

//
// API used to manipulate sound volume/attenuation
//
// Set the current brightness.
- setAudioVolume:(int)v
{
	if ( v < EV_AUDIO_MIN_VOLUME )
		v = EV_AUDIO_MIN_VOLUME;
	else if ( v > EV_AUDIO_MAX_VOLUME )
		v = EV_AUDIO_MAX_VOLUME;
	curVolume = v;
	return self;
}

//
// Volume set programatically, rather than from keyboard
//
- setUserAudioVolume:(int)v
{
	[self setAudioVolume:v];
	// Let sound driver know about the change
	[self evSpecialKeyMsg:	NX_KEYTYPE_SOUND_UP
				direction:NX_KEYDOWN
				flags:0
				level:curVolume];
	
}

- (int)audioVolume
{
	return curVolume;
}

//
// API used to drive event state out to attached screens
//
// On entry to each of these, the driverLock should be set.
//
- setBrightness			// Propagate state out to screens
{
	int i;
	for ( i = 0; i < screens; ++i )
		[self evDispatch:i command:EVLEVEL];

	return self;						
}
- showCursor
{
	return [self evDispatch:currentScreen command:EVSHOW];
}
- hideCursor
{
	return [self evDispatch:currentScreen command:EVHIDE];
}
- moveCursor
{
	return [self evDispatch:currentScreen command:EVMOVE];
}

//
// - attachDefaultEventSources
//	Attach the default event sources.
//	The default sources are machine dependent.
//
- attachDefaultEventSources
{
	id driver;
	id class;
	IOReturn r;
	const char **devClass;

	for ( devClass = defaultEventSources(); *devClass != NULL; ++devClass )
		[self attachEventSource: *devClass];

	return self;
}

- attachEventSource:(const char *)classname
{
	id driver;
	id class;
	if ( (class = objc_getClass(classname)) == nil )
	{
		IOLog( "%s: %s: no such class.\n",
			[self name], classname);
		return nil;
	}
	if ( [class respondsTo:@selector(probe)] == NO )
	{
		IOLog( "%s: %s does not respond to probe.\n",
			[self name], classname);
		return nil;
	}
	if ( (driver = [class probe]) == nil )
	{
		IOLog("%s: probe of %s failed\n",
			[self name], classname  );
		return nil;
	}
	if ( [self registerEventSource: driver] == nil )
	{
		IOLog("%s: becomeOwner of %s failed\n",
			[self name], classname  );
		return nil;
	}
	return driver;
}

//
// - detachEventSources
//	Detach all event sources
//
- detachEventSources
{
	attachedEventSrc *device;

	[eventSrcListLock lock];
	while(!queue_empty(&eventSrcList)) {
		device = (attachedEventSrc *)queue_first(&eventSrcList);
		queue_remove(&eventSrcList,
			device,
			attachedEventSrc *,
			link);
		// Release lock while we tear down dequeued item.
		[eventSrcListLock unlock];

		if ( device->info.eventSrc != nil )
			[device->info.eventSrc relinquishOwnership:self];
		IOFree(device, sizeof (attachedEventSrc));
		[eventSrcListLock lock];
	}
	[eventSrcListLock unlock];
	return self;
}

//
// EventSrcClient implementation
//

//
// A new device instance desires to be added to our list.
// Try to get ownership of the device. If we get it, add it to
// the list.
// 
- registerEventSource:source
{
	attachedEventSrc *device;

	if ( [source becomeOwner:self] != IO_R_SUCCESS )
		return nil;
	device = IOMalloc( sizeof (attachedEventSrc) );
	bzero( device, sizeof (attachedEventSrc) );
	device->info.eventSrc = source;
	// Enter the device on our list.
	[eventSrcListLock lock];
	queue_enter(&eventSrcList,
		device,
		attachedEventSrc *,
		link);
	[eventSrcListLock unlock];
	return self;
}

//
// Called when another client wishes to assume ownership of calling adbDevice.
// This happens when a client attempts a becomeOwner: on a device which is 
// owned by the callee of this method. 
//
// Returns:
//    IO_R_SUCCESS ==> It's OK to give ownership of the device to other client.
//		       In this case, callee no longer owns the device.
//    IO_R_BUSY    ==> Don't transfer ownership.
//
// Note that this call occurs during (i.e., before the return of) a 
// attachDevice: call to the caller of this method.
//
- (IOReturn)relinquishOwnershipRequest	: device;
{
	return (eventsOpen == NO) ? IO_R_SUCCESS : IO_R_BUSY;
}

//
// Method by which a client, who has registered "intent to own" via 
// desireOwnership:client, is notified that the calling device is available.
// Client will typically call becomeOwner: during this call.
//
- (void)canBecomeOwner			: device;
{
	IOReturn drtn;
	drtn = [device becomeOwner: self];
	if(drtn)
	{
		IOLog("%s: becomeOwner of %s failed (%s)\n",
			[self name],
			[device name],
			[self stringFromReturn:drtn]);
	}
}

//
// Process a mouse status change.  The driver should sign extend
// it's deltas and perform any bit flipping needed there.
//
// We take the state as presented and turn it into events.
// 
- relativePointerEvent:(int)buttons deltaX:(int)dx deltaY:(int)dy
{
	ns_time_t ts;
	IOGetTimestamp( &ts );
	return [self relativePointerEvent:buttons
					deltaX:dx
					deltaY:dy
					atTime:ts];
}

- relativePointerEvent:(int)buttons
		deltaX:(int)dx
		deltaY:(int)dy
		atTime:(ns_time_t)ts
{
	unsigned	tick;

	tick = EV_NS_TO_TICK(ts);
	[driverLock lock];
	if ( eventsOpen == NO )
	{
		[driverLock unlock];
		return self;
	}
	// Fake up pressure changes from button state changes
	if ( (buttons & EV_LB) != (((EvGlobals*)evg)->buttons & EV_LB) )
	{
	    if ( buttons & EV_LB )
		lastPressure = MAXPRESSURE;
	    else
		lastPressure = MINPRESSURE;
	}
	[self _setButtonState:buttons atTime:tick];

	// figure cursor movement
	if ( dx || dy )
	{
	    pointerLoc.x += dx;
	    pointerLoc.y += dy;
	    if ( needSetCursorPosition == NO )
		[self _setCursorPosition:&pointerLoc atTime:tick];
	}
	[driverLock unlock];
	return self;
}

- absolutePointerEvent:(int)buttons
		at:(Point *)newLoc
		inProximity:(BOOL)proximity
{
	unsigned int pressure;
	ns_time_t ts;
	IOGetTimestamp( &ts );
	// Fake up pressure changes from button state changes
	[driverLock lock];
	pressure = lastPressure;
	if ( eventsOpen == NO )
	{
		[driverLock unlock];
		return self;
	}
	if ( (buttons & EV_LB) != (((EvGlobals*)evg)->buttons & EV_LB) )
	{
	    if ( buttons & EV_LB )
		pressure = MAXPRESSURE;
	    else
		pressure = MINPRESSURE;
	}
	[driverLock unlock];
	[self absolutePointerEvent:buttons
				at:newLoc
				inProximity:proximity
				withPressure:pressure
				withAngle:90
				atTime:ts];
	return self;
}

- absolutePointerEvent:(int)buttons
		at:(Point *)newLoc
		inProximity:(BOOL)proximity
		withPressure:(int)pressure
{
	ns_time_t ts;
	IOGetTimestamp( &ts );
	[self absolutePointerEvent:buttons
				at:newLoc
				inProximity:proximity
				withPressure:pressure
				withAngle:90
				atTime:ts];
	return self;
}

- absolutePointerEvent:(int)buttons
		at:(Point *)newLoc
		inProximity:(BOOL)proximity
		withPressure:(int)pressure
		withAngle:(int)stylusAngle
		atTime:(ns_time_t)ts
		
{
	NXEventData outData;	/* dummy data */
	unsigned	tick;

	tick = EV_NS_TO_TICK(ts);
	[driverLock lock];
	if ( eventsOpen == NO )
	{
		[driverLock unlock];
		return self;
	}
	
	lastPressure = pressure; 
	if ( newLoc->x != pointerLoc.x || newLoc->y != pointerLoc.y )
	{
	    pointerLoc = *newLoc;
	    if ( needSetCursorPosition == NO )
		    [self _setCursorPosition:&pointerLoc atTime:tick];
	}
	if ( lastProximity != proximity && proximity == YES )
	{
	    ((EvGlobals*)evg)->eventFlags |= NX_STYLUSPROXIMITYMASK;
	    bzero( (char *)&outData, sizeof outData );
	    [self postEvent:NX_FLAGSCHANGED
			    at:(Point *)&pointerLoc
			    atTime:tick
			    withData:&outData];
	}
	if ( proximity == YES )
	    [self _setButtonState:buttons atTime:tick];
	if ( lastProximity != proximity && proximity == NO )
	{
	    ((EvGlobals*)evg)->eventFlags &= ~NX_STYLUSPROXIMITYMASK;
	    bzero( (char *)&outData, sizeof outData );
	    [self postEvent:NX_FLAGSCHANGED
			    at:(Point *)&pointerLoc
			    atTime:tick
			    withData:&outData];
	}
	lastProximity = proximity;
	[driverLock unlock];
	return self;
}

//
// Process a keyboard state change.
// 
- keyboardEvent:(unsigned)eventType
		flags:(unsigned)flags
		keyCode:(unsigned)key
		charCode:(unsigned)charCode
		charSet:(unsigned)charSet
		originalCharCode:(unsigned)origCharCode
		originalCharSet:(unsigned)origCharSet
		repeat:(BOOL)repeat
		atTime:(ns_time_t)ts
{
	NXEventData	outData;
	unsigned	tick;

	tick = EV_NS_TO_TICK(ts);
	outData.key.repeat = repeat;
	outData.key.keyCode = key;
	outData.key.charSet = charSet;
	outData.key.charCode = charCode;
	outData.key.origCharSet = origCharSet;
	outData.key.origCharCode = origCharCode;

	[driverLock lock];
	if ( eventsOpen == NO )
	{
		[driverLock unlock];
		return self;
	}
	((EvGlobals*)evg)->eventFlags = (((EvGlobals*)evg)->eventFlags & ~KEYBOARD_FLAGSMASK)
			| (flags & KEYBOARD_FLAGSMASK);

	[self postEvent:eventType
			at:(Point *)&pointerLoc
			atTime:tick
			withData:&outData];

	[driverLock unlock];
	return self;
}


- keyboardSpecialEvent:(unsigned)eventType
		flags:(unsigned)flags
		keyCode:(unsigned)key
		specialty:(unsigned)flavor
		atTime:(ns_time_t)ts
{
	NXEventData	outData;
	unsigned	tick;
	int		level = -1;

	bzero( (void *)&outData, sizeof outData );
	tick = EV_NS_TO_TICK(ts);

	[driverLock lock];
	if ( eventsOpen == NO )
	{
		[driverLock unlock];
		return self;
	}
	// Update flags.
	((EvGlobals*)evg)->eventFlags = (((EvGlobals*)evg)->eventFlags & ~KEYBOARD_FLAGSMASK)
			| (flags & KEYBOARD_FLAGSMASK);
	// Most of these keys don't generate events.  Forcibly undo autodim.
	if ( autoDimmed == YES )
		[self forceAutoDimState:NO];
	if ( eventType == NX_KEYDOWN )
	{
		switch ( flavor )
		{
			case NX_KEYTYPE_SOUND_UP:
			    if ( (flags & SPECIALKEYS_MODIFIER_MASK) == 0 )
				[self setAudioVolume:[self audioVolume] + 1];
			    level = [self audioVolume];
			    break;
			case NX_KEYTYPE_SOUND_DOWN:
			    if ( (flags & SPECIALKEYS_MODIFIER_MASK) == 0 )
				[self setAudioVolume:[self audioVolume] - 1];
			    level = [self audioVolume];
			    break;
			case NX_KEYTYPE_BRIGHTNESS_UP:
#if 	DEBUG && __nrw__
			    if ( (flags & BRIGHT_BREAK_TO_DEBUGGER_MASK)
				== BRIGHT_BREAK_TO_DEBUGGER_MASK )
			    {
				    [driverLock unlock];
				    break_to_parent();
				    return self;
			    }
#endif	DEBUG && __nrw__
			    if ( (flags & SPECIALKEYS_MODIFIER_MASK) == 0 )
				[self setBrightness:[self brightness] + 1];
			    level = [self brightness];
			    break;
			case NX_KEYTYPE_BRIGHTNESS_DOWN:
			    if ( (flags & SPECIALKEYS_MODIFIER_MASK) == 0 )
				[self setBrightness:[self brightness] - 1];
			    level = [self brightness];
			    break;
			case NX_POWER_KEY:
#if 	DEBUG && __nrw__
				if ( (flags & PWR_BREAK_TO_DEBUGGER_MASK)
				    == PWR_BREAK_TO_DEBUGGER_MASK )
				{
				    [driverLock unlock];
				    break_to_parent();
				    return self;
				}
#endif	DEBUG && __nrw__
#if	__nrw__
				// ICK! Do we really need this "feature"?
				if ( (flags & HARD_POWEROFF_MASK)
				    == HARD_POWEROFF_MASK )
				{
				        [driverLock unlock];
					boot(0,RB_NOSYNC|RB_POWERDOWN,NULL);
					return self; // not reached...
				}
#endif
				outData.compound.subType = 1;
				[self postEvent:NX_SYSDEFINED
						at:(Point *)&pointerLoc
						atTime:tick
						withData:&outData];
				break;
		}
	}
#if 0	/* So far, nothing to do on keyup */
	else if ( eventType == NX_KEYUP )
	{
		switch ( flavor )
		{
			case NX_KEYTYPE_SOUND_UP:
				break;
			case NX_KEYTYPE_SOUND_DOWN:
				break;
			case NX_KEYTYPE_BRIGHTNESS_UP:
				break;
			case NX_KEYTYPE_BRIGHTNESS_DOWN:
				break;
			case NX_POWER_KEY:
				break;
		}
	}
#endif
	[driverLock unlock];
	if ( level != -1 )	// An interesting special key event occurred
	{
		[self evSpecialKeyMsg:	flavor
					direction:eventType
					flags:flags
					level:level];
	}
	return self;
}

/*
 * Update current event flags.  Restricted to keyboard flags only, this
 * method is used to silently update the flags state for keys which both
 * generate characters and flag changes.  The specs say we don't generate
 * a flags-changed event for such keys.  This method is also used to clear
 * the keyboard flags on a keyboard subsystem reset.
 */
- updateEventFlags:(unsigned)flags
{
	[driverLock lock];
	if ( eventsOpen )
	    ((EvGlobals*)evg)->eventFlags = (((EvGlobals*)evg)->eventFlags & ~KEYBOARD_FLAGSMASK)
			    | (flags & KEYBOARD_FLAGSMASK);
	[driverLock unlock];
	return self;
}

/*
 * Return current event flags
 */
- (int)eventFlags
{
	int flags = 0;
	[driverLock lock];
	if ( eventsOpen )
		flags = ((EvGlobals*)evg)->eventFlags;
	[driverLock unlock];
	return flags;
}

//
// - _setButtonState:(int)buttons  atTime:(int)t
//	Update the button state.  Generate button events as needed
//
- _setButtonState:(int)buttons atTime:(unsigned)t
{
	EvGlobals *glob = (EvGlobals *)evg;
	if ((glob->buttons & EV_LB) != (buttons & EV_LB))
	{
	    if (buttons & EV_LB)
	    {
		[self postEvent:NX_LMOUSEDOWN
				at:(Point *)&glob->cursorLoc
				atTime:t
				withData:NULL];
		glob->buttons |= EV_LB;
	    }
	    else
	    {
		[self postEvent:NX_LMOUSEUP
				at:(Point *)&glob->cursorLoc
				atTime:t
				withData:NULL];
		glob->buttons &= ~EV_LB;
	    }
	    // After entering initial up/down event, set up
	    // coalescing state so drags will behave correctly
	    glob->dontCoalesce = glob->dontWantCoalesce;
	    if (glob->dontCoalesce)
		glob->eventFlags |= NX_NONCOALSESCEDMASK;
	    else
		glob->eventFlags &= ~NX_NONCOALSESCEDMASK;
	}
    
	if ((glob->buttons & EV_RB) != (buttons & EV_RB)) {
	    if (buttons & EV_RB) {
		[self postEvent:NX_RMOUSEDOWN
				at:(Point *)&glob->cursorLoc
				atTime:t
				withData:NULL];
		glob->buttons |= EV_RB;
	    } else {
		[self postEvent:NX_RMOUSEUP
				at:(Point *)&glob->cursorLoc
				atTime:t
				withData:NULL];
		glob->buttons &= ~EV_RB;
	    }
	}
	return self;
}
//
//  Sets the cursor position (((EvGlobals*)evg)->cursorLoc) to the new
//  location.  The location is clipped against the cursor pin rectangle,
//  mouse moved/dragged events are generated using the given event mask,
//  and a mouse-exited event may be generated. The cursor image is
//  moved.
//  On entry, the driverLock should be set.
//
- setCursorPosition:(Point *)newLoc
{
	if ( eventsOpen == YES )
	{
	    pointerLoc = *newLoc;
	    if ( needSetCursorPosition == NO )
		[self _setCursorPosition:newLoc atTime:EvTickTimeValue()];
	}
}

//
// This mechanism is used to update the cursor position, possibly generating
// messages to registered frame buffer devices and posting drag, tracking, and
// mouse motion events.
//
// On entry, the driverLock should be set.
// This can be called from setCursorPosition:(Point *)newLoc to set the
// position by a _IOSetParameterFromIntArray() call, directly from the absolute or
// relative pointer device routines, or on a timed event callback.
//
- _setCursorPosition:(Point *)newLoc atTime:(unsigned)t
{
	int newScreen = -1;
	EvGlobals *glob = (EvGlobals *)evg;
    
	if (!screens)
	    return self;

	if ( ev_try_lock(&glob->cursorSema) == 0 ) // host using shmem
	{
		needSetCursorPosition = YES;	  // try again later
		[self scheduleNextPeriodicEvent];
		return self;
	}
	// Past here we hold the cursorSema lock.  Make sure the lock is
	// cleared before returning or the system will be wedged.
	
	needSetCursorPosition = NO;	  // We WILL succeed

	/* Check to see if cursor ventured outside of current screen bounds
	    before worrying about which screen it may have gone to. */
    
	if (!PtInRect(newLoc, &((EvScreen*)evScreen)[currentScreen].bounds)) {
	    /* At this point cursor has gone off screen.  Check to see if moved
		to another screen.  If not, just clip it to current screen. */
    
	    if ((newScreen = [self pointToScreen:newLoc]) < 0) {
		/* Pin new cursor position to cursorPin rect */
		newLoc->x = (newLoc->x < cursorPin.minx) ?
		    cursorPin.minx : ((newLoc->x > cursorPin.maxx) ?
		    cursorPin.maxx : newLoc->x);
		newLoc->y = (newLoc->y < cursorPin.miny) ?
		    cursorPin.miny : ((newLoc->y > cursorPin.maxy) ?
		    cursorPin.maxy : newLoc->y);
	    }
	}

	pointerLoc = *newLoc;	// Sync up pointer with clipped cursor
	/* Catch the no-move case */
	if (glob->cursorLoc.x == newLoc->x && glob->cursorLoc.y == newLoc->y)
	{
	    ev_unlock(&glob->cursorSema);
	    return self;
	}    
	glob->cursorLoc = *newLoc;
	/* If newScreen is zero or positive, then cursor crossed screens */
	if (newScreen >= 0) {
	    /* cursor changed screens */
	    [self hideCursor];	/* hide cursor on old screen */
	    currentScreen = newScreen;
	    cursorPin = ((EvScreen*)evScreen)[currentScreen].bounds;
	    cursorPin.maxx--;	/* Make half-open rectangle */
	    cursorPin.maxy--;
	    [self showCursor];
	} else {
	    /* cursor moved on same screen */
	    [self moveCursor];
	}
	
	/* See if anybody wants the mouse moved or dragged events */
	if (glob->movedMask) {
	    if ((glob->movedMask&NX_LMOUSEDRAGGEDMASK)&&(glob->buttons& EV_LB))
		[self postEvent:NX_LMOUSEDRAGGED
				at:newLoc
				atTime:t
				withData:NULL];
	    else
		if ((glob->movedMask&NX_RMOUSEDRAGGEDMASK) &&
		(glob->buttons & EV_RB))
		    [self postEvent:NX_RMOUSEDRAGGED
				    at:newLoc
				    atTime:t
				    withData:NULL];
		else
		    if (glob->movedMask & NX_MOUSEMOVEDMASK)
			[self postEvent:NX_MOUSEMOVED
					at:newLoc
					atTime:t
					withData:NULL];
	}
    
	/* check new cursor position for leaving glob->mouseRect */
	if (glob->mouseRectValid && (!PtInRect(newLoc, &glob->mouseRect)))
	{
	    if (glob->mouseRectValid)
	    {
		[self postEvent:NX_MOUSEEXITED
				at:newLoc
				atTime:t
				withData:NULL];
		glob->mouseRectValid = 0;
	    }
	}
	ev_unlock(&glob->cursorSema);
	return self;
}

@end


unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.