VirtualBox

Changeset 26624 in vbox


Ignore:
Timestamp:
Feb 18, 2010 10:35:24 AM (15 years ago)
Author:
vboxsync
Message:

Devices, Main, pdmifs.h: initial support for PS/2 touchscreen emulation, based on the Lifebook touchscreen device

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/VBox/pdmifs.h

    r26573 r26624  
    304304     */
    305305    DECLR3CALLBACKMEMBER(int, pfnPutEvent,(PPDMIMOUSEPORT pInterface, int32_t i32DeltaX, int32_t i32DeltaY, int32_t i32DeltaZ, int32_t i32DeltaW, uint32_t fButtonStates));
     306    /**
     307     * Puts an absolute mouse event.
     308     * This is called by the source of mouse events. The event will be passed up until the
     309     * topmost driver, which then calls the registered event handler.
     310     *
     311     * @returns VBox status code.
     312     * @param   pInterface          Pointer to this interface structure.
     313     * @param   i32cX               The X value, in the range 0 to 0xffff.
     314     * @param   i32cY               The Y value, in the range 0 to 0xffff.
     315     * @thread  The emulation thread.
     316     */
     317    DECLR3CALLBACKMEMBER(int, pfnPutEventAbs,(PPDMIMOUSEPORT pInterface, int32_t i32cX, int32_t i32cY));
    306318} PDMIMOUSEPORT;
    307319
     
    316328
    317329
     330/** Pointer to a mouse connector interface. */
     331typedef struct PDMIMOUSECONNECTOR *PPDMIMOUSECONNECTOR;
    318332/**
    319333 * Mouse connector interface (up).
    320334 * Pair with PDMIMOUSEPORT.
    321335 */
    322 typedef PDMIDUMMY PDMIMOUSECONNECTOR;
    323  /** Pointer to a mouse connector interface. */
    324 typedef PDMIMOUSECONNECTOR *PPDMIMOUSECONNECTOR;
     336typedef struct PDMIMOUSECONNECTOR
     337{
     338    /**
     339     * Notifies the the downstream driver when the guest switches the device into or out of absolute mode.
     340     *
     341     * @param   pInterface      Pointer to the this interface.
     342     * @param   fAbs            Whether absolute mode is currently enabled
     343     */
     344    DECLR3CALLBACKMEMBER(void, pfnAbsModeChange,(PPDMIMOUSECONNECTOR pInterface, bool fAbs));
     345
     346} PDMIMOUSECONNECTOR;
     347
    325348/** PDMIMOUSECONNECTOR interface ID.  */
    326349#define PDMIMOUSECONNECTOR_IID                  "847f965f-0eb8-4363-88ac-b0ee58a05bde"
  • trunk/src/VBox/Devices/Input/DevPS2.cpp

    r26572 r26624  
    5757#include "../Builtins.h"
    5858
    59 #define PCKBD_SAVED_STATE_VERSION 3
     59#define PCKBD_SAVED_STATE_VERSION 4
    6060
    6161
     
    162162#define KBD_QUEUE_SIZE 256
    163163
     164/* Supported mouse protocols */
     165enum
     166{
     167    MOUSE_PROT_PS2 = 0,
     168    MOUSE_PROT_IMPS2 = 3,
     169    MOUSE_PROT_IMEX = 4,
     170    MOUSE_PROT_LIFEBOOK = 5
     171};
     172
     173/* Mouse flags */
    164174# define MOUSE_REPORT_HORIZONTAL  0x01
    165 # define MOUSE_OUTSTANDING_CLICK  0x02
     175
     176/** Extended mouse button values for Lifebook mode */
     177/** Downwards scrollwheel movement of one step.  Doesn't affect the mouse
     178 * buttons */
     179# define MOUSE_EXT_VSCROLL_DN   4
     180/** Upwards scrollwheel movement of one step. */
     181# define MOUSE_EXT_VSCROLL_UP   5
     182/** Leftwards scrollwheel movement of one step. */
     183# define MOUSE_EXT_HSCROLL_BW   6
     184/** Rightwards scrollwheel movement of one step. */
     185# define MOUSE_EXT_HSCROLL_FW   7
    166186
    167187typedef struct {
     
    210230    int32_t mouse_dw;
    211231    int32_t mouse_flags;
     232    int32_t mouse_cx;
     233    int32_t mouse_cy;
    212234    uint8_t mouse_buttons;
     235    uint8_t mouse_buttons_reported;
     236    uint8_t mouse_last_button;
    213237
    214238    /** Pointer to the device instance - RC. */
     
    647671}
    648672
    649 static void kbd_mouse_send_packet(KBDState *s, bool fToCmdQueue)
     673static void kbd_mouse_set_reported_buttons(KBDState *s, unsigned fButtons, unsigned fButtonMask)
     674{
     675    s->mouse_buttons_reported |= (fButtons & fButtonMask);
     676    s->mouse_buttons_reported &= (fButtons | ~fButtonMask);
     677}
     678
     679static bool kbd_mouse_test_set_button(KBDState *s, unsigned cIndex)
     680{
     681    unsigned fButtonMask = 1 << (cIndex - 1);
     682
     683    AssertReturn(3 <= cIndex && cIndex <= 5, false);
     684    if (   (s->mouse_buttons & fButtonMask)
     685        && !(s->mouse_buttons_reported & fButtonMask))
     686    {
     687        s->mouse_last_button = cIndex;
     688        kbd_mouse_set_reported_buttons(s, fButtonMask, 0x1c);
     689        return true;
     690    }
     691    return false;
     692}
     693
     694static bool kbd_mouse_test_clear_last_button(KBDState *s)
     695{
     696    unsigned fButtonMask = 1 << (s->mouse_last_button - 1);
     697
     698    if (   s->mouse_last_button != 0
     699        && !(s->mouse_buttons & fButtonMask))
     700    {
     701        s->mouse_last_button = 0;
     702        kbd_mouse_set_reported_buttons(s, 0, fButtonMask);
     703        return true;
     704    }
     705    return false;
     706}
     707
     708/**
     709 * Send a single relative packet in 3-byte PS/2 format, optionally with our
     710 * packed button protocol extension, to the PS/2 controller.
     711 * @param  s               keyboard state object
     712 * @param  dx              relative X value, must be between -256 and +255
     713 * @param  dy              relative y value, must be between -256 and +255
     714 * @param  fButtonsLow     the state of the two first mouse buttons
     715 * @param  fButtonsPacked  the state of the upper three mouse buttons and
     716 *                         scroll wheel movement, packed as per the
     717 *                         MOUSE_EXT_* defines.  For standard PS/2 packets
     718 *                         only pass the value of button 3 here.
     719 */
     720static void kbd_mouse_send_rel3_packet(KBDState *s, bool fToCmdQueue)
    650721{
    651722    int aux = fToCmdQueue ? 1 : 2;
     723    int dx1 =   s->mouse_dx < 0 ? RT_MAX(s->mouse_dx, -256)
     724              : s->mouse_dx > 0 ? RT_MIN(s->mouse_dx, 255) : 0;
     725    int dy1 =   s->mouse_dy < 0 ? RT_MAX(s->mouse_dy, -256)
     726              : s->mouse_dy > 0 ? RT_MIN(s->mouse_dy, 255) : 0;
    652727    unsigned int b;
    653     int dx1, dy1, dz1, dw1;
    654 
    655     dx1 = s->mouse_dx;
    656     dy1 = s->mouse_dy;
    657     dz1 = s->mouse_dz;
    658     dw1 = s->mouse_dw;
    659     LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
    660              dx1, dy1, dz1, dw1));
    661     /* XXX: increase range to 8 bits ? */
    662     if (dx1 > 127)
    663         dx1 = 127;
    664     else if (dx1 < -127)
    665         dx1 = -127;
    666     if (dy1 > 127)
    667         dy1 = 127;
    668     else if (dy1 < -127)
    669         dy1 = -127;
    670     b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
     728    unsigned fButtonsPacked;
     729    unsigned fButtonsLow = s->mouse_buttons & 0x03;
     730    s->mouse_dx -= dx1;
     731    s->mouse_dy -= dy1;
     732    kbd_mouse_set_reported_buttons(s, fButtonsLow, 0x03);
     733    /* When we are not in lifebook mode, we just set the third bit
     734     * in the first packet byte if the middle button is pressed,
     735     * as per the PS/2 protocol. */
     736    if (s->mouse_type != MOUSE_PROT_LIFEBOOK)
     737    {
     738        fButtonsPacked = (s->mouse_buttons & 0x04 ? 0x04 : 0);
     739        kbd_mouse_set_reported_buttons(s, s->mouse_buttons, 0x04);
     740    }
     741    else
     742    {
     743        if (kbd_mouse_test_set_button(s, 3))
     744            fButtonsPacked = 1;
     745        else if (kbd_mouse_test_set_button(s, 4))
     746            fButtonsPacked = 2;
     747        else if (kbd_mouse_test_set_button(s, 5))
     748            fButtonsPacked = 3;
     749        /* Release event for buttons in the range 3-5. */
     750        else if (kbd_mouse_test_clear_last_button(s))
     751            fButtonsPacked = 0;
     752        else if (s->mouse_dz < 0)
     753        {
     754            ++s->mouse_dz;
     755            fButtonsPacked = MOUSE_EXT_VSCROLL_DN;
     756        }
     757        else if (s->mouse_dz > 0)
     758        {
     759            --s->mouse_dz;
     760            fButtonsPacked = MOUSE_EXT_VSCROLL_UP;
     761        }
     762        else if (s->mouse_dw < 0)
     763        {
     764            ++s->mouse_dw;
     765            fButtonsPacked = MOUSE_EXT_HSCROLL_BW;
     766        }
     767        else if (s->mouse_dw > 0)
     768        {
     769            --s->mouse_dw;
     770            fButtonsPacked = MOUSE_EXT_HSCROLL_FW;
     771        }
     772        else
     773            fButtonsPacked = s->mouse_last_button;
     774    }
     775    LogRel3(("%s: dx1=%d, dy1=%d, fButtonsLow=0x%x, fButtonsPacked=0x%x\n",
     776             __PRETTY_FUNCTION__, dx1, dy1, fButtonsLow, fButtonsPacked));
     777    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | fButtonsLow
     778             | (fButtonsPacked & 4) | ((fButtonsPacked & 3) << 6);
    671779    kbd_queue(s, b, aux);
    672780    kbd_queue(s, dx1 & 0xff, aux);
    673781    kbd_queue(s, dy1 & 0xff, aux);
    674     /* extra byte for IMPS/2 or IMEX */
    675     switch(s->mouse_type) {
    676     default:
    677         break;
    678     case 3:
    679         if (dz1 > 127)
    680             dz1 = 127;
    681         else if (dz1 < -127)
    682                 dz1 = -127;
    683         kbd_queue(s, dz1 & 0xff, aux);
    684         break;
    685     case 4:
    686         if (dz1 > 1)
    687             dz1 = 1;
    688         else if (dz1 < -1)
    689             dz1 = -1;
    690         else if (dw1 > 1)
    691             dw1 = 1;
    692         else if (dw1 < -1)
    693             dw1 = -1;
    694         if (dz1)
    695             dw1 = 0;
    696         if ((s->mouse_flags & MOUSE_REPORT_HORIZONTAL) && dw1)
    697             b = 0x40 | (dw1 & 0x3f);
    698         else
    699         {
    700             b =   (dz1 & 0x0f) | ((dw1 << 1) & 0x0f)
    701                 | ((s->mouse_buttons & 0x18) << 1);
    702             s->mouse_flags &= ~MOUSE_OUTSTANDING_CLICK;
    703         }
    704         kbd_queue(s, b, aux);
    705         break;
    706     }
    707 
    708     /* update deltas */
    709     s->mouse_dx -= dx1;
    710     s->mouse_dy -= dy1;
     782}
     783
     784static void kbd_mouse_send_imps2_byte4(KBDState *s, bool fToCmdQueue)
     785{
     786    int aux = fToCmdQueue ? 1 : 2;
     787
     788    int dz1 =   s->mouse_dz < 0 ? RT_MAX(s->mouse_dz, -127)
     789              : s->mouse_dz > 0 ? RT_MIN(s->mouse_dz, 127) : 0;
    711790    s->mouse_dz -= dz1;
    712     s->mouse_dw -= dw1;
     791    kbd_queue(s, dz1 & 0xff, aux);
     792}
     793
     794static void kbd_mouse_send_imex_byte4(KBDState *s, bool fToCmdQueue)
     795{
     796    int aux = fToCmdQueue ? 1 : 2;
     797
     798    if (s->mouse_dw)
     799    {
     800        int dw1 =   s->mouse_dw < 0 ? RT_MAX(s->mouse_dw, -32)
     801                  : s->mouse_dw > 0 ? RT_MIN(s->mouse_dw, 32) : 0;
     802        s->mouse_dw -= dw1;
     803        kbd_queue(s, 0x40 | (dw1 & 0x3f), aux);
     804    }
     805    else if (s->mouse_flags & MOUSE_REPORT_HORIZONTAL && s->mouse_dz)
     806    {
     807        int dz1 =   s->mouse_dz < 0 ? RT_MAX(s->mouse_dz, -32)
     808                  : s->mouse_dz > 0 ? RT_MIN(s->mouse_dz, 32) : 0;
     809        s->mouse_dz -= dz1;
     810        kbd_queue(s, 0x80 | (dz1 & 0x3f), aux);
     811    }
     812    else
     813    {
     814        int dz1 =   s->mouse_dz < 0 ? RT_MAX(s->mouse_dz, -8)
     815                  : s->mouse_dz > 0 ? RT_MIN(s->mouse_dz, 8) : 0;
     816        s->mouse_dz -= dz1;
     817        kbd_mouse_set_reported_buttons(s, s->mouse_buttons, 0x18);
     818        kbd_queue(s, (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1), aux);
     819    }
     820}
     821
     822/**
     823 * Send a single relative packet in (IM)PS/2 or IMEX format to the PS/2
     824 * controller.
     825 * @param  s            keyboard state object
     826 * @param  fToCmdQueue  should this packet go to the command queue (or the
     827 *                      event queue)?
     828 */
     829static void kbd_mouse_send_rel_packet(KBDState *s, bool fToCmdQueue)
     830{
     831    kbd_mouse_send_rel3_packet(s, fToCmdQueue);
     832    if (s->mouse_type == MOUSE_PROT_IMPS2)
     833        kbd_mouse_send_imps2_byte4(s, fToCmdQueue);
     834    if (s->mouse_type == MOUSE_PROT_IMEX)
     835        kbd_mouse_send_imex_byte4(s, fToCmdQueue);
     836}
     837
     838/**
     839 * Send a single absolute packet in 6-byte lifebook format to the PS/2
     840 * controller.
     841 * @param  s         keyboard state object
     842 * @param  cx        absolute X value
     843 * @param  cy        absolute y value
     844 * @param  fButtons  the state of the two first mouse buttons
     845 */
     846static void kbd_mouse_send_abs_packet(KBDState *s, bool fToCmdQueue)
     847{
     848    int aux = fToCmdQueue ? 1 : 2;
     849    int cx1 = s->mouse_cx * 4096 / 0xffff;
     850    int cy1 = 4096 - (s->mouse_cy * 4096 / 0xffff);
     851    unsigned fButtons = s->mouse_buttons & 0x03;
     852    unsigned int b;
     853
     854    LogRel3(("%s: cx1=%d, cy1=%d, fButtons=0x%x\n", __PRETTY_FUNCTION__,
     855             cx1, cy1, fButtons));
     856    b = 4 /* Screen is being touched */ | fButtons;
     857    kbd_queue(s, b, aux);
     858    b = ((cy1 << 2) & 0xc0) | (cx1 >> 6);
     859    kbd_queue(s, b, aux);
     860    b = ((cx1 << 2) & 0xc0) | (cx1 & 0x3f);
     861    kbd_queue(s, b, aux);
     862    kbd_queue(s, 0xc0, aux);  /* This byte is really wasted in the protocol */
     863    b = ((cx1 << 2) & 0xc0) | (cy1 >> 6);
     864    kbd_queue(s, b, aux);
     865    b = ((cy1 << 2) & 0xc0) | (cy1 & 0x3f);
     866    kbd_queue(s, b, aux);
     867}
     868
     869static bool kbd_mouse_rel_unreported(KBDState *s)
     870{
     871   return    s->mouse_dx
     872          || s->mouse_dy
     873          || s->mouse_dz
     874          || s->mouse_dw
     875          || s->mouse_buttons != s->mouse_buttons_reported;
     876}
     877
     878/**
     879 * Send a single packet in (IM)PS/2, IMEX or Lifebook format to the PS/2
     880 * controller.
     881 * @param  s            keyboard state object
     882 * @param  fToCmdQueue  is this the result of a poll on the mouse controller?
     883 */
     884static void kbd_mouse_send_packet(KBDState *s, bool fToCmdQueue)
     885{
     886    if (   kbd_mouse_rel_unreported(s)
     887        || (s->mouse_type != MOUSE_PROT_LIFEBOOK))
     888        kbd_mouse_send_rel_packet(s, fToCmdQueue);
     889    else
     890        kbd_mouse_send_abs_packet(s, fToCmdQueue);
    713891}
    714892
    715893#ifdef IN_RING3
    716 static void pc_kbd_mouse_event(void *opaque,
    717                                int dx, int dy, int dz, int dw, int buttons_state)
    718 {
     894static size_t kbd_mouse_event_queue_free(KBDState *s)
     895{
     896    AssertReturn(s->mouse_event_queue.count <= MOUSE_EVENT_QUEUE_SIZE, 0);
     897    return MOUSE_EVENT_QUEUE_SIZE - s->mouse_event_queue.count;
     898}
     899
     900static void pc_kbd_mouse_event(void *opaque, int dx, int dy, int dz, int dw,
     901                               int buttons_state)
     902{
     903    LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d, buttons_state=0x%x\n",
     904             __PRETTY_FUNCTION__, dx, dy, dz, dw, buttons_state));
    719905    KBDState *s = (KBDState*)opaque;
    720906
     
    722908    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
    723909        return;
     910    AssertReturnVoid((buttons_state & ~0x1f) == 0);
    724911
    725912    s->mouse_dx += dx;
    726913    s->mouse_dy -= dy;
    727914    s->mouse_dz += dz;
    728     s->mouse_dw += dw;
    729     /* In horizontal reporting mode, we may need to send an additional packet
    730      * for the forth and fifth buttons, as they can't share a packet with a
    731      * horizontal scroll delta. */
    732     if (   s->mouse_type == 4
    733         && (s->mouse_buttons & 0x18) != (buttons_state & 0x18))
    734         s->mouse_flags |= MOUSE_OUTSTANDING_CLICK;
     915    if (   (   (s->mouse_type == MOUSE_PROT_IMEX)
     916            && s->mouse_flags & MOUSE_REPORT_HORIZONTAL)
     917        || (s->mouse_type == MOUSE_PROT_LIFEBOOK))
     918        s->mouse_dw += dw;
    735919    s->mouse_buttons = buttons_state;
     920    if (!(s->mouse_status & MOUSE_STATUS_REMOTE))
     921        /* if not remote, send event. Multiple events are sent if
     922           too big deltas */
     923        while (   kbd_mouse_rel_unreported(s)
     924               && kbd_mouse_event_queue_free(s) > 4)
     925            kbd_mouse_send_rel_packet(s, false);
     926}
     927
     928static void pc_kbd_mouse_event_abs(void *opaque, unsigned cx, unsigned cy)
     929{
     930    LogRel3(("%s: cx=%d, cy=%d\n", __PRETTY_FUNCTION__, cx, cy));
     931    KBDState *s = (KBDState*)opaque;
     932
     933    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
     934        return;
     935
     936    if (s->mouse_type != MOUSE_PROT_LIFEBOOK)
     937        return;
     938
     939    s->mouse_cx = cx;
     940    s->mouse_cy = cy;
    736941
    737942    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
    738         (s->mouse_event_queue.count < (MOUSE_EVENT_QUEUE_SIZE - 4))) {
    739         for(;;) {
    740             /* if not remote, send event. Multiple events are sent if
    741                too big deltas */
    742             kbd_mouse_send_packet(s, false);
    743             if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && s->mouse_dw == 0 && !(s->mouse_flags & MOUSE_OUTSTANDING_CLICK))
    744                 break;
    745         }
    746     }
     943        (s->mouse_event_queue.count < (MOUSE_EVENT_QUEUE_SIZE - 4)))
     944        /* if not remote, send event */
     945        kbd_mouse_send_abs_packet(s, false);
    747946}
    748947#endif /* IN_RING3 */
    749948
    750 static void kbd_write_mouse(KBDState *s, int val)
     949static int kbd_write_mouse(KBDState *s, int val)
    751950{
    752951#ifdef DEBUG_MOUSE
     
    765964                s->mouse_wrap = 0;
    766965                kbd_queue(s, AUX_ACK, 1);
    767                 return;
     966                return VINF_SUCCESS;
    768967            } else if (val != AUX_RESET) {
    769968                kbd_queue(s, val, 1);
    770                 return;
     969                return VINF_SUCCESS;
    771970            }
    772971        }
     
    8331032            s->mouse_resolution = 2;
    8341033            s->mouse_status = 0;
    835             s->mouse_type = 0;
     1034            s->mouse_type = MOUSE_PROT_PS2;
    8361035            kbd_queue(s, AUX_ACK, 1);
    8371036            kbd_queue(s, 0xaa, 1);
     
    8791078            else if (val == 200)
    8801079                s->mouse_detect_state = 3;
    881             else if ((val == 80) && s->mouse_type == 4 /* IMEX */)
     1080            else if ((val == 80) && s->mouse_type == MOUSE_PROT_IMEX)
    8821081                /* enable horizontal scrolling, byte two */
    8831082                s->mouse_detect_state = 4;
     
    8891088            {
    8901089                LogRelFlowFunc(("switching mouse device to IMPS/2 mode\n"));
    891                 s->mouse_type = 3; /* IMPS/2 */
     1090                s->mouse_type = MOUSE_PROT_IMPS2;
    8921091            }
    8931092            s->mouse_detect_state = 0;
     
    8971096            {
    8981097                LogRelFlowFunc(("switching mouse device to IMEX mode\n"));
    899                 s->mouse_type = 4; /* IMEX */
     1098                s->mouse_type = MOUSE_PROT_IMEX;
    9001099            }
    9011100            s->mouse_detect_state = 0;
     
    9141113        break;
    9151114    case AUX_SET_RES:
    916         s->mouse_resolution = val;
    917         kbd_queue(s, AUX_ACK, 1);
     1115        if (0 <= val && val < 4)
     1116        {
     1117            s->mouse_resolution = val;
     1118            kbd_queue(s, AUX_ACK, 1);
     1119        }
     1120        else if (val == 6)  /* Lifebook off magic knock */
     1121        {
     1122#ifdef IN_RING3
     1123            LogRelFlowFunc(("switching mouse device to basic PS/2 mode\n"));
     1124            s->mouse_type = MOUSE_PROT_PS2;
     1125            s->Mouse.pDrv->pfnAbsModeChange(s->Mouse.pDrv, false);
     1126#else
     1127            return VINF_IOM_HC_IOPORT_WRITE;
     1128#endif
     1129            kbd_queue(s, AUX_NACK, 1);
     1130        }
     1131        else if (val == 8)  /* Lifebook on magic knock */
     1132        {
     1133#ifdef IN_RING3
     1134            LogRelFlowFunc(("switching mouse device to touch screen mode\n"));
     1135            s->mouse_type = MOUSE_PROT_LIFEBOOK;
     1136            s->Mouse.pDrv->pfnAbsModeChange(s->Mouse.pDrv, true);
     1137#else
     1138            return VINF_IOM_HC_IOPORT_WRITE;
     1139#endif
     1140            kbd_queue(s, AUX_NACK, 1);
     1141        }
     1142        else
     1143            kbd_queue(s, AUX_NACK, 1);
    9181144        s->mouse_write_cmd = -1;
    9191145        break;
    9201146    }
     1147    return VINF_SUCCESS;
    9211148}
    9221149
     
    9631190        break;
    9641191    case KBD_CCMD_WRITE_MOUSE:
    965         kbd_write_mouse(s, val);
     1192        rc = kbd_write_mouse(s, val);
    9661193        break;
    9671194    default:
     
    9941221    s->mouse_sample_rate = 0;
    9951222    s->mouse_wrap = 0;
    996     s->mouse_type = 0;
     1223    s->mouse_type = MOUSE_PROT_PS2;
     1224    s->Mouse.pDrv->pfnAbsModeChange(s->Mouse.pDrv, false);
    9971225    s->mouse_detect_state = 0;
    9981226    s->mouse_dx = 0;
     
    10011229    s->mouse_dw = 0;
    10021230    s->mouse_flags = 0;
     1231    s->mouse_cx = 0x8000;
     1232    s->mouse_cy = 0x8000;
    10031233    s->mouse_buttons = 0;
     1234    s->mouse_buttons_reported = 0;
     1235    s->mouse_last_button = 0;
    10041236    q = &s->queue;
    10051237    q->rptr = 0;
     
    10391271    qemu_put_be32s(f, &s->mouse_dw);
    10401272    qemu_put_be32s(f, &s->mouse_flags);
     1273    qemu_put_be32s(f, &s->mouse_cx);
     1274    qemu_put_be32s(f, &s->mouse_cy);
    10411275    qemu_put_8s(f, &s->mouse_buttons);
     1276    qemu_put_8s(f, &s->mouse_buttons_reported);
     1277    qemu_put_8s(f, &s->mouse_last_button);
    10421278
    10431279    /* XXX: s->scancode_set isn't being saved, but we only really support set 2,
     
    10891325    qemu_get_8s(f, &s->mouse_wrap);
    10901326    qemu_get_8s(f, &s->mouse_type);
     1327    if (s->mouse_type == MOUSE_PROT_LIFEBOOK)
     1328        s->Mouse.pDrv->pfnAbsModeChange(s->Mouse.pDrv, true);
    10911329    qemu_get_8s(f, &s->mouse_detect_state);
    10921330    qemu_get_be32s(f, (uint32_t *)&s->mouse_dx);
     
    10991337    }
    11001338    qemu_get_8s(f, &s->mouse_buttons);
     1339    if (version_id > 3)
     1340    {
     1341        SSMR3GetS32(f, &s->mouse_cx);
     1342        SSMR3GetS32(f, &s->mouse_cy);
     1343        SSMR3GetU8(f, &s->mouse_buttons_reported);
     1344        SSMR3GetU8(f, &s->mouse_last_button);
     1345    }
    11011346    s->queue.count = 0;
    11021347    s->queue.rptr = 0;
     
    14231668
    14241669    pc_kbd_mouse_event(pThis, i32DeltaX, i32DeltaY, i32DeltaZ, i32DeltaW, fButtonStates);
     1670
     1671    PDMCritSectLeave(&pThis->CritSect);
     1672    return VINF_SUCCESS;
     1673}
     1674
     1675/**
     1676 * Mouse event handler.
     1677 *
     1678 * @returns VBox status code.
     1679 * @param   pInterface      Pointer to the mouse port interface (KBDState::Mouse.IPort).
     1680 * @param   i32cX           The X value.
     1681 * @param   i32cY           The Y value.
     1682 */
     1683static DECLCALLBACK(int) kbdMousePutEventAbs(PPDMIMOUSEPORT pInterface, int32_t i32cX, int32_t i32cY)
     1684{
     1685    KBDState *pThis = RT_FROM_MEMBER(pInterface, KBDState, Mouse.IPort);
     1686    int rc = PDMCritSectEnter(&pThis->CritSect, VERR_SEM_BUSY);
     1687    AssertReleaseRC(rc);
     1688
     1689    pc_kbd_mouse_event_abs(pThis, i32cX, i32cY);
    14251690
    14261691    PDMCritSectLeave(&pThis->CritSect);
     
    16191884    pThis->Mouse.IBase.pfnQueryInterface    = kbdMouseQueryInterface;
    16201885    pThis->Mouse.IPort.pfnPutEvent          = kbdMousePutEvent;
     1886    pThis->Mouse.IPort.pfnPutEventAbs       = kbdMousePutEventAbs;
    16211887
    16221888    /*
  • trunk/src/VBox/Devices/Input/DrvMouseQueue.cpp

    r26173 r26624  
    6969    /** The core part owned by the queue manager. */
    7070    PDMQUEUEITEMCORE    Core;
     71    uint32_t            fAbs;
    7172    int32_t             i32DeltaX;
    7273    int32_t             i32DeltaY;
     
    7475    int32_t             i32DeltaW;
    7576    uint32_t            fButtonStates;
     77    int32_t             i32cX;
     78    int32_t             i32cY;
    7679} DRVMOUSEQUEUEITEM, *PDRVMOUSEQUEUEITEM;
    7780
     
    121124    if (pItem)
    122125    {
     126        pItem->fAbs = 0;
    123127        pItem->i32DeltaX = i32DeltaX;
    124128        pItem->i32DeltaY = i32DeltaY;
     
    132136}
    133137
     138/**
     139 * Queues an absolute mouse event.
     140 * Because of the event queueing the EMT context requirement is lifted.
     141 *
     142 * @returns VBox status code.
     143 * @param   pInterface      Pointer to interface structure.
     144 * @param   i32cX           The X value.
     145 * @param   i32cY           The Y value.
     146 * @thread  Any thread.
     147 */
     148static DECLCALLBACK(int) drvMouseQueuePutEventAbs(PPDMIMOUSEPORT pInterface, int32_t i32cX, int32_t i32cY)
     149{
     150    PDRVMOUSEQUEUE pDrv = IMOUSEPORT_2_DRVMOUSEQUEUE(pInterface);
     151    if (pDrv->fInactive)
     152        return VINF_SUCCESS;
     153
     154    PDRVMOUSEQUEUEITEM pItem = (PDRVMOUSEQUEUEITEM)PDMQueueAlloc(pDrv->pQueue);
     155    if (pItem)
     156    {
     157        pItem->fAbs = 1;
     158        pItem->i32cX = i32cX;
     159        pItem->i32cY = i32cY;
     160        PDMQueueInsert(pDrv->pQueue, &pItem->Core);
     161        return VINF_SUCCESS;
     162    }
     163    return VERR_PDM_NO_QUEUE_ITEMS;
     164}
     165
     166
     167/* -=-=-=-=- IConnector -=-=-=-=- */
     168
     169#define PPDMIMOUSECONNECTOR_2_DRVMOUSEQUEUE(pInterface) ( (PDRVMOUSEQUEUE)((char *)(pInterface) - RT_OFFSETOF(DRVMOUSEQUEUE, IConnector)) )
     170
     171
     172/**
     173 * Pass absolute mode status changes from the guest through to the frontend
     174 * driver.
     175 *
     176 * @param   pInterface  Pointer to the mouse connector interface structure.
     177 * @param   fAbs        The new absolute mode state.
     178 */
     179static DECLCALLBACK(void) drvMousePassThruAbsMode(PPDMIMOUSECONNECTOR pInterface, bool fAbs)
     180{
     181    PDRVMOUSEQUEUE pDrv = PPDMIMOUSECONNECTOR_2_DRVMOUSEQUEUE(pInterface);
     182    pDrv->pDownConnector->pfnAbsModeChange(pDrv->pDownConnector, fAbs);
     183}
     184
     185
    134186
    135187/* -=-=-=-=- queue -=-=-=-=- */
     
    147199    PDRVMOUSEQUEUE        pThis = PDMINS_2_DATA(pDrvIns, PDRVMOUSEQUEUE);
    148200    PDRVMOUSEQUEUEITEM    pItem = (PDRVMOUSEQUEUEITEM)pItemCore;
    149     int rc = pThis->pUpPort->pfnPutEvent(pThis->pUpPort, pItem->i32DeltaX, pItem->i32DeltaY, pItem->i32DeltaZ, pItem->i32DeltaW, pItem->fButtonStates);
     201    int rc;
     202    if (!pItem->fAbs)
     203        rc = pThis->pUpPort->pfnPutEvent(pThis->pUpPort, pItem->i32DeltaX, pItem->i32DeltaY, pItem->i32DeltaZ, pItem->i32DeltaW, pItem->fButtonStates);
     204    else
     205        rc = pThis->pUpPort->pfnPutEventAbs(pThis->pUpPort, pItem->i32cX, pItem->i32cY);
    150206    return RT_SUCCESS(rc);
    151207}
     
    241297    /* IBase. */
    242298    pDrvIns->IBase.pfnQueryInterface        = drvMouseQueueQueryInterface;
     299    /* IMouseConnector. */
     300    pDrv->IConnector.pfnAbsModeChange       = drvMousePassThruAbsMode;
    243301    /* IMousePort. */
    244302    pDrv->IPort.pfnPutEvent                 = drvMouseQueuePutEvent;
     303    pDrv->IPort.pfnPutEventAbs              = drvMouseQueuePutEventAbs;
    245304
    246305    /*
  • trunk/src/VBox/Main/MouseImpl.cpp

    r26235 r26624  
    4646} DRVMAINMOUSE, *PDRVMAINMOUSE;
    4747
    48 
     48/** Converts a PDMIMOUSECONNECTOR pointer to a DRVMAINMOUSE pointer. */
     49#define PPDMIMOUSECONNECTOR_2_MAINMOUSE(pInterface) ( (PDRVMAINMOUSE) ((uintptr_t)pInterface - RT_OFFSETOF(DRVMAINMOUSE, IConnector)) )
    4950
    5051// constructor / destructor
     
    5657{
    5758    mpDrv = NULL;
    58     mLastAbsX = 0;
    59     mLastAbsY = 0;
     59    mLastAbsX = 0x8000;
     60    mLastAbsY = 0x8000;
     61    mLastButtons = 0;
    6062    return S_OK;
    6163}
     
    9395    uHostCaps = 0;
    9496#endif
     97    uDevCaps = 0;
    9598
    9699    /* Confirm a successful initialization */
     
    120123}
    121124
     125
    122126// IMouse properties
    123127/////////////////////////////////////////////////////////////////////////////
    124128
     129int Mouse::getVMMDevMouseCaps(uint32_t *pfCaps)
     130{
     131    AssertPtrReturn(pfCaps, E_POINTER);
     132    VMMDev *pVMMDev = mParent->getVMMDev();
     133    ComAssertRet(pVMMDev, E_FAIL);
     134    PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
     135    ComAssertRet(pVMMDevPort, E_FAIL);
     136
     137    int rc = pVMMDevPort->pfnQueryMouseCapabilities(pVMMDevPort, pfCaps);
     138    return RT_SUCCESS(rc) ? S_OK : E_FAIL;
     139}
     140
     141int Mouse::setVMMDevMouseCaps(uint32_t fCaps)
     142{
     143    VMMDev *pVMMDev = mParent->getVMMDev();
     144    ComAssertRet(pVMMDev, E_FAIL);
     145    PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
     146    ComAssertRet(pVMMDevPort, E_FAIL);
     147
     148    int rc = pVMMDevPort->pfnSetMouseCapabilities(pVMMDevPort, fCaps);
     149    return RT_SUCCESS(rc) ? S_OK : E_FAIL;
     150}
     151
    125152/**
    126153 * Returns whether the current setup can accept absolute mouse
     
    140167    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    141168
    142     CHECK_CONSOLE_DRV (mpDrv);
    143 
    144     ComAssertRet(mParent->getVMMDev(), E_FAIL);
    145     ComAssertRet(mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
    146 
    147     *absoluteSupported = FALSE;
    148     uint32_t mouseCaps;
    149     mParent->getVMMDev()->getVMMDevPort()->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(), &mouseCaps);
    150     *absoluteSupported = mouseCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE;
    151 
    152     return S_OK;
    153 }
    154 
    155 /**
    156  * Returns whether the current setup can accept relative mouse
    157  * events.
     169    if (uDevCaps & MOUSE_DEVCAP_ABSOLUTE)
     170        *absoluteSupported = TRUE;
     171    else
     172    {
     173        CHECK_CONSOLE_DRV (mpDrv);
     174
     175        uint32_t mouseCaps;
     176        int rc = getVMMDevMouseCaps(&mouseCaps);
     177        AssertComRCReturn(rc, rc);
     178        *absoluteSupported = mouseCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE;
     179    }
     180
     181    return S_OK;
     182}
     183
     184/**
     185 * Returns whether the guest can currently draw the mouse cursor itself.
    158186 *
    159187 * @returns COM status code
    160188 * @param absoluteSupported address of result variable
    161189 */
    162 STDMETHODIMP Mouse::COMGETTER(NeedsHostCursor) (BOOL *needsHostCursor)
    163 {
    164     if (!needsHostCursor)
     190STDMETHODIMP Mouse::COMGETTER(NeedsHostCursor) (BOOL *pfNeedsHostCursor)
     191{
     192    if (!pfNeedsHostCursor)
    165193        return E_POINTER;
    166194
     
    172200    CHECK_CONSOLE_DRV (mpDrv);
    173201
    174     ComAssertRet(mParent->getVMMDev(), E_FAIL);
    175     ComAssertRet(mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
    176 
    177     *needsHostCursor = FALSE;
    178     uint32_t mouseCaps;
    179     mParent->getVMMDev()->getVMMDevPort()->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(), &mouseCaps);
    180     *needsHostCursor = mouseCaps & VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR;
    181 
     202    uint32_t fMouseCaps;
     203    int rc = getVMMDevMouseCaps(&fMouseCaps);
     204    AssertComRCReturn(rc, rc);
     205    *pfNeedsHostCursor = !!(  fMouseCaps
     206                            & VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
    182207    return S_OK;
    183208}
     
    186211/////////////////////////////////////////////////////////////////////////////
    187212
    188 /**
    189  * Send a mouse event.
    190  *
    191  * @returns COM status code
    192  * @param dx          X movement
    193  * @param dy          Y movement
    194  * @param dz          Z movement
    195  * @param buttonState The mouse button state
    196  */
    197 STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, LONG buttonState)
    198 {
    199     HRESULT rc = S_OK;
    200 
    201     AutoCaller autoCaller(this);
    202     if (FAILED(autoCaller.rc())) return autoCaller.rc();
    203 
    204     AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    205 
    206     CHECK_CONSOLE_DRV (mpDrv);
    207 
    208     ComAssertRet(mParent->getVMMDev(), E_FAIL);
    209     ComAssertRet(mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
    210 
    211     uint32_t mouseCaps;
    212     LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
    213              dx, dy, dz, dw));
    214     mParent->getVMMDev()->getVMMDevPort()
    215         ->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(),
    216                                     &mouseCaps);
    217     /*
    218      * This method being called implies that the host no
    219      * longer wants to use absolute coordinates. If the VMM
    220      * device isn't aware of that yet, tell it.
    221      */
    222     if (mouseCaps & VMMDEV_MOUSE_HOST_CAN_ABSOLUTE)
    223     {
    224         mParent->getVMMDev()->getVMMDevPort()->pfnSetMouseCapabilities(
    225             mParent->getVMMDev()->getVMMDevPort(), uHostCaps);
    226     }
    227 
     213static uint32_t mouseButtonsToPDM(LONG buttonState)
     214{
    228215    uint32_t fButtons = 0;
    229216    if (buttonState & MouseButtonState_LeftButton)
     
    237224    if (buttonState & MouseButtonState_XButton2)
    238225        fButtons |= PDMIMOUSEPORT_BUTTON_X2;
    239 
    240     int vrc = mpDrv->pUpPort->pfnPutEvent(mpDrv->pUpPort, dx, dy, dz, dw, fButtons);
    241     if (RT_FAILURE(vrc))
    242         rc = setError(VBOX_E_IPRT_ERROR,
    243                       tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
    244                       vrc);
     226    return fButtons;
     227}
     228
     229
     230/**
     231 * Send a relative event to the mouse device.
     232 *
     233 * @returns   COM status code
     234 */
     235int Mouse::reportRelEventToMouseDev(int32_t dx, int32_t dy, int32_t dz,
     236                                    int32_t dw, uint32_t fButtons)
     237{
     238    CHECK_CONSOLE_DRV (mpDrv);
     239
     240    if (dx || dy || dz || dw || fButtons != mLastButtons)
     241    {
     242        PPDMIMOUSEPORT pUpPort = mpDrv->pUpPort;
     243        int vrc = pUpPort->pfnPutEvent(pUpPort, dx, dy, dz, dw, fButtons);
     244
     245        if (RT_FAILURE(vrc))
     246            setError(VBOX_E_IPRT_ERROR,
     247                     tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
     248                     vrc);
     249        AssertRCReturn(vrc, VBOX_E_IPRT_ERROR);
     250    }
     251    return S_OK;
     252}
     253
     254
     255/**
     256 * Send an absolute position event to the mouse device.
     257 *
     258 * @returns   COM status code
     259 */
     260int Mouse::reportAbsEventToMouseDev(uint32_t mouseXAbs, uint32_t mouseYAbs)
     261{
     262    CHECK_CONSOLE_DRV (mpDrv);
     263
     264    if (mouseXAbs != mLastAbsX || mouseYAbs != mLastAbsY)
     265    {
     266        int vrc = mpDrv->pUpPort->pfnPutEventAbs(mpDrv->pUpPort, mouseXAbs,
     267                                                 mouseYAbs);
     268        if (RT_FAILURE(vrc))
     269            setError(VBOX_E_IPRT_ERROR,
     270                     tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
     271                     vrc);
     272        AssertRCReturn(vrc, VBOX_E_IPRT_ERROR);
     273    }
     274    return S_OK;
     275}
     276
     277
     278/**
     279 * Send an absolute position event to the VMM device.
     280 *
     281 * @returns   COM status code
     282 */
     283int Mouse::reportAbsEventToVMMDev(uint32_t mouseXAbs, uint32_t mouseYAbs)
     284{
     285    VMMDev *pVMMDev = mParent->getVMMDev();
     286    ComAssertRet(pVMMDev, E_FAIL);
     287    PPDMIVMMDEVPORT pVMMDevPort = pVMMDev->getVMMDevPort();
     288    ComAssertRet(pVMMDevPort, E_FAIL);
     289
     290    if (mouseXAbs != mLastAbsX || mouseYAbs != mLastAbsY)
     291    {
     292        int vrc = pVMMDevPort->pfnSetAbsoluteMouse(pVMMDevPort,
     293                                                   mouseXAbs, mouseYAbs);
     294        if (RT_FAILURE(vrc))
     295            setError(VBOX_E_IPRT_ERROR,
     296                     tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
     297                     vrc);
     298        AssertRCReturn(vrc, VBOX_E_IPRT_ERROR);
     299    }
     300    return S_OK;
     301}
     302
     303/**
     304 * Send a mouse event.
     305 *
     306 * @returns COM status code
     307 * @param dx          X movement
     308 * @param dy          Y movement
     309 * @param dz          Z movement
     310 * @param buttonState The mouse button state
     311 */
     312STDMETHODIMP Mouse::PutMouseEvent(LONG dx, LONG dy, LONG dz, LONG dw, LONG buttonState)
     313{
     314    HRESULT rc = S_OK;
     315
     316    AutoCaller autoCaller(this);
     317    if (FAILED(autoCaller.rc())) return autoCaller.rc();
     318
     319    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
     320
     321    CHECK_CONSOLE_DRV (mpDrv);
     322
     323    LogRel3(("%s: dx=%d, dy=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
     324             dx, dy, dz, dw));
     325    if (!(uDevCaps & MOUSE_DEVCAP_ABSOLUTE))
     326    {
     327        /*
     328         * This method being called implies that the host no
     329         * longer wants to use absolute coordinates. If the VMM
     330         * device isn't aware of that yet, tell it.
     331         */
     332        uint32_t mouseCaps;
     333        rc = getVMMDevMouseCaps(&mouseCaps);
     334        ComAssertComRCRet(rc, rc);
     335
     336        if (mouseCaps & VMMDEV_MOUSE_HOST_CAN_ABSOLUTE)
     337            setVMMDevMouseCaps(uHostCaps);
     338    }
     339
     340    uint32_t fButtons = mouseButtonsToPDM(buttonState);
     341    rc = reportRelEventToMouseDev(dx, dy, dz, dw, fButtons);
     342    if (SUCCEEDED(rc))
     343        mLastButtons = fButtons;
    245344
    246345    return rc;
    247346}
     347
     348/**
     349 * Convert an X value in screen co-ordinates to a value from 0 to 0xffff
     350 *
     351 * @returns   COM status value
     352 */
     353int Mouse::convertDisplayWidth(LONG x, uint32_t *pcX)
     354{
     355    AssertPtrReturn(pcX, E_POINTER);
     356    Display *pDisplay = mParent->getDisplay();
     357    ComAssertRet(pDisplay, E_FAIL);
     358
     359    ULONG displayWidth;
     360    int rc = pDisplay->COMGETTER(Width)(&displayWidth);
     361    ComAssertComRCRet(rc, rc);
     362
     363    *pcX = displayWidth ? (x * 0xFFFF) / displayWidth: 0;
     364    return S_OK;
     365}
     366
     367/**
     368 * Convert a Y value in screen co-ordinates to a value from 0 to 0xffff
     369 *
     370 * @returns   COM status value
     371 */
     372int Mouse::convertDisplayHeight(LONG y, uint32_t *pcY)
     373{
     374    AssertPtrReturn(pcY, E_POINTER);
     375    Display *pDisplay = mParent->getDisplay();
     376    ComAssertRet(pDisplay, E_FAIL);
     377
     378    ULONG displayHeight;
     379    int rc = pDisplay->COMGETTER(Height)(&displayHeight);
     380    ComAssertComRCRet(rc, rc);
     381
     382    *pcY = displayHeight ? (y * 0xFFFF) / displayHeight: 0;
     383    return S_OK;
     384}
     385
    248386
    249387/**
     
    267405    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
    268406
    269     CHECK_CONSOLE_DRV (mpDrv);
    270 
    271     ComAssertRet(mParent->getVMMDev(), E_FAIL);
    272     ComAssertRet(mParent->getVMMDev()->getVMMDevPort(), E_FAIL);
    273 
    274     uint32_t mouseCaps;
    275407    LogRel3(("%s: x=%d, y=%d, dz=%d, dw=%d\n", __PRETTY_FUNCTION__,
    276408             x, y, dz, dw));
    277     mParent->getVMMDev()->getVMMDevPort()
    278         ->pfnQueryMouseCapabilities(mParent->getVMMDev()->getVMMDevPort(),
    279                                     &mouseCaps);
    280     /*
    281      * This method being called implies that the host wants
    282      * to use absolute coordinates. If the VMM device isn't
    283      * aware of that yet, tell it.
    284      */
    285     if (!(mouseCaps & VMMDEV_MOUSE_HOST_CAN_ABSOLUTE))
    286     {
    287         mParent->getVMMDev()->getVMMDevPort()->pfnSetMouseCapabilities(
    288             mParent->getVMMDev()->getVMMDevPort(),
    289             uHostCaps | VMMDEV_MOUSE_HOST_CAN_ABSOLUTE);
    290     }
    291 
    292     Display *pDisplay = mParent->getDisplay();
    293     ComAssertRet(pDisplay, E_FAIL);
    294 
    295     ULONG displayWidth;
    296     ULONG displayHeight;
    297     rc = pDisplay->COMGETTER(Width)(&displayWidth);
     409
     410    uint32_t mouseXAbs;
     411    rc = convertDisplayWidth(x, &mouseXAbs);
    298412    ComAssertComRCRet(rc, rc);
    299     rc = pDisplay->COMGETTER(Height)(&displayHeight);
     413    uint32_t mouseYAbs;
     414    rc = convertDisplayHeight(y, &mouseYAbs);
    300415    ComAssertComRCRet(rc, rc);
    301 
    302     uint32_t mouseXAbs = displayWidth? (x * 0xFFFF) / displayWidth: 0;
    303     uint32_t mouseYAbs = displayHeight? (y * 0xFFFF) / displayHeight: 0;
    304 
    305     /*
    306      * Send the absolute mouse position to the VMM device.
    307      */
    308     int vrc = mParent->getVMMDev()->getVMMDevPort()
    309         ->pfnSetAbsoluteMouse(mParent->getVMMDev()->getVMMDevPort(),
    310                               mouseXAbs, mouseYAbs);
    311     ComAssertRCRet (vrc, E_FAIL);
    312 
    313     // Check if the guest actually wants absolute mouse positions.
    314     if (mouseCaps & VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE)
    315     {
    316         uint32_t fButtons = 0;
    317         if (buttonState & MouseButtonState_LeftButton)
    318             fButtons |= PDMIMOUSEPORT_BUTTON_LEFT;
    319         if (buttonState & MouseButtonState_RightButton)
    320             fButtons |= PDMIMOUSEPORT_BUTTON_RIGHT;
    321         if (buttonState & MouseButtonState_MiddleButton)
    322             fButtons |= PDMIMOUSEPORT_BUTTON_MIDDLE;
    323         if (buttonState & MouseButtonState_XButton1)
    324             fButtons |= PDMIMOUSEPORT_BUTTON_X1;
    325         if (buttonState & MouseButtonState_XButton2)
    326             fButtons |= PDMIMOUSEPORT_BUTTON_X2;
    327 
    328         /* This is a workaround.  In order to alert the Guest Additions to the
    329          * fact that the absolute pointer position has changed, we send a
    330          * a minute movement event to the PS/2 mouse device.  But in order
    331          * to avoid the mouse jiggling every time the use clicks, we check to
    332          * see if the position has really changed since the last mouse event.
     416    uint32_t fButtons = mouseButtonsToPDM(buttonState);
     417    /* Older guest additions rely on a small phony movement event on the
     418     * PS/2 device to notice absolute events. */
     419    bool fNeedsJiggle = false;
     420
     421    if (uDevCaps & MOUSE_DEVCAP_ABSOLUTE)
     422        rc = reportAbsEventToMouseDev(mouseXAbs, mouseYAbs);
     423    else
     424    {
     425        uint32_t mouseCaps;
     426        rc = getVMMDevMouseCaps(&mouseCaps);
     427        ComAssertComRCRet(rc, rc);
     428        /*
     429         * This method being called implies that the host wants
     430         * to use absolute coordinates. If the VMM device isn't
     431         * aware of that yet, tell it.
    333432         */
    334         if (   ((mLastAbsX == mouseXAbs) && (mLastAbsY == mouseYAbs))
    335             || (mouseCaps & VMMDEV_MOUSE_GUEST_USES_VMMDEV))
    336             vrc = mpDrv->pUpPort->pfnPutEvent(mpDrv->pUpPort, 0, 0, dz, dw,
    337                                               fButtons);
    338         else
    339             vrc = mpDrv->pUpPort->pfnPutEvent(mpDrv->pUpPort, 1, 1, dz, dw,
    340                                               fButtons);
    341         mLastAbsX = mouseXAbs;
    342         mLastAbsY = mouseYAbs;
    343         if (RT_FAILURE(vrc))
    344             rc = setError(VBOX_E_IPRT_ERROR,
    345                           tr("Could not send the mouse event to the virtual mouse (%Rrc)"),
    346                           vrc);
    347     }
    348 
     433        if (!(mouseCaps & VMMDEV_MOUSE_HOST_CAN_ABSOLUTE))
     434            setVMMDevMouseCaps(uHostCaps | VMMDEV_MOUSE_HOST_CAN_ABSOLUTE);
     435
     436        /*
     437         * Send the absolute mouse position to the VMM device.
     438         */
     439        rc = reportAbsEventToVMMDev(mouseXAbs, mouseYAbs);
     440        fNeedsJiggle = !(mouseCaps & VMMDEV_MOUSE_GUEST_USES_VMMDEV);
     441    }
     442    ComAssertComRCRet (rc, rc);
     443    mLastAbsX = mouseXAbs;
     444    mLastAbsY = mouseYAbs;
     445    /* We may need to send a relative event for button information or to
     446     * wake the guest up to the changed absolute co-ordinates. */
     447    /* If the event is a pure wake up one, we make sure it contains some
     448     * (possibly phony) event data to make sure it isn't just discarded on
     449     * the way.  Note: we ignore dw as it is optional. */
     450    if (fNeedsJiggle || fButtons != mLastButtons || dz || dw)
     451        rc = reportRelEventToMouseDev(fNeedsJiggle ? 1 : 0, 0, dz, dw,
     452                                      fButtons);
     453    if (SUCCEEDED(rc))
     454        mLastButtons = fButtons;
    349455    return rc;
    350456}
     
    384490        pData->pMouse->mpDrv = NULL;
    385491    }
     492}
     493
     494
     495DECLCALLBACK(void) Mouse::mouseAbsModeChange (PPDMIMOUSECONNECTOR pInterface, bool fAbs)
     496{
     497    PDRVMAINMOUSE pDrv = PPDMIMOUSECONNECTOR_2_MAINMOUSE (pInterface);
     498    if (fAbs)
     499        pDrv->pMouse->uDevCaps |= MOUSE_DEVCAP_ABSOLUTE;
     500    else
     501        pDrv->pMouse->uDevCaps &= ~MOUSE_DEVCAP_ABSOLUTE;
     502    /** @todo we have to hack around the fact that VMMDev may not be
     503     * initialised too close to startup.  The real fix is to change the
     504     * protocol for onMouseCapabilityChange so that we no longer need to
     505     * query VMMDev, but that requires more changes that I want to do in
     506     * the next commit, so it must be put off until the followup one. */
     507    uint32_t fMouseCaps = 0;
     508    int rc = S_OK;
     509    if (   pDrv->pMouse->mParent->getVMMDev()
     510        && pDrv->pMouse->mParent->getVMMDev()->mpDrv)
     511        rc = pDrv->pMouse->getVMMDevMouseCaps(&fMouseCaps);
     512    AssertComRCReturnVoid(rc);
     513    pDrv->pMouse->getParent()->onMouseCapabilityChange (fAbs, fMouseCaps & VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR);
    386514}
    387515
     
    411539     */
    412540    pDrvIns->IBase.pfnQueryInterface        = Mouse::drvQueryInterface;
     541
     542    pData->IConnector.pfnAbsModeChange      = Mouse::mouseAbsModeChange;
    413543
    414544    /*
  • trunk/src/VBox/Main/include/MouseImpl.h

    r26173 r26624  
    4646typedef ConsoleEventBuffer<MouseEvent> MouseEventBuffer;
    4747
     48enum
     49{
     50    MOUSE_DEVCAP_ABSOLUTE = 1
     51};
     52
    4853class ATL_NO_VTABLE Mouse :
    4954    public VirtualBoxBase,
     
    9095    static const PDMDRVREG  DrvReg;
    9196
     97    Console *getParent() const
     98    {
     99        return mParent;
     100    }
     101
    92102private:
    93103
    94104    static DECLCALLBACK(void *) drvQueryInterface(PPDMIBASE pInterface, const char *pszIID);
     105    static DECLCALLBACK(void)   mouseAbsModeChange (PPDMIMOUSECONNECTOR pInterface, bool fAbs);
    95106    static DECLCALLBACK(int)    drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags);
    96107    static DECLCALLBACK(void)   drvDestruct(PPDMDRVINS pDrvIns);
     108   
     109    int getVMMDevMouseCaps(uint32_t *pfCaps);
     110    int setVMMDevMouseCaps(uint32_t fCaps);
     111    int reportRelEventToMouseDev(int32_t dx, int32_t dy, int32_t dz,
     112                                 int32_t dw, uint32_t fButtons);
     113    int reportAbsEventToMouseDev(uint32_t mouseXAbs, uint32_t mouseYAbs);
     114    int reportAbsEventToVMMDev(uint32_t mouseXAbs, uint32_t mouseYAbs);
     115    int convertDisplayWidth(LONG x, uint32_t *pcX);
     116    int convertDisplayHeight(LONG y, uint32_t *pcY);
     117    bool needsRelativeEvent(uint32_t cXAbs, uint32_t cYAbs, int32_t dz, int32_t dw, uint32_t fButtons, uint32_t fCaps);
    97118
    98119    const ComObjPtr<Console, ComWeakRef> mParent;
     
    101122
    102123    LONG uHostCaps;
     124    LONG uDevCaps;
    103125    uint32_t mLastAbsX;
    104126    uint32_t mLastAbsY;
     127    uint32_t mLastButtons;
    105128};
    106129
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette